diff options
author | Mikhail Svetkin <mikhail.svetkin@qt.io> | 2019-03-25 16:09:50 +0100 |
---|---|---|
committer | Mikhail Svetkin <mikhail.svetkin@qt.io> | 2019-04-08 13:49:38 +0000 |
commit | 5147076e5ede09fafa96e147ab41dbb5744b8655 (patch) | |
tree | 2c8840d062c6e3069448d933bceaa6d6abf8dd1f | |
parent | be06bd66b8c8613498df06026dd8f10164dbd4ff (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.cpp | 3 | ||||
-rw-r--r-- | src/httpserver/qhttpserverrequest.cpp | 8 | ||||
-rw-r--r-- | src/httpserver/qhttpserverrequest_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qhttpserver/tst_qhttpserver.cpp | 62 |
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"); |