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