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);
...
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);
...
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 have trouble executing a LibCurl statement, at least it seems. I try to send off a 15MB file to a port where a script is listening that will process the file and return a response. However, before I get any response, the program crashes (only on 1 pptx file of 15MB, which is way larger than 'normal' other files)
However, does anyone see something strange in the LibCurl logs:
* timeout on name lookup is not supported
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 13621 (#0)
> PUT //File processing argument//
Host: localhost:13621
Accept: application/json
Accept: application/json
Content-Length: 15828910
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Tue, 14 Mar 2017 20:37:41 GMT
< Transfer-Encoding: chunked
< Server: Jetty(8.y.z-SNAPSHOT)
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
Process returned -1073741571 (0xC00000FD) execution time : 12.682 s
The code I use:
curl = curl_easy_init();
if (curl) {
CurlResponse = "";
host = "localhost:13621";
LibcurlHeaders = curl_slist_append(LibcurlHeaders, "Expect:");
LibcurlHeaders = curl_slist_append(LibcurlHeaders, "Accept: application/json");
curl_easy_setopt(curl, CURLOPT_URL, (host).c_str());
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, LibcurlHeaders);
curl_easy_setopt(curl, CURLOPT_VERBOSE, CurlVerbose);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, LibcurlResponse);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &CurlResponse);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
Thanks for your reply
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#define server "smtps://smtp.gmail.com"
#define to "email#gmail.com"
#define from "email#gmail.com"
#define pwd "****"
typedef struct
{
char** mem;
size_t size;
} payload_data;
size_t reader(void *ptr, size_t size, size_t nmemb, void *userp)
{
char* str = NULL;
payload_data *data = (payload_data *)userp;
if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1))
return 0;
str = data->mem[data->size];
if (str)
{
size_t len = strlen(str);
memcpy(ptr, str, len);
++data->size;
return len;
}
return 0;
}
void TestCurl()
{
static const char *info[] =
{
"To: <"to">\r\n"
"From: <"from">\r\n",
"Subject: TestCurl\r\n",
"\r\n",
"Messaging with libcurl..\r\n",
"\r\n",//"\r\n.\r\nQUIT\r\n",
NULL
};
CURLcode res = CURLE_OK;
payload_data data = {0};
CURL* curl = curl_easy_init();
struct curl_slist* recipients = NULL;
if (curl)
{
data.mem = info;
curl_easy_setopt(curl, CURLOPT_URL, server);
curl_easy_setopt(curl, CURLOPT_USERNAME, from);
curl_easy_setopt(curl, CURLOPT_PASSWORD, pwd);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from);
recipients = curl_slist_append(recipients, to);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, reader);
curl_easy_setopt(curl, CURLOPT_READDATA, &data);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); //DOES NOT WORK WITHOUT THIS!
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
}
and the result is:
* Rebuilt URL to: smtps://smtp.gmail.com/
* timeout on name lookup is not supported
* Hostname was NOT found in DNS cache
* Trying 74.125.69.108...
* Connected to smtp.gmail.com (74.125.69.108) port 465 (#0)
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
* subject: C=US; ST=California; L=Mountain View; O=Google Inc; CN=smtp.gm
ail.com
* start date: 2014-07-15 08:40:38 GMT
* expire date: 2015-04-04 15:15:55 GMT
* subjectAltName: smtp.gmail.com matched
* issuer: C=US; O=Google Inc; CN=Google Internet Authority G2
* SSL certificate verify result: unable to get local issuer certificate (
20), continuing anyway.
< 220 mx.google.com ESMTP 141sm5490110ioz.39 - gsmtp
> EHLO Kira
< 250-mx.google.com at your service, [my_ip_address]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER
< 250-ENHANCEDSTATUSCODES
< 250-PIPELINING
< 250-CHUNKING
< 250 SMTPUTF8
> AUTH LOGIN
< 334 VXNlcm5hbWU6
> encrypted_username
< 334 UGFzc3dvcmQ6
> encrypted_password
< 235 2.7.0 Accepted
> MAIL FROM:<email#gmail.com>
< 250 2.1.0 OK 141sm5490110ioz.39 - gsmtp
> RCPT TO:<email#gmail.com>
< 250 2.1.5 OK 141sm5490110ioz.39 - gsmtp
> DATA
< 354 Go ahead 141sm5490110ioz.39 - gsmtp
< 250 2.0.0 OK 1413861121 141sm5490110ioz.39 - gsmtp
* Connection #0 to host smtp.gmail.com left intact
Process returned 0 (0x0) execution time : 1.524 s
Press any key to continue.
I can't get it to send QUIT. I tried adding QUIT to the "info" array but it just adds it as part of the message. I tried terminating with \r\n\r\n.\r\n but no cigar..
The email gets sent successfully.. I just can't get it to quit. Every time I send a new email, it increases the "Connection #X to host smtp.gmail.com left intact".. Even though I did the curl cleanup..
Any ideas how I can get it to quit and stop leaving the host intact? Is it leaking somewhere? Why does it do this?
First, it actually closes the connection when you close the easy handle - since that's where the connection cache is kept when using the easy interface. Depending on your libcurl version it may not send a QUIT and you may not see it in the verbose output (since the closing is done after the handle in which you set CURLOPT_VERBOSE to TRUE in is already gone).
The libcurl way to force a closure of a connection after the specific transfer is done, is to set CURLOPT_FORBID_REUSE. In a similar spirit you can set CURLOPT_FRESH_CONNECT to force using a new connection instead of re-using an old.
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;
}