Qt HTTP request sending DELETE with Data - c++

rest API:
someting/post expects 'token' as bytearray body data
something/delete expects 'token' as bytearray body data
Using Qt I can prepare the data in a QByteArray and send via deleteResource (that doesn't accepts a data parameter) and I can use sendCustomRequest that accepts a data parameter, but if I use the later with DELETE I have no data.
With POST, I do have the data.
Minimal code example, python server - just to exemplify. the Qt code is below.:
#route('/something/delete', "DELETE")
def somethingDelete(url, post):
print(post) # empty
#route('/something/delete2', "POST")
def somethingDelete2(url, post):
print(post) # correct output.
and the Qt code that triggers the server calls - This code is higly shortened to simplify, but the idea is that.
QNetworkRequest req;
req.setRawHeader("OCS-APIREQUEST", "true");
req.setUrl = Utility::concatUrlPath(account()->url(), path());
QByteArray bufferData("token=" + _token);
sendCustomRequest(req, "POST", bufferData);
as soon as I change the POST to DELETE, I don't get the token, but the correct python function is executed.

The DELETE HTTP verb does not have a request body so your buffer is probably simply dropped by Qt. To use DELETE you would need to encode your token in the URL.

As of Qt 5.9.2, it seems that Qt might ignore body data when performing a DELETE operation.
In Qt code in QNetworkReplyHttpImplPrivate::postRequest(), one can see that createUploadByteDevice() is not called when the operation is QNetworkAccessManager::DeleteOperation.
However, this is only valid when the DELETE request is sent by calling QNetworkAccessManager::deleteResource(), which is the only way to create a network request with the QNetworkAccessManager::DeleteOperation operation. Also note that this function does not allow you to send any body data.
If you use QNetworkAccessManager::sendCustomRequest() to send the request, then as far as Qt is concerned the operation is QNetworkAccessManager::CustomOperation. The custom verb you pass is not processed further, and Qt will behave exactly the same whatever the value of verb is. Even if verb is a known value like POST or DELETE.
This means that Qt does not discard the body data.
So if you used QNetworkAccessManager::sendCustomRequest(), as you claim, your body data is sent to the server (confirmed by Wireshark). So the issue is not on Qt side, but on the server side.

Related

C++ Boost http post request [duplicate]

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";

Translate text using google without API

I am trying to write a simple free translator (QT widget) using the online translation service.
The idea is to send the standard get request to an online translator, and then parse the response.
But the reply does not contain the translated text ! I guess this is because the service uses AJAX.
In the example, I am using the google translator, but I get similar results with other translators (yandex, deepl).
I know that there is a way to use the shareware API, but since the project is not commercial at the moment, I do not want to register a bank card.
Is there a browser-like way to get translation without the API and use it for free ?
I have searched for any information, but to my surprise, it was outdated and irrelevant at the moment (since Google closed the free service).
And one more question. When I tried to cast the result to a QString (QString s = reply->readAll().toString() or QString s = reply->readAll().toStdString().c_str()), I got a distorted htlm code (a lot of NUL characters at the beginning of the file). I assume that this is due to a misinterpretation of the escape sequences, but how then to cast the result correctly ? Even in the current version, there is some garbage at the beginning of the file (NUL NUL Уi).
The code I use is:
void getTranslate() {
QNetworkAccessManager manager;
QUrl url("https://translate.google.com/#view=home&op=translate&sl=en&tl=ru&text=Hello%2C%20World%20!");
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
do {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} while(!reply->isFinished());
QFile html("out.html");
if (html.open(QIODevice::ReadWrite)) {
QDataStream out(&html);
out << reply->readAll();
}
reply->close();
delete reply;
}
looking at Google Translate it uses AJAX Request, to get the translation. You could try to change the URL to something like this (this is where the ajax request goes to):
https://translate.google.de/translate_a/single?client=webapp&sl=auto&tl=en&hl=de&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=sos&dt=ss&dt=t&dt=gt&otf=2&ssel=0&tsel=0&xid=45662847&kc=1&tk=656516.836633&q=dies%20ist%20ein%20test
This request returns JSON data, which should be easy to parse.
I am not sure what all the parameters are for, but maybe this information is helpful for you.
I belive your problems with screen-scraping approach may be that the translate application uses Ajax to call the server-side and retrieve the translation. The page you get when downloading using QNetworkRequest is merely the JS application, it doesn't actually contain the translation. That doesn't get filled in until after a call has been made from the page to the server.
And that is why it isn't working. Perhaps you could get it working somehow, so let us know how you do it :-)

How to modify the HTTP::Response after it has been written to

I'm trying to write some tooling for Crystal (specifically Kemal) where I can see if the response content type is text/html and modify the response body thats has already been written to the HTTP::Response before it is sent to the client by injecting an HTML element into the existing html response body.
I've noticed that HTTP::Server::Response is write-only, but things like Gzip::Writer are able to modify the body.
How can I modify the HTTP::Server::Response html body before it is sent to the client?
It's written in Crystal, so let's just take a look at the source on how others do this.
Taking the CompressHandler as an example, the basic idea is to replace the response's IO with something that allows the desired control:
context.response.output = Gzip::Writer.new(context.response.output, sync_close: true)
# ...
call_next(context)
So how can we make use of that to modify the response that's being written?
A naive (and slow) example would be to just keep hold of the original output and provide a IO::Memory instead:
client = context.response.output
io = IO::Memory.new
context.response.output = io
call_next(context)
body = io.to_s
new_body = inject_html(body)
client.print new_body
Of course that would only work when this handler comes before any handler that turns the response into non-plaintext (like the above CompressHandler).
A smarter solution would provide a custom IO implementation that just wraps the original IO, watching what's written to it and inject whatever it wants to inject at the right point. Examples of such wrapping IOs can be found at IO::Delimited, IO::Sized and IO::MultieWriter among others, the pattern is really common to prevent unnecessary allocations.

Reading Jetty Server Request body without making it null

I have a Jetty.Server.Request object, which is an HTTP request whose body I need to use in multiple methods.
I access the body's contents like so -
String contents = baseRequest.getReader().readLine();
However, this seems to remove the body from the HTTP request. If I then try to access it again like so -
String contents2 = baseRequest.getReader().readLine();
contents2 will be null.
How can I read the body of the request object without affecting the request?
Per the Servlet spec, the stream is only available once.
Make a copy of it yourself (either to memory, or to disk for later reading)
This is by design, as many request bodies can by quite large and there simply wouldn't be enough memory to handle rereads in a sane way.
Be sure you check out the prior answers for this:
Http Servlet request lose params from POST body after read it once
As those answer demonstrate a few ways to accomplish multiple reads of the same request body.

Error with Flex HTTPService and Django, even though POST is successful

(This is the first time I've done this actually.)
<mx:HTTPService id="post_update" method="POST" result="{Dumper.info('bye')}"/>
The result handler above is just for debugging purposes, but its never hit, even though what I'm uploading via POST...
post_update.url = getPath(parentDocument.url)+"update";
post_update.send(new_sel);
...is received and handled successfully by my Django view:
def wc_post(request) :
request.session['wc'] = request.POST
return http.HttpResponse("<ok/>", mimetype="text/xml")
As far as what I'm sending back from Django, I'm following the guidelines here:
Sending Images From Flex to a Server
I just don't want it to generate an error on the Flex side considering Django is actually receiving and processing the data. Any help appreciated. Can't remember the text of the error in Flex at the moment.
UPDATE: new_sel (what I'm posting from Flex) is just a Flex Object, with various text fields.
UPDATE: various error messages from event.message (in fault handler):
faultCode = "Server.Error.Request"
faultString = "HTTP request error"; DSStatusCode = 500; errorID = 2032; type = "ioError"
This is more grasping at straws than answers, but do I have to send a particular type of header back from Django- the default sent by Django includes a 200 success status code, and the response I was sending of "<ok/>" with mime type of "text/xml" was following the example exactly that I provided from that other source.
And also the url I'm sending the POST to is localhost:8000/wr_view1/wr_webcube/update, and I previously successfully did a GET to localhost:8000/wr_view1/wr_webcube/webcube.xml, and despite the .xml extension in the case of GET, it was still being handled by Django (and without errors in Flex). In the case of this POST, once again, the data is actually succesfully sent and handled by Django, but Flex is returning Error 2032, which I found out can mean numerous different things including cross domain issues, but don't see how that's the case here.
Just had to return HttpResponse("ok") Didn't like it being sent as xml for some reason. So much ado about nothing I guess.