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