From 259a167beb094929b3b26c8072b970f3903ef65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 22 Mar 2021 11:02:52 +0100 Subject: HTTP/2 authentication required With Qt 6 we made HTTP/2 default, which exposed missing handling of 401 Unauthorized (and 407 Proxy Authentication Required). In HTTP/1.* we would handle this after the response had finished, while handling the status code. For h2 this path isn't used since it is heavily reliant on the structure we have for HTTP/1.* (one request per channel). So we must handle the status code and header directly. Having that part fixed exposed another issue - when resetting/rewinding uploaded data we were not resetting the 'totallyUploadedData' counter in the reply (this, in turn, exposed another small issue). Because of that we did not actually send any data on the retry, only sending the content-length followed by no data. Finally, the small issue mentioned in the previous paragraph was how we check if we have uploaded all our data. It was only checking if the byte-device was atEnd(), which it was. But only because it had not yet prepared any data for us. Fixes: QTBUG-91284 Change-Id: I798d105b02688b18a02897cc476f19f57a47f98f Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne (cherry picked from commit 52a0eb4791727157a7b385f7e022faad28da4821) --- tests/auto/network/access/http2/http2srv.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'tests/auto/network/access/http2/http2srv.cpp') diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index a8eebf5a24..c374b6abd8 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -120,6 +120,11 @@ void Http2Server::setResponseBody(const QByteArray &body) responseBody = body; } +void Http2Server::setAuthenticationHeader(const QByteArray &authentication) +{ + authenticationHeader = authentication; +} + void Http2Server::emulateGOAWAY(int timeout) { Q_ASSERT(timeout >= 0); @@ -138,6 +143,17 @@ bool Http2Server::isClearText() const return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect; } +QByteArray Http2Server::requestAuthorizationHeader() +{ + const auto isAuthHeader = [](const HeaderField &field) { + return field.name == "authorization"; + }; + const auto requestHeaders = decoder.decodedHeader(); + const auto authentication = + std::find_if(requestHeaders.cbegin(), requestHeaders.cend(), isAuthHeader); + return authentication == requestHeaders.cend() ? QByteArray() : authentication->value; +} + void Http2Server::startServer() { if (listen()) { @@ -736,6 +752,9 @@ void Http2Server::handleDATA() streamWindows.erase(it); emit receivedData(streamID); } + emit receivedDATAFrame(streamID, + QByteArray(reinterpret_cast(inboundFrame.dataBegin()), + inboundFrame.dataSize())); } void Http2Server::handleWINDOW_UPDATE() @@ -816,6 +835,9 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) if (emptyBody) writer.addFlag(FrameFlag::END_STREAM); + // We assume any auth is correct. Leaves the checking to the test itself + const bool hasAuth = !requestAuthorizationHeader().isEmpty(); + HttpHeader header; if (redirectWhileReading) { if (redirectSent) { @@ -832,6 +854,10 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"), QString::number(targetPort)).toLatin1()}); + } else if (!authenticationHeader.isEmpty() && !hasAuth) { + header.push_back({ ":status", "401" }); + header.push_back(HPack::HeaderField("www-authenticate", authenticationHeader)); + authenticationHeader.clear(); } else { header.push_back({":status", "200"}); } -- cgit v1.2.3 From 7e722fe1fac3f8c581f6339c77d189fd757bb15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 28 Apr 2021 18:19:57 +0200 Subject: Let the h2 test server both send and receive DATA frames And use this in the authenticationRequired test. Change-Id: I18e991eb67168214c2c4f829afaca5018568e989 Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov (cherry picked from commit deda40b8591a387e634ebfcf48287c14162ef332) Reviewed-by: Qt CI Bot --- tests/auto/network/access/http2/http2srv.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests/auto/network/access/http2/http2srv.cpp') diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index c374b6abd8..e2f039e2f7 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -748,8 +748,10 @@ void Http2Server::handleDATA() } if (inboundFrame.flags().testFlag(FrameFlag::END_STREAM)) { - closedStreams.insert(streamID); // Enter "half-closed remote" state. - streamWindows.erase(it); + if (responseBody.isEmpty()) { + closedStreams.insert(streamID); // Enter "half-closed remote" state. + streamWindows.erase(it); + } emit receivedData(streamID); } emit receivedDATAFrame(streamID, -- cgit v1.2.3