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 QtWebSockets module of the Qt Toolkit.
7**
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 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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qwebsocketserver.h"
41#include "qwebsocketserver_p.h"
42#ifndef QT_NO_SSL
43#include "qsslserver_p.h"
44#endif
45#include "qwebsocketprotocol.h"
46#include "qwebsockethandshakerequest_p.h"
47#include "qwebsockethandshakeresponse_p.h"
48#include "qwebsocket.h"
49#include "qwebsocket_p.h"
50#include "qwebsocketcorsauthenticator.h"
51
52#include <QtCore/QTimer>
53#include <QtNetwork/QTcpServer>
54#include <QtNetwork/QTcpSocket>
55#include <QtNetwork/QNetworkProxy>
56
57QT_BEGIN_NAMESPACE
58
59//both constants are taken from the default settings of Apache
60//see: http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfieldsize and
61//http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfields
62const int MAX_HEADERLINE_LENGTH = 8 * 1024; //maximum length of a http request header line
63const int MAX_HEADERLINES = 100; //maximum number of http request header lines
64
65/*!
66 \internal
67 */
68QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
69 QWebSocketServerPrivate::SslMode secureMode) :
70 QObjectPrivate(),
71 m_pTcpServer(nullptr),
72 m_serverName(serverName),
73 m_secureMode(secureMode),
74 m_pendingConnections(),
75 m_error(QWebSocketProtocol::CloseCodeNormal),
76 m_errorString(),
77 m_maxPendingConnections(30),
78 m_handshakeTimeout(10000)
79{}
80
81/*!
82 \internal
83 */
84void QWebSocketServerPrivate::init()
85{
86 Q_Q(QWebSocketServer);
87 if (m_secureMode == NonSecureMode) {
88 m_pTcpServer = new QTcpServer(q);
89 if (Q_LIKELY(m_pTcpServer))
90 QObjectPrivate::connect(m_pTcpServer, &QTcpServer::newConnection,
91 this, &QWebSocketServerPrivate::onNewConnection);
92 else
93 qFatal("Could not allocate memory for tcp server.");
94 } else {
95#ifndef QT_NO_SSL
96 QSslServer *pSslServer = new QSslServer(q);
97 m_pTcpServer = pSslServer;
98 if (Q_LIKELY(m_pTcpServer)) {
99 QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
100 this, &QWebSocketServerPrivate::onNewConnection,
101 Qt::QueuedConnection);
102 QObjectPrivate::connect(pSslServer, &QSslServer::startedEncryptionHandshake,
103 this, &QWebSocketServerPrivate::startHandshakeTimeout);
104 QObject::connect(pSslServer, &QSslServer::peerVerifyError,
105 q, &QWebSocketServer::peerVerifyError);
106 QObject::connect(pSslServer, &QSslServer::sslErrors,
107 q, &QWebSocketServer::sslErrors);
108 QObject::connect(pSslServer, &QSslServer::preSharedKeyAuthenticationRequired,
109 q, &QWebSocketServer::preSharedKeyAuthenticationRequired);
110 }
111#else
112 qFatal("SSL not supported on this platform.");
113#endif
114 }
115 QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q, &QWebSocketServer::acceptError);
116}
117
118/*!
119 \internal
120 */
121QWebSocketServerPrivate::~QWebSocketServerPrivate()
122{
123}
124
125/*!
126 \internal
127 */
128void QWebSocketServerPrivate::close(bool aboutToDestroy)
129{
130 Q_Q(QWebSocketServer);
131 m_pTcpServer->close();
132 while (!m_pendingConnections.isEmpty()) {
133 QWebSocket *pWebSocket = m_pendingConnections.dequeue();
134 pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway,
135 QWebSocketServer::tr("Server closed."));
136 pWebSocket->deleteLater();
137 }
138 if (!aboutToDestroy) {
139 //emit signal via the event queue, so the server gets time
140 //to process any hanging events, like flushing buffers aso
141 QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
142 }
143}
144
145/*!
146 \internal
147 */
148QString QWebSocketServerPrivate::errorString() const
149{
150 if (m_errorString.isEmpty())
151 return m_pTcpServer->errorString();
152 else
153 return m_errorString;
154}
155
156/*!
157 \internal
158 */
159bool QWebSocketServerPrivate::hasPendingConnections() const
160{
161 return !m_pendingConnections.isEmpty();
162}
163
164/*!
165 \internal
166 */
167bool QWebSocketServerPrivate::isListening() const
168{
169 return m_pTcpServer->isListening();
170}
171
172/*!
173 \internal
174 */
175bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
176{
177 bool success = m_pTcpServer->listen(address, port);
178 if (!success)
179 setErrorFromSocketError(m_pTcpServer->serverError(), m_pTcpServer->errorString());
180 return success;
181}
182
183/*!
184 \internal
185 */
186int QWebSocketServerPrivate::maxPendingConnections() const
187{
188 return m_maxPendingConnections;
189}
190
191/*!
192 \internal
193 */
194void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
195{
196 if (m_pendingConnections.size() < maxPendingConnections())
197 m_pendingConnections.enqueue(pWebSocket);
198}
199
200/*!
201 \internal
202 */
203void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
204 const QString &errorDescription)
205{
206 Q_UNUSED(error);
207 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
208}
209
210/*!
211 \internal
212 */
213QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
214{
215 QWebSocket *pWebSocket = nullptr;
216 if (Q_LIKELY(!m_pendingConnections.isEmpty()))
217 pWebSocket = m_pendingConnections.dequeue();
218 return pWebSocket;
219}
220
221/*!
222 \internal
223 */
224void QWebSocketServerPrivate::pauseAccepting()
225{
226 m_pTcpServer->pauseAccepting();
227}
228
229#ifndef QT_NO_NETWORKPROXY
230/*!
231 \internal
232 */
233QNetworkProxy QWebSocketServerPrivate::proxy() const
234{
235 return m_pTcpServer->proxy();
236}
237
238/*!
239 \internal
240 */
241void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
242{
243 m_pTcpServer->setProxy(networkProxy);
244}
245#endif
246/*!
247 \internal
248 */
249void QWebSocketServerPrivate::resumeAccepting()
250{
251 m_pTcpServer->resumeAccepting();
252}
253
254/*!
255 \internal
256 */
257QHostAddress QWebSocketServerPrivate::serverAddress() const
258{
259 return m_pTcpServer->serverAddress();
260}
261
262/*!
263 \internal
264 */
265QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
266{
267 return m_error;
268}
269
270/*!
271 \internal
272 */
273quint16 QWebSocketServerPrivate::serverPort() const
274{
275 return m_pTcpServer->serverPort();
276}
277
278/*!
279 \internal
280 */
281void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
282{
283 if (m_pTcpServer->maxPendingConnections() <= numConnections)
284 m_pTcpServer->setMaxPendingConnections(numConnections + 1);
285 m_maxPendingConnections = numConnections;
286}
287
288/*!
289 \internal
290 */
291bool QWebSocketServerPrivate::setSocketDescriptor(qintptr socketDescriptor)
292{
293 return m_pTcpServer->setSocketDescriptor(socketDescriptor);
294}
295
296/*!
297 \internal
298 */
299qintptr QWebSocketServerPrivate::socketDescriptor() const
300{
301 return m_pTcpServer->socketDescriptor();
302}
303
304/*!
305 \internal
306 */
307QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
308{
309 QList<QWebSocketProtocol::Version> supportedVersions;
310 supportedVersions << QWebSocketProtocol::currentVersion(); //we only support V13
311 return supportedVersions;
312}
313
314/*!
315 \internal
316 */
317QStringList QWebSocketServerPrivate::supportedProtocols() const
318{
319 QStringList supportedProtocols;
320 return supportedProtocols; //no protocols are currently supported
321}
322
323/*!
324 \internal
325 */
326QStringList QWebSocketServerPrivate::supportedExtensions() const
327{
328 QStringList supportedExtensions;
329 return supportedExtensions; //no extensions are currently supported
330}
331
332/*!
333 \internal
334 */
335void QWebSocketServerPrivate::setServerName(const QString &serverName)
336{
337 if (m_serverName != serverName)
338 m_serverName = serverName;
339}
340
341/*!
342 \internal
343 */
344QString QWebSocketServerPrivate::serverName() const
345{
346 return m_serverName;
347}
348
349/*!
350 \internal
351 */
352QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
353{
354 return m_secureMode;
355}
356
357#ifndef QT_NO_SSL
358void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
359{
360 if (m_secureMode == SecureMode)
361 qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
362}
363
364QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
365{
366 if (m_secureMode == SecureMode)
367 return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
368 else
369 return QSslConfiguration::defaultConfiguration();
370}
371#endif
372
373void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
374{
375 if ((m_error != code) || (m_errorString != errorString)) {
376 Q_Q(QWebSocketServer);
377 m_error = code;
378 m_errorString = errorString;
379 Q_EMIT q->serverError(code);
380 }
381}
382
383/*!
384 \internal
385 */
386void QWebSocketServerPrivate::onNewConnection()
387{
388 while (m_pTcpServer->hasPendingConnections()) {
389 QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
390 if (Q_LIKELY(pTcpSocket) && m_secureMode == NonSecureMode)
391 startHandshakeTimeout(pTcpSocket);
392 handleConnection(pTcpSocket);
393 }
394}
395
396/*!
397 \internal
398 */
399void QWebSocketServerPrivate::onSocketDisconnected()
400{
401 Q_Q(QWebSocketServer);
402 QObject *sender = q->sender();
403 if (Q_LIKELY(sender)) {
404 QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender);
405 if (Q_LIKELY(pTcpSocket))
406 pTcpSocket->deleteLater();
407 }
408}
409
410/*!
411 \internal
412 */
413void QWebSocketServerPrivate::handshakeReceived()
414{
415 Q_Q(QWebSocketServer);
416 QObject *sender = q->sender();
417 if (Q_UNLIKELY(!sender)) {
418 return;
419 }
420 QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender);
421 if (Q_UNLIKELY(!pTcpSocket)) {
422 return;
423 }
424 //When using Google Chrome the handshake in received in two parts.
425 //Therefore, the readyRead signal is emitted twice.
426 //This is a guard against the BEAST attack.
427 //See: https://www.imperialviolet.org/2012/01/15/beastfollowup.html
428 //For Safari, the handshake is delivered at once
429 //FIXME: For FireFox, the readyRead signal is never emitted
430 //This is a bug in FireFox (see https://bugzilla.mozilla.org/show_bug.cgi?id=594502)
431
432 // According to RFC822 the body is separated from the headers by a null line (CRLF)
433 if (!pTcpSocket->peek(pTcpSocket->bytesAvailable()).endsWith(QByteArrayLiteral("\r\n\r\n"))) {
434 return;
435 }
436 disconnect(pTcpSocket, &QTcpSocket::readyRead,
437 this, &QWebSocketServerPrivate::handshakeReceived);
438 bool success = false;
439 bool isSecure = (m_secureMode == SecureMode);
440
441 if (m_pendingConnections.length() >= maxPendingConnections()) {
442 pTcpSocket->close();
443 pTcpSocket->deleteLater();
444 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
445 QWebSocketServer::tr("Too many pending connections."));
446 return;
447 }
448
449 QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
450 QTextStream textStream(pTcpSocket);
451 request.readHandshake(textStream, MAX_HEADERLINE_LENGTH, MAX_HEADERLINES);
452
453 if (request.isValid()) {
454 QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
455 Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
456
457 QWebSocketHandshakeResponse response(request,
458 m_serverName,
459 corsAuthenticator.allowed(),
460 supportedVersions(),
461 supportedProtocols(),
462 supportedExtensions());
463
464 if (response.isValid()) {
465 QTextStream httpStream(pTcpSocket);
466 httpStream << response;
467 httpStream.flush();
468
469 if (response.canUpgrade()) {
470 QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
471 request,
472 response);
473 if (pWebSocket) {
474 finishHandshakeTimeout(pTcpSocket);
475 addPendingConnection(pWebSocket);
476 Q_EMIT q->newConnection();
477 success = true;
478 } else {
479 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
480 QWebSocketServer::tr("Upgrade to WebSocket failed."));
481 }
482 }
483 else {
484 setError(response.error(), response.errorString());
485 }
486 } else {
487 setError(QWebSocketProtocol::CloseCodeProtocolError,
488 QWebSocketServer::tr("Invalid response received."));
489 }
490 }
491 if (!success) {
492 pTcpSocket->close();
493 }
494}
495
496void QWebSocketServerPrivate::handleConnection(QTcpSocket *pTcpSocket) const
497{
498 if (Q_LIKELY(pTcpSocket)) {
499 // Use a queued connection because a QSslSocket needs the event loop to process incoming
500 // data. If not queued, data is incomplete when handshakeReceived is called.
501 QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
502 this, &QWebSocketServerPrivate::handshakeReceived,
503 Qt::QueuedConnection);
504 if (pTcpSocket->canReadLine()) {
505 // We received some data! We must emit now to be sure that handshakeReceived is called
506 // since the data could have been received before the signal and slot was connected.
507 emit pTcpSocket->readyRead();
508 }
509 QObjectPrivate::connect(pTcpSocket, &QTcpSocket::disconnected,
510 this, &QWebSocketServerPrivate::onSocketDisconnected);
511 }
512}
513
514void QWebSocketServerPrivate::startHandshakeTimeout(QTcpSocket *pTcpSocket)
515{
516 if (m_handshakeTimeout < 0)
517 return;
518
519 QTimer *handshakeTimer = new QTimer(pTcpSocket);
520 handshakeTimer->setSingleShot(true);
521 handshakeTimer->setObjectName(QStringLiteral("handshakeTimer"));
522 QObject::connect(handshakeTimer, &QTimer::timeout, [=]() {
523 pTcpSocket->close();
524 });
525 handshakeTimer->start(m_handshakeTimeout);
526}
527
528void QWebSocketServerPrivate::finishHandshakeTimeout(QTcpSocket *pTcpSocket)
529{
530 if (QTimer *handshakeTimer = pTcpSocket->findChild<QTimer *>(QStringLiteral("handshakeTimer"))) {
531 handshakeTimer->stop();
532 delete handshakeTimer;
533 }
534}
535
536QT_END_NAMESPACE
537