From 49643145e13ff74cb3ecf6f5680fa23c91f661ff Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 29 Sep 2017 10:16:11 +0200 Subject: HTTP/2 protocol handler: set redirect URL on reply For HTTP/1 it's done when no data expected and response headers received - protocol handler emits channel->allDone which handles the status code and sets (if needed) a redirectUrl. HTTP/2 protocol handler cannot emit allDone (it has many requests multiplexed and actually cannot say allDone yet). So we set a redirect url if we have the corresponding status code and found 'location' header. Task-number: QTBUG-63471 Change-Id: Ibd3438ef918c245a46b8c0128910a89b9a418448 Reviewed-by: Andy Shaw Reviewed-by: Edward Welbourne --- src/network/access/qhttp2protocolhandler.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 44ab637da8..114feb91b7 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -1034,12 +1034,26 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } const auto httpReplyPrivate = httpReply->d_func(); + + // For HTTP/1 'location' is handled (and redirect URL set) when a protocol + // handler emits channel->allDone(). Http/2 protocol handler never emits + // allDone, since we have many requests multiplexed in one channel at any + // moment and we are probably not done yet. So we extract url and set it + // here, if needed. + int statusCode = 0; + QUrl redirectUrl; + for (const auto &pair : headers) { const auto &name = pair.name; auto value = pair.value; + // TODO: part of this code copies what SPDY protocol handler does when + // processing headers. Binary nature of HTTP/2 and SPDY saves us a lot + // of parsing and related errors/bugs, but it would be nice to have + // more detailed validation of headers. if (name == ":status") { - httpReply->setStatusCode(value.left(3).toInt()); + statusCode = value.left(3).toInt(); + httpReply->setStatusCode(statusCode); httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4)); } else if (name == ":version") { httpReplyPrivate->majorVersion = value.at(5) - '0'; @@ -1050,6 +1064,8 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (ok) httpReply->setContentLength(length); } else { + if (name == "location") + redirectUrl = QUrl::fromEncoded(value); QByteArray binder(", "); if (name == "set-cookie") binder = "\n"; @@ -1057,6 +1073,9 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } } + if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) + httpReply->setRedirectUrl(redirectUrl); + if (connectionType == Qt::DirectConnection) emit httpReply->headerChanged(); else -- cgit v1.2.3