I'm struggeling with doing a GET request passing a query string. Everytime I run it I get 410 gone response, I checked if the link got deleted but it's still accessible.
My code:
CURLUcode rc;
CURLU* url = curl_url();
CURL* handle = curl_easy_init();
CURLcode res;
struct curl_slist* list = NULL;
if (handle) {
rc = curl_url_set(url, CURLUPART_HOST, "www.example.com", 0);
rc = curl_url_set(url, CURLUPART_QUERY,"b=sashio", CURLU_APPENDQUERY);
rc = curl_url_set(url, CURLUPART_QUERY, "id=me_ZwNjBQRlZGL0AwR0ZQNjAQR1AQZ3At==", CURLU_APPENDQUERY);
rc = curl_url_set(url, CURLUPART_SCHEME, "http", 0);
rc = curl_url_set(url, CURLUPART_PATH, "/en/m.php?", 0);
curl_easy_setopt(handle, CURLOPT_CURLU, url);
list = curl_slist_append(list, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(handle, CURLOPT_ENCODING, "");
}
res = curl_easy_perform(handle);
Verbose output :
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 410 Gone
< Date: Wed, 12 Aug 2020 19:41:23 GMT
< Server: Apache
< X-UA-Compatible: IE=EmulateIE9
< Last-Modified: Wed, 12 Aug 2020 19:41:23 GMT
< Cache-Control: private, must-revalidate, max-age=0
< Etag: "1804121564-00010031-BZGZ0AGt5BQt2AGD1ZQZ1AmV"
< Set-Cookie: PHPSESSID=tp3mbkk7148cm989areejhhd90; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Pragma: no-cache
< Content-Length: 192
< Connection: close
< Content-Type: text/html
<
* Closing connection 0
Thanks for everyone specially #AndreasWenzel. The browser was sending a cookie to the server like AndreasWenzel said. So in the headers I added the cookie, now I receive a correct response.
Have a nice day!
Related
I'm trying to send an image buff with cUrl to the telegram API using c++. Just to know I' m developing on Windows 10.
Here is all I have done.
First I send a photo from my hard drive using curl from terminal using this command:
curl -s -X POST "https://api.telegram.org/bottoken/sendPhoto" -F chat_id=id -F photo="#D:/a.jpg"
On the telegram chat I receive the photo with this command meanwhile on the console in which I did the cUrl request I have a response like this:
{"ok":true,"result":{"message_id":2398,"from":{"id":id,"is_bot":true,"first_name":"botname","username":"stuff"},"chat":{"id":chatid,"first_name":"userdata","username":"userdata","type":"private"},"date":1588929212,"photo":[{"file_id":"reallylongfileid","file_unique_id":"shorterid","file_size":26307,"width":240,"height":320}]}}
If I import this request using the Import tab and selecting raw text in Postman and execute it I have this response:
{
"ok": false,
"error_code": 400,
"description": "Bad Request: wrong HTTP URL specified"
}
If I try to use the postman generated code:
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
// I added CURLOPT_VERBOSE
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.telegram.org/bottoken/sendPhoto");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
struct curl_slist *headers = NULL;
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_mime *mime;
curl_mimepart *part;
mime = curl_mime_init(curl);
part = curl_mime_addpart(mime);
curl_mime_name(part, "chat_id");
curl_mime_data(part, "mychatid", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(mime);
curl_mime_name(part, "photo");
curl_mime_data(part, "#D:/a.jpg", CURL_ZERO_TERMINATED);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
res = curl_easy_perform(curl);
curl_mime_free(mime);
}
curl_easy_cleanup(curl);
I have this response on the console:
* Trying 149.154.167.220...
* TCP_NODELAY set
* Connected to api.telegram.org (149.154.167.220) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* SSL certificate problem: self signed certificate in certificate chain
* Closing connection 0
So I added this option to the code I wrote before:
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
and the new response is:
* Trying 149.154.167.220...
* TCP_NODELAY set
* Connected to api.telegram.org (149.154.167.220) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: OU=Domain Control Validated; CN=api.telegram.org
* start date: Mar 24 13:48:17 2020 GMT
* expire date: May 23 16:17:38 2022 GMT
* subjectAltName: host "api.telegram.org" matched cert's "api.telegram.org"
* issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU=http://certs.godaddy.com/repository/; CN=Go Daddy Secure Certificate Authority - G2
* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> POST /botmybottoken/sendPhoto HTTP/1.1
Host: api.telegram.org
Accept: */*
Content-Length: 254
Content-Type: multipart/form-data; boundary=------------------------9b6fc10336ea9470
* We are completely uploaded and fine
* old SSL session ID is stale, removing
< HTTP/1.1 400 Bad Request
< Server: nginx/1.16.1
< Date: Fri, 08 May 2020 09:25:10 GMT
< Content-Type: application/json
< Content-Length: 83
< Connection: keep-alive
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: Content-Length,Content-Type,Date,Server,Connection
<
{"ok":false,"error_code":400,"description":"Bad Request: wrong HTTP URL specified"}* Connection #0 to host api.telegram.org left intact
* Closing connection 0
If I try to send this image buffer:
cv::Mat img(260, 301, CV_8UC3, cv::Scalar(0, 0, 0));
std::vector<uchar> buff;
std::vector<int> param(2);
param[0] = cv::IMWRITE_JPEG_QUALITY;
param[1] = 80;
cv::imencode(".jpg", img, buff, param);
std::string strImg((char*)buff.data(), buff.size());
And if I modify the request code only from this:
curl_mime_data(part, "#D:/a.jpg", CURL_ZERO_TERMINATED);
To this:
curl_mime_data(part, strImg.data(), strImg.size());
I have this response in the console:
* Trying 149.154.167.220...
* TCP_NODELAY set
* Connected to api.telegram.org (149.154.167.220) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: OU=Domain Control Validated; CN=api.telegram.org
* start date: Mar 24 13:48:17 2020 GMT
* expire date: May 23 16:17:38 2022 GMT
* subjectAltName: host "api.telegram.org" matched cert's "api.telegram.org"
* issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU=http://certs.godaddy.com/repository/; CN=Go Daddy Secure Certificate Authority - G2
* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> POST /botmybottoken/sendPhoto HTTP/1.1
Host: api.telegram.org
Accept: */*
Content-Length: 2164
Content-Type: multipart/form-data; boundary=------------------------f5bde0e2e0ef8114
Expect: 100-continue
* old SSL session ID is stale, removing
< HTTP/1.1 100 Continue
* We are completely uploaded and fine
< HTTP/1.1 400 Bad Request
< Server: nginx/1.16.1
< Date: Fri, 08 May 2020 09:30:34 GMT
< Content-Type: application/json
< Content-Length: 128
< Connection: keep-alive
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: Content-Length,Content-Type,Date,Server,Connection
<
{"ok":false,"error_code":400,"description":"Bad Request: wrong remote file identifier specified: Wrong character in the string"}* Connection #0 to host api.telegram.org left intact
* Closing connection 0
I don't want to use any c++ telegram bot library because I have just to send a Message or a photo.
I' m able to send a message with cUrl code.
With photos, I have some problems.
Because I have to do this two simple actions I prefer to use only cUrl and nothing else.
I need help cause I'm not understanding what's wrong.
I know I write a lot but I wish this could help you to understand everything better and faster.
Thank you!
int sendTelegramPhoto(string chat_id, string path_to_photo, string caption = NULL){
CURL *curl;
CURLcode response;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.telegram.org/bottoken/sendPhoto");
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
struct curl_slist *headers = NULL;
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_slist_append(headers, "Content-Type: multipart/form-data");
curl_slist_append(headers, "charset=utf-8");
curl_mime *mime;
curl_mimepart *part;
mime = curl_mime_init(curl);
part = curl_mime_addpart(mime);
curl_mime_name(part, "chat_id");
curl_mime_data(part, chat_id.c_str(), CURL_ZERO_TERMINATED);
part = curl_mime_addpart(mime);
curl_mime_name(part, "photo");
curl_mime_filedata(part, path_to_photo.c_str());
curl_mime_type(part, "image/jpeg");
part = curl_mime_addpart(mime);
curl_mime_name(part, "caption");
curl_mime_data(part, caption.c_str().c_str(), CURL_ZERO_TERMINATED);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
response = curl_easy_perform(curl);
curl_mime_free(mime);
curl_slist_free_all(headers);
}
curl_easy_cleanup(curl);
return 0;
}
cv::Mat img(260, 301, CV_8UC3, cv::Scalar(0, 0, 0));
std::vector<uchar> buff;
std::vector<int> param(2);
param[0] = cv::IMWRITE_JPEG_QUALITY;
param[1] = 80;
cv::imencode(".jpg", img, buff, param);
std::string strImg((char*)buff.data(), buff.size());
CURLcode ret;
CURL* hnd;
curl_mime* mime1;
curl_mimepart* part1;
mime1 = NULL;
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "https://api.telegram.org/bottoken/sendPhoto");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
mime1 = curl_mime_init(hnd);
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, "mychatid", CURL_ZERO_TERMINATED);
curl_mime_name(part1, "chat_id");
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, strImg.data(), strImg.size());
curl_mime_filename(part1, "myimage.jpg");
curl_mime_name(part1, "photo");
curl_easy_setopt(hnd, CURLOPT_MIMEPOST, mime1);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.87.0-DEV");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
ret = curl_easy_perform(hnd);
...
So I've taken up the challenge of doing webhooks in c++ and I wanted to just get some help with the post requests. Here is the code I have at the moment, I wanted to send embeds through post requests in C++.
Here is my code along with errors and all, the webhook is still active if you want to test yourself. Am trying to keep it all using windows librarys on purpose.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int Plug(string address, string port, SOCKET* csock) {
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
PADDRINFOA result;
ADDRINFOA hints;
ZeroMemory(&hints, sizeof(ADDRINFO));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int res = getaddrinfo(address.c_str(), port.c_str(), &hints, &result);
*csock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == connect(*csock, (SOCKADDR*)result->ai_addr, sizeof(SOCKADDR))) return WSAGetLastError();
return 0;
}
void Unplug(SOCKET* csock) {
closesocket(*csock);
WSACleanup();
}
string PostRequest(string host, string query, string data) {
string req = "POST " + query + " HTTP/1.1" + "\r\n";
req += "Host: " + host + "\r\n";
req += "Content-Type: application/x-www-form-urlencoded\r\n";
req += "Content-Length: " + to_string(data.length()) + "\r\n";
req += "Connection: Close";
req += "\r\n\r\n" + data + "\r\n\r\n";
SOCKET s;;
Plug(host, "80", &s);
Send(&s, req);
while (GetAvailable(&s) == 0) Sleep(10);
string result = Receive(&s);
//if (result.find("\r\n\r\n") == string::npos && DEBUG) return result;
//if (result.find("\r\n\r\n") == string::npos) return "PR_INVALID_RESPONSE";
//result = result.substr(result.find("\r\n\r\n") + 4, string::npos);
Unplug(&s);
return result;
}
int main() {
//https://discordapp.com/api/webhooks/705211476553629747/zwzqZMnTTgLtHBm3kc_DvvD71IW9FfE4ur-PQlkgeZhd56cT7UjSJCWI-V8wPiEUWV2w
std::cout<<PostRequest("162.159.129.233","/api/webhooks/705249405141516360/s8ioXr6IZEeuPnMi1O37CmY3o5pUZcu6ho7aIJdieSAqgGyTXOZjkOZdMNe1uJre6dto","{'embeds': [{'description': '**ERROR**: `TESTSTRING`\n', 'color': 4508791}]}");
}
However when I make the post requests it is unable to send my content and instead returns 400. I've tried a few more things but Im wondering if its my query?
HTTP/1.1 301 Moved Permanently
Cache-Control: max-age=3600
Cf-Ray: 58bd304dec1ff2c0-WAW
Cf-Request-Id: 026a1c84ad0000f2c054113200000001
Date: Thu, 30 Apr 2020 00:36:28 GMT
Expires: Thu, 30 Apr 2020 01:36:28 GMT
Location: MYWEBHOOKURL
Server: cloudflare
Set-Cookie: __cfruid=5adc23f36cce3f0a398b8f9e91429b4349ef9314-1588206988; path=/; domain=.discordapp.com; HttpOnly
Vary: Accept-Encoding
Content-Length: 0
Connection: close
And lets say I use discords actual ip instead of resolving it I end up getting
this instead
HTTP/1.1 403 Forbidden
Cache-Control: max-age=15
Cf-Ray: 58bd37782e6dffbc-WAW
Cf-Request-Id: 026a20ff1a0000ffbcc89df200000001
Content-Type: text/plain; charset=UTF-8
Date: Thu, 30 Apr 2020 00:41:21 GMT
Expires: Thu, 30 Apr 2020 00:41:36 GMT
Server: cloudflare
Set-Cookie: __cfduid=d4cb17401215362929759e2da8110f0e31588207281; expires=Sat, 30-May-20 00:41:21 GMT; path=/; domain=.162.159.129.233; HttpOnly; SameSite=Lax
Vary: Accept-Encoding
Content-Length: 16
Connection: close
error code: 1003
If you have any ideas dont hesitate to put them down below, ive been lost on this for a long time.
You could just use D++ to post to webhooks:
https://dpp.dev/classdpp_1_1webhook.html
In fact you could do everything with this lib instead of rolling your own solution.
I am using libcurl with C++ in order send a POST request off to query some information off of RateBeer on a particular beer. It says the data has been sent off but I am getting a "POST fields empty" error (which is from the graphQL side I assume).
The following is a dump of the current result (I have a print of the raw post data as well)
* Trying 13.249.142.63...
* TCP_NODELAY set
* Connected to api.r8.beer (13.249.142.63) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=*.r8.beer
* start date: Aug 14 00:00:00 2018 GMT
* expire date: Sep 14 12:00:00 2019 GMT
* subjectAltName: host "api.r8.beer" matched cert's "*.r8.beer"
* issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
* SSL certificate verify ok.
> POST /v1/api/graphql/ HTTP/1.1
Host: api.r8.beer
User-Agent: libcurl-agent/1.0
Content-Type:application/json
Accept:application/json
x-api-[key:Removed for privacy]
Transfer-Encoding: chunked
cb
* upload completely sent off: 210 out of 203 bytes
< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json
< Content-Length: 61
< Connection: keep-alive
< Date: Thu, 31 Jan 2019 16:07:38 GMT
< x-amzn-RequestId: 547d7bc7-2572-11e9-b411-af48978c268e
< CF-RAY: 4a1d6eb288bda66b-DUB
< Access-Control-Allow-Origin: *
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, x-api-key, x-api-auth
< x-amzn-Remapped-Connection: keep-alive
< X-Request-Id: 54b37fa0-2572-11e9-ac7f-9d4fc71779d1
< Set-Cookie: __cfduid=d84de3db6937ad5bef73abca5ae68e43a1548950858; expires=Fri, 31-Jan-20 16:07:38 GMT; path=/; domain=.r8.beer; HttpOnly; Secure
< x-amz-apigw-id: UYGDpFkeDoEFR2w=
< x-amzn-Remapped-Server: cloudflare
< X-Powered-By: Express
< x-amzn-Remapped-Date: Thu, 31 Jan 2019 16:07:38 GMT
< X-Cache: Error from cloudfront
< Via: 1.1 feeead777aa6b11f4775062f1953fdc4.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: kg0xraCi9C9zdmNff3iEZXOBpTMKPwNSQa6nzV-tyXqCdVCFFOP2Jg==
<
* Connection #0 to host api.r8.beer left intact
{"query":"query{\nTruth:beerSearch(query: \"Truth\", first : 5) {\n...beerfields\n}\n}\nfragment beerfields on BeerList{\nitems{\nname\nbrewer{\nname\n}\ndescription\nratingCount\n}\n}","variables":"{}"}
Response: POST body missing. Did you forget use body-parser middleware Response End
Some debugging I have tried in this conquest:
Changing the code to use a readback callback instead of using the POST_FIELDS default, same result
Messing with the capitalization of headers
Changed the transfer method to using chunked
Trying to POST to the sandbox API and the production API
Here is the query function:
NOTE: m_api is just a member with the api key and the api base URL
void cURLWrapperRateBeer::QueryBeerList(const CBeerList& inBeerList)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl)
{
// Construct the header struct
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type:application/json");
headers = curl_slist_append(headers, "Accept:application/json");
std::string keyPhrase = std::string("x-api-key:").append(m_api.second);
headers = curl_slist_append(headers, keyPhrase.c_str());
headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
// Set the URL and the data we want
curl_easy_setopt(curl, CURLOPT_URL, m_api.first.c_str());
// Signify our intention to post data
curl_easy_setopt(curl, CURLOPT_POST, 1L);
// Verbose Output
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// Give it a user agent
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
std::string data = CreateRequestURL(inBeerList);
data.append("\0");
// Set up the data container for our push request
const char* c_data = data.c_str();
std::cout << c_data;
struct WriteStatus data_container;
data_container.p = c_data;
data_container.remaining = (long)strlen(c_data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_container.p);
/*
Define the buffer for writing memory and what the callback function will
use for its buffer
*/
//curl_easy_setopt(curl, CURLOPT_READFUNCTION, &cURLWrapperRateBeer::ReadData);
//curl_easy_setopt(curl, CURLOPT_READDATA, &data_container);
// Size of the data
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)data_container.remaining);
// Handler for reading response
std::string response;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &cURLWrapperRateBeer::WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
// Set our custom set of headers
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
//std::cout << "DUMP : " << data_container.p;
}
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
std::cout << "Response: " << response;
std:: cout << "Response End";
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
}
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
I am writing an application for work that needs to perform HTTP requests to a server, and get a response, in JSON back.
At the moment, my code connects to the server, and gets a response back, which is great. However, I also need to send data to the server, which will process it, and send me the jSON.
My problem is that I am able to send, thanks to POSTFIELDS, only a single "field", and won't get any response if I insert more that one.
The code is the following:
// writefunc works, so there is no point adding its code in here
size_t Simulator::writefunc(void *ptr, size_t size, size_t nmemb, struct string *buffer_in);
void Simulator::move(Player *player)
{
std::ostringstream ss_url;
ss_url << API_URL << "functionCalled";
char const *url = ss_url.str().c_str();
std::ostringstream ss_postfields;
// This will not work - And all values do NOT contain any space
// The server do NOT receive any data (in POST and GET)
ss_postfields << "user_name=" << player->getName()
<< "&user_secret=" << player->secret()
<< "&app_id=" << player->getApp_id()
<< "&lat=" << player->getLocation()->getLat()
<<"&lon=" << player->getLocation()->getLon();
// This will not work either
// ss_postfields << "user_name=nicolas&app_id=2";
// This works and will send the data to the server, which will receive and process it.
// ss_postfields << "user_name=" << player->getName();
const char *postfields = ss_postfields.str().c_str();
CURL *curl_handle;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
if(curl_handle){
struct string s;
init_string(&s);
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &s);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, postfields);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(postfields));
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
CURLcode res = curl_easy_perform(curl_handle);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
exit(0);
}
printf("%s\n", s.ptr);
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
}
}
I thought I would also give the output of CURLOPT_HEADER and CURLOPT_VERBOSE for when I send only 1 value, or multiple values:
When I Send One value only:
* About to connect() to localhost port 8888 (#0)
* Trying ::1...
* connected
* Connected to localhost (::1) port 8888 (#0)
> POST [api_url] HTTP/1.1
Host: localhost:8888
Accept: */*
Content-Length: 22
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 22 out of 22 bytes
< HTTP/1.1 200 OK
< Date: Sun, 24 Nov 2013 17:25:14 GMT
< Server: Apache
< X-Powered-By: PHP/5.3.20
< Cache-Control: no-cache
< X-Debug-Token: a41727
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* Connection #0 to host localhost left intact
0
HTTP/1.1 200 OK
Date: Sun, 24 Nov 2013 17:25:14 GMT
Server: Apache
X-Powered-By: PHP/5.3.20
Cache-Control: no-cache
X-Debug-Token: a41727
Transfer-Encoding: chunked
Content-Type: application/json
[ OUTPUT FROM SERVER HERE ]
* Closing connection #0
And when I send multiple values:
* About to connect() to localhost port 8888 (#0)
* Trying ::1...
* connected
* Connected to localhost (::1) port 8888 (#0)
> POST [api_url] HTTP/1.1
Host: localhost:8888
Accept: */*
Content-Length: 1
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 1 out of 1 bytes
< HTTP/1.1 200 OK
< Date: Sun, 24 Nov 2013 17:30:13 GMT
< Server: Apache
< X-Powered-By: PHP/5.3.20
< Cache-Control: no-cache
< X-Debug-Token: d1947e
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* Connection #0 to host localhost left intact
0
HTTP/1.1 200 OK
Date: Sun, 24 Nov 2013 17:30:13 GMT
Server: Apache
X-Powered-By: PHP/5.3.20
Cache-Control: no-cache
X-Debug-Token: d1947e
Transfer-Encoding: chunked
Content-Type: application/json
[ OUTPUT FROM SERVER HERE ]
* Closing connection #0
Well you seem to be missing an equals sign!
ss_postfields << "user_name=" << player->getName()
<< "&user_secret=" << player->secret()
<< "&app_id=" << player->getApp_id()
<< "&lat=" << player->getLocation()->getLat()
<<"&lon=" << player->getLocation()->getLon();
instead of
ss_postfields << "user_name=" << player->getName()
<< "&user_secret" << player->secret()
<< "&app_id=" << player->getApp_id()
<< "&lat=" << player->getLocation()->getLat()
<<"&lon=" << player->getLocation()->getLon();
Since I was in a rush, I rewrote everything using HTTP sockets. But I could not be done with this issue, so I went back to it, and finally found the problem. It seems like cUrl does not really like streams.
I thought I would update this post in the case anyone is having the same issue:
Therefore, something like the following will NOT work:
std::ostringstream ss_postfields;
// This will not work - And all values do NOT contain any space
// The server do NOT receive any data (in POST and GET)
ss_postfields << "user_name=" << player->getName()
<< "&user_secret=" << player->getSecret();
const char *postfields = ss_postfields.str().c_str();
// ...
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, postfields);
CURLcode res = curl_easy_perform(curl_handle);
However, and bizarrely, this will work:
std::string str_postfields;
std::string user_name = player->getName();
std::string user_secret = player->getSecret();
std::string str_postfields = "user_name=" +user_name +"&user_secret=" +user_secret;
const char *postfields = str_postfields.c_str();
// ...
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, postfields);
CURLcode res = curl_easy_perform(curl_handle);
I wrote this simple code to check network connection or our iOS apps:
int CL_Network::checkConnectionInt1(){
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
curl_easy_cleanup(curl);
return -1;
}
Our test are ok, return 0 when Wi-Fi enabled, but Apple reviewer return 23 (CURL_WRITE_ERROR) with Wi-Fi enable or disable.
The reviewer tells us others strange behaviors (considering Wi-Fi enabled)
iPod touch with iOS 5.1 returns 0, with same Wi-Fi where iPhone5 with iOS 6.3 returns 23
iPhone 5 with iOS 6.3 run step by step debug returns 0 (I don't know if it is happened only one time or always)
Have you any suggestions?
Last note, verbose output of curl_easy_perform
About to connect() to www.google.com port 80 (#0)
Trying 173.194.35.20...
connected
Connected to www.google.com (173.194.35.20) port 80 (#0)
GET / HTTP/1.1 Host: www.google.com Accept: /
< HTTP/1.1 302 Found < Location: http://www.google.it/ <
Cache-Control: private < Content-Type: text/html; charset=UTF-8 <
Set-Cookie:
PREF=ID=08f8ea131f5d39dd:FF=0:TM=1367680782:LM=1367680782:S=at5IyKNTpeoFFnif; expires=Mon, 04-May-2015 15:19:42 GMT; path=/; domain=.google.com <
Set-Cookie:
NID=67=uPKHTXNtVuYy4QOwVHstK4NzMGZcDssYW.....;
expires=Sun, 03-Nov-2013 15:19:42 GMT; path=/; domain=.google.com;
HttpOnly < P3P: CP="This is not a P3P policy! See
http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657
for more info." < Date: Sat, 04 May 2013 15:19:42 GMT < Server: gws <
Content-Length: 218 < X-XSS-Protection: 1; mode=block <
X-Frame-Options: SAMEORIGIN <
302 Moved 302 Moved The document
has moved here.
* Connection #0 to host www.google.com left intact
* Closing connection #0 2013-05-04 17:19:42.183
testcurl[1468:c07] checkConnection 1: 0
You need to write a writecallback as well
size_t CurlWriteCallback(char* buf, size_t size, size_t nmemb, void* up)
{
TRACE("CURL - Response received:\n%s", buf);
TRACE("CURL - Response handled %d bytes:\n%s", size*nmemb);
// tell curl how many bytes we handled
return size*nmemb;
}
// ...
int CL_Network::checkConnectionInt1(){
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
curl_easy_cleanup(curl);
return -1;
}