There was no '?' between path and query. Bug detected by someone on the internet.
[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, 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_func()->setExtension(response.getAcceptedExtension());
193     pWebSocket->d_func()->setOrigin(request.getOrigin());
194     pWebSocket->d_func()->setRequestUrl(request.getRequestUrl());
195     pWebSocket->d_func()->setProtocol(response.getAcceptedProtocol());
196     pWebSocket->d_func()->setResourceName(request.getRequestUrl().toString(QUrl::RemoveUserInfo));
197     pWebSocket->d_func()->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     Q_Q(QWebSocket);
208     if (!m_isClosingHandshakeSent)
209     {
210         quint32 maskingKey = 0;
211         if (m_mustMask)
212         {
213             maskingKey = generateMaskingKey();
214         }
215         quint16 code = qToBigEndian<quint16>(closeCode);
216         QByteArray payload;
217         payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
218         if (!reason.isEmpty())
219         {
220             payload.append(reason.toUtf8());
221         }
222         if (m_mustMask)
223         {
224             QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
225         }
226         QByteArray frame = getFrameHeader(QWebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
227         frame.append(payload);
228         m_pSocket->write(frame);
229         m_pSocket->flush();
230
231         m_isClosingHandshakeSent = true;
232
233         Q_EMIT q->aboutToClose();
234     }
235     m_pSocket->close();
236 }
237
238 /*!
239     \internal
240  */
241 void QWebSocketPrivate::open(const QUrl &url, bool mask)
242 {
243     m_dataProcessor.clear();
244     m_isClosingHandshakeReceived = false;
245     m_isClosingHandshakeSent = false;
246
247     setRequestUrl(url);
248     QString resourceName = url.path();
249     if (!url.query().isEmpty())
250     {
251         resourceName.append("?" + url.query());
252     }
253     if (resourceName.isEmpty())
254     {
255         resourceName = "/";
256     }
257     setResourceName(resourceName);
258     enableMasking(mask);
259
260     setSocketState(QAbstractSocket::ConnectingState);
261
262     m_pSocket->connectToHost(url.host(), url.port(80));
263 }
264
265 /*!
266     \internal
267  */
268 void QWebSocketPrivate::ping(const QByteArray &payload)
269 {
270     Q_ASSERT(payload.length() < 126);
271     m_pingTimer.restart();
272     QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OC_PING, payload.size(), 0 /*do not mask*/, true);
273     pingFrame.append(payload);
274     writeFrame(pingFrame);
275 }
276
277 /*!
278   \internal
279     Sets the version to use for the websocket protocol; this must be set before the socket is opened.
280 */
281 void QWebSocketPrivate::setVersion(QWebSocketProtocol::Version version)
282 {
283     m_version = version;
284 }
285
286 /*!
287     \internal
288     Sets the resource name of the connection; must be set before the socket is openend
289 */
290 void QWebSocketPrivate::setResourceName(const QString &resourceName)
291 {
292     m_resourceName = resourceName;
293 }
294
295 /*!
296   \internal
297  */
298 void QWebSocketPrivate::setRequestUrl(const QUrl &requestUrl)
299 {
300     m_requestUrl = requestUrl;
301 }
302
303 /*!
304   \internal
305  */
306 void QWebSocketPrivate::setOrigin(const QString &origin)
307 {
308     m_origin = origin;
309 }
310
311 /*!
312   \internal
313  */
314 void QWebSocketPrivate::setProtocol(const QString &protocol)
315 {
316     m_protocol = protocol;
317 }
318
319 /*!
320   \internal
321  */
322 void QWebSocketPrivate::setExtension(const QString &extension)
323 {
324     m_extension = extension;
325 }
326
327 /*!
328   \internal
329  */
330 void QWebSocketPrivate::enableMasking(bool enable)
331 {
332     m_mustMask = enable;
333 }
334
335 /*!
336  * \internal
337  */
338 qint64 QWebSocketPrivate::doWriteData(const QByteArray &data, bool isBinary)
339 {
340     return doWriteFrames(data, isBinary);
341 }
342
343 /*!
344  * \internal
345  */
346 void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
347 {
348     Q_Q(QWebSocket);
349     //pass through signals
350     connect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), q, SIGNAL(error(QAbstractSocket::SocketError)));
351     connect(pTcpSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), q, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
352     connect(pTcpSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
353     connect(pTcpSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
354     //connect(pTcpSocket, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
355
356     //catch signals
357     connect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
358     connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
359
360     connect(&m_dataProcessor, SIGNAL(textFrameReceived(QString,bool)), q, SIGNAL(textFrameReceived(QString,bool)));
361     connect(&m_dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)), q, SIGNAL(binaryFrameReceived(QByteArray,bool)));
362     connect(&m_dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)), q, SIGNAL(binaryMessageReceived(QByteArray)));
363     connect(&m_dataProcessor, SIGNAL(textMessageReceived(QString)), q, SIGNAL(textMessageReceived(QString)));
364     connect(&m_dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)), this, SLOT(close(QWebSocketProtocol::CloseCode,QString)));
365     connect(&m_dataProcessor, SIGNAL(pingReceived(QByteArray)), this, SLOT(processPing(QByteArray)));
366     connect(&m_dataProcessor, SIGNAL(pongReceived(QByteArray)), this, SLOT(processPong(QByteArray)));
367     connect(&m_dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)), this, SLOT(processClose(QWebSocketProtocol::CloseCode,QString)));
368 }
369
370 /*!
371  * \internal
372  */
373 void QWebSocketPrivate::releaseConnections(const QTcpSocket *pTcpSocket)
374 {
375     Q_Q(QWebSocket);
376     if (pTcpSocket)
377     {
378         //pass through signals
379         disconnect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), q, SIGNAL(error(QAbstractSocket::SocketError)));
380         disconnect(pTcpSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), q, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
381         disconnect(pTcpSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
382         disconnect(pTcpSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
383         //disconnect(pTcpSocket, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
384
385         //catched signals
386         disconnect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
387         disconnect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
388     }
389     disconnect(&m_dataProcessor, SIGNAL(pingReceived(QByteArray)), this, SLOT(processPing(QByteArray)));
390     disconnect(&m_dataProcessor, SIGNAL(pongReceived(QByteArray)), this, SLOT(processPong(QByteArray)));
391     disconnect(&m_dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)), this, SLOT(processClose(QWebSocketProtocol::CloseCode,QString)));
392     disconnect(&m_dataProcessor, SIGNAL(textFrameReceived(QString,bool)), q, SIGNAL(textFrameReceived(QString,bool)));
393     disconnect(&m_dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)), q, SIGNAL(binaryFrameReceived(QByteArray,bool)));
394     disconnect(&m_dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)), q, SIGNAL(binaryMessageReceived(QByteArray)));
395     disconnect(&m_dataProcessor, SIGNAL(textMessageReceived(QString)), q, SIGNAL(textMessageReceived(QString)));
396     disconnect(&m_dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)), this, SLOT(close(QWebSocketProtocol::CloseCode,QString)));
397 }
398
399 /*!
400     \internal
401  */
402 QWebSocketProtocol::Version QWebSocketPrivate::version() const
403 {
404     return m_version;
405 }
406
407 /*!
408     \internal
409  */
410 QString QWebSocketPrivate::resourceName() const
411 {
412     return m_resourceName;
413 }
414
415 /*!
416     \internal
417  */
418 QUrl QWebSocketPrivate::requestUrl() const
419 {
420     return m_requestUrl;
421 }
422
423 /*!
424     \internal
425  */
426 QString QWebSocketPrivate::origin() const
427 {
428     return m_origin;
429 }
430
431 /*!
432     \internal
433  */
434 QString QWebSocketPrivate::protocol() const
435 {
436     return m_protocol;
437 }
438
439 /*!
440     \internal
441  */
442 QString QWebSocketPrivate::extension() const
443 {
444     return m_extension;
445 }
446
447 /*!
448  * \internal
449  */
450 QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength, quint32 maskingKey, bool lastFrame) const
451 {
452     QByteArray header;
453     quint8 byte = 0x00;
454     bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL;
455
456     if (ok)
457     {
458         //FIN, RSV1-3, opcode
459         byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00));        //FIN, opcode
460         //RSV-1, RSV-2 and RSV-3 are zero
461         header.append(static_cast<char>(byte));
462
463         //Now write the masking bit and the payload length byte
464         byte = 0x00;
465         if (maskingKey != 0)
466         {
467             byte |= 0x80;
468         }
469         if (payloadLength <= 125)
470         {
471             byte |= static_cast<quint8>(payloadLength);
472             header.append(static_cast<char>(byte));
473         }
474         else if (payloadLength <= 0xFFFFU)
475         {
476             byte |= 126;
477             header.append(static_cast<char>(byte));
478             quint16 swapped = qToBigEndian<quint16>(static_cast<quint16>(payloadLength));
479             header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 2);
480         }
481         else if (payloadLength <= 0x7FFFFFFFFFFFFFFFULL)
482         {
483             byte |= 127;
484             header.append(static_cast<char>(byte));
485             quint64 swapped = qToBigEndian<quint64>(payloadLength);
486             header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 8);
487         }
488
489         //Write mask
490         if (maskingKey != 0)
491         {
492             header.append(static_cast<const char *>(static_cast<const void *>(&maskingKey)), sizeof(quint32));
493         }
494     }
495     else
496     {
497         //setErrorString("WebSocket::getHeader: payload too big!");
498         //Q_EMIT q_ptr->error(QAbstractSocket::DatagramTooLargeError);
499         qDebug() << "WebSocket::getHeader: payload too big!";
500     }
501
502     return header;
503 }
504
505 /*!
506  * \internal
507  */
508 qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
509 {
510     Q_Q(QWebSocket);
511     const QWebSocketProtocol::OpCode firstOpCode = isBinary ? QWebSocketProtocol::OC_BINARY : QWebSocketProtocol::OC_TEXT;
512
513     int numFrames = data.size() / FRAME_SIZE_IN_BYTES;
514     QByteArray tmpData(data);
515     tmpData.detach();
516     char *payload = tmpData.data();
517     quint64 sizeLeft = static_cast<quint64>(data.size()) % FRAME_SIZE_IN_BYTES;
518     if (sizeLeft)
519     {
520         ++numFrames;
521     }
522     if (numFrames == 0)     //catch the case where the payload is zero bytes; in that case, we still need to send a frame
523     {
524         numFrames = 1;
525     }
526     quint64 currentPosition = 0;
527     qint64 bytesWritten = 0;
528     qint64 payloadWritten = 0;
529     quint64 bytesLeft = data.size();
530
531     for (int i = 0; i < numFrames; ++i)
532     {
533         quint32 maskingKey = 0;
534         if (m_mustMask)
535         {
536             maskingKey = generateMaskingKey();
537         }
538
539         bool isLastFrame = (i == (numFrames - 1));
540         bool isFirstFrame = (i == 0);
541
542         quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
543         QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode : QWebSocketProtocol::OC_CONTINUE;
544
545         //write header
546         bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
547
548         //write payload
549         if (size > 0)
550         {
551             char *currentData = payload + currentPosition;
552             if (m_mustMask)
553             {
554                 QWebSocketProtocol::mask(currentData, size, maskingKey);
555             }
556             qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
557             if (written > 0)
558             {
559                 bytesWritten += written;
560                 payloadWritten += written;
561             }
562             else
563             {
564                 setErrorString(tr("Error writing bytes to socket: %1.").arg(m_pSocket->errorString()));
565                 qDebug() << errorString();
566                 m_pSocket->flush();
567                 Q_EMIT q->error(QAbstractSocket::NetworkError);
568                 break;
569             }
570         }
571         currentPosition += size;
572         bytesLeft -= size;
573     }
574     if (payloadWritten != data.size())
575     {
576         setErrorString(tr("Bytes written %1 != %2.").arg(payloadWritten).arg(data.size()));
577         qDebug() << errorString();
578         Q_EMIT q->error(QAbstractSocket::NetworkError);
579     }
580     return payloadWritten;
581 }
582
583 /*!
584  * \internal
585  */
586 quint32 QWebSocketPrivate::generateRandomNumber() const
587 {
588     return static_cast<quint32>((static_cast<double>(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
589 }
590
591 /*!
592     \internal
593  */
594 quint32 QWebSocketPrivate::generateMaskingKey() const
595 {
596     return generateRandomNumber();
597 }
598
599 /*!
600     \internal
601  */
602 QByteArray QWebSocketPrivate::generateKey() const
603 {
604     QByteArray key;
605
606     for (int i = 0; i < 4; ++i)
607     {
608         quint32 tmp = generateRandomNumber();
609         key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
610     }
611
612     return key.toBase64();
613 }
614
615
616 /*!
617     \internal
618  */
619 QString QWebSocketPrivate::calculateAcceptKey(const QString &key) const
620 {
621     QString tmpKey = key % "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
622     QByteArray hash = QCryptographicHash::hash(tmpKey.toLatin1(), QCryptographicHash::Sha1);
623     return QString(hash.toBase64());
624 }
625
626 /*!
627     \internal
628  */
629 qint64 QWebSocketPrivate::writeFrames(const QList<QByteArray> &frames)
630 {
631     qint64 written = 0;
632     for (int i = 0; i < frames.size(); ++i)
633     {
634         written += writeFrame(frames[i]);
635     }
636     return written;
637 }
638
639 /*!
640     \internal
641  */
642 qint64 QWebSocketPrivate::writeFrame(const QByteArray &frame)
643 {
644     return m_pSocket->write(frame);
645 }
646
647 /*!
648     \internal
649  */
650 QString readLine(QTcpSocket *pSocket)
651 {
652     QString line;
653     char c;
654     while (pSocket->getChar(&c))
655     {
656         if (c == '\r')
657         {
658             pSocket->getChar(&c);
659             break;
660         }
661         else
662         {
663             line.append(QChar(c));
664         }
665     }
666     return line;
667 }
668
669 //called on the client for a server handshake response
670 /*!
671     \internal
672  */
673 void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
674 {
675     Q_Q(QWebSocket);
676     if (pSocket == 0)
677     {
678         return;
679     }
680
681     bool ok = false;
682     QString errorDescription;
683
684     const QString regExpStatusLine("^(HTTP/[0-9]+\\.[0-9]+)\\s([0-9]+)\\s(.*)");
685     const QRegularExpression regExp(regExpStatusLine);
686     QString statusLine = readLine(pSocket);
687     QString httpProtocol;
688     int httpStatusCode;
689     QString httpStatusMessage;
690     QRegularExpressionMatch match = regExp.match(statusLine);
691     if (match.hasMatch())
692     {
693         QStringList tokens = match.capturedTexts();
694         tokens.removeFirst();   //remove the search string
695         if (tokens.length() == 3)
696         {
697             httpProtocol = tokens[0];
698             httpStatusCode = tokens[1].toInt();
699             httpStatusMessage = tokens[2].trimmed();
700             ok = true;
701         }
702     }
703     if (!ok)
704     {
705         errorDescription = tr("Invalid statusline in response: %1.").arg(statusLine);
706     }
707     else
708     {
709         QString headerLine = readLine(pSocket);
710         QMap<QString, QString> headers;
711         while (!headerLine.isEmpty())
712         {
713             QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
714             headers.insertMulti(headerField[0], headerField[1]);
715             headerLine = readLine(pSocket);
716         }
717
718         QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
719         QString upgrade = headers.value("Upgrade", "");
720         QString connection = headers.value("Connection", "");
721         //unused for the moment
722         //QString extensions = headers.value("Sec-WebSocket-Extensions", "");
723         //QString protocol = headers.value("Sec-WebSocket-Protocol", "");
724         QString version = headers.value("Sec-WebSocket-Version", "");
725
726         if (httpStatusCode == 101)      //HTTP/x.y 101 Switching Protocols
727         {
728             bool conversionOk = false;
729             float version = httpProtocol.midRef(5).toFloat(&conversionOk);
730             //TODO: do not check the httpStatusText right now
731             ok = !(acceptKey.isEmpty() ||
732                    (!conversionOk || (version < 1.1f)) ||
733                    (upgrade.toLower() != "websocket") ||
734                    (connection.toLower() != "upgrade"));
735             if (ok)
736             {
737                 QString accept = calculateAcceptKey(m_key);
738                 ok = (accept == acceptKey);
739                 if (!ok)
740                 {
741                     errorDescription = tr("Accept-Key received from server %1 does not match the client key %2.").arg(acceptKey).arg(accept);
742                 }
743             }
744             else
745             {
746                 errorDescription = tr("Invalid statusline in response: %1.").arg(statusLine);
747             }
748         }
749         else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
750         {
751             if (!version.isEmpty())
752             {
753                 QStringList versions = version.split(", ", QString::SkipEmptyParts);
754                 if (!versions.contains(QString::number(QWebSocketProtocol::currentVersion())))
755                 {
756                     //if needed to switch protocol version, then we are finished here
757                     //because we cannot handle other protocols than the RFC one (v13)
758                     errorDescription = tr("Handshake: Server requests a version that we don't support: %1.").arg(versions.join(", "));
759                     ok = false;
760                 }
761                 else
762                 {
763                     //we tried v13, but something different went wrong
764                     errorDescription = tr("Unknown error condition encountered. Aborting connection.");
765                     ok = false;
766                 }
767             }
768         }
769         else
770         {
771             errorDescription = tr("Unhandled http status code: %1.").arg(httpStatusCode);
772             ok = false;
773         }
774
775         if (!ok)
776         {
777             qDebug() << errorDescription;
778             setErrorString(errorDescription);
779             Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
780         }
781         else
782         {
783             //handshake succeeded
784             setSocketState(QAbstractSocket::ConnectedState);
785             Q_EMIT q->connected();
786         }
787     }
788 }
789
790 /*!
791     \internal
792  */
793 void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketState)
794 {
795     Q_Q(QWebSocket);
796     QAbstractSocket::SocketState webSocketState = this->state();
797     switch (socketState)
798     {
799     case QAbstractSocket::ConnectedState:
800     {
801         if (webSocketState == QAbstractSocket::ConnectingState)
802         {
803             m_key = generateKey();
804             QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() % ":" % QString::number(m_requestUrl.port(80)), origin(), "", "", m_key);
805             m_pSocket->write(handshake.toLatin1());
806         }
807         break;
808     }
809     case QAbstractSocket::ClosingState:
810     {
811         if (webSocketState == QAbstractSocket::ConnectedState)
812         {
813             setSocketState(QAbstractSocket::ClosingState);
814         }
815         break;
816     }
817     case QAbstractSocket::UnconnectedState:
818     {
819         if (webSocketState != QAbstractSocket::UnconnectedState)
820         {
821             setSocketState(QAbstractSocket::UnconnectedState);
822             Q_EMIT q->disconnected();
823         }
824         break;
825     }
826     case QAbstractSocket::HostLookupState:
827     case QAbstractSocket::ConnectingState:
828     case QAbstractSocket::BoundState:
829     case QAbstractSocket::ListeningState:
830     {
831         //do nothing
832         //to make C++ compiler happy;
833         break;
834     }
835     default:
836     {
837         break;
838     }
839     }
840 }
841
842 //order of events:
843 //connectToHost is called
844 //our socket state is set to "connecting", and tcpSocket->connectToHost is called
845 //the tcpsocket is opened, a handshake message is sent; a readyRead signal is thrown
846 //this signal is catched by processData
847 //when OUR socket state is in the "connecting state", this means that
848 //we have received data from the server (response to handshake), and that we
849 //should "upgrade" our socket to a websocket (connected state)
850 //if our socket was already upgraded, then we need to process websocket data
851 /*!
852  \internal
853  */
854 void QWebSocketPrivate::processData()
855 {
856     while (m_pSocket->bytesAvailable())
857     {
858         if (state() == QAbstractSocket::ConnectingState)
859         {
860             processHandshake(m_pSocket);
861         }
862         else
863         {
864             m_dataProcessor.process(m_pSocket);
865         }
866     }
867 }
868
869 /*!
870  \internal
871  */
872 void QWebSocketPrivate::processPing(QByteArray data)
873 {
874     quint32 maskingKey = 0;
875     if (m_mustMask)
876     {
877         maskingKey = generateMaskingKey();
878     }
879     m_pSocket->write(getFrameHeader(QWebSocketProtocol::OC_PONG, data.size(), maskingKey, true));
880     if (data.size() > 0)
881     {
882         if (m_mustMask)
883         {
884             QWebSocketProtocol::mask(&data, maskingKey);
885         }
886         m_pSocket->write(data);
887     }
888 }
889
890 /*!
891  \internal
892  */
893 void QWebSocketPrivate::processPong(QByteArray data)
894 {
895     Q_Q(QWebSocket);
896     Q_EMIT q->pong(static_cast<quint64>(m_pingTimer.elapsed()), data);
897 }
898
899 /*!
900  \internal
901  */
902 void QWebSocketPrivate::processClose(QWebSocketProtocol::CloseCode closeCode, QString closeReason)
903 {
904     m_isClosingHandshakeReceived = true;
905     close(closeCode, closeReason);
906 }
907
908 /*!
909     \internal
910  */
911 QString QWebSocketPrivate::createHandShakeRequest(QString resourceName,
912                                                   QString host,
913                                                   QString origin,
914                                                   QString extensions,
915                                                   QString protocols,
916                                                   QByteArray key)
917 {
918     QStringList handshakeRequest;
919
920     handshakeRequest << "GET " % resourceName % " HTTP/1.1" <<
921                         "Host: " % host <<
922                         "Upgrade: websocket" <<
923                         "Connection: Upgrade" <<
924                         "Sec-WebSocket-Key: " % QString(key);
925     if (!origin.isEmpty())
926     {
927         handshakeRequest << "Origin: " % origin;
928     }
929     handshakeRequest << "Sec-WebSocket-Version: " % QString::number(QWebSocketProtocol::currentVersion());
930     if (extensions.length() > 0)
931     {
932         handshakeRequest << "Sec-WebSocket-Extensions: " % extensions;
933     }
934     if (protocols.length() > 0)
935     {
936         handshakeRequest << "Sec-WebSocket-Protocol: " % protocols;
937     }
938     handshakeRequest << "\r\n";
939
940     return handshakeRequest.join("\r\n");
941 }
942
943 /*!
944     \internal
945  */
946 QAbstractSocket::SocketState QWebSocketPrivate::state() const
947 {
948     return m_socketState;
949 }
950
951 /*!
952     \internal
953  */
954 bool QWebSocketPrivate::waitForConnected(int msecs)
955 {
956     return m_pSocket->waitForConnected(msecs);
957 }
958
959 /*!
960     \internal
961  */
962 bool QWebSocketPrivate::waitForDisconnected(int msecs)
963 {
964     return m_pSocket->waitForDisconnected(msecs);
965 }
966
967 /*!
968     \internal
969  */
970 void QWebSocketPrivate::setSocketState(QAbstractSocket::SocketState state)
971 {
972     Q_Q(QWebSocket);
973     if (m_socketState != state)
974     {
975         m_socketState = state;
976         Q_EMIT q->stateChanged(m_socketState);
977     }
978 }
979
980 /*!
981     \internal
982  */
983 void QWebSocketPrivate::setErrorString(const QString &errorString)
984 {
985     m_errorString = errorString;
986 }
987
988 /*!
989     \internal
990  */
991 QHostAddress QWebSocketPrivate::localAddress() const
992 {
993     return m_pSocket->localAddress();
994 }
995
996 /*!
997     \internal
998  */
999 quint16 QWebSocketPrivate::localPort() const
1000 {
1001     return m_pSocket->localPort();
1002 }
1003
1004 /*!
1005     \internal
1006  */
1007 QAbstractSocket::PauseModes QWebSocketPrivate::pauseMode() const
1008 {
1009     return m_pSocket->pauseMode();
1010 }
1011
1012 /*!
1013     \internal
1014  */
1015 QHostAddress QWebSocketPrivate::peerAddress() const
1016 {
1017     return m_pSocket->peerAddress();
1018 }
1019
1020 /*!
1021     \internal
1022  */
1023 QString QWebSocketPrivate::peerName() const
1024 {
1025     return m_pSocket->peerName();
1026 }
1027
1028 /*!
1029     \internal
1030  */
1031 quint16 QWebSocketPrivate::peerPort() const
1032 {
1033     return m_pSocket->peerPort();
1034 }
1035
1036 /*!
1037     \internal
1038  */
1039 QNetworkProxy QWebSocketPrivate::proxy() const
1040 {
1041     return m_pSocket->proxy();
1042 }
1043
1044 /*!
1045     \internal
1046  */
1047 qint64 QWebSocketPrivate::readBufferSize() const
1048 {
1049     return m_pSocket->readBufferSize();
1050 }
1051
1052 /*!
1053     \internal
1054  */
1055 void QWebSocketPrivate::resume()
1056 {
1057     m_pSocket->resume();
1058 }
1059
1060 /*!
1061   \internal
1062  */
1063 void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
1064 {
1065     m_pSocket->setPauseMode(pauseMode);
1066 }
1067
1068 /*!
1069     \internal
1070  */
1071 void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
1072 {
1073     m_pSocket->setProxy(networkProxy);
1074 }
1075
1076 /*!
1077     \internal
1078  */
1079 void QWebSocketPrivate::setReadBufferSize(qint64 size)
1080 {
1081     m_pSocket->setReadBufferSize(size);
1082 }
1083
1084 /*!
1085     \internal
1086  */
1087 void QWebSocketPrivate::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
1088 {
1089     m_pSocket->setSocketOption(option, value);
1090 }
1091
1092 /*!
1093     \internal
1094  */
1095 QVariant QWebSocketPrivate::socketOption(QAbstractSocket::SocketOption option)
1096 {
1097     return m_pSocket->socketOption(option);
1098 }
1099
1100 /*!
1101     \internal
1102  */
1103 bool QWebSocketPrivate::isValid() const
1104 {
1105     return m_pSocket->isValid();
1106 }
1107
1108 QT_END_NAMESPACE