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