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 <andy.shaw@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Timur Pocheptsov 2017-09-29 10:16:11 +02:00
parent 06cb408979
commit 49643145e1

View File

@ -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