C++ Boost http post request [duplicate] - c++

I've to use a C++ library for sending data to a REST-Webservice of our company.
I start with Boost and Beast and with the example given here under Code::Blocks in a Ubuntu 16.04 enviroment.
The documentation doesn't helped me in following problem:
My code is, more or less, equal to the example and I can compile and send a GET-request to my test webservice successfully.
But how can I set data inside the request (req) from this definition:
:
beast::http::request<beast::http::string_body> req;
req.method("GET");
req.target("/");
:
I tried to use some req.body.???, but code completition doesn't give me a hint about functionality (btw. don't work). I know that req.method must be changed to "POST" to send data.
Google doesn't show new example about this, only the above code is found as a example.
Someone with a hint to a code example or using about the Beast (roar). Or should I use websockets? Or only boost::asio like answered here?
Thanks in advance and excuse my bad english.

Small addition to Eliott Paris's answer:
Correct syntax for setting body is
req.body() = "name=foo";
You should add
req.prepare_payload();
after setting the body to set body size in HTTP headers.

To send data with your request you'll need to fill the body and specify the content type.
beast::http::request<beast::http::string_body> req;
req.method(beast::http::verb::post);
req.target("/");
If you want to send "key=value" as a "x-www-form-urlencoded" pair:
req.set(beast::http::field::content_type, "application/x-www-form-urlencoded");
req.body() = "name=foo";
Or raw data:
req.set(beast::http::field::content_type, "text/plain");
req.body() = "Some raw data";

Related

How can I send a POST request in C ++ without using sockets

I have python code that sends a POST request and gets a json, I need to rewrite it in C ++ (Windows 10, Visual Studio 2019). I don’t understand what tools can really do everything I need without complicating the code.
There will be a console application that must send a request to send or receive data, more precisely a video stream.
I read about Boost.Asio, but it seems to work only with sockets, is there any way without them? At first I wanted to use it, as the most famous. I read about сurl, but it hasn't been updated for a long time, is it still relevant?
headers_predict = {
"Content-type": "application/json;charset=UTF-8",
"Accept": "application/json",
"X-Session-ID": session_id
}
data_predict = {
"audio": {
"data": sound_base64,
"mime": "audio/pcm16"
},
"package_id": ""
}
url = 'https://cp.speechpro.com/recognize'
r = requests.post(url, headers=headers_predict,
data=json.dumps(data_predict))
print('Response: %s' % r.text)
I wouldn't want to use sockets, because I don't understand them.
I need to be able to set the header and data as a json.
sockets, is there any way without them?
Technically, HTTP does not specify the underlying transport protocol and it can work with any sort of streaming transport. You could for example write the request into a file.
But, if you currently use TCP and don't want to change that, then you must use sockets. You don't need to interact with them directly if you use an existing HTTP client library.

GET request with body timing out with URLSession and Alamofire

I'm working with a slightly unconventional API that is expecting a JSON body with a GET request and I have no control over this. Unfortunately, every time I attempt to make the request, it seems to completely disappear and never make it to the API. I originally wrote the request using a standard URLSession and then switched to try Alamofire in an attempt to fix it but ended with the same result. My request looks like this:
Alamofire.request("http://192.168.1.1:8000/connect/", method: .get, parameters: ["test": "test"], encoding: JSONEncoding.default)
.responseJSON { response in
let body = response.request?.httpBody
guard response.result.isSuccess else {
onCompletion(nil)
return
}
onCompletion(response.result.value as! [String : Any]?)
}
This exact code works for a different request where there is no JSON in the body, but seemingly the moment I add it, it just times out. This has already been discussed on the alamofire github repo (https://github.com/Alamofire/Alamofire/issues/1819) but the final comment with what should be working code isn't really any different to mine, so doesn't provide any help, nor do the other linked issues.
Printing the request with debugPrint gives me this curl command
$ curl -i \
-H "Content-Type: application/json" \
-d "{\"test\":\"test\"}" \
"http://192.168.1.1:8000/connect/"
Which is missing the -X GET flag, but when I add that in, the request works as expected and the server responds, so I know the API itself is working and is happy processing the JSON in the body, so I'm at a loss as to what's going on.
I've installed Timberjack to attempt to trace things, which didn't give me any more info at all, just what I already knew
Request: GET http://192.168.1.1:8000/connect/
Headers: [
Content-Type : application/json
Content-Length : 24
]
Although I'm not sure if it's supposed to be showing me the body as well which it isn't?
In both cases (URLSession and Alamofire) the request gives the following output which I don't see at any other time:
2017-01-22 23:31:09.797453 my-app[3755:1349066] [] nw_endpoint_flow_service_writes [2 192.168.1.1:8000 ready socket-flow (satisfied)] Write request has 4294967295 frame count, 0 byte count
2017-01-22 23:32:04.484182 my-app[3755:1349066] [] __tcp_connection_write_eof_block_invoke Write close callback received error: [89] Operation canceled
Anyone have any ideas on what's going on as I'm completely at a loss at this point.
Update
I've done some more digging. If I change the endpoint to https://httpbin.org/get then the request goes through just fine and I get a response. Whilst this kind of suggests the API server is refusing to process the request, it's still working with the cURL command so that can't really be the issue.
I also forgot to mention (although not sure it should make a difference) that the API I'm trying to communicate with is connected via an ad-hoc wifi. Other requests to it work just fine though so I can definitely communicate with it.
Update 2
So I've been able to switch the server to using POST instead of GET and unsurprisingly it now works, however I would still love to know of a solution to the original problem
URLSession and CFHTTPMessage cannot send a message body for a GET request. They send the content length for the body, but do not send the body itself. This results in a timeout.
In order to resolve this issue I've used libcurl to handle the GET requests which have a message body to my project. I use URLSession everywhere else. When you add a body to a request using libcurl it changes the request to a POST, but that can be changed back to a GET after setting the body and before submitting the request.

gSoap: How to set or change cookies on client in Qt?

I'am use next code for authorization on server by service, and get other service'methods using cookie identifer for authorizathion.
TerminalControllerBinding soapObj;
soap_init1(soapObj.soap, SOAP_C_UTFSTRING);
soapObj.endpoint = "http://192.168.*.*/path/to/service";
ns1__getTemplatesResponse *response = new ns1__getTemplatesResponse;
std::string auth_res = "";
soapObj.ns1__auth("user", "password", auth_res);
QString sessid = QString::fromStdString(auth_res);
qDebug() << sessid;
soapObj.soap->cookies = soap_cookie(soapObj.soap, "sessid", sessid.toAscii().data(), ".");
Server not getting cookie "sessid"
I am kind of confused by the code you posted: You allocate memory for ns1__getTemplatesResponse, then do some apparently unrelated stuff; in fact you do not reference it again at all. Furthermore soap_cookie is a struct and soap->cookies is basically a list. So there is no magic that transfers the cookies to the server here.
I think what you want is soap_set_cookie. You can find a little more information on client side cookies here, but there isn't any example code. Much more helpful however is actually the server side documentation (the handling of cookies doesn't differ much).
Also notice that you either need to compile with -DWITH_COOKIES or define the macro yourself in stdsoap.h if you haven't done so already.

Using cpp-netlib 0.8 as a HTTP Proxy - Helpless

I am trying to use cpp-netlib in a project of mine. I simply need to create a HTTP proxy into which I can plug in some functionality later. For now, I just need to listen to requests, send request to a new site, and forward the answer of the new request to the first request.
This is the code I have so far:
std::string ip = source(request);
http::client client;
std::ostringstream url;
url << "www.example.com/image.jpg";
http::client::request clientRequest(url.str());
http::client::response clientResponse = client.get(clientRequest);
response = server::response::stock_reply(server::response::ok);
response.headers = clientResponse.headers(); //This is not possible - not correct type or something
response.content = clientResponse.body();
Results in error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::multimap<_Kty,_Ty>' (or there is no acceptable conversion)
A request to the test image I am using yields 19.4kb data in the response. If I do the same request through the above code (without header copying) I get an answer with about 4kb data, which the browser tries to show as text (default header). It does seem like an image though, even in text.
Anyone out there that is familiar with cpp-netlib-0.8? is response.content = clientResponse.body(); the correct way? How can I add the correct headers?
It's altogether too much template weirdness in cpp-netlib for me to understand it right now!
Thanks...
Instead of using:
response.content = clientResponse.body();
the correct way is:
std::string body_content = body(clientResponse);
also, you are using response as variable, while your variable is actually clientResponse
For more examples read cpp-netlib v0.8 documentation

Uploading a file over HTTP/HTTPS and/or FTP/FTPS on a Mac

I have found numerous examples on uploading a file to a web server via C++ on Windows.
However I am struggling after a lot of searching (and I thought I was good with Google!) to find any examples to help me achieve the same on a Mac.
Can anyone point me towards some help on how to upload a file to a web server on a Mac OS using either C++ or objective C?
It can be via either HTTP/HTTPS or FTP/FTPS (or both).
Thanks!
You could use 'libcurl', see this article on Wikipedia.
You would want to use an NSURLConnection with a NSMutableURLRequest, something like this:
NSMutableURLRequest *theRequest=[[NSMutableURLRequest alloc] init];
[theRequest addValue:#"attachment;filename=\"file2.gif\"" forHTTPHeaderField:#"Content-disposition"];
[theRequest addValue:#"image/gif" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue:#"binary" forHTTPHeaderField:#"Content-Transfer-Encoding"];
[theRequest setHttpBody:myBodyNSDataObject];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
receivedData=[[NSMutableData data] retain];
} else {
// inform the user that the download could not be made
}
You can modify or set headers using the NSMutableURLRequest method:
- (void)addValue:(NSString *)value forHTTPHeaderField:(NSString *)field
The response will be whatever the server comes back with. You can check out Apple's documentation for the rest of the delegate methods to implement to get the body of the response back. You should have the NSData object representing the content of the file you want to upload ready. Doing the same using FTP is a bit more involved, but this will work to post the file body up. You will want to make sure your NSData object is set up like the body of an HTTP post, such that you set up the headers like:
[theRequest addValue:#"attachment;filename=\"file2.gif\"" forHTTPHeaderField:#"Content-disposition"];
[theRequest addValue:#"image/gif" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue:#"binary" forHTTPHeaderField:#"Content-Transfer-Encoding"];
And then you should append the body. On the server side, you can get the file name and the bytes composing the file.
This is not exactly the code you should use, but it should give you a good idea of how to proceed.
connection Kit might be what your looking for