mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-04-28 03:14:32 +00:00
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>
This commit is contained in:
parent
be06bd66b8
commit
5147076e5e
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user