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