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