Accessing QNetworkRequest data before it's sent - c++

Is there any way to see the data that will be sent (or has been sent) during (or after) a call to QNetworkAccessManager::post(QNetworkRequest,QByteArray) on the client side?
In other words, I would like to see the raw HTTP request in it's entirety:
POST /somepage.php HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
name=need&just=tosee

It was a while since I had to debug my requests and things may have been changed in Qt, but I had to access the different parts of the requests using various functions in order to obtain all the details.
I created a wrapper for the post function which would print the details before posting the request. Here's a code snippet that extracts and prints the URL, raw headers and data for instance:
void debugRequest(QNetworkRequest request, QByteArray data = QByteArray())
{
...
qDebug() << request.url().toString();
const QList<QByteArray>& rawHeaderList(request.rawHeaderList());
foreach (QByteArray rawHeader, rawHeaderList) {
qDebug() << request.rawHeader(rawHeader);
}
qDebug() << data;
...
}

Related

wild card match on request headers for nginx

I am using nginx as a proxy server to send the requests to backend pool members .
I have a header -- Content-Type: multipart/form-data; boundary="21ad608c-8e00-4c0c-8a06-5ed1280e9532"
The boundary value in the header changes all the time.
How can I do a header check for only "Content-Type: multipart/form-data;" value and route the requests to the backend. when I do a print of $http_content_type value , everything including boundary value is getting printed . I am not able to do an if check on just " Content-Type: multipart/form-data; " value .
Can I put a wild card in the nginx config like -- "multipart/form-data; * " to pass the if loop ?
Please let me know.
An Nginx wildcard? Yes, sort of, via a regex:
if ($http_content_type !~ '^multipart/form-data;') deny-the-request
This means that the Content-Type must start with multipart/form-data;. After that, any boundary=...whatever... is allowed.
Complete example:
location /-/upload-public-file {
limit_except POST OPTIONS {
deny all;
}
if ($http_content_type !~ '^multipart/form-data;') {
return 406; # status code Not acceptable
}

Amazon SES Sending email with attachments

I am trying to send mails with attachment by using Amazon SES
HttpRequest httpReq = new HttpRequest();
httpReq.setMethod('POST');
httpReq.setEndpoint('https://email.us-east-1.amazonaws.com');
Blob bsig = Crypto.generateMac('HmacSHA256', Blob.valueOf(awsFormattedNow), Blob.valueOf(secret));
httpReq.setHeader('X-Amzn-Authorization','AWS3-HTTPS AWSAccessKeyId='+key+', Algorithm=HmacSHA256, Signature='+EncodingUtil.base64Encode(bsig));
httpReq.setHeader('Date',awsFormattedNow);
httpReq.setHeader('From','sample#gmail.com');
httpReq.setHeader('To','sample#gmail.com');
httpReq.setHeader('Subject','Hello');
httpReq.setHeader('Accept-Language','en-US');
httpReq.setHeader('Content-Language','en-US');
httpReq.setHeader('Content-Type','multipart/mixed;boundary=\"_003_97DCB304C5294779BEBCFC8357FCC4D2\"');
httpReq.setHeader('MIME-Version','1.0');
// httpReq.setHeader('Action','SendRawEmail');
String email = 'Action=SendRawEmail';
email += '--_003_97DCB304C5294779BEBCFC8357FCC4D2 \n Content-Type: text/plain; charset="us-ascii" \n Content-Transfer-Encoding: quoted-printable \n';
email +='Hi Andrew. Here are the customer service names and telephone numbers I promised you.';
httpReq.setBody(email);
System.debug(httpReq.getBody());
Http http = new Http();
HttpResponse response = http.send(httpReq);
I am getting error like
<AccessDeniedException>
<Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>
Kindly please help me where i am doing wrong .Thanks in advance
Take another look at the documentation. There are several issues with your code.
SES expects an HTTP POST with all of the parameters strung together consistent with application/x-www-form-urlencoded POST requests.
Your HTTP request needs to be Content-type: application/x-www-form-urlencoded, not multipart/mixed... -- that's part of the raw message you're trying to send.
You are mixing up things that should be in the body, and setting HTTP request headers, instead. For example, these are also incorrect:
httpReq.setHeader('From','sample#gmail.com');
httpReq.setHeader('To','sample#gmail.com');
httpReq.setHeader('Subject','Hello');
These should go in the request body, not in the HTTP request headers. Also, the values are urlencoded. From the example code:
Action=SendEmail
&Source=user%40example.com
&Destination.ToAddresses.member.1=allan%40example.com
The line breaks were added for clarity.
Your interests might be best served by trying to successfully send a simple e-mail, first, and then later attempting to modify your code to support attachments, because you have numerous errors that will need to be corrected before this code will work properly.
http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-requests.html
http://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html

How do I get the Content-Encoding in a POCO::Net::HTTPResponse object?

I'm fetching a server page using Poco::Net::HTTPClientSession with an appropriate Poco::Net::HTTPRequest, which works fine. Now I get a response back, and sometimes the returned page will be gzipped.
I need to find out when that is the case, so that I may deflate if necessary. The HTTP header that should indicate this, is Content-Encoding: gzip; but there's no getContentEncoding() method in Poco::Net::HTTPResponse.
Here's a non-working snippet (because there's no resp.getContentEncoding()):
// resp is the Poco::Net::HTTPResponse object,
// sess is the Poco::Net::HTTPClientSession
std::istream &in = sess.receiveResponse(resp);
// Get the server-returned body as a string (potentially deflate)
std::ostringstream serveroutput;
if (resp.getContentEncoding() == "gzip") {
Poco::InflatingInputStream
inflater(in, Poco::InflatingStreamBuf::STREAM_GZIP);
Poco::StreamCopier::copyStream(inflater, serveroutput);
} else
Poco::StreamCopier::copyStream(in, serveroutput);
// Now we can get at the body as a string
std::string txt = serveroutput.str();
Does anyone know how to get at the raw headers, so that I can inspect the header Content-Encoding myself, or of another useful method to determine whether a server response is gzipped?
if the server set the Content-Encoding header
you could get the encoding value like the following.
resp.get("Content-Encoding")

HTTP/1.1 500 Internal Server Error when calling Web Service from .NET Client

I'm trying to connect to a https web service (not .NET as far as I know).
I can't control the other side in any way, I just got some standards and a wsdl to operate
with it.
I have created at first the client using Add Service Reference, tried some things until I get through some problems, where one most serious was that I couldn't add the Authentication header to the message which was resulting in fail.
Added the service using old Add Web Reference and seemed more easily managed and appropriate, using a partial class and override the GetWebRequest, I added this code so I can preauthenticate with the service and add the security header, which they don't mention in the wsdl link. I know that it is not mandatory for services to tell this but it would be nice my Web Service creators fellow developers.
protected override WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
if (PreAuthenticate)
{
NetworkCredential networkCredentials = Credentials.GetCredential(uri, "Basic");
if (networkCredentials != null)
{
byte[] credentialBuffer = new UTF8Encoding()
.GetBytes(networkCredentials.UserName + ":" + networkCredentials.Password);
request.Headers["Authorization"] = "Basic" + Convert.ToBase64String(credentialBuffer);
}
else
{
throw new ApplicationException("No network credentials");
}
}
return request;
}
To call the service I added this code:
using (Service client = new Service()) // autogenerated Service class
{
client.EnableDecompression = true;
// Create the network credentials and assign
// them to the service credentials
NetworkCredential netCredential = new NetworkCredential("test1", "test1");
Uri uri = new Uri(client.Url);
ICredentials credentials = netCredential.GetCredential(uri, "Basic");
client.Credentials = credentials;
// Be sure to set PreAuthenticate to true or else
// authentication will not be sent.
client.PreAuthenticate = true;
// Make the web service call.
Request req = new Request { UserName = "test2", Password = "test2"; // an object created from autogenerated code
RequestResult result = client.processMessage(req); // autogenerated code
}
While testing this call and checking with fiddler my request. I see 2 calls a keep alive call with these header, nothing special.
CONNECT server:443 HTTP/1.1
Host: server
Connection: Keep-Alive
Sending 570 returning a 200 result.
HTTP/1.1 200 Connection Established
FiddlerGateway: Direct
StartTime: 00:05:13.743
Connection: close
And the call with the data sending 571 result 500 error:
POST /host/Service HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.5448)
Authorization: BasicdXNlcOTc3MzQyMGTDFTR4dftfrdg5 // changed this hash for security reasons
VsDebuggerCausalityData: // Removed this hash for security reasons
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Host: server-host-url
Content-Length: 7238
Expect: 100-continue
Accept-Encoding: gzip
Connection: Keep-Alive
The error exception in .NET client:
Error on verifying message against security policy Error code:1000
As you see the Authorization header exist. I also tried with adding a space after Basic you can see above where exactly in the overriden method, and seemed fiddler recognized it better and also decoded the username:password header.
This results into that response:
HTTP/1.1 500 Internal Server Error
Date: Sat, 21 Apr 2012 21:05:22 GMT
Server: Oracle-Application-Server-11g
X-Powered-By: Servlet/2.5 JSP/2.1
X-Cnection: close
Transfer-Encoding: chunked
Content-Type: text/xml;charset="utf-8"
Content-Language: en
X-Pad: avoid browser bug
Set-Cookie: BIGipServerpoolXoas243_254_9999=437682499.99988.0000; path=/
The strange thing I wonder first is if the first call should be preauthenticated, the handshake keep alive one? This 500 error I know that causes when authentication header is not present, but mine is. Preauthentication is what I need to know how it should happen and I guess it's not working if it should appear in the 1st message.
Another strange thing is that if I change the 2 pairs of passwords opposite, I see on fiddler that I get 3 messages, 1 with the handshake and result in 200 and "TWO" others with 401 Authorization Required.
This drives me crazy. Any help appreciated to save my soul.
Thank you!

how to parse HTTP POST(file upload) stream?

I am using actionscript engine to upload a file, the engine will select the file and send the file over network thru HTTP POST command, the document says the POST message is like:
POST /handler.cfm HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
User-Agent: Shockwave Flash
Host: www.example.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"
MyFile.jpg
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="photo"; filename="MyFile.jpg"
Content-Type: application/octet-stream
FileDataHere
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"
Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--
In server side I have a C++ program listens on port 80 and parse the POST message. I only want the file name and file data. How to decode the file data using c++, is it base64 encoded and is there a library can do it for me? I want to decode the binary, and write it to the file, thanks!
No, there is no encoding. The body of each subpart of the multipart message is included as verbatim bytes. Consequently you have to be careful to choose a boundary string that doesn't occur anywhere in the file data.
To parse a multipart/form-data form submission you will enough of a MIME parser to parse the headers, pick out parameters you want like boundary and name, and split the received message by the boundary string. This is not completely trivial, so you may want to consider existing libraries.
(Unfortunately, what browsers actually do in HTTP differs a bit from the standard MIME rules outlined in RFC 1341. In particular, field name and filename parameters tend to include non-ASCII characters and unescaped quotes. But if you are generating the POST yourself hopefully you can steer clear of these areas of contention.)
In the absence of a "Content_Transfer_Encoding" header, it is assumed data is encoded in "7bit" (RFC 1521; RFC 1867; RFC 2616).
I don't know if tere's a C library to parse / decode HTTP POSTs. I'm pretty sure there are though :)
You can upload unlimited size of data/file. Try this solution
const char* ctype = "multipart/form-data; boundary=----WebKitFormBoundaryfm9qwXVLSbFKKR88";
size_t content_length = 1459606;
http_payload* hp = new http_payload(ctype, content_length);
if (hp->is_multipart()) {
int ret = hp->read_all("C:\\temp\\");
if (ret < 0) {
std::cout << hp->get_last_error() << std::endl;
hp->clear();
}
else {
std::string dir_str("C:\\upload_dir\\");
ret = hp->read_files([&dir_str](http_posted_file* file) {
std::string path(dir_str.c_str());
path.append(file->get_file_name());
file->save_as(path.c_str());
file->clear(); path.clear();
std::string().swap(path);
});
hp->clear();
std::cout << "Total file uploaded :" << ret << std::endl;
}
}
else {
int ret = hp->read_all();
if (ret < 0) {
std::cout << hp->get_last_error() << std::endl;
hp->clear();
}
else {
std::cout << "Posted data :" << hp->get_body() << std::endl;
hp->clear();
}
}
https://github.com/safeonlineworld/web_jsx/blob/0d08773c95f4ae8a9799dbd29e0a4cd84413d108/src/web_jsx/core/http_payload.cpp#L402