Update license headers and add new license files
[contrib/qtwebsockets.git] / src / websockets / qwebsocketserver_p.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtWebSockets module of the Qt Toolkit.
7 **
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.
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 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.
25 **
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.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "qwebsocketserver.h"
35 #include "qwebsocketserver_p.h"
36 #ifndef QT_NO_SSL
37 #include "qsslserver_p.h"
38 #endif
39 #include "qwebsocketprotocol.h"
40 #include "qwebsockethandshakerequest_p.h"
41 #include "qwebsockethandshakeresponse_p.h"
42 #include "qwebsocket.h"
43 #include "qwebsocket_p.h"
44 #include "qwebsocketcorsauthenticator.h"
45
46 #include <QtNetwork/QTcpServer>
47 #include <QtNetwork/QTcpSocket>
48 #include <QtNetwork/QNetworkProxy>
49
50 QT_BEGIN_NAMESPACE
51
52 /*!
53     \internal
54  */
55 QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
56                                                  QWebSocketServerPrivate::SslMode secureMode,
57                                                  QWebSocketServer * const pWebSocketServer) :
58     QObjectPrivate(),
59     q_ptr(pWebSocketServer),
60     m_pTcpServer(Q_NULLPTR),
61     m_serverName(serverName),
62     m_secureMode(secureMode),
63     m_pendingConnections(),
64     m_error(QWebSocketProtocol::CloseCodeNormal),
65     m_errorString(),
66     m_maxPendingConnections(30)
67 {
68     Q_ASSERT(pWebSocketServer);
69 }
70
71 /*!
72     \internal
73  */
74 void QWebSocketServerPrivate::init()
75 {
76     if (m_secureMode == NonSecureMode) {
77         m_pTcpServer = new QTcpServer();
78         if (Q_LIKELY(m_pTcpServer))
79             QObjectPrivate::connect(m_pTcpServer, &QTcpServer::newConnection,
80                                     this, &QWebSocketServerPrivate::onNewConnection);
81         else
82             qFatal("Could not allocate memory for tcp server.");
83     } else {
84 #ifndef QT_NO_SSL
85         QSslServer *pSslServer = new QSslServer();
86         m_pTcpServer = pSslServer;
87         if (Q_LIKELY(m_pTcpServer)) {
88             QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
89                                     this, &QWebSocketServerPrivate::onNewConnection,
90                                     Qt::QueuedConnection);
91             QObject::connect(pSslServer, &QSslServer::peerVerifyError,
92                              q_ptr, &QWebSocketServer::peerVerifyError);
93             QObject::connect(pSslServer, &QSslServer::sslErrors,
94                              q_ptr, &QWebSocketServer::sslErrors);
95         }
96 #else
97         qFatal("SSL not supported on this platform.");
98 #endif
99     }
100     QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError);
101 }
102
103 /*!
104     \internal
105  */
106 QWebSocketServerPrivate::~QWebSocketServerPrivate()
107 {
108     close(true);
109     m_pTcpServer->deleteLater();
110 }
111
112 /*!
113     \internal
114  */
115 void QWebSocketServerPrivate::close(bool aboutToDestroy)
116 {
117     Q_Q(QWebSocketServer);
118     m_pTcpServer->close();
119     while (!m_pendingConnections.isEmpty()) {
120         QWebSocket *pWebSocket = m_pendingConnections.dequeue();
121         pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway,
122                           QWebSocketServer::tr("Server closed."));
123         pWebSocket->deleteLater();
124     }
125     if (!aboutToDestroy) {
126         //emit signal via the event queue, so the server gets time
127         //to process any hanging events, like flushing buffers aso
128         QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
129     }
130 }
131
132 /*!
133     \internal
134  */
135 QString QWebSocketServerPrivate::errorString() const
136 {
137     if (m_errorString.isEmpty())
138         return m_pTcpServer->errorString();
139     else
140         return m_errorString;
141 }
142
143 /*!
144     \internal
145  */
146 bool QWebSocketServerPrivate::hasPendingConnections() const
147 {
148     return !m_pendingConnections.isEmpty();
149 }
150
151 /*!
152     \internal
153  */
154 bool QWebSocketServerPrivate::isListening() const
155 {
156     return m_pTcpServer->isListening();
157 }
158
159 /*!
160     \internal
161  */
162 bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
163 {
164     bool success = m_pTcpServer->listen(address, port);
165     if (!success)
166         setErrorFromSocketError(m_pTcpServer->serverError(), m_pTcpServer->errorString());
167     return success;
168 }
169
170 /*!
171     \internal
172  */
173 int QWebSocketServerPrivate::maxPendingConnections() const
174 {
175     return m_maxPendingConnections;
176 }
177
178 /*!
179     \internal
180  */
181 void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
182 {
183     if (m_pendingConnections.size() < maxPendingConnections())
184         m_pendingConnections.enqueue(pWebSocket);
185 }
186
187 /*!
188     \internal
189  */
190 void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
191                                                       const QString &errorDescription)
192 {
193     Q_UNUSED(error);
194     setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
195 }
196
197 /*!
198     \internal
199  */
200 QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
201 {
202     QWebSocket *pWebSocket = Q_NULLPTR;
203     if (Q_LIKELY(!m_pendingConnections.isEmpty()))
204         pWebSocket = m_pendingConnections.dequeue();
205     return pWebSocket;
206 }
207
208 /*!
209     \internal
210  */
211 void QWebSocketServerPrivate::pauseAccepting()
212 {
213     m_pTcpServer->pauseAccepting();
214 }
215
216 #ifndef QT_NO_NETWORKPROXY
217 /*!
218     \internal
219  */
220 QNetworkProxy QWebSocketServerPrivate::proxy() const
221 {
222     return m_pTcpServer->proxy();
223 }
224
225 /*!
226     \internal
227  */
228 void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
229 {
230     m_pTcpServer->setProxy(networkProxy);
231 }
232 #endif
233 /*!
234     \internal
235  */
236 void QWebSocketServerPrivate::resumeAccepting()
237 {
238     m_pTcpServer->resumeAccepting();
239 }
240
241 /*!
242     \internal
243  */
244 QHostAddress QWebSocketServerPrivate::serverAddress() const
245 {
246     return m_pTcpServer->serverAddress();
247 }
248
249 /*!
250     \internal
251  */
252 QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
253 {
254     return m_error;
255 }
256
257 /*!
258     \internal
259  */
260 quint16 QWebSocketServerPrivate::serverPort() const
261 {
262     return m_pTcpServer->serverPort();
263 }
264
265 /*!
266     \internal
267  */
268 void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
269 {
270     if (m_pTcpServer->maxPendingConnections() <= numConnections)
271         m_pTcpServer->setMaxPendingConnections(numConnections + 1);
272     m_maxPendingConnections = numConnections;
273 }
274
275 /*!
276     \internal
277  */
278 bool QWebSocketServerPrivate::setSocketDescriptor(qintptr socketDescriptor)
279 {
280     return m_pTcpServer->setSocketDescriptor(socketDescriptor);
281 }
282
283 /*!
284     \internal
285  */
286 qintptr QWebSocketServerPrivate::socketDescriptor() const
287 {
288     return m_pTcpServer->socketDescriptor();
289 }
290
291 /*!
292     \internal
293  */
294 QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
295 {
296     QList<QWebSocketProtocol::Version> supportedVersions;
297     supportedVersions << QWebSocketProtocol::currentVersion();  //we only support V13
298     return supportedVersions;
299 }
300
301 /*!
302     \internal
303  */
304 QStringList QWebSocketServerPrivate::supportedProtocols() const
305 {
306     QStringList supportedProtocols;
307     return supportedProtocols;  //no protocols are currently supported
308 }
309
310 /*!
311     \internal
312  */
313 QStringList QWebSocketServerPrivate::supportedExtensions() const
314 {
315     QStringList supportedExtensions;
316     return supportedExtensions; //no extensions are currently supported
317 }
318
319 /*!
320   \internal
321  */
322 void QWebSocketServerPrivate::setServerName(const QString &serverName)
323 {
324     if (m_serverName != serverName)
325         m_serverName = serverName;
326 }
327
328 /*!
329   \internal
330  */
331 QString QWebSocketServerPrivate::serverName() const
332 {
333     return m_serverName;
334 }
335
336 /*!
337   \internal
338  */
339 QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
340 {
341     return m_secureMode;
342 }
343
344 #ifndef QT_NO_SSL
345 void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
346 {
347     if (m_secureMode == SecureMode)
348         qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
349 }
350
351 QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
352 {
353     if (m_secureMode == SecureMode)
354         return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
355     else
356         return QSslConfiguration::defaultConfiguration();
357 }
358 #endif
359
360 void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
361 {
362     if ((m_error != code) || (m_errorString != errorString)) {
363         Q_Q(QWebSocketServer);
364         m_error = code;
365         m_errorString = errorString;
366         Q_EMIT q->serverError(code);
367     }
368 }
369
370 /*!
371     \internal
372  */
373 void QWebSocketServerPrivate::onNewConnection()
374 {
375     QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
376     //use a queued connection because a QSslSocket
377     //needs the event loop to process incoming data
378     //if not queued, data is incomplete when handshakeReceived is called
379     QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
380                             this, &QWebSocketServerPrivate::handshakeReceived,
381                             Qt::QueuedConnection);
382 }
383
384 /*!
385     \internal
386  */
387 void QWebSocketServerPrivate::onCloseConnection()
388 {
389     if (Q_LIKELY(currentSender)) {
390         QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
391         if (Q_LIKELY(pTcpSocket))
392             pTcpSocket->close();
393     }
394 }
395
396 /*!
397     \internal
398  */
399 void QWebSocketServerPrivate::handshakeReceived()
400 {
401     if (Q_UNLIKELY(!currentSender)) {
402         return;
403     }
404     QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
405     if (Q_UNLIKELY(!pTcpSocket)) {
406         return;
407     }
408     //When using Google Chrome the handshake in received in two parts.
409     //Therefore, the readyRead signal is emitted twice.
410     //This is a guard against the BEAST attack.
411     //See: https://www.imperialviolet.org/2012/01/15/beastfollowup.html
412     //For Safari, the handshake is delivered at once
413     //FIXME: For FireFox, the readyRead signal is never emitted
414     //This is a bug in FireFox (see https://bugzilla.mozilla.org/show_bug.cgi?id=594502)
415     if (!pTcpSocket->canReadLine()) {
416         return;
417     }
418     disconnect(pTcpSocket, &QTcpSocket::readyRead,
419                this, &QWebSocketServerPrivate::handshakeReceived);
420     Q_Q(QWebSocketServer);
421     bool success = false;
422     bool isSecure = false;
423
424     if (m_pendingConnections.length() >= maxPendingConnections()) {
425         pTcpSocket->close();
426         pTcpSocket->deleteLater();
427         setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
428                  QWebSocketServer::tr("Too many pending connections."));
429         return;
430     }
431
432     QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
433     QTextStream textStream(pTcpSocket);
434     request.readHandshake(textStream);
435
436     if (request.isValid()) {
437         QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
438         Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
439
440         QWebSocketHandshakeResponse response(request,
441                                              m_serverName,
442                                              corsAuthenticator.allowed(),
443                                              supportedVersions(),
444                                              supportedProtocols(),
445                                              supportedExtensions());
446
447         if (response.isValid()) {
448             QTextStream httpStream(pTcpSocket);
449             httpStream << response;
450             httpStream.flush();
451
452             if (response.canUpgrade()) {
453                 QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
454                                                                         request,
455                                                                         response);
456                 if (pWebSocket) {
457                     addPendingConnection(pWebSocket);
458                     Q_EMIT q->newConnection();
459                     success = true;
460                 } else {
461                     setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
462                              QWebSocketServer::tr("Upgrade to WebSocket failed."));
463                 }
464             }
465             else {
466                 setError(response.error(), response.errorString());
467             }
468         } else {
469             setError(QWebSocketProtocol::CloseCodeProtocolError,
470                      QWebSocketServer::tr("Invalid response received."));
471         }
472     }
473     if (!success) {
474         pTcpSocket->close();
475     }
476 }
477
478 QT_END_NAMESPACE