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