Qhttp request and response debugging - qt

OS: Windows XP/Vista
Qt version: 4.6.1
Using OpenSSL
I need to watch the actual requests and responses that is going through the wire for QHttp requests and responses and in some cases need to interrupt the request. I tried with few of the http debuggers available in the market but they seem to work only for requests that are using the WinInet functions. Unfortunately, the openssldump utility is not present on windows platforms.
Thank you.

Wouldn't using QNetworkAccessManger instead of QHttp (which is obsolete) and reimplementing
QNetworkReply * QNetworkAccessManager::createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 ) [virtual protected]
give you what you need?
Take a look at How to tell QWebPage not to load specific type of resources?. This is for QNAM used by QWebPage but it's the same for any code using QNAM.

Related

Using QNetworkAccessManager offline

My application consists from two apps. And one of them may ask another to perform some commands through a REST call (call an URL on localhost). For this purposes we use QNetworkAccessManager (for put, get and post request).
Now there is a problem - device may go offline sometimes and when he does it - for some reason we can't use rest calls through access manager. It seems that it happen when network configuration that it uses is destroyed (like disabling Wifi adapter etc). When this configuration is restored (enabled Wifi), access manager starts work again.
Another detail - when we start app while we are offline - it works regardless of online state. It may be related to this.
This reproduces on both Win and Mac.
So the question is how can i reliably use QNetworkAccessManager for this purposes irregardless of devices online state? We use this manager only for localhost REST calls. What default network configuration or behavior should i set?
Example of usage below:
mNetManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setRawHeader("User-Agent", "AppName/1.0");
request.setUrl(QUrl(url));
*reply = mNetManager->get(request);
Edit: online state is not required, since i need this access manager only for accessing local URLs on browser
It appears you can force network accessibility to get local content:
mNetManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setRawHeader("User-Agent", "AppName/1.0");
request.setUrl(QUrl(url));
mNetManager->setNetworkAccessible(QNetworkAccessManager::Accessible); // <--
auto reply = mNetManager->get(request);
The QNetworkAccessManager have stuff for network availability. Why not using it?
QNetworkAccessManager * mNetManager = new QNetworkAccessManager(this);
connect(mNetManager, &QNetworkAccessManager::networkAccessibleChanged,
this, &YourClass::slotExecutedWhenNetworkAccessibilityChanges);
NetworkAccessibility netAcc = mNetManager->networkAccessible();
switch (netAcc) {
case QNetworkAccessManager::Accessible:
// You are online.
break;
case QNetworkAccessManager::NotAccessible:
// You are offline.
break;
case QNetworkAccessManager::UnknownAccessibility:
default:
// You know nothing, Jon Snow.
break;
}

Asynchronous WebSockets in Winhttp Windows 8

I want just to add WebSockets to my app that uses WinHTTP in async mode.
When I need a WebSocket I call the following.
Before sending request:
WinHttpSetOption(context->hRequest, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
In WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
appContext->pIoRequest->hWebSocketHandle = WinHttpWebSocketCompleteUpgrade(appContext->hRequest, NULL);
WinHttpWebSocketReceive(appContext->pIoRequest->hWebSocketHandle, appContext->pszOutBuffer,RESPONSE_BUFFER_SIZE, NULL, NULL);
all without errors.
Now I see in Fiddler that the server sends some data to my WebSocket but there is no WINHTTP_CALLBACK_STATUS_READ_COMPLETE triggered.
Any ideas why this is? How can I read asynchronously from my WebSocket? Sending data to the WebSocket works well.
Omg! I found how its work!
You MUST call additional WinHttpSetStatusCallback to set WebSocket callback for WebSocketHandle returned in WinHttpWebSocketCompleteUpgrade and this callback MUST differ then that from call WinHttpWebSocketCompleteUpgrade was made!
It is no possible to set a context pointer by WinHttpSetOption with WINHTTP_OPTION_CONTEXT_VALUE flag! Its not work. dwContext In WebSocketCallback has wrong data. Call to WinHttpQueryOption in WebSocketCallback return wrong context data. I think that is a BUG in Windows 8.1. I write my own handler to connect my context with WebSocketHandle.
All of this is NOT documented in MSDN! Most of all, I did not google any info about async winhttp websocket usage... So, I am the first=) I will be very glad if my research will help you!
It seems websockets do not get PING and PONG messages to the callback!

How does a VLC client ask the server for more data in application layer (HTTP)?

I am working on a project related to video streaming. I have been reading the http code extensively in the access_output and access modules. My question is regarding how the client asks the server to send more data in the application layer, specifically using http. I assume it is within the httpd file located in the src/network folder, but I have been writing to log files and I can't seem to figure out how the client asks for the data. It really seems like the server just sends it to the client without acknowledgement, but I highly doubt this is the case.
Thank you so much for your help!
Requesting more data is achieved using HTTP GET with a Range header.
Examples:
Range: bytes=123-
Range: bytes=123-456
In VLC you can find the relevant code in modules/access/http.c:
static int Request( access_t *p_access, uint64_t i_tell )
{
[...]
/* Offset */
if( p_sys->i_version == 1 && ! p_sys->b_continuous )
{
p_sys->b_persist = true;
net_Printf( p_access, p_sys->fd, pvs,
"Range: bytes=%"PRIu64"-\r\n", i_tell );
net_Printf( p_access, p_sys->fd, pvs, "Connection: close\r\n" );
}
See also: HTTP Range Requests in the RFC.

Qt login to steam with QNetworkAccessManager

I'm using QT 5.0.2 prebuilt and QT creator 2.7.0 and my goal is to login to steam network programmatically using uname, password and steamguard code. Or to be more precise: get QNetworkAccessManager from its initial uninitialized state to the state where it could retrieve any data from steam related sites as if it was logged in as some user.
So the login happens in 4 steps (4 request-response combos):
NOTE: Steam site javascript uses post in all requests, but it seems that get also works.
Assume username "hyper"
1. Initial request:
post https://store.steampowered.com/login/getrsakey/?username=hyper
Here is my function:
void http::steam_auth(const QString &uname, const QString &pwd)
{
QString encrypted_password, sg, pkey_exp, pkey_mod, timestamp, emailsteamid;
QJsonDocument json_buffer;
QByteArray buffer;
QUrl rsa(steam_getrsa), login(steam_dologin); //steam login urls
QUrlQuery urlquery;
Here we send our request:
urlquery.addQueryItem("username", uname); //first step
urlquery.addQueryItem("l", "english"); //set communication language
rsa.setQuery(urlquery);
QNetworkRequest first(rsa);
QNetworkReply *reply = this->get(first);
buffer = reply->readAll();
As a response we get:
{"success":true,"publickey_mod":"AC41A964789638B6A3B3BD5ADD9F3680FA45881C70FD2032B10A3BB6D2ACF021C2B3D564DC44DE3054E3BF78A1753399223C794A0DED03A76CD1F1DFE851E30F0D6F14484C258EB6053676A47D20A68E11ECCD783F343594DDA3817AA5DCCE75FAF5C68BB197DA1FF12F22F9FCD83624D00A23CC57A367563ADBBCEDF5C8742A57B12A4BD04DC02A55C80F4F6984B1E2D5A99081510326E1C6BAB2C2723560487E8F7EA1A2CB55AEFC5594C9FBB71CAD553CB2D866214BC41156259FEC55362D38DCDBE8FADFB577FE0736CE3E37AF6D2CDDF28FA218C1E477E29B17713BFC48A227455B6B0DE09884CC0820CE40CD4877D93704D00E20A235FCF55D100A01C1","publickey_exp":"010001","timestamp":"284691100000"}
Which means everything is ok.
Now we need to encrypt our password before sending it
json_buffer = QJsonDocument::fromJson(buffer);
pkey_exp = json_buffer.object().value("publickey_exp").toString();
pkey_mod = json_buffer.object().value("publickey_mod").toString();
timestamp = json_buffer.object().value("timestamp").toString();
delete reply;
urlquery.clear();
encrypted_password = app::core::get_encrypted_password(pwd, pkey_exp, pkey_mod);
2. Send encrypted password:
urlquery.addQueryItem("username", uname);
urlquery.addQueryItem("password", encrypted_password);
urlquery.addQueryItem("emailauth", "");
urlquery.addQueryItem("captchagid", "");
urlquery.addQueryItem("captcha_text", "");
urlquery.addQueryItem("emailsteamid", "");
urlquery.addQueryItem("rsatimestamp", timestamp);
urlquery.addQueryItem("remember_login", "false");
login.setQuery(urlquery);
QNetworkRequest second(login);
second.setUrl(login);
reply = this->get(second);
buffer = reply->readAll();
We get a request string as follows:
post https://store.steampowered.com/login/dologin/?username=solidbeetle2&password=YmhTKVkRXyiCYe6wx+ZJ8PIhzj4A4BLWgJFOE5ge7nbIAM6m1G9qHh+Iqx30ZLdB0wW0xdWDNCgHBNPHKLA+P2pYhPF0DeL9v8UQsers6NCNNPZ0SFN4HhNlu6Gwh8QAjrNykev7N5FADXwJnFjPBvmvthATmrktVEtFYF54lckaPnijXYSDIpfEjmG8+bCDKT/GLaUiftA2QauUY9ap8WHSEoykiTmfL344ghzjhCA33UKx0NIgBrDdI1RLfHVcmAcU/c9NEhoHLOT93n8hqWY+YVx9VbOcKqqZPrbCiQoU2BZrqK6N7aj+K6kH0VWHH7+LD2KJx4BUJgHOmNqVDg%3D%3D&emailauth=&captchagid=&captcha_text=&emailsteamid=&rsatimestamp=50693150000&remember_login=false
It is perfectly valid as far as I can tell, JS on steam site sends ajax with the same, but...
Here is the problem
When I get a response with this it says message:Invalid login in json... But if I save the full query string from my request to file and then paste it either in browser or in HTTP Request builder inside HTTP Analyzer, it works fine displaying message:SteamGuard
What could be wrong? Is there something I'm missing? Does QNetworkAccessManager break this somehow?:c
Sorry if something is not clear, I'll try my best to explain again if needed.
Thanks in advance!
P.S. Is there any solid way to examine requests my app is sending?
P.S.S. my qt creator seems to crash when debugging projects with qml option, idk why...
I have inspected all this stuff and finally was able to achieve my goal.
In short the problem was in qt's web-oriented classes. It seemed obvious that qurlquery should encode characters such as / or = in their %-encoded form.. but it is NOT the case, therefore I had to replace them manually in QString. If someone needs a working routine, it can be found here (Its not pretty :c)

Qt creator SSL enable

I have a program built with Qt creator. I need to send an https post to Google's C2DM servers.
When I try using QSslSocket, it says that my SSL is not working.
The Qt documentation states that it doesn't ship with SSL support for legal reasons, and QSslSocket is just a wrapper and that I need to install OpenSSL myself. I've tried copying the DLLs but it still doesn't work. Can someone walk me through the steps of installing OpenSSL and getting it to work with Qt Creator?
Why not use QNetworkAccessManager? I use something like this to post JSON to a web service:
void HttpPoster::post(){
if(!manager)
manager = new QNetworkAccessManager(this);
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setPeerVerifyMode(QSslSocket::VerifyNone);
//config.setProtocol(QSsl::TlsV1);
QNetworkRequest request ;
request.setUrl(QUrl("https://somehost.somedomain"));
request.setRawHeader("User-Agent", "MyApp");
request.setRawHeader("Content-type", "text/json");
request.setSslConfiguration(config);
if(!reply){
reply = manager->post(request,m_Data);
}
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(handleErrors(QNetworkReply::NetworkError)));
connect(reply,SIGNAL(sslErrors(QList<QSslError>)),this,SLOT(handleSSLErrors(QList<QSslError>)));
connect(reply,SIGNAL(finished()),this,SLOT(replyFinished()));
}
There's some methods omitted (handle errors, handle replies, handle ssl errors, etc). You can find much better examples in the docs.

Resources