I want to intercept, inspect and (if needed) reject AJAX-Requests based on the Fingerprint of the SSL-Certificate. I use the QNetworkAccessManager::createRequest(...)
function to issue requests. Everything works fine when I use QWebFrame::load(...)
. Even the content which is loaded within the request (like .css or .js files) emit signals. Unfortunately no AJAX-Requests emits any Signals. I know that the Signals are connected to the very same slots (for "normal" as well as AJAX-Requests) within MyNetworkAccessManager::createRequest(...)
function.
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
connect(reply, SIGNAL(readyRead()), this, SLOT(handleStarted()));
connect(reply, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(handleSslErrors(const QList<QSslError> &)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleNetworkError()));
Why are AJAX Requests so different? Where can I access them?
From what I can tell, AJAX requests do emit the finished signal on QNetworkAccessManager. You need connect to the instance of QNetworkAccessManager on your QWebPage instance:
QWebPage *page = ui->webView->page();
QNetworkAccessManager *nam = page->networkAccessManager();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
QFile file;
file.setFileName(":/js/jquery-2.1.1.min.js"); // jQuery is loaded as a resource
file.open(QIODevice::ReadOnly);
QString jQuery = file.readAll();
file.close();
ui->webView->load(QUrl("about:blank"));
QWebFrame *frame = m_page->mainFrame();
frame->evaluateJavaScript(jQuery); // load jQuery
// check that jQuery is loaded
frame->evaluateJavaScript("$(document).ready(function() { alert('jQuery loaded!'); });");
// do an AJAX GET
frame->evaluateJavaScript("$.ajax({"
"url: 'http://www.json-generator.com/api/json/get/cqkXBAEoQy?indent=2',"
"method: 'GET',"
"dataType: 'json'"
"}).done(function (data) {"
"for (var i = 0; i < data.length; i++) {"
"alert(data[i].name);"
"}"
"}).error(function (data) { alert('AJAX error'); });");
Then you can monitor replies in the replyFinished slot like so:
void MainWindow::replyFinished(QNetworkReply *reply)
{
QByteArray bytes = reply->readAll();
QString str = QString::fromUtf8(bytes.data(), bytes.size());
QString replyUrl = reply->url().toString();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << statusCode;
qDebug() << replyUrl;
qDebug() << str;
}
I have noticed that jQuery AJAX's done promise doesn't seem to execute when you do anything with the QNetworkReply, but you can see that the request actually finishes in the debug console.
See my GitHub repository to try out the above code: https://github.com/pcmantinker/QtWebkitAJAX
As far as blocking connections based on SSL certificates, you'd have to subclass QNetworkAccessManager and override QNetworkAccessManager::createRequest. Something like this could work:
QNetworkReply *CustomQNetworkAccessManager::createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
QNetworkRequest req(request);
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
QSslConfiguration *sslConfig = reply->sslConfiguration();
QList<QSslCertificate> sslCaCerts = sslConfig->caCertificates();
// do something with sslCaCerts
return reply;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With