summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikhail Svetkin <mikhail.svetkin@qt.io>2019-03-25 16:09:50 +0100
committerMikhail Svetkin <mikhail.svetkin@qt.io>2019-04-08 13:49:38 +0000
commit5147076e5ede09fafa96e147ab41dbb5744b8655 (patch)
tree2c8840d062c6e3069448d933bceaa6d6abf8dd1f
parentbe06bd66b8c8613498df06026dd8f10164dbd4ff (diff)
Fix support for keep-alive connection
QAbstractHttpServer did not clear a request's internal properties (headers, url, body). If a request has a keep-alive header, QAbstractHttpServer should clear the request's internal properties. Change-Id: I2dfd0565369bd3291cd8d9900045c5a7f9d43ca3 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/httpserver/qabstracthttpserver.cpp3
-rw-r--r--src/httpserver/qhttpserverrequest.cpp8
-rw-r--r--src/httpserver/qhttpserverrequest_p.h2
-rw-r--r--tests/auto/qhttpserver/tst_qhttpserver.cpp62
4 files changed, 72 insertions, 3 deletions
diff --git a/src/httpserver/qabstracthttpserver.cpp b/src/httpserver/qabstracthttpserver.cpp
index a00bbf4..c07e687 100644
--- a/src/httpserver/qabstracthttpserver.cpp
+++ b/src/httpserver/qabstracthttpserver.cpp
@@ -94,6 +94,9 @@ void QAbstractHttpServerPrivate::handleReadyRead()
if (!socket->isTransactionStarted())
socket->startTransaction();
+ if (requestPrivate->state == QHttpServerRequestPrivate::State::OnMessageComplete)
+ requestPrivate->clear();
+
if (!requestPrivate->parse(socket)) {
socket->disconnect();
return;
diff --git a/src/httpserver/qhttpserverrequest.cpp b/src/httpserver/qhttpserverrequest.cpp
index f6c52dd..b92024a 100644
--- a/src/httpserver/qhttpserverrequest.cpp
+++ b/src/httpserver/qhttpserverrequest.cpp
@@ -116,6 +116,14 @@ uint QHttpServerRequestPrivate::headerHash(const QString &key) const
return qHash(key.toLower(), headersSeed);
}
+void QHttpServerRequestPrivate::clear()
+{
+ url.clear();
+ lastHeader.clear();
+ headers.clear();
+ body.clear();
+}
+
bool QHttpServerRequestPrivate::parseUrl(const char *at, size_t length, bool connect, QUrl *url)
{
static const std::map<std::size_t, std::function<void(const QString &, QUrl *)>> functions {
diff --git a/src/httpserver/qhttpserverrequest_p.h b/src/httpserver/qhttpserverrequest_p.h
index e128663..0a493f0 100644
--- a/src/httpserver/qhttpserverrequest_p.h
+++ b/src/httpserver/qhttpserverrequest_p.h
@@ -85,6 +85,8 @@ public:
const uint headersSeed = uint(qGlobalQHashSeed());
uint headerHash(const QString &key) const;
+ void clear();
+
private:
static http_parser_settings httpParserSettings;
static bool parseUrl(const char *at, size_t length, bool connect, QUrl *url);
diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp
index aeb3a92..9fb33d1 100644
--- a/tests/auto/qhttpserver/tst_qhttpserver.cpp
+++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp
@@ -84,6 +84,7 @@ private slots:
void initTestCase();
void routeGet_data();
void routeGet();
+ void routeKeepAlive();
void routePost_data();
void routePost();
void routeDelete_data();
@@ -180,9 +181,6 @@ void tst_QHttpServer::initTestCase()
.arg(request.query().queryItemValue("key"));
});
- urlBase = QStringLiteral("http://localhost:%1%2").arg(httpserver.listen());
-
-
httpserver.router()->addConverter<CustomArg>(QLatin1String("[+-]?\\d+"));
httpserver.route("/check-custom-type/", [] (const CustomArg &customArg) {
return QString("data = %1").arg(customArg.data);
@@ -364,6 +362,64 @@ void tst_QHttpServer::routeGet()
QCOMPARE(reply->readAll(), body);
}
+void tst_QHttpServer::routeKeepAlive()
+{
+ httpserver.route("/keep-alive", [] (const QHttpServerRequest &req) -> QHttpServerResponse {
+ if (req.headers()["Connection"] != "keep-alive")
+ return QHttpServerResponse::StatusCode::NotFound;
+
+ return QString("header: %1, query: %2, body: %3, method: %4")
+ .arg(req.value("CustomHeader"),
+ req.url().query(),
+ req.body())
+ .arg(static_cast<int>(req.method()));
+ });
+
+ QNetworkAccessManager networkAccessManager;
+ QNetworkRequest request(urlBase.arg("/keep-alive"));
+ request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));
+
+ auto checkReply = [] (QNetworkReply *reply, const QString &response) {
+ QTRY_VERIFY(reply->isFinished());
+
+ QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), "text/html");
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+ QCOMPARE(reply->readAll(), response);
+ };
+
+ checkReply(networkAccessManager.get(request),
+ QString("header: , query: , body: , method: %1")
+ .arg(static_cast<int>(QHttpServerRequest::Method::Get)));
+ if (QTest::currentTestFailed())
+ return;
+
+ request.setUrl(urlBase.arg("/keep-alive?po=98"));
+ request.setRawHeader("CustomHeader", "1");
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "text/html");
+
+ checkReply(networkAccessManager.post(request, QByteArray("test")),
+ QString("header: 1, query: po=98, body: test, method: %1")
+ .arg(static_cast<int>(QHttpServerRequest::Method::Post)));
+ if (QTest::currentTestFailed())
+ return;
+
+ request = QNetworkRequest(urlBase.arg("/keep-alive"));
+ request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "text/html");
+
+ checkReply(networkAccessManager.post(request, QByteArray("")),
+ QString("header: , query: , body: , method: %1")
+ .arg(static_cast<int>(QHttpServerRequest::Method::Post)));
+ if (QTest::currentTestFailed())
+ return;
+
+ checkReply(networkAccessManager.get(request),
+ QString("header: , query: , body: , method: %1")
+ .arg(static_cast<int>(QHttpServerRequest::Method::Get)));
+ if (QTest::currentTestFailed())
+ return;
+}
+
void tst_QHttpServer::routePost_data()
{
QTest::addColumn<QString>("url");