I have this code
struct curl_slist *pCURL_List = NULL;
pCURL_List = curl_slist_append(pCURL_List, "Content-type: application/x-amf");
curl_easy_setopt(m_pCURL, CURLOPT_HTTPHEADER, pCURL_List);
curl_easy_perform(m_pCURL);
and right after curl_easy_perform(m_pCURL); I need to reset the headers (the first part of the code). If I do curl_slist_free_all(pCURL_List); the next curl_easy_perform(m_pCURL); crashes the program.
I sure have the other parameters, the program is quite big and everything works EXCEPT calls after these lines.
Also, when I said that I need to reset the headers, I mean that I'd like curl to set back the old default values of Content-type. If I do
pCURL_List = curl_slist_append(pCURL_List, "Content-type:");
afaik it will delete the "Content-type" header.
For the crash, did you set CURLOPT_HTTPHEADER back to null before calling curl_easy_perform the second time? I'm thinking the list itself was freed but the CURL handle still has a pointer to the now invalid memory.
Related
I have a python test script that performs an API streaming using requests.post(). It looks like so:
response = requests.post(url_events, data="XYZ", stream=True, headers = {"A":"B"})
if (response.ok):
for chunk in response.iter_content(chunk_size=256):
print chunk
I'm trying to figure out how can I have the same logic but using C++. From what I found the curl library may help, however I cannot find how to pass data field. This is the code I have so far:
CURL* connection = curl_easy_init();
// set url
curl_easy_setopt(connection, CURLOPT_URL, url_events);
// set header
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "A:B");
code = curl_easy_setopt(connection, CURLOPT_HTTPHEADER, headers);
// set streaming callback that will print every received message
curl_easy_setopt(connection, CURLOPT_WRITEFUNCTION, printCallback);
// start connection
code = curl_easy_perform(connection);
// ...
curl_easy_cleanup(connection);
curl_slist_free_all(headers);
I was looking through the curl.h file trying to find how to specify the data field, but nothing seems to fit (based on the name)?
Am I on the right track? Would using curl be the right approach for my task, or should I be looking into some other C,C++ libraries? An example that does the same task as above request.post() is appreciated, or a suggestion how to achieve the same using curl.
I have noticed that libcurl for C++ changes the URL provided to some weird symbols. Here is the code:
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
cout << "http://subdomain.mydomain.com/folder/check.php?key=" + key << endl;
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://subdomain.mydomain.com/folder/check.php?key=" + addon_key);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl_handle);
That's what I get in the console:
http://subdomain.mydomain.com/folder/check.php?key=tasdasm34234k23l423m4234mn23n4jk23bjk4b23nasdasdasdasdsdsd
* Rebuilt URL to: � ��g/
* IDN support not present, can't parse Unicode domains
* getaddrinfo(3) failed for � ��g:80
* Couldn't resolve host '� ��g'
* Closing connection 0
This code works perfectly fine when I build my project in Windows, but when I build it with Linux, this happens. If I just try to access "http://subdomain.mydomain.com/folder/check.php" with this code, it works, but as soon as I add the key, libcurl changes the whole URL.
Thanks in advance.
Like I said in my comment, the CURL library is a library of C functions, and C functions doesn't know anything about objects or classes from C++.
When you do "http://subdomain.mydomain.com/folder/check.php?key=" + addon_key the result is a (temporary) std::string object. Passing that to a C function will not work well, and I'm surprised that the compiler actually let you pass that argument without complaining. It should have been a compiler error I think, or at the very least should give you a stern warning.
You can solve this by creating another variable to store the string object, and the use the c_str member function to get a C-style string (a pointer to constant char):
std::string url = "http://subdomain.mydomain.com/folder/check.php?key=" + addon_key;
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
I don't know if cURL copies the string, or if you need to keep the url variable alive until you're all done.
That it apparently work on Windows is nothing more than pure luck. Passing a C++ object to a function that does not expect it is undefined behavior.
The libcurl examples contains an example for custom HTTP headers.
The example makes use of curl_slist_append like this:
struct curl_slist *chunk = NULL;
/* Remove a header curl would otherwise add by itself */
chunk = curl_slist_append(chunk, "Accept:");
/* Add a custom header */
chunk = curl_slist_append(chunk, "Another: yes");
/* Modify a header curl otherwise adds differently */
chunk = curl_slist_append(chunk, "Host: example.com");
/* Add a header with "blank" contents to the right of the colon. Note that
we're then using a semicolon in the string we pass to curl! */
chunk = curl_slist_append(chunk, "X-silly-header;");
According to the documentation of curl_slist_append a null pointer will be returned if something goes wrong:
RETURN VALUE
A null pointer is returned if anything went wrong, otherwise the new
list pointer is returned.
Question:
When for example the call
chunk = curl_slist_append(chunk, "Another: yes");
fails, won't the original list, that chunk previously pointed to, be lost? And as a consequence: won't this leak memory?
Or is there some magic that I am missing and that is not mentioned in the curl_slist_append documentation?
To make matters worse: won't the next call to curl_slist_append possibly create a new list (unlikely as we are probably out of memory already, but possible)?
Your suspicions seem entirely correct. The source for curl_slist_append can be viewed here.
I have a code, where, in one local function I use curl_easy_setopt to set the proxy URL. And in another local function I call curl_easy_perform. But when te control moves from one function to another, the proxy url set using local variable contains junk characters and the DNS query returns an error. The libcurl help page says that when we do setopt the string values is copied by the curl library. But I feel the library just referes to that value whenever it needs it. It doesn't copy the string. So if local variable is used to set proxy url, it will contain junk by the time I call curl_easy_perform.
Following is the example code snippet.
void funcSetOpt
{
char ProxyUrl[] = "someproxy";
curl_easy_setopt(curlHandle, CURLOPT_PROXY, ProxyUrl);
}
void funcPerform
{
curl_easy_perform(curlHandle);
}
That would imply that you're using a fairly old libcurl version and the following section from the curl_easy_setopt man page might affect you:
Before version 7.17.0, strings were not copied. Instead the user was
forced keep them available until libcurl no longer needed them.
Currently, I'm working on a HTTP Proxy using libcurl in C++.
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
Above is my code to customize HTTP request header. The headers parameter is a curl_slist pointer variable. I have append all necessary heads information like Accept, Keep Alive, Referer and so on using curl_slist_append() method. However, when I used wireshark to observe the network traffic, I found that CURL didn't use my customized headers while it used "Accept: * / *\r\n".
Does anyone know how to disable the internal header of CURL?
try CURLOPT_ENCODING, don't know about C++ but in PHP:
The contents of the "Accept-Encoding: " header. This enables decoding
of the response. Supported encodings are "identity", "deflate", and
"gzip". If an empty string, "", is set, a header containing all
supported encoding types is sent.
CURLOPT_HTTPHEADER is the way to add, remove or replace internally used headers. If you have problems with this, show us a full program that repeats the problem and we might be able to help out.