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