diff options
Diffstat (limited to 'src/network/access/http2/http2protocol.cpp')
-rw-r--r-- | src/network/access/http2/http2protocol.cpp | 132 |
1 files changed, 62 insertions, 70 deletions
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp index baae68bc30..8e7e176c41 100644 --- a/src/network/access/http2/http2protocol.cpp +++ b/src/network/access/http2/http2protocol.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "http2protocol_p.h" #include "http2frames_p.h" @@ -50,6 +14,10 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + +QT_IMPL_METATYPE_EXTERN_TAGGED(Http2::Settings, Http2__Settings) + Q_LOGGING_CATEGORY(QT_HTTP2, "qt.network.http2") namespace Http2 @@ -108,12 +76,10 @@ void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetwor Q_ASSERT(request); // RFC 2616, 14.10 // RFC 7540, 3.2 - QByteArray value(request->headerField("Connection")); + const QByteArray connectionHeader = request->headerField("Connection"); + const auto separator = connectionHeader.isEmpty() ? QByteArrayView() : QByteArrayView(", "); // We _append_ 'Upgrade': - if (value.size()) - value += ", "; - - value += "Upgrade, HTTP2-Settings"; + QByteArray value = connectionHeader + separator + "Upgrade, HTTP2-Settings"; request->setHeaderField("Connection", value); // This we just (re)write. request->setHeaderField("Upgrade", "h2c"); @@ -128,7 +94,7 @@ void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, { if (errorCode > quint32(HTTP_1_1_REQUIRED)) { error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("RST_STREAM with unknown error code (%1)"); + errorMessage = "RST_STREAM with unknown error code (%1)"_L1; errorMessage = errorMessage.arg(errorCode); return; } @@ -142,61 +108,61 @@ void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, break; case PROTOCOL_ERROR: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("HTTP/2 protocol error"); + errorMessage = "HTTP/2 protocol error"_L1; break; case INTERNAL_ERROR: error = QNetworkReply::InternalServerError; - errorMessage = QLatin1String("Internal server error"); + errorMessage = "Internal server error"_L1; break; case FLOW_CONTROL_ERROR: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Flow control error"); + errorMessage = "Flow control error"_L1; break; case SETTINGS_TIMEOUT: error = QNetworkReply::TimeoutError; - errorMessage = QLatin1String("SETTINGS ACK timeout error"); + errorMessage = "SETTINGS ACK timeout error"_L1; break; case STREAM_CLOSED: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Server received frame(s) on a half-closed stream"); + errorMessage = "Server received frame(s) on a half-closed stream"_L1; break; case FRAME_SIZE_ERROR: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Server received a frame with an invalid size"); + errorMessage = "Server received a frame with an invalid size"_L1; break; case REFUSE_STREAM: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Server refused a stream"); + errorMessage = "Server refused a stream"_L1; break; case CANCEL: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Stream is no longer needed"); + errorMessage = "Stream is no longer needed"_L1; break; case COMPRESSION_ERROR: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Server is unable to maintain the " - "header compression context for the connection"); + errorMessage = "Server is unable to maintain the " + "header compression context for the connection"_L1; break; case CONNECT_ERROR: // TODO: in Qt6 we'll have to add more error codes in QNetworkReply. error = QNetworkReply::UnknownNetworkError; - errorMessage = QLatin1String("The connection established in response " - "to a CONNECT request was reset or abnormally closed"); + errorMessage = "The connection established in response " + "to a CONNECT request was reset or abnormally closed"_L1; break; case ENHANCE_YOUR_CALM: error = QNetworkReply::UnknownServerError; - errorMessage = QLatin1String("Server dislikes our behavior, excessive load detected."); + errorMessage = "Server dislikes our behavior, excessive load detected."_L1; break; case INADEQUATE_SECURITY: error = QNetworkReply::ContentAccessDenied; - errorMessage = QLatin1String("The underlying transport has properties " - "that do not meet minimum security " - "requirements"); + errorMessage = "The underlying transport has properties " + "that do not meet minimum security " + "requirements"_L1; break; case HTTP_1_1_REQUIRED: error = QNetworkReply::ProtocolFailure; - errorMessage = QLatin1String("Server requires that HTTP/1.1 " - "be used instead of HTTP/2."); + errorMessage = "Server requires that HTTP/1.1 " + "be used instead of HTTP/2."_L1; } } @@ -218,19 +184,45 @@ QNetworkReply::NetworkError qt_error(quint32 errorCode) bool is_protocol_upgraded(const QHttpNetworkReply &reply) { - if (reply.statusCode() == 101) { - // Do some minimal checks here - we expect 'Upgrade: h2c' to be found. - const auto &header = reply.header(); - for (const QPair<QByteArray, QByteArray> &field : header) { - if (field.first.compare("upgrade", Qt::CaseInsensitive) == 0 && - field.second.compare("h2c", Qt::CaseInsensitive) == 0) - return true; - } + if (reply.statusCode() != 101) + return false; + + // Do some minimal checks here - we expect 'Upgrade: h2c' to be found. + for (const auto &v : reply.header().values(QHttpHeaders::WellKnownHeader::Upgrade)) { + if (v.compare("h2c", Qt::CaseInsensitive) == 0) + return true; } return false; } +std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames) +{ + std::vector<uchar> hpackBlock; + + size_t total = 0; + for (const auto &frame : frames) { + if (qAddOverflow(total, size_t{frame.hpackBlockSize()}, &total)) + return hpackBlock; + } + + if (!total) + return hpackBlock; + + hpackBlock.resize(total); + auto dst = hpackBlock.begin(); + for (const auto &frame : frames) { + if (const auto hpackBlockSize = frame.hpackBlockSize()) { + const uchar *src = frame.hpackBlockBegin(); + std::copy(src, src + hpackBlockSize, dst); + dst += hpackBlockSize; + } + } + + return hpackBlock; +} + + } // namespace Http2 QT_END_NAMESPACE |