Fix invalid Date header field in handshake response
[contrib/qtwebsockets.git] / src / websockets / qwebsocket_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: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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwebsocket.h"
43 #include "qwebsocket_p.h"
44 #include "qwebsocketprotocol_p.h"
45 #include "qwebsockethandshakerequest_p.h"
46 #include "qwebsockethandshakeresponse_p.h"
47 #include "qdefaultmaskgenerator_p.h"
48
49 #include <QtCore/QUrl>
50 #include <QtNetwork/QAuthenticator>
51 #include <QtNetwork/QTcpSocket>
52 #include <QtCore/QByteArray>
53 #include <QtCore/QtEndian>
54 #include <QtCore/QCryptographicHash>
55 #include <QtCore/QRegularExpression>
56 #include <QtCore/QStringList>
57 #include <QtNetwork/QHostAddress>
58 #include <QtCore/QStringBuilder>   //for more efficient string concatenation
59 #ifndef QT_NONETWORKPROXY
60 #include <QtNetwork/QNetworkProxy>
61 #endif
62 #ifndef QT_NO_SSL
63 #include <QtNetwork/QSslConfiguration>
64 #include <QtNetwork/QSslError>
65 #endif
66
67 #include <QtCore/QDebug>
68
69 #include <limits>
70
71 QT_BEGIN_NAMESPACE
72
73 const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2;      //maximum size of a frame when sending a message
74
75 QWebSocketConfiguration::QWebSocketConfiguration() :
76 #ifndef QT_NO_SSL
77     m_sslConfiguration(QSslConfiguration::defaultConfiguration()),
78     m_ignoredSslErrors(),
79     m_ignoreSslErrors(false),
80 #endif
81 #ifndef QT_NO_NETWORKPROXY
82     m_proxy(QNetworkProxy::DefaultProxy),
83 #endif
84     m_pSocket(Q_NULLPTR)
85 {
86 }
87
88 /*!
89     \internal
90 */
91 QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version,
92                                      QWebSocket *pWebSocket) :
93     QObjectPrivate(),
94     q_ptr(pWebSocket),
95     m_pSocket(),
96     m_errorString(),
97     m_version(version),
98     m_resourceName(),
99     m_requestUrl(),
100     m_origin(origin),
101     m_protocol(),
102     m_extension(),
103     m_socketState(QAbstractSocket::UnconnectedState),
104     m_pauseMode(QAbstractSocket::PauseNever),
105     m_readBufferSize(0),
106     m_key(),
107     m_mustMask(true),
108     m_isClosingHandshakeSent(false),
109     m_isClosingHandshakeReceived(false),
110     m_closeCode(QWebSocketProtocol::CloseCodeNormal),
111     m_closeReason(),
112     m_pingTimer(),
113     m_dataProcessor(),
114     m_configuration(),
115     m_pMaskGenerator(&m_defaultMaskGenerator),
116     m_defaultMaskGenerator()
117 {
118 }
119
120 /*!
121     \internal
122 */
123 QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version,
124                                      QWebSocket *pWebSocket) :
125     QObjectPrivate(),
126     q_ptr(pWebSocket),
127     m_pSocket(pTcpSocket),
128     m_errorString(pTcpSocket->errorString()),
129     m_version(version),
130     m_resourceName(),
131     m_requestUrl(),
132     m_origin(),
133     m_protocol(),
134     m_extension(),
135     m_socketState(pTcpSocket->state()),
136     m_pauseMode(pTcpSocket->pauseMode()),
137     m_readBufferSize(pTcpSocket->readBufferSize()),
138     m_key(),
139     m_mustMask(true),
140     m_isClosingHandshakeSent(false),
141     m_isClosingHandshakeReceived(false),
142     m_closeCode(QWebSocketProtocol::CloseCodeNormal),
143     m_closeReason(),
144     m_pingTimer(),
145     m_dataProcessor(),
146     m_configuration(),
147     m_pMaskGenerator(&m_defaultMaskGenerator),
148     m_defaultMaskGenerator()
149 {
150 }
151
152 /*!
153     \internal
154 */
155 void QWebSocketPrivate::init()
156 {
157     Q_ASSERT(q_ptr);
158     Q_ASSERT(m_pMaskGenerator);
159
160     m_pMaskGenerator->seed();
161
162     if (m_pSocket) {
163         makeConnections(m_pSocket.data());
164     }
165 }
166
167 /*!
168     \internal
169 */
170 QWebSocketPrivate::~QWebSocketPrivate()
171 {
172     if (!m_pSocket)
173         return;
174     if (state() == QAbstractSocket::ConnectedState)
175         close(QWebSocketProtocol::CloseCodeGoingAway, QWebSocket::tr("Connection closed"));
176     releaseConnections(m_pSocket.data());
177 }
178
179 /*!
180     \internal
181  */
182 void QWebSocketPrivate::abort()
183 {
184     if (m_pSocket)
185         m_pSocket->abort();
186 }
187
188 /*!
189     \internal
190  */
191 QAbstractSocket::SocketError QWebSocketPrivate::error() const
192 {
193     QAbstractSocket::SocketError err = QAbstractSocket::UnknownSocketError;
194     if (Q_LIKELY(m_pSocket))
195         err = m_pSocket->error();
196     return err;
197 }
198
199 /*!
200     \internal
201  */
202 QString QWebSocketPrivate::errorString() const
203 {
204     QString errMsg;
205     if (!m_errorString.isEmpty())
206         errMsg = m_errorString;
207     else if (m_pSocket)
208         errMsg = m_pSocket->errorString();
209     return errMsg;
210 }
211
212 /*!
213     \internal
214  */
215 bool QWebSocketPrivate::flush()
216 {
217     bool result = true;
218     if (Q_LIKELY(m_pSocket))
219         result = m_pSocket->flush();
220     return result;
221 }
222
223 /*!
224     \internal
225  */
226 qint64 QWebSocketPrivate::sendTextMessage(const QString &message)
227 {
228     return doWriteFrames(message.toUtf8(), false);
229 }
230
231 /*!
232     \internal
233  */
234 qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data)
235 {
236     return doWriteFrames(data, true);
237 }
238
239 #ifndef QT_NO_SSL
240 /*!
241     \internal
242  */
243 void QWebSocketPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
244 {
245     m_configuration.m_sslConfiguration = sslConfiguration;
246 }
247
248 /*!
249     \internal
250  */
251 QSslConfiguration QWebSocketPrivate::sslConfiguration() const
252 {
253     return m_configuration.m_sslConfiguration;
254 }
255
256 /*!
257     \internal
258  */
259 void QWebSocketPrivate::ignoreSslErrors(const QList<QSslError> &errors)
260 {
261     m_configuration.m_ignoredSslErrors = errors;
262 }
263
264 /*!
265  * \internal
266  */
267 void QWebSocketPrivate::ignoreSslErrors()
268 {
269     m_configuration.m_ignoreSslErrors = true;
270     if (Q_LIKELY(m_pSocket)) {
271         QSslSocket *pSslSocket = qobject_cast<QSslSocket *>(m_pSocket.data());
272         if (Q_LIKELY(pSslSocket))
273             pSslSocket->ignoreSslErrors();
274     }
275 }
276
277 #endif
278
279 /*!
280   Called from QWebSocketServer
281   \internal
282  */
283 QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket,
284                                            const QWebSocketHandshakeRequest &request,
285                                            const QWebSocketHandshakeResponse &response,
286                                            QObject *parent)
287 {
288     QWebSocket *pWebSocket = new QWebSocket(pTcpSocket, response.acceptedVersion(), parent);
289     if (Q_LIKELY(pWebSocket)) {
290         pWebSocket->d_func()->setExtension(response.acceptedExtension());
291         pWebSocket->d_func()->setOrigin(request.origin());
292         pWebSocket->d_func()->setRequestUrl(request.requestUrl());
293         pWebSocket->d_func()->setProtocol(response.acceptedProtocol());
294         pWebSocket->d_func()->setResourceName(request.requestUrl().toString(QUrl::RemoveUserInfo));
295         //a server should not send masked frames
296         pWebSocket->d_func()->enableMasking(false);
297     }
298
299     return pWebSocket;
300 }
301
302 /*!
303     \internal
304  */
305 void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString reason)
306 {
307     if (Q_UNLIKELY(!m_pSocket))
308         return;
309     if (!m_isClosingHandshakeSent) {
310         Q_Q(QWebSocket);
311         const quint16 code = qToBigEndian<quint16>(closeCode);
312         QByteArray payload;
313         payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
314         if (!reason.isEmpty())
315             payload.append(reason.toUtf8());
316         quint32 maskingKey = 0;
317         if (m_mustMask) {
318             maskingKey = generateMaskingKey();
319             QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
320         }
321         QByteArray frame = getFrameHeader(QWebSocketProtocol::OpCodeClose,
322                                           payload.size(), maskingKey, true);
323         frame.append(payload);
324         m_pSocket->write(frame);
325         m_pSocket->flush();
326
327         m_isClosingHandshakeSent = true;
328
329         Q_EMIT q->aboutToClose();
330     }
331     m_pSocket->close();
332 }
333
334 /*!
335     \internal
336  */
337 void QWebSocketPrivate::open(const QUrl &url, bool mask)
338 {
339     //just delete the old socket for the moment;
340     //later, we can add more 'intelligent' handling by looking at the URL
341     //m_pSocket.reset();
342     Q_Q(QWebSocket);
343     if (!url.isValid() || url.toString().contains(QStringLiteral("\r\n"))) {
344         setErrorString(QWebSocket::tr("Invalid URL."));
345         Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
346         return;
347     }
348     QTcpSocket *pTcpSocket = m_pSocket.take();
349     if (pTcpSocket) {
350         releaseConnections(pTcpSocket);
351         pTcpSocket->deleteLater();
352     }
353     //if (m_url != url)
354     if (Q_LIKELY(!m_pSocket)) {
355         m_dataProcessor.clear();
356         m_isClosingHandshakeReceived = false;
357         m_isClosingHandshakeSent = false;
358
359         setRequestUrl(url);
360         QString resourceName = url.path();
361         if (resourceName.contains(QStringLiteral("\r\n"))) {
362             setRequestUrl(QUrl());  //clear requestUrl
363             setErrorString(QWebSocket::tr("Invalid resource name."));
364             Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
365             return;
366         }
367         if (!url.query().isEmpty()) {
368             if (!resourceName.endsWith(QChar::fromLatin1('?'))) {
369                 resourceName.append(QChar::fromLatin1('?'));
370             }
371             resourceName.append(url.query());
372         }
373         if (resourceName.isEmpty())
374             resourceName = QStringLiteral("/");
375         setResourceName(resourceName);
376         enableMasking(mask);
377
378     #ifndef QT_NO_SSL
379         if (url.scheme() == QStringLiteral("wss")) {
380             if (!QSslSocket::supportsSsl()) {
381                 const QString message =
382                         QWebSocket::tr("SSL Sockets are not supported on this platform.");
383                 setErrorString(message);
384                 Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError);
385             } else {
386                 QSslSocket *sslSocket = new QSslSocket;
387                 m_pSocket.reset(sslSocket);
388                 if (Q_LIKELY(m_pSocket)) {
389                     m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
390                     m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
391                     m_pSocket->setReadBufferSize(m_readBufferSize);
392                     m_pSocket->setPauseMode(m_pauseMode);
393
394                     makeConnections(m_pSocket.data());
395                     setSocketState(QAbstractSocket::ConnectingState);
396
397                     sslSocket->setSslConfiguration(m_configuration.m_sslConfiguration);
398                     if (Q_UNLIKELY(m_configuration.m_ignoreSslErrors))
399                         sslSocket->ignoreSslErrors();
400                     else
401                         sslSocket->ignoreSslErrors(m_configuration.m_ignoredSslErrors);
402     #ifndef QT_NO_NETWORKPROXY
403                     sslSocket->setProxy(m_configuration.m_proxy);
404     #endif
405                     sslSocket->connectToHostEncrypted(url.host(), url.port(443));
406                 } else {
407                     const QString message = QWebSocket::tr("Out of memory.");
408                     setErrorString(message);
409                     Q_EMIT q->error(QAbstractSocket::SocketResourceError);
410                 }
411             }
412         } else
413     #endif
414         if (url.scheme() == QStringLiteral("ws")) {
415             m_pSocket.reset(new QTcpSocket);
416             if (Q_LIKELY(m_pSocket)) {
417                 m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
418                 m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
419                 m_pSocket->setReadBufferSize(m_readBufferSize);
420                 m_pSocket->setPauseMode(m_pauseMode);
421
422                 makeConnections(m_pSocket.data());
423                 setSocketState(QAbstractSocket::ConnectingState);
424     #ifndef QT_NO_NETWORKPROXY
425                 m_pSocket->setProxy(m_configuration.m_proxy);
426     #endif
427                 m_pSocket->connectToHost(url.host(), url.port(80));
428             } else {
429                 const QString message = QWebSocket::tr("Out of memory.");
430                 setErrorString(message);
431                 Q_EMIT q->error(QAbstractSocket::SocketResourceError);
432             }
433         } else {
434             const QString message =
435                     QWebSocket::tr("Unsupported WebSocket scheme: %1").arg(url.scheme());
436             setErrorString(message);
437             Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError);
438         }
439     }
440 }
441
442 /*!
443     \internal
444  */
445 void QWebSocketPrivate::ping(const QByteArray &payload)
446 {
447     QByteArray payloadTruncated = payload.left(125);
448     m_pingTimer.restart();
449     QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OpCodePing, payloadTruncated.size(),
450                                           0 /*do not mask*/, true);
451     pingFrame.append(payloadTruncated);
452     qint64 ret = writeFrame(pingFrame);
453     Q_UNUSED(ret);
454 }
455
456 /*!
457   \internal
458     Sets the version to use for the WebSocket protocol;
459     this must be set before the socket is opened.
460 */
461 void QWebSocketPrivate::setVersion(QWebSocketProtocol::Version version)
462 {
463     if (m_version != version)
464         m_version = version;
465 }
466
467 /*!
468     \internal
469     Sets the resource name of the connection; must be set before the socket is openend
470 */
471 void QWebSocketPrivate::setResourceName(const QString &resourceName)
472 {
473     if (m_resourceName != resourceName)
474         m_resourceName = resourceName;
475 }
476
477 /*!
478   \internal
479  */
480 void QWebSocketPrivate::setRequestUrl(const QUrl &requestUrl)
481 {
482     if (m_requestUrl != requestUrl)
483         m_requestUrl = requestUrl;
484 }
485
486 /*!
487   \internal
488  */
489 void QWebSocketPrivate::setOrigin(const QString &origin)
490 {
491     if (m_origin != origin)
492         m_origin = origin;
493 }
494
495 /*!
496   \internal
497  */
498 void QWebSocketPrivate::setProtocol(const QString &protocol)
499 {
500     if (m_protocol != protocol)
501         m_protocol = protocol;
502 }
503
504 /*!
505   \internal
506  */
507 void QWebSocketPrivate::setExtension(const QString &extension)
508 {
509     if (m_extension != extension)
510         m_extension = extension;
511 }
512
513 /*!
514   \internal
515  */
516 void QWebSocketPrivate::enableMasking(bool enable)
517 {
518     if (m_mustMask != enable)
519         m_mustMask = enable;
520 }
521
522 /*!
523  * \internal
524  */
525 void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
526 {
527     Q_ASSERT(pTcpSocket);
528     Q_Q(QWebSocket);
529
530     if (Q_LIKELY(pTcpSocket)) {
531         //pass through signals
532         typedef void (QAbstractSocket:: *ASErrorSignal)(QAbstractSocket::SocketError);
533         typedef void (QWebSocket:: *WSErrorSignal)(QAbstractSocket::SocketError);
534         QObject::connect(pTcpSocket,
535                          static_cast<ASErrorSignal>(&QAbstractSocket::error),
536                          q, static_cast<WSErrorSignal>(&QWebSocket::error));
537 #ifndef QT_NO_NETWORKPROXY
538         QObject::connect(pTcpSocket, &QAbstractSocket::proxyAuthenticationRequired, q,
539                          &QWebSocket::proxyAuthenticationRequired);
540 #endif // QT_NO_NETWORKPROXY
541         QObject::connect(pTcpSocket, &QAbstractSocket::readChannelFinished, q,
542                          &QWebSocket::readChannelFinished);
543         QObject::connect(pTcpSocket, &QAbstractSocket::aboutToClose, q, &QWebSocket::aboutToClose);
544
545         //catch signals
546         QObjectPrivate::connect(pTcpSocket, &QAbstractSocket::stateChanged, this,
547                                 &QWebSocketPrivate::processStateChanged);
548         //!!!important to use a QueuedConnection here;
549         //with QTcpSocket there is no problem, but with QSslSocket the processing hangs
550         QObjectPrivate::connect(pTcpSocket, &QAbstractSocket::readyRead, this,
551                                 &QWebSocketPrivate::processData, Qt::QueuedConnection);
552 #ifndef QT_NO_SSL
553         const QSslSocket * const sslSocket = qobject_cast<const QSslSocket *>(pTcpSocket);
554         if (sslSocket) {
555             QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten, q,
556                              &QWebSocket::bytesWritten);
557             typedef void (QSslSocket:: *sslErrorSignalType)(const QList<QSslError> &);
558             QObject::connect(sslSocket,
559                              static_cast<sslErrorSignalType>(&QSslSocket::sslErrors),
560                              q, &QWebSocket::sslErrors);
561         } else
562 #endif // QT_NO_SSL
563         {
564             QObject::connect(pTcpSocket, &QAbstractSocket::bytesWritten, q,
565                              &QWebSocket::bytesWritten);
566         }
567     }
568
569     QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::textFrameReceived, q,
570                      &QWebSocket::textFrameReceived);
571     QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryFrameReceived, q,
572                      &QWebSocket::binaryFrameReceived);
573     QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryMessageReceived, q,
574                      &QWebSocket::binaryMessageReceived);
575     QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::textMessageReceived, q,
576                      &QWebSocket::textMessageReceived);
577     QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::errorEncountered, this,
578                             &QWebSocketPrivate::close);
579     QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::pingReceived, this,
580                             &QWebSocketPrivate::processPing);
581     QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::pongReceived, this,
582                             &QWebSocketPrivate::processPong);
583     QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::closeReceived, this,
584                             &QWebSocketPrivate::processClose);
585 }
586
587 /*!
588  * \internal
589  */
590 void QWebSocketPrivate::releaseConnections(const QTcpSocket *pTcpSocket)
591 {
592     if (Q_LIKELY(pTcpSocket))
593         pTcpSocket->disconnect(pTcpSocket);
594     m_dataProcessor.disconnect();
595 }
596
597 /*!
598     \internal
599  */
600 QWebSocketProtocol::Version QWebSocketPrivate::version() const
601 {
602     return m_version;
603 }
604
605 /*!
606     \internal
607  */
608 QString QWebSocketPrivate::resourceName() const
609 {
610     return m_resourceName;
611 }
612
613 /*!
614     \internal
615  */
616 QUrl QWebSocketPrivate::requestUrl() const
617 {
618     return m_requestUrl;
619 }
620
621 /*!
622     \internal
623  */
624 QString QWebSocketPrivate::origin() const
625 {
626     return m_origin;
627 }
628
629 /*!
630     \internal
631  */
632 QString QWebSocketPrivate::protocol() const
633 {
634     return m_protocol;
635 }
636
637 /*!
638     \internal
639  */
640 QString QWebSocketPrivate::extension() const
641 {
642     return m_extension;
643 }
644
645 /*!
646  * \internal
647  */
648 QWebSocketProtocol::CloseCode QWebSocketPrivate::closeCode() const
649 {
650     return m_closeCode;
651 }
652
653 /*!
654  * \internal
655  */
656 QString QWebSocketPrivate::closeReason() const
657 {
658     return m_closeReason;
659 }
660
661 /*!
662  * \internal
663  */
664 QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode,
665                                              quint64 payloadLength, quint32 maskingKey,
666                                              bool lastFrame)
667 {
668     QByteArray header;
669     quint8 byte = 0x00;
670     bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL;
671
672     if (Q_LIKELY(ok)) {
673         //FIN, RSV1-3, opcode (RSV-1, RSV-2 and RSV-3 are zero)
674         byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00));
675         header.append(static_cast<char>(byte));
676
677         byte = 0x00;
678         if (maskingKey != 0)
679             byte |= 0x80;
680         if (payloadLength <= 125) {
681             byte |= static_cast<quint8>(payloadLength);
682             header.append(static_cast<char>(byte));
683         } else if (payloadLength <= 0xFFFFU) {
684             byte |= 126;
685             header.append(static_cast<char>(byte));
686             quint16 swapped = qToBigEndian<quint16>(static_cast<quint16>(payloadLength));
687             header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 2);
688         } else if (payloadLength <= 0x7FFFFFFFFFFFFFFFULL) {
689             byte |= 127;
690             header.append(static_cast<char>(byte));
691             quint64 swapped = qToBigEndian<quint64>(payloadLength);
692             header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 8);
693         }
694
695         if (maskingKey != 0) {
696             const quint32 mask = qToBigEndian<quint32>(maskingKey);
697             header.append(static_cast<const char *>(static_cast<const void *>(&mask)),
698                           sizeof(quint32));
699         }
700     } else {
701         setErrorString(QStringLiteral("WebSocket::getHeader: payload too big!"));
702         Q_EMIT q_ptr->error(QAbstractSocket::DatagramTooLargeError);
703     }
704
705     return header;
706 }
707
708 /*!
709  * \internal
710  */
711 qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
712 {
713     qint64 payloadWritten = 0;
714     if (Q_UNLIKELY(!m_pSocket) || (state() != QAbstractSocket::ConnectedState))
715         return payloadWritten;
716
717     Q_Q(QWebSocket);
718     const QWebSocketProtocol::OpCode firstOpCode = isBinary ?
719                 QWebSocketProtocol::OpCodeBinary : QWebSocketProtocol::OpCodeText;
720
721     int numFrames = data.size() / FRAME_SIZE_IN_BYTES;
722     QByteArray tmpData(data);
723     tmpData.detach();
724     char *payload = tmpData.data();
725     quint64 sizeLeft = quint64(data.size()) % FRAME_SIZE_IN_BYTES;
726     if (Q_LIKELY(sizeLeft))
727         ++numFrames;
728
729     //catch the case where the payload is zero bytes;
730     //in this case, we still need to send a frame
731     if (Q_UNLIKELY(numFrames == 0))
732         numFrames = 1;
733     quint64 currentPosition = 0;
734     qint64 bytesWritten = 0;
735     quint64 bytesLeft = data.size();
736
737     for (int i = 0; i < numFrames; ++i) {
738         quint32 maskingKey = 0;
739         if (m_mustMask)
740             maskingKey = generateMaskingKey();
741
742         const bool isLastFrame = (i == (numFrames - 1));
743         const bool isFirstFrame = (i == 0);
744
745         const quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
746         const QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode
747                                                                : QWebSocketProtocol::OpCodeContinue;
748
749         //write header
750         bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
751
752         //write payload
753         if (Q_LIKELY(size > 0)) {
754             char *currentData = payload + currentPosition;
755             if (m_mustMask)
756                 QWebSocketProtocol::mask(currentData, size, maskingKey);
757             qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
758             if (Q_LIKELY(written > 0)) {
759                 bytesWritten += written;
760                 payloadWritten += written;
761             } else {
762                 m_pSocket->flush();
763                 setErrorString(QWebSocket::tr("Error writing bytes to socket: %1.")
764                                .arg(m_pSocket->errorString()));
765                 Q_EMIT q->error(QAbstractSocket::NetworkError);
766                 break;
767             }
768         }
769         currentPosition += size;
770         bytesLeft -= size;
771     }
772     if (Q_UNLIKELY(payloadWritten != data.size())) {
773         setErrorString(QWebSocket::tr("Bytes written %1 != %2.")
774                        .arg(payloadWritten).arg(data.size()));
775         Q_EMIT q->error(QAbstractSocket::NetworkError);
776     }
777     return payloadWritten;
778 }
779
780 /*!
781     \internal
782  */
783 quint32 QWebSocketPrivate::generateMaskingKey() const
784 {
785     return m_pMaskGenerator->nextMask();
786 }
787
788 /*!
789     \internal
790  */
791 QByteArray QWebSocketPrivate::generateKey() const
792 {
793     QByteArray key;
794
795     for (int i = 0; i < 4; ++i) {
796         const quint32 tmp = m_pMaskGenerator->nextMask();
797         key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
798     }
799
800     return key.toBase64();
801 }
802
803
804 /*!
805     \internal
806  */
807 QString QWebSocketPrivate::calculateAcceptKey(const QByteArray &key) const
808 {
809     const QByteArray tmpKey = key + QByteArrayLiteral("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
810     const QByteArray hash = QCryptographicHash::hash(tmpKey, QCryptographicHash::Sha1).toBase64();
811     return QString::fromLatin1(hash);
812 }
813
814 /*!
815     \internal
816  */
817 qint64 QWebSocketPrivate::writeFrames(const QList<QByteArray> &frames)
818 {
819     qint64 written = 0;
820     if (Q_LIKELY(m_pSocket)) {
821         QList<QByteArray>::const_iterator it;
822         for (it = frames.cbegin(); it < frames.cend(); ++it)
823             written += writeFrame(*it);
824     }
825     return written;
826 }
827
828 /*!
829     \internal
830  */
831 qint64 QWebSocketPrivate::writeFrame(const QByteArray &frame)
832 {
833     qint64 written = 0;
834     if (Q_LIKELY(m_pSocket))
835         written = m_pSocket->write(frame);
836     return written;
837 }
838
839 /*!
840     \internal
841  */
842 QString readLine(QTcpSocket *pSocket)
843 {
844     Q_ASSERT(pSocket);
845     QString line;
846     char c;
847     while (pSocket->getChar(&c)) {
848         if (c == char('\r')) {
849             pSocket->getChar(&c);
850             break;
851         } else {
852             line.append(QChar::fromLatin1(c));
853         }
854     }
855     return line;
856 }
857
858 //called on the client for a server handshake response
859 /*!
860     \internal
861  */
862 void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
863 {
864     Q_Q(QWebSocket);
865     if (Q_UNLIKELY(!pSocket))
866         return;
867
868     bool ok = false;
869     QString errorDescription;
870
871     const QString regExpStatusLine(QStringLiteral("^(HTTP/[0-9]+\\.[0-9]+)\\s([0-9]+)\\s(.*)"));
872     const QRegularExpression regExp(regExpStatusLine);
873     const QString statusLine = readLine(pSocket);
874     QString httpProtocol;
875     int httpStatusCode;
876     QString httpStatusMessage;
877     const QRegularExpressionMatch match = regExp.match(statusLine);
878     if (Q_LIKELY(match.hasMatch())) {
879         QStringList tokens = match.capturedTexts();
880         tokens.removeFirst();   //remove the search string
881         if (tokens.length() == 3) {
882             httpProtocol = tokens[0];
883             httpStatusCode = tokens[1].toInt();
884             httpStatusMessage = tokens[2].trimmed();
885             ok = true;
886         }
887     }
888     if (Q_UNLIKELY(!ok)) {
889         errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(statusLine);
890     } else {
891         QString headerLine = readLine(pSocket);
892         QMap<QString, QString> headers;
893         while (!headerLine.isEmpty()) {
894             const QStringList headerField = headerLine.split(QStringLiteral(": "),
895                                                              QString::SkipEmptyParts);
896             if (headerField.size() == 2) {
897                 headers.insertMulti(headerField[0].toLower(), headerField[1]);
898             }
899             headerLine = readLine(pSocket);
900         }
901
902         const QString acceptKey = headers.value(QStringLiteral("sec-websocket-accept"),
903                                                 QString());
904         const QString upgrade = headers.value(QStringLiteral("upgrade"), QString());
905         const QString connection = headers.value(QStringLiteral("connection"), QString());
906 //        unused for the moment
907 //        const QString extensions = headers.value(QStringLiteral("sec-websocket-extensions"),
908 //                                                 QString());
909 //        const QString protocol = headers.value(QStringLiteral("sec-websocket-protocol"),
910 //                                               QString());
911         const QString version = headers.value(QStringLiteral("sec-websocket-version"),
912                                               QString());
913
914         if (Q_LIKELY(httpStatusCode == 101)) {
915             //HTTP/x.y 101 Switching Protocols
916             bool conversionOk = false;
917             const float version = httpProtocol.midRef(5).toFloat(&conversionOk);
918             //TODO: do not check the httpStatusText right now
919             ok = !(acceptKey.isEmpty() ||
920                    (!conversionOk || (version < 1.1f)) ||
921                    (upgrade.toLower() != QStringLiteral("websocket")) ||
922                    (connection.toLower() != QStringLiteral("upgrade")));
923             if (ok) {
924                 const QString accept = calculateAcceptKey(m_key);
925                 ok = (accept == acceptKey);
926                 if (!ok)
927                     errorDescription =
928                       QWebSocket::tr("Accept-Key received from server %1 does not match the client key %2.")
929                             .arg(acceptKey).arg(accept);
930             } else {
931                 errorDescription =
932                     QWebSocket::tr("QWebSocketPrivate::processHandshake: Invalid statusline in response: %1.")
933                         .arg(statusLine);
934             }
935         } else if (httpStatusCode == 400) {
936             //HTTP/1.1 400 Bad Request
937             if (!version.isEmpty()) {
938                 const QStringList versions = version.split(QStringLiteral(", "),
939                                                            QString::SkipEmptyParts);
940                 if (!versions.contains(QString::number(QWebSocketProtocol::currentVersion()))) {
941                     //if needed to switch protocol version, then we are finished here
942                     //because we cannot handle other protocols than the RFC one (v13)
943                     errorDescription =
944                             QWebSocket::tr("Handshake: Server requests a version that we don't support: %1.")
945                             .arg(versions.join(QStringLiteral(", ")));
946                     ok = false;
947                 } else {
948                     //we tried v13, but something different went wrong
949                     errorDescription =
950                         QWebSocket::tr("QWebSocketPrivate::processHandshake: Unknown error condition encountered. Aborting connection.");
951                     ok = false;
952                 }
953             }
954         } else {
955             errorDescription =
956                     QWebSocket::tr("QWebSocketPrivate::processHandshake: Unhandled http status code: %1 (%2).")
957                         .arg(httpStatusCode).arg(httpStatusMessage);
958             ok = false;
959         }
960
961         if (!ok) {
962             setErrorString(errorDescription);
963             Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
964         } else {
965             //handshake succeeded
966             setSocketState(QAbstractSocket::ConnectedState);
967             Q_EMIT q->connected();
968         }
969     }
970 }
971
972 /*!
973     \internal
974  */
975 void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketState)
976 {
977     Q_ASSERT(m_pSocket);
978     Q_Q(QWebSocket);
979     QAbstractSocket::SocketState webSocketState = this->state();
980     switch (socketState) {
981     case QAbstractSocket::ConnectedState:
982         if (webSocketState == QAbstractSocket::ConnectingState) {
983             m_key = generateKey();
984             const QString handshake =
985                     createHandShakeRequest(m_resourceName,
986                                            m_requestUrl.host()
987                                                 % QStringLiteral(":")
988                                                 % QString::number(m_requestUrl.port(80)),
989                                            origin(),
990                                            QString(),
991                                            QString(),
992                                            m_key);
993             if (handshake.isEmpty()) {
994                 m_pSocket->abort();
995                 Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
996                 return;
997             }
998             m_pSocket->write(handshake.toLatin1());
999         }
1000         break;
1001
1002     case QAbstractSocket::ClosingState:
1003         if (webSocketState == QAbstractSocket::ConnectedState)
1004             setSocketState(QAbstractSocket::ClosingState);
1005         break;
1006
1007     case QAbstractSocket::UnconnectedState:
1008         if (webSocketState != QAbstractSocket::UnconnectedState) {
1009             setSocketState(QAbstractSocket::UnconnectedState);
1010             Q_EMIT q->disconnected();
1011         }
1012         break;
1013
1014     case QAbstractSocket::HostLookupState:
1015     case QAbstractSocket::ConnectingState:
1016     case QAbstractSocket::BoundState:
1017     case QAbstractSocket::ListeningState:
1018         //do nothing
1019         //to make C++ compiler happy;
1020         break;
1021     default:
1022         break;
1023     }
1024 }
1025
1026 /*!
1027  \internal
1028  */
1029 void QWebSocketPrivate::processData()
1030 {
1031     Q_ASSERT(m_pSocket);
1032     while (m_pSocket->bytesAvailable()) {
1033         if (state() == QAbstractSocket::ConnectingState)
1034             processHandshake(m_pSocket.data());
1035         else
1036             m_dataProcessor.process(m_pSocket.data());
1037     }
1038 }
1039
1040 /*!
1041  \internal
1042  */
1043 void QWebSocketPrivate::processPing(const QByteArray &data)
1044 {
1045     Q_ASSERT(m_pSocket);
1046     quint32 maskingKey = 0;
1047     if (m_mustMask)
1048         maskingKey = generateMaskingKey();
1049     m_pSocket->write(getFrameHeader(QWebSocketProtocol::OpCodePong, data.size(), maskingKey, true));
1050     if (data.size() > 0) {
1051         QByteArray maskedData = data;
1052         if (m_mustMask)
1053             QWebSocketProtocol::mask(&maskedData, maskingKey);
1054         m_pSocket->write(maskedData);
1055     }
1056 }
1057
1058 /*!
1059  \internal
1060  */
1061 void QWebSocketPrivate::processPong(const QByteArray &data)
1062 {
1063     Q_Q(QWebSocket);
1064     Q_EMIT q->pong(static_cast<quint64>(m_pingTimer.elapsed()), data);
1065 }
1066
1067 /*!
1068  \internal
1069  */
1070 void QWebSocketPrivate::processClose(QWebSocketProtocol::CloseCode closeCode, QString closeReason)
1071 {
1072     m_isClosingHandshakeReceived = true;
1073     close(closeCode, closeReason);
1074 }
1075
1076 /*!
1077     \internal
1078  */
1079 QString QWebSocketPrivate::createHandShakeRequest(QString resourceName,
1080                                                   QString host,
1081                                                   QString origin,
1082                                                   QString extensions,
1083                                                   QString protocols,
1084                                                   QByteArray key)
1085 {
1086     QStringList handshakeRequest;
1087     if (resourceName.contains(QStringLiteral("\r\n"))) {
1088         setErrorString(QWebSocket::tr("The resource name contains newlines. " \
1089                                       "Possible attack detected."));
1090         return QString();
1091     }
1092     if (host.contains(QStringLiteral("\r\n"))) {
1093         setErrorString(QWebSocket::tr("The hostname contains newlines. " \
1094                                       "Possible attack detected."));
1095         return QString();
1096     }
1097     if (origin.contains(QStringLiteral("\r\n"))) {
1098         setErrorString(QWebSocket::tr("The origin contains newlines. " \
1099                                       "Possible attack detected."));
1100         return QString();
1101     }
1102     if (extensions.contains(QStringLiteral("\r\n"))) {
1103         setErrorString(QWebSocket::tr("The extensions attribute contains newlines. " \
1104                                       "Possible attack detected."));
1105         return QString();
1106     }
1107     if (protocols.contains(QStringLiteral("\r\n"))) {
1108         setErrorString(QWebSocket::tr("The protocols attribute contains newlines. " \
1109                                       "Possible attack detected."));
1110         return QString();
1111     }
1112
1113     handshakeRequest << QStringLiteral("GET ") % resourceName % QStringLiteral(" HTTP/1.1") <<
1114                         QStringLiteral("Host: ") % host <<
1115                         QStringLiteral("Upgrade: websocket") <<
1116                         QStringLiteral("Connection: Upgrade") <<
1117                         QStringLiteral("Sec-WebSocket-Key: ") % QString::fromLatin1(key);
1118     if (!origin.isEmpty())
1119         handshakeRequest << QStringLiteral("Origin: ") % origin;
1120     handshakeRequest << QStringLiteral("Sec-WebSocket-Version: ")
1121                             % QString::number(QWebSocketProtocol::currentVersion());
1122     if (extensions.length() > 0)
1123         handshakeRequest << QStringLiteral("Sec-WebSocket-Extensions: ") % extensions;
1124     if (protocols.length() > 0)
1125         handshakeRequest << QStringLiteral("Sec-WebSocket-Protocol: ") % protocols;
1126     handshakeRequest << QStringLiteral("\r\n");
1127
1128     return handshakeRequest.join(QStringLiteral("\r\n"));
1129 }
1130
1131 /*!
1132     \internal
1133  */
1134 QAbstractSocket::SocketState QWebSocketPrivate::state() const
1135 {
1136     return m_socketState;
1137 }
1138
1139 /*!
1140     \internal
1141  */
1142 void QWebSocketPrivate::setSocketState(QAbstractSocket::SocketState state)
1143 {
1144     Q_Q(QWebSocket);
1145     if (m_socketState != state) {
1146         m_socketState = state;
1147         Q_EMIT q->stateChanged(m_socketState);
1148     }
1149 }
1150
1151 /*!
1152     \internal
1153  */
1154 void QWebSocketPrivate::setErrorString(const QString &errorString)
1155 {
1156     if (m_errorString != errorString)
1157         m_errorString = errorString;
1158 }
1159
1160 /*!
1161     \internal
1162  */
1163 QHostAddress QWebSocketPrivate::localAddress() const
1164 {
1165     QHostAddress address;
1166     if (Q_LIKELY(m_pSocket))
1167         address = m_pSocket->localAddress();
1168     return address;
1169 }
1170
1171 /*!
1172     \internal
1173  */
1174 quint16 QWebSocketPrivate::localPort() const
1175 {
1176     quint16 port = 0;
1177     if (Q_LIKELY(m_pSocket))
1178         port = m_pSocket->localPort();
1179     return port;
1180 }
1181
1182 /*!
1183     \internal
1184  */
1185 QAbstractSocket::PauseModes QWebSocketPrivate::pauseMode() const
1186 {
1187     return m_pauseMode;
1188 }
1189
1190 /*!
1191     \internal
1192  */
1193 QHostAddress QWebSocketPrivate::peerAddress() const
1194 {
1195     QHostAddress address;
1196     if (Q_LIKELY(m_pSocket))
1197         address = m_pSocket->peerAddress();
1198     return address;
1199 }
1200
1201 /*!
1202     \internal
1203  */
1204 QString QWebSocketPrivate::peerName() const
1205 {
1206     QString name;
1207     if (Q_LIKELY(m_pSocket))
1208         name = m_pSocket->peerName();
1209     return name;
1210 }
1211
1212 /*!
1213     \internal
1214  */
1215 quint16 QWebSocketPrivate::peerPort() const
1216 {
1217     quint16 port = 0;
1218     if (Q_LIKELY(m_pSocket))
1219         port = m_pSocket->peerPort();
1220     return port;
1221 }
1222
1223 #ifndef QT_NO_NETWORKPROXY
1224 /*!
1225     \internal
1226  */
1227 QNetworkProxy QWebSocketPrivate::proxy() const
1228 {
1229     return m_configuration.m_proxy;
1230 }
1231
1232 /*!
1233     \internal
1234  */
1235 void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
1236 {
1237     if (m_configuration.m_proxy != networkProxy)
1238         m_configuration.m_proxy = networkProxy;
1239 }
1240 #endif  //QT_NO_NETWORKPROXY
1241
1242 /*!
1243     \internal
1244  */
1245 void QWebSocketPrivate::setMaskGenerator(const QMaskGenerator *maskGenerator)
1246 {
1247     if (!maskGenerator)
1248         m_pMaskGenerator = &m_defaultMaskGenerator;
1249     else if (maskGenerator != m_pMaskGenerator)
1250         m_pMaskGenerator = const_cast<QMaskGenerator *>(maskGenerator);
1251 }
1252
1253 /*!
1254     \internal
1255  */
1256 const QMaskGenerator *QWebSocketPrivate::maskGenerator() const
1257 {
1258     Q_ASSERT(m_pMaskGenerator);
1259     return m_pMaskGenerator;
1260 }
1261
1262 /*!
1263     \internal
1264  */
1265 qint64 QWebSocketPrivate::readBufferSize() const
1266 {
1267     return m_readBufferSize;
1268 }
1269
1270 /*!
1271     \internal
1272  */
1273 void QWebSocketPrivate::resume()
1274 {
1275     if (Q_LIKELY(m_pSocket))
1276         m_pSocket->resume();
1277 }
1278
1279 /*!
1280   \internal
1281  */
1282 void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
1283 {
1284     m_pauseMode = pauseMode;
1285     if (Q_LIKELY(m_pSocket))
1286         m_pSocket->setPauseMode(m_pauseMode);
1287 }
1288
1289 /*!
1290     \internal
1291  */
1292 void QWebSocketPrivate::setReadBufferSize(qint64 size)
1293 {
1294     m_readBufferSize = size;
1295     if (Q_LIKELY(m_pSocket))
1296         m_pSocket->setReadBufferSize(m_readBufferSize);
1297 }
1298
1299 /*!
1300     \internal
1301  */
1302 bool QWebSocketPrivate::isValid() const
1303 {
1304     return (m_pSocket && m_pSocket->isValid() &&
1305             (m_socketState == QAbstractSocket::ConnectedState));
1306 }
1307
1308 QT_END_NAMESPACE