1 /****************************************************************************
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL21$
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26 ** In addition, as a special exception, Digia gives you certain additional
27 ** rights. These rights are described in the Digia Qt LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
32 ****************************************************************************/
33 #include <QtTest/QtTest>
34 #include <QtTest/qtestcase.h>
35 #include <QtCore/QDebug>
36 #include <QtCore/QByteArray>
37 #include <QtCore/QtEndian>
39 #include "private/qwebsockethandshakerequest_p.h"
40 #include "private/qwebsocketprotocol_p.h"
41 #include "QtWebSockets/qwebsocketprotocol.h"
45 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
46 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
48 class tst_HandshakeRequest : public QObject
53 tst_HandshakeRequest();
57 void cleanupTestCase();
61 void tst_initialization();
63 void tst_invalidStream_data();
64 void tst_invalidStream();
66 void tst_multipleValuesInConnectionHeader();
67 void tst_multipleVersions();
70 tst_HandshakeRequest::tst_HandshakeRequest()
73 void tst_HandshakeRequest::initTestCase()
77 void tst_HandshakeRequest::cleanupTestCase()
80 void tst_HandshakeRequest::init()
82 qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
83 qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
86 void tst_HandshakeRequest::cleanup()
90 void tst_HandshakeRequest::tst_initialization()
93 QWebSocketHandshakeRequest request(0, false);
94 QCOMPARE(request.port(), 0);
95 QVERIFY(!request.isSecure());
96 QVERIFY(!request.isValid());
97 QCOMPARE(request.extensions().length(), 0);
98 QCOMPARE(request.protocols().length(), 0);
99 QCOMPARE(request.headers().size(), 0);
100 QCOMPARE(request.key().length(), 0);
101 QCOMPARE(request.origin().length(), 0);
102 QCOMPARE(request.host().length(), 0);
103 QVERIFY(request.requestUrl().isEmpty());
104 QCOMPARE(request.resourceName().length(), 0);
105 QCOMPARE(request.versions().length(), 0);
108 QWebSocketHandshakeRequest request(80, true);
109 QCOMPARE(request.port(), 80);
110 QVERIFY(request.isSecure());
111 QVERIFY(!request.isValid());
112 QCOMPARE(request.extensions().length(), 0);
113 QCOMPARE(request.protocols().length(), 0);
114 QCOMPARE(request.headers().size(), 0);
115 QCOMPARE(request.key().length(), 0);
116 QCOMPARE(request.origin().length(), 0);
117 QCOMPARE(request.host().length(), 0);
118 QVERIFY(request.requestUrl().isEmpty());
119 QCOMPARE(request.resourceName().length(), 0);
120 QCOMPARE(request.versions().length(), 0);
123 QWebSocketHandshakeRequest request(80, true);
125 QCOMPARE(request.port(), 80);
126 QVERIFY(request.isSecure());
127 QVERIFY(!request.isValid());
128 QCOMPARE(request.extensions().length(), 0);
129 QCOMPARE(request.protocols().length(), 0);
130 QCOMPARE(request.headers().size(), 0);
131 QCOMPARE(request.key().length(), 0);
132 QCOMPARE(request.origin().length(), 0);
133 QCOMPARE(request.host().length(), 0);
134 QVERIFY(request.requestUrl().isEmpty());
135 QCOMPARE(request.resourceName().length(), 0);
136 QCOMPARE(request.versions().length(), 0);
140 void tst_HandshakeRequest::tst_invalidStream_data()
142 QTest::addColumn<QString>("dataStream");
144 QTest::newRow("garbage on 2 lines") << QStringLiteral("foofoofoo\r\nfoofoo\r\n\r\n");
145 QTest::newRow("garbage on 1 line") << QStringLiteral("foofoofoofoofoo");
146 QTest::newRow("Correctly formatted but invalid fields")
147 << QStringLiteral("VERB RESOURCE PROTOCOL");
149 //internally the fields are parsed and indexes are used to convert
150 //to a http version for instance
151 //this test checks if there doesn't occur an out-of-bounds exception
152 QTest::newRow("Correctly formatted but invalid short fields") << QStringLiteral("V R P");
153 QTest::newRow("Invalid \\0 character in header") << QStringLiteral("V R\0 P");
154 QTest::newRow("Invalid HTTP version in header") << QStringLiteral("V R HTTP/invalid");
155 QTest::newRow("Empty header field") << QStringLiteral("GET . HTTP/1.1\r\nHEADER: ");
156 QTest::newRow("All zeros") << QString::fromUtf8(QByteArray(10, char(0)));
157 QTest::newRow("Invalid hostname") << QStringLiteral("GET . HTTP/1.1\r\nHost: \xFF\xFF");
158 //doing extensive QStringLiteral concatenations here, because
159 //MSVC 2010 complains when using concatenation literal strings about
160 //concatenation of wide and narrow strings (error C2308)
161 QTest::newRow("Complete header - Invalid WebSocket version")
162 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: ") +
163 QStringLiteral("\xFF\xFF\r\n") +
164 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
165 QStringLiteral("Upgrade: websocket\r\n") +
166 QStringLiteral("Connection: Upgrade\r\n\r\n");
167 QTest::newRow("Complete header - Invalid verb")
168 << QStringLiteral("XXX . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
169 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
170 QStringLiteral("Upgrade: websocket\r\n") +
171 QStringLiteral("Connection: Upgrade\r\n\r\n");
172 QTest::newRow("Complete header - Invalid HTTP version")
173 << QStringLiteral("GET . HTTP/a.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
174 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
175 QStringLiteral("Upgrade: websocket\r\n") +
176 QStringLiteral("Connection: Upgrade\r\n\r\n");
177 QTest::newRow("Complete header - Invalid connection")
178 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
179 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
180 QStringLiteral("Upgrade: websocket\r\n") +
181 QStringLiteral("Connection: xxxxxxx\r\n\r\n");
182 QTest::newRow("Complete header - Invalid upgrade")
183 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
184 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
185 QStringLiteral("Upgrade: wabsocket\r\n") +
186 QStringLiteral("Connection: Upgrade\r\n\r\n");
187 QTest::newRow("Complete header - Upgrade contains too many values")
188 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
189 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
190 QStringLiteral("Upgrade: websocket,ftp\r\n") +
191 QStringLiteral("Connection: Upgrade\r\n\r\n");
194 void tst_HandshakeRequest::tst_invalidStream()
196 QFETCH(QString, dataStream);
199 QTextStream textStream(&data);
200 QWebSocketHandshakeRequest request(80, true);
202 textStream << dataStream;
204 request.readHandshake(textStream);
206 QVERIFY(!request.isValid());
207 QCOMPARE(request.port(), 80);
208 QVERIFY(request.isSecure());
209 QCOMPARE(request.extensions().length(), 0);
210 QCOMPARE(request.protocols().length(), 0);
211 QCOMPARE(request.headers().size(), 0);
212 QCOMPARE(request.key().length(), 0);
213 QCOMPARE(request.origin().length(), 0);
214 QCOMPARE(request.host().length(), 0);
215 QVERIFY(request.requestUrl().isEmpty());
216 QCOMPARE(request.resourceName().length(), 0);
217 QCOMPARE(request.versions().length(), 0);
221 * This is a regression test
222 * Checks for validity when more than one value is present in Connection
224 void tst_HandshakeRequest::tst_multipleValuesInConnectionHeader()
226 //doing extensive QStringLiteral concatenations here, because
227 //MSVC 2010 complains when using concatenation literal strings about
228 //concatenation of wide and narrow strings (error C2308)
229 QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: ") +
230 QStringLiteral("foo.com\r\nSec-WebSocket-Version: 13\r\n") +
231 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
232 QStringLiteral("Upgrade: websocket\r\n") +
233 QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n");
235 QTextStream textStream(&data);
236 QWebSocketHandshakeRequest request(80, false);
238 textStream << header;
240 request.readHandshake(textStream);
242 QVERIFY(request.isValid());
243 QCOMPARE(request.port(), 80);
244 QVERIFY(!request.isSecure());
245 QCOMPARE(request.extensions().length(), 0);
246 QCOMPARE(request.protocols().length(), 0);
247 QCOMPARE(request.headers().size(), 5);
248 QCOMPARE(request.key().length(), 9);
249 QCOMPARE(request.origin().length(), 0);
250 QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test"));
251 QCOMPARE(request.host(), QStringLiteral("foo.com"));
252 QCOMPARE(request.resourceName().length(), 5);
253 QCOMPARE(request.versions().length(), 1);
254 QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13);
257 void tst_HandshakeRequest::tst_multipleVersions()
259 QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: foo.com\r\n") +
260 QStringLiteral("Sec-WebSocket-Version: 4, 5, 6, 7, 8, 13\r\n") +
261 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
262 QStringLiteral("Upgrade: websocket\r\n") +
263 QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n");
265 QTextStream textStream(&data);
266 QWebSocketHandshakeRequest request(80, false);
268 textStream << header;
270 request.readHandshake(textStream);
272 QVERIFY(request.isValid());
273 QCOMPARE(request.port(), 80);
274 QVERIFY(!request.isSecure());
275 QCOMPARE(request.extensions().length(), 0);
276 QCOMPARE(request.protocols().length(), 0);
277 QCOMPARE(request.headers().size(), 5);
278 QVERIFY(request.headers().contains(QStringLiteral("host")));
279 QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-version")));
280 QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-key")));
281 QVERIFY(request.headers().contains(QStringLiteral("upgrade")));
282 QVERIFY(request.headers().contains(QStringLiteral("connection")));
283 QCOMPARE(request.key(), QStringLiteral("AVDFBDDFF"));
284 QCOMPARE(request.origin().length(), 0);
285 QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test"));
286 QCOMPARE(request.host(), QStringLiteral("foo.com"));
287 QCOMPARE(request.resourceName().length(), 5);
288 QCOMPARE(request.versions().length(), 6);
289 //should be 13 since the list is ordered in decreasing order
290 QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13);
293 QTEST_MAIN(tst_HandshakeRequest)
295 #include "tst_handshakerequest.moc"