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