From 670266a075c7c312c6a7f9465298bfec0b968ee2 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 7 Dec 2016 10:07:25 +0100 Subject: Fix the parser of port in hand shake request Use QUrl::setAuthority() to parse host and port. The request is invalid when having username or password in Host. Task-number: QTBUG-57357 Change-Id: I4e7c0370794dce15359d372a1e36dc0383083204 Reviewed-by: Thiago Macieira --- src/websockets/qwebsockethandshakerequest.cpp | 16 ++-- .../handshakerequest/tst_handshakerequest.cpp | 103 +++++++++++++++++++++ 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/src/websockets/qwebsockethandshakerequest.cpp b/src/websockets/qwebsockethandshakerequest.cpp index 81c5f97..ddeee2d 100644 --- a/src/websockets/qwebsockethandshakerequest.cpp +++ b/src/websockets/qwebsockethandshakerequest.cpp @@ -275,16 +275,12 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH if (m_requestUrl.isRelative()) { // see http://tools.ietf.org/html/rfc6455#page-17 // No. 4 item in "The requirements for this handshake" - int idx = host.indexOf(QStringLiteral(":")); - bool ok = false; - int port = 0; - if (idx != -1) { - port = host.rightRef(host.length() - idx - 1).toInt(&ok); - host.truncate(idx); + m_requestUrl.setAuthority(host); + if (!m_requestUrl.userName().isNull()) { // If the username is null, the password must be too. + m_isValid = false; + clear(); + return; } - m_requestUrl.setHost(host); - if (ok) - m_requestUrl.setPort(port); } if (m_requestUrl.scheme().isEmpty()) { const QString scheme = isSecure() ? QStringLiteral("wss") : QStringLiteral("ws"); @@ -337,7 +333,7 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH //TODO: authentication field - m_isValid = !(host.isEmpty() || + m_isValid = !(m_requestUrl.host().isEmpty() || resourceName.isEmpty() || m_versions.isEmpty() || m_key.isEmpty() || diff --git a/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp b/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp index 3419546..4a9603f 100644 --- a/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp +++ b/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp @@ -67,6 +67,9 @@ private Q_SLOTS: void tst_qtbug_39355(); void tst_qtbug_48123_data(); void tst_qtbug_48123(); + + void tst_qtbug_57357_data(); + void tst_qtbug_57357(); // ipv6 related }; tst_HandshakeRequest::tst_HandshakeRequest() @@ -375,6 +378,106 @@ void tst_HandshakeRequest::tst_qtbug_48123() QCOMPARE(request.isValid(), shouldBeValid); } +void tst_HandshakeRequest::tst_qtbug_57357_data() +{ + QTest::addColumn("header"); + QTest::addColumn("valid"); + QTest::addColumn("host"); + QTest::addColumn("port"); + + QString header = QLatin1String("GET /ABC/DEF/ HTTP/1.1\r\nHost: %1%2\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n\r\n"); + + QTest::newRow("ipv4-1") << header.arg(QStringLiteral("10.0.0.1")).arg(QStringLiteral(":1234")) << true + << QStringLiteral("10.0.0.1") + << 1234; + QTest::newRow("ipv4-2") << header.arg(QStringLiteral("127.0.0.1")).arg(QStringLiteral(":1111")) << true + << QStringLiteral("127.0.0.1") + << 1111; + QTest::newRow("ipv4-wo-port") << header.arg(QStringLiteral("10.0.0.1")).arg(QStringLiteral("")) << true + << QStringLiteral("10.0.0.1") + << 8080; + + QTest::newRow("ipv6-1") << header.arg(QStringLiteral("[56:56:56:56:56:56:56:56]")).arg(QStringLiteral(":1234")) << true + << QStringLiteral("56:56:56:56:56:56:56:56") + << 1234; + QTest::newRow("ipv6-2") << header.arg(QStringLiteral("[::ffff:129.144.52.38]")).arg(QStringLiteral(":1111")) << true + << QStringLiteral("::ffff:129.144.52.38") + << 1111; + QTest::newRow("ipv6-wo-port") << header.arg(QStringLiteral("[56:56:56:56:56:56:56:56]")).arg(QStringLiteral("")) << true + << QStringLiteral("56:56:56:56:56:56:56:56") + << 8080; + QTest::newRow("ipv6-invalid-1") << header.arg(QStringLiteral("56:56:56:56:56:56:56:56]")).arg(QStringLiteral(":1234")) << false + << QStringLiteral("") + << 1234; + + QTest::newRow("host-1") << header.arg(QStringLiteral("foo.com")).arg(QStringLiteral(":1234")) << true + << QStringLiteral("foo.com") + << 1234; + QTest::newRow("host-2") << header.arg(QStringLiteral("bar.net")).arg(QStringLiteral(":1111")) << true + << QStringLiteral("bar.net") + << 1111; + QTest::newRow("host-wo-port") << header.arg(QStringLiteral("foo.com")).arg(QStringLiteral("")) << true + << QStringLiteral("foo.com") + << 8080; + + QTest::newRow("localhost-1") << header.arg(QStringLiteral("localhost")).arg(QStringLiteral(":1234")) << true + << QStringLiteral("localhost") + << 1234; + QTest::newRow("localhost-2") << header.arg(QStringLiteral("localhost")).arg(QStringLiteral(":1111")) << true + << QStringLiteral("localhost") + << 1111; + QTest::newRow("localhost-wo-port") << header.arg(QStringLiteral("localhost")).arg(QStringLiteral("")) << true + << QStringLiteral("localhost") + << 8080; + + // reference: qtbase/tests/auto/corelib/io/qurl/tst_qurl.cpp: void tst_QUrl::ipvfuture_data() + QTest::newRow("ipvfuture-1") << header.arg(QStringLiteral("[v7.1234]")).arg(QStringLiteral(":1234")) << true + << QStringLiteral("v7.1234") + << 1234; + + QTest::newRow("invalid-1") << header.arg(QStringLiteral("abc:def@foo.com")).arg(QStringLiteral("")) << false + << QStringLiteral("foo.com") + << 8080; + QTest::newRow("invalid-2") << header.arg(QStringLiteral(":def@foo.com")).arg(QStringLiteral("")) << false + << QStringLiteral("foo.com") + << 8080; + QTest::newRow("invalid-3") << header.arg(QStringLiteral("abc:@foo.com")).arg(QStringLiteral("")) << false + << QStringLiteral("foo.com") + << 8080; + QTest::newRow("invalid-4") << header.arg(QStringLiteral("@foo.com")).arg(QStringLiteral("")) << false + << QStringLiteral("foo.com") + << 8080; + QTest::newRow("invalid-5") << header.arg(QStringLiteral("foo.com/")).arg(QStringLiteral("")) << false + << QStringLiteral("foo.com") + << 8080; +} + +void tst_HandshakeRequest::tst_qtbug_57357() +{ + QFETCH(QString, header); + QFETCH(bool, valid); + QFETCH(QString, host); + QFETCH(int, port); + + QByteArray data; + QTextStream textStream(&data); + QWebSocketHandshakeRequest request(8080, false); + + textStream << header; + textStream.seek(0); + request.readHandshake(textStream, MAX_HEADERLINE_LENGTH, MAX_HEADERS); + + QCOMPARE(request.isValid(), valid); + if (valid) { + QCOMPARE(request.host(), host); + QCOMPARE(request.port(), port); + } +} + QTEST_MAIN(tst_HandshakeRequest) #include "tst_handshakerequest.moc" -- cgit v1.2.1