Error 411 (Length Required) in post request with header, but header has Content-Length. libCurl - c++

I use this options:
curl_easy_setopt(curl, CURLOPT_URL, urlUpload);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
It must be post request with header. And in header variable there is length
***
char sizeStr[50];
sprintf(sizeStr, "Content-Length: %d", body.length());
***
header = curl_slist_append(header, sizeStr);
***
What I'm trying to do is to upload video to YouTube, I'm using their manual
And I receive such error.
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<title>Error 411 (Length Required)!!1</title>
<style>
*many symbols here*
</style>
<a href=//www.google.com/ id=g><img src=//www.google.com/images/logo_sm.gif alt=Google></a>
<p><b>411.</b> <ins>Thatв€™s an error.</ins>
<p>POST requests require a <code>Content-length</code> header. <ins>Thatв€™s all we know.</ins>
Maybe I must use some other CURLoptions?
UPDATE:
when I set
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
I also receive
* About to connect() to uploads.gdata.youtube.com port 80 (#0)
* Trying 74.125.XX.XXX... * connected
* Connected to uploads.gdata.youtube.com (74.125.XX.XXX) port 80 (#0)
> POST /feeds/api/users/default/uploads HTTP/1.1
Accept: */*
Host: uploads.gdata.youtube.com
Authorization: GoogleLogin auth=DQAAAIkAAACTK9tZPCTY1XQvXGkg4qkaIuZ1QO-Bh6- ZyzOHuigFNC_gR4Piep4NljAjdOP4s-k7vqj-j4LdckXM9jxzlElgtaxr- CShI1vIWkjm5ZtFsj3a9v1YqFmjIkEi3NCP2ON18D9jmXSIarPqprWiOK0n3oxznCBhm4osXwJ1yRstVVM5bG5mOlC331eMCrOKp3E
GData-Version: 2
X-GData-Key: key=AI39si59VMkm6DATDmfG_Df6D23jfto3xRVfbAEMrFBv035pdRZ5AYMPsRXbGLCRXXnK5jz6KCSWSkuXOTrlDIIKWy7Le9fkQQ
Slug: screen.avi
Content-Type: multipart/related; boundary="d31fcjR2"
Content-length: 910273
Connection: close
* HTTP 1.0, assume close after body
< HTTP/1.0 411 Length Required
< Content-Type: text/html; charset=UTF-8
< Content-Length: 11791
< Date: Fri, 02 Sep 2011 16:09:58 GMT
< Server: GFE/2.0
<
* Closing connection #0

This error was because in the authentication string that I receive from YouTube was in the end the new line symbol, I erase it and this error disappeared.

CURLOPT_POSTFIELDS will make a content-length get added automatically by libcurl, no need to make a custom one. However, as you're already sending a content-length header that is clearly not the missing length the server is talking about.
Your request also sends a "Connection: close" so there's something more of the code that you didn't show us.

Related

char* escape "\" are being lost in libcurl's POSTFIELD

I have two examples of using POSTFIELDS - the first works fine and the second does not
I am not sure if this is down to libcurl or the compiler removing the escape "\" from the character 'send'.
if I make 'send' an std::string rather that a char* then I get a bad request error saying "unexpected token in Json"
this is a comparison of how I am using POSTFIELDS
char* send;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"var\":\"info\"}");
and
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, send);
I get a 500 error that shows as
Unhandled error in PUT /random/page 500 AssertionError [ERR_ASSERTION]: The data argument must be an object
There is also problem with the output from libcurl
> PUT /random/page HTTP/1.1
Host: 127.0.0.1:3000
Accept: application/json
Content-Type: application/json
charsets: utf-8
Content-Length: 364
* upload completely sent off: 364 out of 364 bytes
< HTTP/1.1 500 Internal Server Error
< X-Powered-By: Express
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< X-Content-Type-Options: nosniff
< Content-Type: application/json; charset=utf-8
< Date: Wed, 14 Aug 2019 11:30:55 GMT
< Connection: keep-alive
< Content-Length: 62
The content length at the bottom does not match the request

OAuth2 with beast boost returns temporary redirect 307

I'm trying to implement an app with access to google drive in beast boost C++ usingoauth2 authentication.
https://developers.google.com/identity/protocols/OAuth2ForDevices
I try to get the user code in Postman with the following POST request:
POST /o/oauth2/device/code HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&client_id=610490019085-l1v2mv7lv95lu7cr111vbtqmp1bigv42.apps.googleusercontent.com
And it works perfectly fine, returning:
{
"verification_url": "https://www.google.com/device",
"expires_in": 1800,
"interval": 5,
"device_code": "AH-1Ng0IgBnIXIUeltwDoL7AwNExNTT0rozdxD5FMnP8dip4DaDi8_XtzK2aVT92YKYmYa7KWqHRVqw5AmJCDtalzK3k6pvbFw",
"user_code": "LWZY-BDXD"
}
Now I want to do the same request in C++ using boost, with the following code snippet for the request:
http::request<http::string_body> req{http::verb::post, "/o/oauth2/device/code", 11};
req.set(http::field::host, "accounts.google.com");
req.set("Cache-Control", "no-cache");
req.set(http::field::content_type, "application/x-www-form-urlencoded");
req.body() = "scope=https://www.googleapis.com/auth/drive.file&client_id=610490019085-l1v2mv7lv95lu7cr111vbtqmp1bigv42.apps.googleusercontent.com";
req.prepare_payload();
This one returns:
HTTP/1.0 307 Temporary Redirect
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Date: Mon, 14 May 2018 11:06:01 GMT
Location: https://accounts.google.com/o/oauth2/device/code
Content-Length: 232
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
<HTML>
<HEAD>
<TITLE>Temporary Redirect</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Temporary Redirect</H1>
The document has moved here.
</BODY>
</HTML>
Any ideas how I can get the JSON returned as with Postman?
Thank You!
Beast is a low-level protocol library, it doesn't know anything about resolving domain names or connecting sockets. It doesn't even know about TCP/IP, just how to serialize and deserialize HTTP/1 messages over objects which meet Asio's stream concept requirements (examples: SyncReadStream, or AsyncWriteStream). You have to handle redirects yourself. If you get a redirect response, extract the Location field value and parse the URI, resolve the domain, and then issue another GET request for the specified resource.
It is my hope that other folks (maybe you?) will build on top of beast and provide higher-level functionality like this in the form of open source libraries.

How to set proxy authorization in libcurl

Actually I am trying to post some data to the URL.But I am getting stuck because of proxy.
The below code snippet is always giving proxy authorization required even though setting the values.
Please let me know any thing needs to be changed in the code.
Here is the code snippet that I am using
curl_easy_setopt(curl_handle, CURLOPT_PROXY, "proxy proxy.xyz.com:8080");
curl_easy_setopt(curl_handle, CURLOPT_PROXYTYPE, "CURLPROXY_HTTP");
curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "abc/xyz:pwd");
curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, jsonResult);
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://username:password#url");
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error);
res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
return false;
}
I have used the CURLOPT_VERBOSE option
Below is the output
* About to connect() to proxy proxy.xyz.com port 8080 (#0)
* Trying proxy ip... * connected
* Server auth using Basic with user 'abc/xyz'
> POST http://username:password#url HTTP/1.1
Authorization: Basic aW5kaWEvNjY2NTU3Ok5vdkAyMDE0
Host:ip:8080
Accept: */*
Proxy-Connection: Keep-Alive
Content-Length: 53
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 53 out of 53 bytes
< HTTP/1.1 407 Proxy Authorization Required
< Date: Thu, 04 Dec 2014 05:17:15 GMT
< Via: 1.1 localhost.localdomain
< Proxy-Connection: keep-alive
< Cache-Control: no-store
< Content-Type: text/html
< Content-Language: en
< Proxy-Authenticate: Negotiate
< Proxy-Authenticate: NTLM
< Content-Length: 322
<
<HEAD><TITLE>Proxy Authorization Required</TITLE></HEAD>
<BODY BGCOLOR="white" FGCOLOR="black"><H1>Proxy Authorization Required</H1><HR>
<FONT FACE="Helvetica,Arial"><B>
Description: Authorization is required for access to this proxy</B></FONT>
<HR>
<!-- default "Proxy Authorization Required" response (407) -->
</BODY>
* Connection #0 to host proxy.xyz.com left intact
Thanks in advance
If you still get a 407 back, it means the proxy rejected the credentials (or method) you used.
Set CURLOPT_VERBOSE and verify that the request looks like you want it and double-check that the proxy really accepts what you send it.
CURLOPT_PROXYTYPE is not a string so the code you shown above will not work. In fact, proxy type HTTP is default if not set so you can just remove that line.
Finally, not related to your problem, but using CUSTOMREQUEST like that is not recommended since POSTFIELDS already implies a POST.

determining HTTP version using raw sockets in C

I am trying to create raw sockets in C/C++, then create a request message and then send that message to a target server. If the port I specify happens to be 80 I want to send a HTTP request to determine the HTTP version that the target server is using. For e.g I send GET HTTP/1.0 to www.google.com.
For some servers it returns HTTP/1.1 400 bad request. While in some cases it responds with an XML message. I know the GET command is wrong since I am not specifying any object to actually GET. So is there a generic way to do this?
Try:
HEAD / HTTP/1.0\r\n
\r\n
Or:
GET / HTTP/1.0\r\n
\r\n
The first line of the servers response should contain the HTTP version. Note that some servers will return 400 Bad Request if the Host: <hostname> is omitted from the header (which is not required in 1.0, but in 1.1). I would do:
Try:
HEAD / HTTP/1.0\r\n
Host: <hostname>\r\n
\r\n
Or:
GET / HTTP/1.0\r\n
Host: <hostname>\r\n
\r\n
If you don't require the message body, you should use HEAD as it will require less data to receive.
You will have to progressively try each version of HTTP. For example, if I query google.com with HTTP 1.0, it will respond with HTTP 1.0:
$ printf "HEAD / HTTP/1.0\nHost: google.com\n\n" | nc google.com 80
HTTP/1.0 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Tue, 26 Nov 2013 19:44:42 GMT
Expires: Thu, 26 Dec 2013 19:44:42 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic
If I query it with HTTP 1.1, it will respond with HTTP 1.1:
$ printf "HEAD / HTTP/1.1\nHost: google.com\n\n" | nc google.com 80
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Tue, 26 Nov 2013 19:44:47 GMT
Expires: Thu, 26 Dec 2013 19:44:47 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic
GET / HTTP/1.0\r\n
Host: www.google.com\r\n
\r\n
This is a basic HTTP request. Alternatively, you can use HEAD instead of GET, sinse you only want the headers, but some basic servers don't recognize HEAD as a valid method.
Not every server will support HTTP/1.0, they will most likely ignore this and answer as HTTP/1.1, others will just ape the version in your request and not really mean it.
It can be frustrating to try to determine the HTTP version in a random server. Perhaps you should instead use 1.1 in the request and see if the server answers with 1.0, I believe it may be the safest way to know if the server is at least giving a damn.

CURL Post method in c++

Suppose we have a HTTP request like following:
POST /safebrowsing/downloads?client=Firefox&appver=3.0.8&pver=2.2&wrkey=AKEgNiux-3bBzAgJeFWgqbneh_GLc2OrmgXnpxPrdH1-hFpbAM8k1ovPA8GB_UMRueBHnL3QJ7gsdQOWVm6QJr_VZNgAm8jmLQ== HTTP/1.1
Host: safebrowsing.clients.google.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/2009033100 Ubuntu/9.04 (jaunty) Firefox/3.0.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Length: 120
Content-Type: text/plain
Cookie: PREF=ID=551a1b8848e36099:U=e6fa7464d7c48884:FF=0:TM=1327553284:LM=1345022478:S=Qd0IssyrqLi17a4s; NID=62=R9Y5bkQ5iLF8zlyhma1gnRBfxPDoWuG2FibC2wc5u0eAIQgAuo4WCXMeLhdPZ7FXJEpN2Sw1a6da6QUNP7OC5OqTYK0Y39vd6c2fUh4BhY2B5CGsKtHuQ5RCpSnefSkb
goog-malware-shavar;a:83372-91327:s:59904-95254:mac
goog-phish-shavar;a:227421-233955,235041-235401:s:107142-110470:mac
I already built up the part of code to handle the headers. However, the message-body part I'm not sure how to deal with. I have read CURL sample code, they provide solution for HTTP form POST which is not the way to handle my data. Does anyone know what parameter I should use to handle message-body using curl_easy_setopt() function?
FYI: cURL provides a very convenient option that lists the ad-hoc options for a given HTTP request:
--libcurl <file> Dump libcurl equivalent code of this command line
When in doubt you should perform your request via cURL (and corresponding options, e.g. to perform a POST, etc) while using this option since it outputs the list of curl_easy_setopt options:
curl --libcurl out.c http://stackoverflow.com/ > /dev/null
Then open the out.c file within your editor:
...
curl_easy_setopt(hnd, CURLOPT_URL, "http://stackoverflow.com/");
curl_easy_setopt(hnd, CURLOPT_PROXY, NULL);
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0);
...
const char *post_data = "any_data";
...
curl_easy_setopt(curl_handle, CURLOPT_POST, 1);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, post_data);