QH2Connection: Fix issue with unity-build/odr

The static function appeared in two places, and in a unity-build
this fails quite visibly.

Change-Id: I60000d01194a2c79ca9c101f2a6d3f77f469f1a7
Reviewed-by:  Alexey Edelev <alexey.edelev@qt.io>
Reviewed-by: Nodir Temirkhodjaev <nodir.temir@gmail.com>
(cherry picked from commit a3a48815cc9430d6f5c736a312ea4ea5c0895205)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Mårten Nordheim 2024-01-18 12:27:08 +01:00 committed by Qt Cherry-pick Bot
parent be4f933c0a
commit f6039b08b3
4 changed files with 48 additions and 87 deletions

View File

@ -504,6 +504,49 @@ void Decoder::handleStreamError(BitIStream &inputStream)
// HTTP2 layer will end with session error/COMPRESSION_ERROR.
}
std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader)
{
constexpr QByteArrayView names[] = { ":authority", ":method", ":path", ":scheme" };
enum PseudoHeaderEnum
{
Authority,
Method,
Path,
Scheme
};
std::array<std::optional<QByteArrayView>, std::size(names)> pseudoHeaders{};
for (const auto &field : requestHeader) {
const auto *it = std::find(std::begin(names), std::end(names), QByteArrayView(field.name));
if (it != std::end(names)) {
const auto index = std::distance(std::begin(names), it);
if (field.value.isEmpty() || pseudoHeaders.at(index).has_value())
return {};
pseudoHeaders[index] = field.value;
}
}
auto optionalIsSet = [](const auto &x) { return x.has_value(); };
if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), optionalIsSet)) {
// All four required, HTTP/2 8.1.2.3.
return {};
}
const QByteArrayView method = pseudoHeaders[Method].value();
if (method.compare("get", Qt::CaseInsensitive) != 0 &&
method.compare("head", Qt::CaseInsensitive) != 0) {
return {};
}
QUrl url;
url.setScheme(QLatin1StringView(pseudoHeaders[Scheme].value()));
url.setAuthority(QLatin1StringView(pseudoHeaders[Authority].value()));
url.setPath(QLatin1StringView(pseudoHeaders[Path].value()));
if (!url.isValid())
return {};
return url;
}
}
QT_END_NAMESPACE

View File

@ -18,8 +18,10 @@
#include "hpacktable_p.h"
#include <QtCore/qglobal.h>
#include <QtCore/qurl.h>
#include <vector>
#include <optional>
QT_BEGIN_NAMESPACE
@ -112,6 +114,7 @@ private:
FieldLookupTable lookupTable;
};
std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader);
}
QT_END_NAMESPACE

View File

@ -21,49 +21,6 @@ Q_LOGGING_CATEGORY(qHttp2ConnectionLog, "qt.network.http2.connection", QtCritica
using namespace Qt::StringLiterals;
using namespace Http2;
static std::optional<QUrl> makeUrl(const HPack::HttpHeader &requestHeader)
{
constexpr QByteArrayView names[] = { ":authority", ":method", ":path", ":scheme" };
enum PseudoHeaderEnum
{
Authority,
Method,
Path,
Scheme
};
std::array<std::optional<QByteArrayView>, std::size(names)> pseudoHeaders{};
for (const auto &field : requestHeader) {
const auto *it = std::find(std::begin(names), std::end(names), QByteArrayView(field.name));
if (it != std::end(names)) {
const auto index = std::distance(std::begin(names), it);
if (field.value.isEmpty() || pseudoHeaders.at(index).has_value())
return {};
pseudoHeaders[index] = field.value;
}
}
auto optionalIsSet = [](const auto &x) { return x.has_value(); };
if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), optionalIsSet)) {
// All four required, HTTP/2 8.1.2.3.
return {};
}
const QByteArrayView method = pseudoHeaders[Method].value();
if (method.compare("get", Qt::CaseInsensitive) != 0 &&
method.compare("head", Qt::CaseInsensitive) != 0) {
return {};
}
QUrl url;
url.setScheme(QLatin1StringView(pseudoHeaders[Scheme].value()));
url.setAuthority(QLatin1StringView(pseudoHeaders[Authority].value()));
url.setPath(QLatin1StringView(pseudoHeaders[Path].value()));
if (!url.isValid())
return {};
return url;
}
QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept
: QObject(connection), m_streamID(streamID)
{
@ -1297,7 +1254,7 @@ void QHttp2Connection::handleContinuedHEADERS()
streamIt.value()->handleHEADERS(continuedFrames[0].flags(), decoder.decodedHeader());
break;
case FrameType::PUSH_PROMISE: {
std::optional<QUrl> promiseKey = makeUrl(decoder.decodedHeader());
std::optional<QUrl> promiseKey = HPack::makePromiseKeyUrl(decoder.decodedHeader());
if (!promiseKey)
return; // invalid URL/key !
if (m_promisedStreams.contains(*promiseKey))

View File

@ -1468,54 +1468,12 @@ quint32 QHttp2ProtocolHandler::allocateStreamID()
return streamID;
}
static std::optional<QUrl> makeUrl(const HPack::HttpHeader &requestHeader)
{
constexpr QByteArrayView names[] = { ":authority", ":method", ":path", ":scheme" };
enum PseudoHeaderEnum
{
Authority,
Method,
Path,
Scheme
};
std::array<std::optional<QByteArrayView>, std::size(names)> pseudoHeaders{};
for (const auto &field : requestHeader) {
const auto it = std::find(std::begin(names), std::end(names), QByteArrayView(field.name));
if (it != std::end(names)) {
const auto index = std::distance(std::begin(names), it);
if (field.value.isEmpty() || pseudoHeaders.at(index).has_value())
return {};
pseudoHeaders[index] = field.value;
}
}
if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), [](const auto &x) { return x.has_value();})) {
// All four required, HTTP/2 8.1.2.3.
return {};
}
const QByteArrayView method = pseudoHeaders[Method].value();
if (method.compare("get", Qt::CaseInsensitive) != 0 &&
method.compare("head", Qt::CaseInsensitive) != 0) {
return {};
}
QUrl url;
url.setScheme(QLatin1StringView(pseudoHeaders[Scheme].value()));
url.setAuthority(QLatin1StringView(pseudoHeaders[Authority].value()));
url.setPath(QLatin1StringView(pseudoHeaders[Path].value()));
if (!url.isValid())
return {};
return url;
}
bool QHttp2ProtocolHandler::tryReserveStream(const Http2::Frame &pushPromiseFrame,
const HPack::HttpHeader &requestHeader)
{
Q_ASSERT(pushPromiseFrame.type() == FrameType::PUSH_PROMISE);
const auto url = makeUrl(requestHeader);
const auto url = HPack::makePromiseKeyUrl(requestHeader);
if (!url.has_value())
return false;