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:LGPL$
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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtTest/qtestcase.h>
43 #include <QtCore/QDebug>
44 #include <QtCore/QByteArray>
45 #include <QtCore/QtEndian>
47 #include "private/qwebsockethandshakerequest_p.h"
48 #include "private/qwebsocketprotocol_p.h"
49 #include "QtWebSockets/qwebsocketprotocol.h"
53 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
54 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
56 class tst_HandshakeRequest : public QObject
61 tst_HandshakeRequest();
65 void cleanupTestCase();
69 void tst_initialization();
71 void tst_invalidStream_data();
72 void tst_invalidStream();
74 void tst_multipleValuesInConnectionHeader();
75 void tst_multipleVersions();
78 tst_HandshakeRequest::tst_HandshakeRequest()
81 void tst_HandshakeRequest::initTestCase()
85 void tst_HandshakeRequest::cleanupTestCase()
88 void tst_HandshakeRequest::init()
90 qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
91 qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
94 void tst_HandshakeRequest::cleanup()
98 void tst_HandshakeRequest::tst_initialization()
101 QWebSocketHandshakeRequest request(0, false);
102 QCOMPARE(request.port(), 0);
103 QVERIFY(!request.isSecure());
104 QVERIFY(!request.isValid());
105 QCOMPARE(request.extensions().length(), 0);
106 QCOMPARE(request.protocols().length(), 0);
107 QCOMPARE(request.headers().size(), 0);
108 QCOMPARE(request.key().length(), 0);
109 QCOMPARE(request.origin().length(), 0);
110 QCOMPARE(request.host().length(), 0);
111 QVERIFY(request.requestUrl().isEmpty());
112 QCOMPARE(request.resourceName().length(), 0);
113 QCOMPARE(request.versions().length(), 0);
116 QWebSocketHandshakeRequest request(80, true);
117 QCOMPARE(request.port(), 80);
118 QVERIFY(request.isSecure());
119 QVERIFY(!request.isValid());
120 QCOMPARE(request.extensions().length(), 0);
121 QCOMPARE(request.protocols().length(), 0);
122 QCOMPARE(request.headers().size(), 0);
123 QCOMPARE(request.key().length(), 0);
124 QCOMPARE(request.origin().length(), 0);
125 QCOMPARE(request.host().length(), 0);
126 QVERIFY(request.requestUrl().isEmpty());
127 QCOMPARE(request.resourceName().length(), 0);
128 QCOMPARE(request.versions().length(), 0);
131 QWebSocketHandshakeRequest request(80, true);
133 QCOMPARE(request.port(), 80);
134 QVERIFY(request.isSecure());
135 QVERIFY(!request.isValid());
136 QCOMPARE(request.extensions().length(), 0);
137 QCOMPARE(request.protocols().length(), 0);
138 QCOMPARE(request.headers().size(), 0);
139 QCOMPARE(request.key().length(), 0);
140 QCOMPARE(request.origin().length(), 0);
141 QCOMPARE(request.host().length(), 0);
142 QVERIFY(request.requestUrl().isEmpty());
143 QCOMPARE(request.resourceName().length(), 0);
144 QCOMPARE(request.versions().length(), 0);
148 void tst_HandshakeRequest::tst_invalidStream_data()
150 QTest::addColumn<QString>("dataStream");
152 QTest::newRow("garbage on 2 lines") << QStringLiteral("foofoofoo\r\nfoofoo\r\n\r\n");
153 QTest::newRow("garbage on 1 line") << QStringLiteral("foofoofoofoofoo");
154 QTest::newRow("Correctly formatted but invalid fields")
155 << QStringLiteral("VERB RESOURCE PROTOCOL");
157 //internally the fields are parsed and indexes are used to convert
158 //to a http version for instance
159 //this test checks if there doesn't occur an out-of-bounds exception
160 QTest::newRow("Correctly formatted but invalid short fields") << QStringLiteral("V R P");
161 QTest::newRow("Invalid \\0 character in header") << QStringLiteral("V R\0 P");
162 QTest::newRow("Invalid http version in header") << QStringLiteral("V R HTTP/invalid");
163 QTest::newRow("Empty header field") << QStringLiteral("GET . HTTP/1.1\r\nHEADER: ");
164 QTest::newRow("All zeros") << QString::fromUtf8(QByteArray(10, char(0)));
165 QTest::newRow("Invalid hostname") << QStringLiteral("GET . HTTP/1.1\r\nHost: \xFF\xFF");
166 //doing extensive QStringLiteral concatenations here, because
167 //MSVC 2010 complains when using concatenation literal strings about
168 //concatenation of wide and narrow strings (error C2308)
169 QTest::newRow("Complete header - Invalid websocket version")
170 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: ") +
171 QStringLiteral("\xFF\xFF\r\n") +
172 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
173 QStringLiteral("Upgrade: websocket\r\n") +
174 QStringLiteral("Connection: Upgrade\r\n\r\n");
175 QTest::newRow("Complete header - Invalid verb")
176 << QStringLiteral("XXX . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
177 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
178 QStringLiteral("Upgrade: websocket\r\n") +
179 QStringLiteral("Connection: Upgrade\r\n\r\n");
180 QTest::newRow("Complete header - Invalid http version")
181 << QStringLiteral("GET . HTTP/a.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
182 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
183 QStringLiteral("Upgrade: websocket\r\n") +
184 QStringLiteral("Connection: Upgrade\r\n\r\n");
185 QTest::newRow("Complete header - Invalid connection")
186 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
187 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
188 QStringLiteral("Upgrade: websocket\r\n") +
189 QStringLiteral("Connection: xxxxxxx\r\n\r\n");
190 QTest::newRow("Complete header - Invalid upgrade")
191 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
192 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
193 QStringLiteral("Upgrade: wabsocket\r\n") +
194 QStringLiteral("Connection: Upgrade\r\n\r\n");
195 QTest::newRow("Complete header - Upgrade contains too many values")
196 << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") +
197 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
198 QStringLiteral("Upgrade: websocket,ftp\r\n") +
199 QStringLiteral("Connection: Upgrade\r\n\r\n");
202 void tst_HandshakeRequest::tst_invalidStream()
204 QFETCH(QString, dataStream);
207 QTextStream textStream(&data);
208 QWebSocketHandshakeRequest request(80, true);
210 textStream << dataStream;
212 request.readHandshake(textStream);
214 QVERIFY(!request.isValid());
215 QCOMPARE(request.port(), 80);
216 QVERIFY(request.isSecure());
217 QCOMPARE(request.extensions().length(), 0);
218 QCOMPARE(request.protocols().length(), 0);
219 QCOMPARE(request.headers().size(), 0);
220 QCOMPARE(request.key().length(), 0);
221 QCOMPARE(request.origin().length(), 0);
222 QCOMPARE(request.host().length(), 0);
223 QVERIFY(request.requestUrl().isEmpty());
224 QCOMPARE(request.resourceName().length(), 0);
225 QCOMPARE(request.versions().length(), 0);
229 * This is a regression test
230 * Checks for validity when more than one value is present in Connection
232 void tst_HandshakeRequest::tst_multipleValuesInConnectionHeader()
234 //doing extensive QStringLiteral concatenations here, because
235 //MSVC 2010 complains when using concatenation literal strings about
236 //concatenation of wide and narrow strings (error C2308)
237 QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: ") +
238 QStringLiteral("foo.com\r\nSec-WebSocket-Version: 13\r\n") +
239 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
240 QStringLiteral("Upgrade: websocket\r\n") +
241 QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n");
243 QTextStream textStream(&data);
244 QWebSocketHandshakeRequest request(80, false);
246 textStream << header;
248 request.readHandshake(textStream);
250 QVERIFY(request.isValid());
251 QCOMPARE(request.port(), 80);
252 QVERIFY(!request.isSecure());
253 QCOMPARE(request.extensions().length(), 0);
254 QCOMPARE(request.protocols().length(), 0);
255 QCOMPARE(request.headers().size(), 5);
256 QCOMPARE(request.key().length(), 9);
257 QCOMPARE(request.origin().length(), 0);
258 QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test"));
259 QCOMPARE(request.host(), QStringLiteral("foo.com"));
260 QCOMPARE(request.resourceName().length(), 5);
261 QCOMPARE(request.versions().length(), 1);
262 QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13);
265 void tst_HandshakeRequest::tst_multipleVersions()
267 QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: foo.com\r\n") +
268 QStringLiteral("Sec-WebSocket-Version: 4, 5, 6, 7, 8, 13\r\n") +
269 QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") +
270 QStringLiteral("Upgrade: websocket\r\n") +
271 QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n");
273 QTextStream textStream(&data);
274 QWebSocketHandshakeRequest request(80, false);
276 textStream << header;
278 request.readHandshake(textStream);
280 QVERIFY(request.isValid());
281 QCOMPARE(request.port(), 80);
282 QVERIFY(!request.isSecure());
283 QCOMPARE(request.extensions().length(), 0);
284 QCOMPARE(request.protocols().length(), 0);
285 QCOMPARE(request.headers().size(), 5);
286 QVERIFY(request.headers().contains(QStringLiteral("Host")));
287 QVERIFY(request.headers().contains(QStringLiteral("Sec-WebSocket-Version")));
288 QVERIFY(request.headers().contains(QStringLiteral("Sec-WebSocket-Key")));
289 QVERIFY(request.headers().contains(QStringLiteral("Upgrade")));
290 QVERIFY(request.headers().contains(QStringLiteral("Connection")));
291 QCOMPARE(request.key(), QStringLiteral("AVDFBDDFF"));
292 QCOMPARE(request.origin().length(), 0);
293 QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test"));
294 QCOMPARE(request.host(), QStringLiteral("foo.com"));
295 QCOMPARE(request.resourceName().length(), 5);
296 QCOMPARE(request.versions().length(), 6);
297 //should be 13 since the list is ordered in decreasing order
298 QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13);
301 QTEST_MAIN(tst_HandshakeRequest)
303 #include "tst_handshakerequest.moc"