Encode the port from host URI when encoding the :authority header

According to RFC :authority header should include host name and
port if it's not the default one. In current implementation we
ignore this requirement, which is incorrect. Also we cannot use
QUrl::authority, since RFC explicitly states:

  The authority MUST NOT include the deprecated userinfo
  subcomponent for http or https schemed URIs.

https://www.rfc-editor.org/rfc/rfc7540.html#section-8.1.2.3

Pick-to: 6.8 6.9
Change-Id: I69428f7c013a44a47f36443a82819233e4cb852e
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
This commit is contained in:
Alexey Edelev 2025-01-28 20:54:31 +01:00
parent c3ee8ef3a6
commit 8bcd951804
1 changed files with 16 additions and 1 deletions

View File

@ -268,6 +268,8 @@ public:
}
[[nodiscard]] QByteArrayView contentType() const { return m_contentType; }
[[nodiscard]] const QByteArray &authorityHeader() const { return m_authorityHeader; }
std::shared_ptr<QAbstractProtobufSerializer> serializer;
QUrl hostUri;
QGrpcHttp2Channel *q_ptr = nullptr;
@ -311,6 +313,7 @@ private:
ConnectionState m_state = Connecting;
std::function<void()> m_reconnectFunction;
QByteArray m_authorityHeader;
Q_DISABLE_COPY_MOVE(QGrpcHttp2ChannelPrivate)
};
@ -459,7 +462,7 @@ void Http2Handler::prepareInitialRequest(QGrpcOperationContext *operationContext
QByteArray service{ operationContext->service().data(), operationContext->service().size() };
QByteArray method{ operationContext->method().data(), operationContext->method().size() };
m_initialHeaders = HPack::HttpHeader{
{ AuthorityHeader.toByteArray(), channel->hostUri.host().toLatin1() },
{ AuthorityHeader.toByteArray(), channel->authorityHeader() },
{ MethodHeader.toByteArray(), "POST"_ba },
{ PathHeader.toByteArray(), QByteArray('/' + service + '/' + method) },
{ SchemeHeader.toByteArray(),
@ -655,6 +658,7 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Ch
QString::fromLatin1(it.value()));
}
bool nonDefaultPort = false;
#if QT_CONFIG(localserver)
if (hostUri.scheme() == "unix"_L1) {
auto *localSocket = initSocket<QLocalSocket>();
@ -680,6 +684,8 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Ch
auto *sslSocket = initSocket<QSslSocket>();
if (hostUri.port() < 0) {
hostUri.setPort(443);
} else {
nonDefaultPort = hostUri.port() != 443;
}
if (const auto userSslConfig = channelOptions.sslConfiguration(); userSslConfig) {
@ -718,6 +724,8 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Ch
auto *httpSocket = initSocket<QTcpSocket>();
if (hostUri.port() < 0) {
hostUri.setPort(80);
} else {
nonDefaultPort = hostUri.port() != 80;
}
QObject::connect(httpSocket, &QAbstractSocket::connected, this,
@ -734,6 +742,13 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Ch
httpSocket->connectToHost(hostUri.host(), static_cast<quint16>(hostUri.port()));
};
}
m_authorityHeader = hostUri.host().toLatin1();
if (nonDefaultPort) {
m_authorityHeader += ':';
m_authorityHeader += QByteArray::number(hostUri.port());
}
m_reconnectFunction();
}