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