1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #include <QtTest/QtTest> |
29 | #include <QtTest/qtestcase.h> |
30 | #include <QtCore/QDebug> |
31 | #include <QtCore/QByteArray> |
32 | #include <QtCore/QtEndian> |
33 | |
34 | #include "private/qwebsockethandshakerequest_p.h" |
35 | #include "private/qwebsocketprotocol_p.h" |
36 | #include "QtWebSockets/qwebsocketprotocol.h" |
37 | |
38 | QT_USE_NAMESPACE |
39 | |
40 | Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) |
41 | Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) |
42 | |
43 | const int = 8 * 1024; |
44 | const int = 100; |
45 | |
46 | class tst_HandshakeRequest : public QObject |
47 | { |
48 | Q_OBJECT |
49 | |
50 | public: |
51 | tst_HandshakeRequest(); |
52 | |
53 | private Q_SLOTS: |
54 | void initTestCase(); |
55 | void cleanupTestCase(); |
56 | void init(); |
57 | void cleanup(); |
58 | |
59 | void tst_initialization(); |
60 | |
61 | void tst_invalidStream_data(); |
62 | void tst_invalidStream(); |
63 | |
64 | void tst_multipleValuesInConnectionHeader(); |
65 | void tst_multipleVersions(); |
66 | void tst_parsingWhitespaceInHeaders(); |
67 | |
68 | void tst_qtbug_39355(); |
69 | void tst_qtbug_48123_data(); |
70 | void tst_qtbug_48123(); |
71 | |
72 | void tst_qtbug_57357_data(); |
73 | void tst_qtbug_57357(); // ipv6 related |
74 | }; |
75 | |
76 | tst_HandshakeRequest::tst_HandshakeRequest() |
77 | {} |
78 | |
79 | void tst_HandshakeRequest::initTestCase() |
80 | { |
81 | } |
82 | |
83 | void tst_HandshakeRequest::cleanupTestCase() |
84 | {} |
85 | |
86 | void tst_HandshakeRequest::init() |
87 | { |
88 | qRegisterMetaType<QWebSocketProtocol::OpCode>(typeName: "QWebSocketProtocol::OpCode" ); |
89 | qRegisterMetaType<QWebSocketProtocol::CloseCode>(typeName: "QWebSocketProtocol::CloseCode" ); |
90 | } |
91 | |
92 | void tst_HandshakeRequest::cleanup() |
93 | { |
94 | } |
95 | |
96 | void tst_HandshakeRequest::tst_initialization() |
97 | { |
98 | { |
99 | QWebSocketHandshakeRequest request(0, false); |
100 | QCOMPARE(request.port(), 0); |
101 | QVERIFY(!request.isSecure()); |
102 | QVERIFY(!request.isValid()); |
103 | QCOMPARE(request.extensions().length(), 0); |
104 | QCOMPARE(request.protocols().length(), 0); |
105 | QCOMPARE(request.headers().size(), 0); |
106 | QCOMPARE(request.key().length(), 0); |
107 | QCOMPARE(request.origin().length(), 0); |
108 | QCOMPARE(request.host().length(), 0); |
109 | QVERIFY(request.requestUrl().isEmpty()); |
110 | QCOMPARE(request.resourceName().length(), 0); |
111 | QCOMPARE(request.versions().length(), 0); |
112 | } |
113 | { |
114 | QWebSocketHandshakeRequest request(80, true); |
115 | QCOMPARE(request.port(), 80); |
116 | QVERIFY(request.isSecure()); |
117 | QVERIFY(!request.isValid()); |
118 | QCOMPARE(request.extensions().length(), 0); |
119 | QCOMPARE(request.protocols().length(), 0); |
120 | QCOMPARE(request.headers().size(), 0); |
121 | QCOMPARE(request.key().length(), 0); |
122 | QCOMPARE(request.origin().length(), 0); |
123 | QCOMPARE(request.host().length(), 0); |
124 | QVERIFY(request.requestUrl().isEmpty()); |
125 | QCOMPARE(request.resourceName().length(), 0); |
126 | QCOMPARE(request.versions().length(), 0); |
127 | } |
128 | { |
129 | QWebSocketHandshakeRequest request(80, true); |
130 | request.clear(); |
131 | QCOMPARE(request.port(), 80); |
132 | QVERIFY(request.isSecure()); |
133 | QVERIFY(!request.isValid()); |
134 | QCOMPARE(request.extensions().length(), 0); |
135 | QCOMPARE(request.protocols().length(), 0); |
136 | QCOMPARE(request.headers().size(), 0); |
137 | QCOMPARE(request.key().length(), 0); |
138 | QCOMPARE(request.origin().length(), 0); |
139 | QCOMPARE(request.host().length(), 0); |
140 | QVERIFY(request.requestUrl().isEmpty()); |
141 | QCOMPARE(request.resourceName().length(), 0); |
142 | QCOMPARE(request.versions().length(), 0); |
143 | } |
144 | } |
145 | |
146 | void tst_HandshakeRequest::tst_invalidStream_data() |
147 | { |
148 | QTest::addColumn<QString>(name: "dataStream" ); |
149 | |
150 | QTest::newRow(dataTag: "garbage on 2 lines" ) << QStringLiteral("foofoofoo\r\nfoofoo\r\n\r\n" ); |
151 | QTest::newRow(dataTag: "garbage on 1 line" ) << QStringLiteral("foofoofoofoofoo" ); |
152 | QTest::newRow(dataTag: "Correctly formatted but invalid fields" ) |
153 | << QStringLiteral("VERB RESOURCE PROTOCOL" ); |
154 | |
155 | //internally the fields are parsed and indexes are used to convert |
156 | //to a http version for instance |
157 | //this test checks if there doesn't occur an out-of-bounds exception |
158 | QTest::newRow(dataTag: "Correctly formatted but invalid short fields" ) << QStringLiteral("V R P" ); |
159 | QTest::newRow(dataTag: "Invalid \\0 character in header" ) << QStringLiteral("V R\0 P" ); |
160 | QTest::newRow(dataTag: "Invalid HTTP version in header" ) << QStringLiteral("V R HTTP/invalid" ); |
161 | QTest::newRow(dataTag: "Empty header field" ) << QStringLiteral("GET . HTTP/1.1\r\nHEADER: " ); |
162 | QTest::newRow(dataTag: "All zeros" ) << QString::fromUtf8(str: QByteArray(10, char(0))); |
163 | QTest::newRow(dataTag: "Invalid hostname" ) << QStringLiteral("GET . HTTP/1.1\r\nHost: \xFF\xFF" ); |
164 | //doing extensive QStringLiteral concatenations here, because |
165 | //MSVC 2010 complains when using concatenation literal strings about |
166 | //concatenation of wide and narrow strings (error C2308) |
167 | QTest::newRow(dataTag: "Complete header - Invalid WebSocket version" ) |
168 | << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: " ) + |
169 | QStringLiteral("\xFF\xFF\r\n" ) + |
170 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
171 | QStringLiteral("Upgrade: websocket\r\n" ) + |
172 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
173 | QTest::newRow(dataTag: "Complete header - Invalid verb" ) |
174 | << QStringLiteral("XXX . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
175 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
176 | QStringLiteral("Upgrade: websocket\r\n" ) + |
177 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
178 | QTest::newRow(dataTag: "Complete header - Invalid HTTP version" ) |
179 | << QStringLiteral("GET . HTTP/a.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
180 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
181 | QStringLiteral("Upgrade: websocket\r\n" ) + |
182 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
183 | QTest::newRow(dataTag: "Complete header - Invalid connection" ) |
184 | << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
185 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
186 | QStringLiteral("Upgrade: websocket\r\n" ) + |
187 | QStringLiteral("Connection: xxxxxxx\r\n\r\n" ); |
188 | QTest::newRow(dataTag: "Complete header - Invalid upgrade" ) |
189 | << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
190 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
191 | QStringLiteral("Upgrade: wabsocket\r\n" ) + |
192 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
193 | QTest::newRow(dataTag: "Complete header - Upgrade contains too many values" ) |
194 | << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
195 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
196 | QStringLiteral("Upgrade: websocket,ftp\r\n" ) + |
197 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
198 | QTest::newRow(dataTag: "Invalid header - starts with continuation" ) |
199 | << QStringLiteral("GET . HTTP/1.1\r\n Host: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
200 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
201 | QStringLiteral("Upgrade: websocket\r\n" ) + |
202 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
203 | QTest::newRow(dataTag: "Invalid header - no colon" ) |
204 | << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n" ) + |
205 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
206 | QStringLiteral("Upgrade: websocket\r\n" ) + |
207 | QStringLiteral("X-Custom foo\r\n" ) + |
208 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
209 | } |
210 | |
211 | void tst_HandshakeRequest::tst_invalidStream() |
212 | { |
213 | QFETCH(QString, dataStream); |
214 | |
215 | QByteArray data; |
216 | QTextStream textStream(&data); |
217 | QWebSocketHandshakeRequest request(80, true); |
218 | |
219 | textStream << dataStream; |
220 | textStream.seek(pos: 0); |
221 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
222 | |
223 | QVERIFY(!request.isValid()); |
224 | QCOMPARE(request.port(), 80); |
225 | QVERIFY(request.isSecure()); |
226 | QCOMPARE(request.extensions().length(), 0); |
227 | QCOMPARE(request.protocols().length(), 0); |
228 | QCOMPARE(request.headers().size(), 0); |
229 | QCOMPARE(request.key().length(), 0); |
230 | QCOMPARE(request.origin().length(), 0); |
231 | QCOMPARE(request.host().length(), 0); |
232 | QVERIFY(request.requestUrl().isEmpty()); |
233 | QCOMPARE(request.resourceName().length(), 0); |
234 | QCOMPARE(request.versions().length(), 0); |
235 | } |
236 | |
237 | /* |
238 | * This is a regression test |
239 | * Checks for validity when more than one value is present in Connection |
240 | */ |
241 | void tst_HandshakeRequest::tst_multipleValuesInConnectionHeader() |
242 | { |
243 | //doing extensive QStringLiteral concatenations here, because |
244 | //MSVC 2010 complains when using concatenation literal strings about |
245 | //concatenation of wide and narrow strings (error C2308) |
246 | QString = QStringLiteral("GET /test HTTP/1.1\r\nHost: " ) + |
247 | QStringLiteral("foo.com\r\nSec-WebSocket-Version: 13\r\n" ) + |
248 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
249 | QStringLiteral("Upgrade: websocket\r\n" ) + |
250 | QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n" ); |
251 | QByteArray data; |
252 | QTextStream textStream(&data); |
253 | QWebSocketHandshakeRequest request(80, false); |
254 | |
255 | textStream << header; |
256 | textStream.seek(pos: 0); |
257 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
258 | |
259 | QVERIFY(request.isValid()); |
260 | QCOMPARE(request.port(), 80); |
261 | QVERIFY(!request.isSecure()); |
262 | QCOMPARE(request.extensions().length(), 0); |
263 | QCOMPARE(request.protocols().length(), 0); |
264 | QCOMPARE(request.headers().size(), 5); |
265 | QCOMPARE(request.key().length(), 9); |
266 | QCOMPARE(request.origin().length(), 0); |
267 | QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test" )); |
268 | QCOMPARE(request.host(), QStringLiteral("foo.com" )); |
269 | QCOMPARE(request.resourceName().length(), 5); |
270 | QCOMPARE(request.versions().length(), 1); |
271 | QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); |
272 | } |
273 | |
274 | /* |
275 | * This is a regression test |
276 | * Checks for RFC compliant header parsing |
277 | */ |
278 | void tst_HandshakeRequest::tst_parsingWhitespaceInHeaders() |
279 | { |
280 | //doing extensive QStringLiteral concatenations here, because |
281 | //MSVC 2010 complains when using concatenation literal strings about |
282 | //concatenation of wide and narrow strings (error C2308) |
283 | QString = QStringLiteral("GET /test HTTP/1.1\r\nHost: " ) + |
284 | QStringLiteral("foo.com\r\nSec-WebSocket-Version:13\r\n" ) + |
285 | QStringLiteral("Sec-WebSocket-Key: AVD \r\n\tFBDDFF \r\n" ) + |
286 | QStringLiteral("Upgrade:websocket \r\n" ) + |
287 | QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n" ); |
288 | QByteArray data; |
289 | QTextStream textStream(&data); |
290 | QWebSocketHandshakeRequest request(80, false); |
291 | |
292 | textStream << header; |
293 | textStream.seek(pos: 0); |
294 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
295 | |
296 | QVERIFY(request.isValid()); |
297 | QCOMPARE(request.key(), QStringLiteral("AVD FBDDFF" )); |
298 | QCOMPARE(request.versions().length(), 1); |
299 | QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); |
300 | } |
301 | |
302 | void tst_HandshakeRequest::tst_multipleVersions() |
303 | { |
304 | QString = QStringLiteral("GET /test HTTP/1.1\r\nHost: foo.com\r\n" ) + |
305 | QStringLiteral("Sec-WebSocket-Version: 4, 5, 6, 7, 8, 13\r\n" ) + |
306 | QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n" ) + |
307 | QStringLiteral("Upgrade: websocket\r\n" ) + |
308 | QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n" ); |
309 | QByteArray data; |
310 | QTextStream textStream(&data); |
311 | QWebSocketHandshakeRequest request(80, false); |
312 | |
313 | textStream << header; |
314 | textStream.seek(pos: 0); |
315 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
316 | |
317 | QVERIFY(request.isValid()); |
318 | QCOMPARE(request.port(), 80); |
319 | QVERIFY(!request.isSecure()); |
320 | QCOMPARE(request.extensions().length(), 0); |
321 | QCOMPARE(request.protocols().length(), 0); |
322 | QCOMPARE(request.headers().size(), 5); |
323 | QVERIFY(request.headers().contains(QStringLiteral("host" ))); |
324 | QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-version" ))); |
325 | QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-key" ))); |
326 | QVERIFY(request.headers().contains(QStringLiteral("upgrade" ))); |
327 | QVERIFY(request.headers().contains(QStringLiteral("connection" ))); |
328 | QCOMPARE(request.key(), QStringLiteral("AVDFBDDFF" )); |
329 | QCOMPARE(request.origin().length(), 0); |
330 | QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test" )); |
331 | QCOMPARE(request.host(), QStringLiteral("foo.com" )); |
332 | QCOMPARE(request.resourceName().length(), 5); |
333 | QCOMPARE(request.versions().length(), 6); |
334 | //should be 13 since the list is ordered in decreasing order |
335 | QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); |
336 | } |
337 | |
338 | void tst_HandshakeRequest::tst_qtbug_39355() |
339 | { |
340 | QString = QStringLiteral("GET /ABC/DEF/ HTTP/1.1\r\nHost: localhost:1234\r\n" ) + |
341 | QStringLiteral("Sec-WebSocket-Version: 13\r\n" ) + |
342 | QStringLiteral("Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n" ) + |
343 | QStringLiteral("Upgrade: websocket\r\n" ) + |
344 | QStringLiteral("Connection: Upgrade\r\n\r\n" ); |
345 | QByteArray data; |
346 | QTextStream textStream(&data); |
347 | QWebSocketHandshakeRequest request(8080, false); |
348 | |
349 | textStream << header; |
350 | textStream.seek(pos: 0); |
351 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
352 | |
353 | QVERIFY(request.isValid()); |
354 | QCOMPARE(request.port(), 1234); |
355 | QCOMPARE(request.host(), QStringLiteral("localhost" )); |
356 | } |
357 | |
358 | void tst_HandshakeRequest::tst_qtbug_48123_data() |
359 | { |
360 | QTest::addColumn<QString>(name: "header" ); |
361 | QTest::addColumn<bool>(name: "shouldBeValid" ); |
362 | const QString = QStringLiteral("GET /ABC/DEF/ HTTP/1.1\r\nHost: localhost:1234\r\n" ) + |
363 | QStringLiteral("Sec-WebSocket-Version: 13\r\n" ) + |
364 | QStringLiteral("Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n" ) + |
365 | QStringLiteral("Upgrade: websocket\r\n" ) + |
366 | QStringLiteral("Connection: Upgrade\r\n" ); |
367 | const int = header.count(QStringLiteral("\r\n" )) - 1; //-1: exclude requestline |
368 | |
369 | //a headerline should not be larger than MAX_HEADERLINE_LENGTH characters (excluding CRLF) |
370 | QString = header; |
371 | illegalHeader.append(s: QString(MAX_HEADERLINE_LENGTH + 1, QLatin1Char('c'))); |
372 | illegalHeader.append(QStringLiteral("\r\n\r\n" )); |
373 | |
374 | QTest::newRow(dataTag: "headerline too long" ) << illegalHeader << false; |
375 | |
376 | QString = header; |
377 | const QString = QStringLiteral("X-CUSTOM-KEY: " ); |
378 | legalHeader.append(s: headerKey); |
379 | legalHeader.append(s: QString(MAX_HEADERLINE_LENGTH - headerKey.length(), QLatin1Char('c'))); |
380 | legalHeader.append(QStringLiteral("\r\n\r\n" )); |
381 | |
382 | QTest::newRow(dataTag: "headerline with maximum length" ) << legalHeader << true; |
383 | |
384 | //a header should not contain more than MAX_HEADERS header lines (excluding the request line) |
385 | //test with MAX_HEADERS + 1 |
386 | illegalHeader = header; |
387 | const QString (QStringLiteral("Host: localhost:1234\r\n" )); |
388 | for (int i = 0; i < (MAX_HEADERS - numHeaderLines + 1); ++i) { |
389 | illegalHeader.append(s: headerLine); |
390 | } |
391 | illegalHeader.append(QStringLiteral("\r\n" )); |
392 | |
393 | QTest::newRow(dataTag: "too many headerlines" ) << illegalHeader << false; |
394 | |
395 | //test with MAX_HEADERS header lines (excluding the request line) |
396 | legalHeader = header; |
397 | for (int i = 0; i < (MAX_HEADERS - numHeaderLines); ++i) { |
398 | legalHeader.append(s: headerLine); |
399 | } |
400 | legalHeader.append(QStringLiteral("\r\n" )); |
401 | |
402 | QTest::newRow(dataTag: "just enough headerlines" ) << legalHeader << true; |
403 | } |
404 | |
405 | void tst_HandshakeRequest::tst_qtbug_48123() |
406 | { |
407 | QFETCH(QString, ); |
408 | QFETCH(bool, shouldBeValid); |
409 | |
410 | QByteArray data; |
411 | QTextStream textStream(&data); |
412 | QWebSocketHandshakeRequest request(8080, false); |
413 | |
414 | textStream << header; |
415 | textStream.seek(pos: 0); |
416 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
417 | |
418 | QCOMPARE(request.isValid(), shouldBeValid); |
419 | } |
420 | |
421 | void tst_HandshakeRequest::tst_qtbug_57357_data() |
422 | { |
423 | QTest::addColumn<QString>(name: "header" ); |
424 | QTest::addColumn<bool>(name: "valid" ); |
425 | QTest::addColumn<QString>(name: "host" ); |
426 | QTest::addColumn<int>(name: "port" ); |
427 | |
428 | QString = QLatin1String("GET /ABC/DEF/ HTTP/1.1\r\nHost: %1%2\r\n" |
429 | "Sec-WebSocket-Version: 13\r\n" |
430 | "Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n" |
431 | "Upgrade: websocket\r\n" |
432 | "Connection: Upgrade\r\n\r\n" ); |
433 | |
434 | QTest::newRow(dataTag: "ipv4-1" ) << header.arg(QStringLiteral("10.0.0.1" )).arg(QStringLiteral(":1234" )) << true |
435 | << QStringLiteral("10.0.0.1" ) |
436 | << 1234; |
437 | QTest::newRow(dataTag: "ipv4-2" ) << header.arg(QStringLiteral("127.0.0.1" )).arg(QStringLiteral(":1111" )) << true |
438 | << QStringLiteral("127.0.0.1" ) |
439 | << 1111; |
440 | QTest::newRow(dataTag: "ipv4-wo-port" ) << header.arg(QStringLiteral("10.0.0.1" )).arg(QStringLiteral("" )) << true |
441 | << QStringLiteral("10.0.0.1" ) |
442 | << 8080; |
443 | |
444 | QTest::newRow(dataTag: "ipv6-1" ) << header.arg(QStringLiteral("[56:56:56:56:56:56:56:56]" )).arg(QStringLiteral(":1234" )) << true |
445 | << QStringLiteral("56:56:56:56:56:56:56:56" ) |
446 | << 1234; |
447 | QTest::newRow(dataTag: "ipv6-2" ) << header.arg(QStringLiteral("[::ffff:129.144.52.38]" )).arg(QStringLiteral(":1111" )) << true |
448 | << QStringLiteral("::ffff:129.144.52.38" ) |
449 | << 1111; |
450 | QTest::newRow(dataTag: "ipv6-wo-port" ) << header.arg(QStringLiteral("[56:56:56:56:56:56:56:56]" )).arg(QStringLiteral("" )) << true |
451 | << QStringLiteral("56:56:56:56:56:56:56:56" ) |
452 | << 8080; |
453 | QTest::newRow(dataTag: "ipv6-invalid-1" ) << header.arg(QStringLiteral("56:56:56:56:56:56:56:56]" )).arg(QStringLiteral(":1234" )) << false |
454 | << QStringLiteral("" ) |
455 | << 1234; |
456 | |
457 | QTest::newRow(dataTag: "host-1" ) << header.arg(QStringLiteral("foo.com" )).arg(QStringLiteral(":1234" )) << true |
458 | << QStringLiteral("foo.com" ) |
459 | << 1234; |
460 | QTest::newRow(dataTag: "host-2" ) << header.arg(QStringLiteral("bar.net" )).arg(QStringLiteral(":1111" )) << true |
461 | << QStringLiteral("bar.net" ) |
462 | << 1111; |
463 | QTest::newRow(dataTag: "host-wo-port" ) << header.arg(QStringLiteral("foo.com" )).arg(QStringLiteral("" )) << true |
464 | << QStringLiteral("foo.com" ) |
465 | << 8080; |
466 | |
467 | QTest::newRow(dataTag: "localhost-1" ) << header.arg(QStringLiteral("localhost" )).arg(QStringLiteral(":1234" )) << true |
468 | << QStringLiteral("localhost" ) |
469 | << 1234; |
470 | QTest::newRow(dataTag: "localhost-2" ) << header.arg(QStringLiteral("localhost" )).arg(QStringLiteral(":1111" )) << true |
471 | << QStringLiteral("localhost" ) |
472 | << 1111; |
473 | QTest::newRow(dataTag: "localhost-wo-port" ) << header.arg(QStringLiteral("localhost" )).arg(QStringLiteral("" )) << true |
474 | << QStringLiteral("localhost" ) |
475 | << 8080; |
476 | |
477 | // reference: qtbase/tests/auto/corelib/io/qurl/tst_qurl.cpp: void tst_QUrl::ipvfuture_data() |
478 | QTest::newRow(dataTag: "ipvfuture-1" ) << header.arg(QStringLiteral("[v7.1234]" )).arg(QStringLiteral(":1234" )) << true |
479 | << QStringLiteral("v7.1234" ) |
480 | << 1234; |
481 | |
482 | QTest::newRow(dataTag: "invalid-1" ) << header.arg(QStringLiteral("abc:def@foo.com" )).arg(QStringLiteral("" )) << false |
483 | << QStringLiteral("foo.com" ) |
484 | << 8080; |
485 | QTest::newRow(dataTag: "invalid-2" ) << header.arg(QStringLiteral(":def@foo.com" )).arg(QStringLiteral("" )) << false |
486 | << QStringLiteral("foo.com" ) |
487 | << 8080; |
488 | QTest::newRow(dataTag: "invalid-3" ) << header.arg(QStringLiteral("abc:@foo.com" )).arg(QStringLiteral("" )) << false |
489 | << QStringLiteral("foo.com" ) |
490 | << 8080; |
491 | QTest::newRow(dataTag: "invalid-4" ) << header.arg(QStringLiteral("@foo.com" )).arg(QStringLiteral("" )) << false |
492 | << QStringLiteral("foo.com" ) |
493 | << 8080; |
494 | QTest::newRow(dataTag: "invalid-5" ) << header.arg(QStringLiteral("foo.com/" )).arg(QStringLiteral("" )) << false |
495 | << QStringLiteral("foo.com" ) |
496 | << 8080; |
497 | } |
498 | |
499 | void tst_HandshakeRequest::tst_qtbug_57357() |
500 | { |
501 | QFETCH(QString, ); |
502 | QFETCH(bool, valid); |
503 | QFETCH(QString, host); |
504 | QFETCH(int, port); |
505 | |
506 | QByteArray data; |
507 | QTextStream textStream(&data); |
508 | QWebSocketHandshakeRequest request(8080, false); |
509 | |
510 | textStream << header; |
511 | textStream.seek(pos: 0); |
512 | request.readHandshake(textStream, maxHeaderLineLength: MAX_HEADERLINE_LENGTH, maxHeaders: MAX_HEADERS); |
513 | |
514 | QCOMPARE(request.isValid(), valid); |
515 | if (valid) { |
516 | QCOMPARE(request.host(), host); |
517 | QCOMPARE(request.port(), port); |
518 | } |
519 | } |
520 | |
521 | QTEST_MAIN(tst_HandshakeRequest) |
522 | |
523 | #include "tst_handshakerequest.moc" |
524 | |