2 QWebSockets implements the WebSocket protocol as defined in RFC 6455.
3 Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com)
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.
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.
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
20 #include "qwebsocket.h"
21 #include "qwebsocket_p.h"
22 #include "handshakerequest_p.h"
23 #include "handshakeresponse_p.h"
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>
43 const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2; //maximum size of a frame when sending a message
48 QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent) :
51 m_pSocket(new QTcpSocket(this)),
59 m_socketState(QAbstractSocket::UnconnectedState),
62 m_isClosingHandshakeSent(false),
63 m_isClosingHandshakeReceived(false),
67 Q_ASSERT(pWebSocket != 0);
68 makeConnections(m_pSocket);
69 qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
75 QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent) :
78 m_pSocket(pTcpSocket),
79 m_errorString(pTcpSocket->errorString()),
86 m_socketState(pTcpSocket->state()),
89 m_isClosingHandshakeSent(false),
90 m_isClosingHandshakeReceived(false),
94 Q_ASSERT(pWebSocket != 0);
95 makeConnections(m_pSocket);
101 QWebSocketPrivate::~QWebSocketPrivate()
103 if (state() == QAbstractSocket::ConnectedState)
105 close(QWebSocketProtocol::CC_GOING_AWAY, QWebSocket::tr("Connection closed"));
107 releaseConnections(m_pSocket);
108 m_pSocket->deleteLater();
115 void QWebSocketPrivate::abort()
123 QAbstractSocket::SocketError QWebSocketPrivate::error() const
125 return m_pSocket->error();
131 QString QWebSocketPrivate::errorString() const
133 if (!m_errorString.isEmpty())
135 return m_errorString;
139 return m_pSocket->errorString();
146 bool QWebSocketPrivate::flush()
148 return m_pSocket->flush();
154 qint64 QWebSocketPrivate::write(const char *message)
156 return write(QString::fromUtf8(message));
162 qint64 QWebSocketPrivate::write(const char *message, qint64 maxSize)
164 return write(QString::fromUtf8(message, static_cast<int>(maxSize)));
170 qint64 QWebSocketPrivate::write(const QString &message)
172 return doWriteData(message.toUtf8(), false);
178 qint64 QWebSocketPrivate::write(const QByteArray &data)
180 return doWriteData(data, true);
186 QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket,
187 const HandshakeRequest &request,
188 const HandshakeResponse &response,
191 QWebSocket *pWebSocket = new QWebSocket(pTcpSocket, response.getAcceptedVersion(), parent);
192 pWebSocket->d_ptr->setExtension(response.getAcceptedExtension());
193 pWebSocket->d_ptr->setOrigin(request.getOrigin());
194 pWebSocket->d_ptr->setRequestUrl(request.getRequestUrl());
195 pWebSocket->d_ptr->setProtocol(response.getAcceptedProtocol());
196 pWebSocket->d_ptr->setResourceName(request.getRequestUrl().toString(QUrl::RemoveUserInfo));
197 pWebSocket->d_ptr->enableMasking(false); //a server should not send masked frames
205 void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString reason)
207 if (!m_isClosingHandshakeSent)
209 quint32 maskingKey = 0;
212 maskingKey = generateMaskingKey();
214 quint16 code = qToBigEndian<quint16>(closeCode);
216 payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
217 if (!reason.isEmpty())
219 payload.append(reason.toUtf8());
223 QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
225 QByteArray frame = getFrameHeader(QWebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
226 frame.append(payload);
227 m_pSocket->write(frame);
230 m_isClosingHandshakeSent = true;
232 Q_EMIT q_ptr->aboutToClose();
240 void QWebSocketPrivate::open(const QUrl &url, bool mask)
242 m_dataProcessor.clear();
243 m_isClosingHandshakeReceived = false;
244 m_isClosingHandshakeSent = false;
247 QString resourceName = url.path() + url.query();
248 if (resourceName.isEmpty())
252 setResourceName(resourceName);
255 setSocketState(QAbstractSocket::ConnectingState);
257 m_pSocket->connectToHost(url.host(), url.port(80));
263 void QWebSocketPrivate::ping()
265 m_pingTimer.restart();
266 QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OC_PING, 0, 0, true);
267 writeFrame(pingFrame);
272 Sets the version to use for the websocket protocol; this must be set before the socket is opened.
274 void QWebSocketPrivate::setVersion(QWebSocketProtocol::Version version)
281 Sets the resource name of the connection; must be set before the socket is openend
283 void QWebSocketPrivate::setResourceName(QString resourceName)
285 m_resourceName = resourceName;
291 void QWebSocketPrivate::setRequestUrl(QUrl requestUrl)
293 m_requestUrl = requestUrl;
299 void QWebSocketPrivate::setOrigin(QString origin)
307 void QWebSocketPrivate::setProtocol(QString protocol)
309 m_protocol = protocol;
315 void QWebSocketPrivate::setExtension(QString extension)
317 m_extension = extension;
323 void QWebSocketPrivate::enableMasking(bool enable)
331 qint64 QWebSocketPrivate::doWriteData(const QByteArray &data, bool isBinary)
333 return doWriteFrames(data, isBinary);
339 void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
341 //pass through signals
342 connect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), q_ptr, SIGNAL(error(QAbstractSocket::SocketError)));
343 connect(pTcpSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), q_ptr, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
344 connect(pTcpSocket, SIGNAL(readChannelFinished()), q_ptr, SIGNAL(readChannelFinished()));
345 connect(pTcpSocket, SIGNAL(aboutToClose()), q_ptr, SIGNAL(aboutToClose()));
346 //connect(pTcpSocket, SIGNAL(bytesWritten(qint64)), q_ptr, SIGNAL(bytesWritten(qint64)));
349 connect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
350 connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
352 connect(&m_dataProcessor, SIGNAL(controlFrameReceived(QWebSocketProtocol::OpCode, QByteArray)), this, SLOT(processControlFrame(QWebSocketProtocol::OpCode, QByteArray)));
353 connect(&m_dataProcessor, SIGNAL(textFrameReceived(QString,bool)), q_ptr, SIGNAL(textFrameReceived(QString,bool)));
354 connect(&m_dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)), q_ptr, SIGNAL(binaryFrameReceived(QByteArray,bool)));
355 connect(&m_dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)), q_ptr, SIGNAL(binaryMessageReceived(QByteArray)));
356 connect(&m_dataProcessor, SIGNAL(textMessageReceived(QString)), q_ptr, SIGNAL(textMessageReceived(QString)));
357 connect(&m_dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)), this, SLOT(close(QWebSocketProtocol::CloseCode,QString)));
363 void QWebSocketPrivate::releaseConnections(const QTcpSocket *pTcpSocket)
367 //pass through signals
368 disconnect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), q_ptr, SIGNAL(error(QAbstractSocket::SocketError)));
369 disconnect(pTcpSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), q_ptr, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
370 disconnect(pTcpSocket, SIGNAL(readChannelFinished()), q_ptr, SIGNAL(readChannelFinished()));
371 //disconnect(pTcpSocket, SIGNAL(aboutToClose()), q_ptr, SIGNAL(aboutToClose()));
372 //disconnect(pTcpSocket, SIGNAL(bytesWritten(qint64)), q_ptr, SIGNAL(bytesWritten(qint64)));
375 disconnect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
376 disconnect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
378 disconnect(&m_dataProcessor, SIGNAL(controlFrameReceived(QWebSocketProtocol::OpCode,QByteArray)), this, SLOT(processControlFrame(QWebSocketProtocol::OpCode,QByteArray)));
379 disconnect(&m_dataProcessor, SIGNAL(textFrameReceived(QString,bool)), q_ptr, SIGNAL(textFrameReceived(QString,bool)));
380 disconnect(&m_dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)), q_ptr, SIGNAL(binaryFrameReceived(QByteArray,bool)));
381 disconnect(&m_dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)), q_ptr, SIGNAL(binaryMessageReceived(QByteArray)));
382 disconnect(&m_dataProcessor, SIGNAL(textMessageReceived(QString)), q_ptr, SIGNAL(textMessageReceived(QString)));
383 disconnect(&m_dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)), this, SLOT(close(QWebSocketProtocol::CloseCode,QString)));
389 QWebSocketProtocol::Version QWebSocketPrivate::version() const
397 QString QWebSocketPrivate::resourceName() const
399 return m_resourceName;
405 QUrl QWebSocketPrivate::requestUrl() const
413 QString QWebSocketPrivate::origin() const
421 QString QWebSocketPrivate::protocol() const
429 QString QWebSocketPrivate::extension() const
437 QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength, quint32 maskingKey, bool lastFrame) const
441 bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL;
445 //FIN, RSV1-3, opcode
446 byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00)); //FIN, opcode
447 //RSV-1, RSV-2 and RSV-3 are zero
448 header.append(static_cast<char>(byte));
450 //Now write the masking bit and the payload length byte
456 if (payloadLength <= 125)
458 byte |= static_cast<quint8>(payloadLength);
459 header.append(static_cast<char>(byte));
461 else if (payloadLength <= 0xFFFFU)
464 header.append(static_cast<char>(byte));
465 quint16 swapped = qToBigEndian<quint16>(static_cast<quint16>(payloadLength));
466 header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 2);
468 else if (payloadLength <= 0x7FFFFFFFFFFFFFFFULL)
471 header.append(static_cast<char>(byte));
472 quint64 swapped = qToBigEndian<quint64>(payloadLength);
473 header.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 8);
479 header.append(static_cast<const char *>(static_cast<const void *>(&maskingKey)), sizeof(quint32));
484 //setErrorString("WebSocket::getHeader: payload too big!");
485 //Q_EMIT q_ptr->error(QAbstractSocket::DatagramTooLargeError);
486 qDebug() << "WebSocket::getHeader: payload too big!";
495 qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
497 const QWebSocketProtocol::OpCode firstOpCode = isBinary ? QWebSocketProtocol::OC_BINARY : QWebSocketProtocol::OC_TEXT;
499 int numFrames = data.size() / FRAME_SIZE_IN_BYTES;
500 QByteArray tmpData(data);
502 char *payload = tmpData.data();
503 quint64 sizeLeft = static_cast<quint64>(data.size()) % FRAME_SIZE_IN_BYTES;
508 if (numFrames == 0) //catch the case where the payload is zero bytes; in that case, we still need to send a frame
512 quint64 currentPosition = 0;
513 qint64 bytesWritten = 0;
514 qint64 payloadWritten = 0;
515 quint64 bytesLeft = data.size();
517 for (int i = 0; i < numFrames; ++i)
519 quint32 maskingKey = 0;
522 maskingKey = generateMaskingKey();
525 bool isLastFrame = (i == (numFrames - 1));
526 bool isFirstFrame = (i == 0);
528 quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
529 QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode : QWebSocketProtocol::OC_CONTINUE;
532 bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
537 char *currentData = payload + currentPosition;
540 QWebSocketProtocol::mask(currentData, size, maskingKey);
542 qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
545 bytesWritten += written;
546 payloadWritten += written;
550 setErrorString(QWebSocket::tr("Error writing bytes to socket: %1.").arg(m_pSocket->errorString()));
551 qDebug() << errorString();
553 Q_EMIT q_ptr->error(QAbstractSocket::NetworkError);
557 currentPosition += size;
560 if (payloadWritten != data.size())
562 setErrorString(QWebSocket::tr("Bytes written %1 != %2.").arg(payloadWritten).arg(data.size()));
563 qDebug() << errorString();
564 Q_EMIT q_ptr->error(QAbstractSocket::NetworkError);
566 return payloadWritten;
572 quint32 QWebSocketPrivate::generateRandomNumber() const
574 return static_cast<quint32>((static_cast<double>(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
580 quint32 QWebSocketPrivate::generateMaskingKey() const
582 return generateRandomNumber();
588 QByteArray QWebSocketPrivate::generateKey() const
592 for (int i = 0; i < 4; ++i)
594 quint32 tmp = generateRandomNumber();
595 key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
598 return key.toBase64();
605 QString QWebSocketPrivate::calculateAcceptKey(const QString &key) const
607 QString tmpKey = key % "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
608 QByteArray hash = QCryptographicHash::hash(tmpKey.toLatin1(), QCryptographicHash::Sha1);
609 return QString(hash.toBase64());
615 qint64 QWebSocketPrivate::writeFrames(const QList<QByteArray> &frames)
618 for (int i = 0; i < frames.size(); ++i)
620 written += writeFrame(frames[i]);
628 qint64 QWebSocketPrivate::writeFrame(const QByteArray &frame)
630 return m_pSocket->write(frame);
636 QString readLine(QTcpSocket *pSocket)
640 while (pSocket->getChar(&c))
644 pSocket->getChar(&c);
649 line.append(QChar(c));
655 //called on the client for a server handshake response
659 void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
667 QString errorDescription;
669 const QString regExpStatusLine("^(HTTP/[0-9]+\\.[0-9]+)\\s([0-9]+)\\s(.*)");
670 const QRegularExpression regExp(regExpStatusLine);
671 QString statusLine = readLine(pSocket);
672 QString httpProtocol;
674 QString httpStatusMessage;
675 QRegularExpressionMatch match = regExp.match(statusLine);
676 if (match.hasMatch())
678 QStringList tokens = match.capturedTexts();
679 tokens.removeFirst(); //remove the search string
680 if (tokens.length() == 3)
682 httpProtocol = tokens[0];
683 httpStatusCode = tokens[1].toInt();
684 httpStatusMessage = tokens[2].trimmed();
690 errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(statusLine);
694 QString headerLine = readLine(pSocket);
695 QMap<QString, QString> headers;
696 while (!headerLine.isEmpty())
698 QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
699 headers.insertMulti(headerField[0], headerField[1]);
700 headerLine = readLine(pSocket);
703 QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
704 QString upgrade = headers.value("Upgrade", "");
705 QString connection = headers.value("Connection", "");
706 //unused for the moment
707 //QString extensions = headers.value("Sec-WebSocket-Extensions", "");
708 //QString protocol = headers.value("Sec-WebSocket-Protocol", "");
709 QString version = headers.value("Sec-WebSocket-Version", "");
711 if (httpStatusCode == 101) //HTTP/x.y 101 Switching Protocols
713 bool conversionOk = false;
714 float version = httpProtocol.midRef(5).toFloat(&conversionOk);
715 //TODO: do not check the httpStatusText right now
716 ok = !(acceptKey.isEmpty() ||
717 (!conversionOk || (version < 1.1f)) ||
718 (upgrade.toLower() != "websocket") ||
719 (connection.toLower() != "upgrade"));
722 QString accept = calculateAcceptKey(m_key);
723 ok = (accept == acceptKey);
726 errorDescription = QWebSocket::tr("Accept-Key received from server %1 does not match the client key %2.").arg(acceptKey).arg(accept);
731 errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(statusLine);
734 else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
736 if (!version.isEmpty())
738 QStringList versions = version.split(", ", QString::SkipEmptyParts);
739 if (!versions.contains(QString::number(QWebSocketProtocol::currentVersion())))
741 //if needed to switch protocol version, then we are finished here
742 //because we cannot handle other protocols than the RFC one (v13)
743 errorDescription = QWebSocket::tr("Handshake: Server requests a version that we don't support: %1.").arg(versions.join(", "));
748 //we tried v13, but something different went wrong
749 errorDescription = QWebSocket::tr("Unknown error condition encountered. Aborting connection.");
756 errorDescription = QWebSocket::tr("Unhandled http status code: %1.").arg(httpStatusCode);
762 qDebug() << errorDescription;
763 setErrorString(errorDescription);
764 Q_EMIT q_ptr->error(QAbstractSocket::ConnectionRefusedError);
768 //handshake succeeded
769 setSocketState(QAbstractSocket::ConnectedState);
770 Q_EMIT q_ptr->connected();
778 void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketState)
780 QAbstractSocket::SocketState webSocketState = this->state();
783 case QAbstractSocket::ConnectedState:
785 if (webSocketState == QAbstractSocket::ConnectingState)
787 m_key = generateKey();
788 QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() % ":" % QString::number(m_requestUrl.port(80)), origin(), "", "", m_key);
789 m_pSocket->write(handshake.toLatin1());
793 case QAbstractSocket::ClosingState:
795 if (webSocketState == QAbstractSocket::ConnectedState)
797 setSocketState(QAbstractSocket::ClosingState);
801 case QAbstractSocket::UnconnectedState:
803 if (webSocketState != QAbstractSocket::UnconnectedState)
805 setSocketState(QAbstractSocket::UnconnectedState);
806 Q_EMIT q_ptr->disconnected();
810 case QAbstractSocket::HostLookupState:
811 case QAbstractSocket::ConnectingState:
812 case QAbstractSocket::BoundState:
813 case QAbstractSocket::ListeningState:
816 //to make C++ compiler happy;
827 //connectToHost is called
828 //our socket state is set to "connecting", and tcpSocket->connectToHost is called
829 //the tcpsocket is opened, a handshake message is sent; a readyRead signal is thrown
830 //this signal is catched by processData
831 //when OUR socket state is in the "connecting state", this means that
832 //we have received data from the server (response to handshake), and that we
833 //should "upgrade" our socket to a websocket (connected state)
834 //if our socket was already upgraded, then we need to process websocket data
838 void QWebSocketPrivate::processData()
840 while (m_pSocket->bytesAvailable())
842 if (state() == QAbstractSocket::ConnectingState)
844 processHandshake(m_pSocket);
848 m_dataProcessor.process(m_pSocket);
856 void QWebSocketPrivate::processControlFrame(QWebSocketProtocol::OpCode opCode, QByteArray frame)
860 case QWebSocketProtocol::OC_PING:
862 quint32 maskingKey = 0;
865 maskingKey = generateMaskingKey();
867 m_pSocket->write(getFrameHeader(QWebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
868 if (frame.size() > 0)
872 QWebSocketProtocol::mask(&frame, maskingKey);
874 m_pSocket->write(frame);
878 case QWebSocketProtocol::OC_PONG:
880 Q_EMIT q_ptr->pong(static_cast<quint64>(m_pingTimer.elapsed()));
883 case QWebSocketProtocol::OC_CLOSE:
885 quint16 closeCode = QWebSocketProtocol::CC_NORMAL;
887 if (frame.size() > 0) //close frame can have a close code and reason
889 closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
890 if (!QWebSocketProtocol::isCloseCodeValid(closeCode))
892 closeCode = QWebSocketProtocol::CC_PROTOCOL_ERROR;
893 closeReason = QWebSocket::tr("Invalid close code %1 detected.").arg(closeCode);
897 if (frame.size() > 2)
899 QTextCodec *tc = QTextCodec::codecForName("UTF-8");
900 QTextCodec::ConverterState state(QTextCodec::ConvertInvalidToNull);
901 closeReason = tc->toUnicode(frame.constData() + 2, frame.size() - 2, &state);
902 bool failed = (state.invalidChars != 0) || (state.remainingChars != 0);
905 closeCode = QWebSocketProtocol::CC_WRONG_DATATYPE;
906 closeReason = QWebSocket::tr("Invalid UTF-8 code encountered.");
911 m_isClosingHandshakeReceived = true;
912 close(static_cast<QWebSocketProtocol::CloseCode>(closeCode), closeReason);
915 case QWebSocketProtocol::OC_CONTINUE:
916 case QWebSocketProtocol::OC_BINARY:
917 case QWebSocketProtocol::OC_TEXT:
918 case QWebSocketProtocol::OC_RESERVED_3:
919 case QWebSocketProtocol::OC_RESERVED_4:
920 case QWebSocketProtocol::OC_RESERVED_5:
921 case QWebSocketProtocol::OC_RESERVED_6:
922 case QWebSocketProtocol::OC_RESERVED_7:
923 case QWebSocketProtocol::OC_RESERVED_B:
924 case QWebSocketProtocol::OC_RESERVED_D:
925 case QWebSocketProtocol::OC_RESERVED_E:
926 case QWebSocketProtocol::OC_RESERVED_F:
927 case QWebSocketProtocol::OC_RESERVED_V:
930 //case added to make C++ compiler happy
935 qDebug() << "WebSocket::processData: Invalid opcode detected:" << static_cast<int>(opCode);
945 QString QWebSocketPrivate::createHandShakeRequest(QString resourceName,
952 QStringList handshakeRequest;
954 handshakeRequest << "GET " % resourceName % " HTTP/1.1" <<
956 "Upgrade: websocket" <<
957 "Connection: Upgrade" <<
958 "Sec-WebSocket-Key: " % QString(key);
959 if (!origin.isEmpty())
961 handshakeRequest << "Origin: " % origin;
963 handshakeRequest << "Sec-WebSocket-Version: " % QString::number(QWebSocketProtocol::currentVersion());
964 if (extensions.length() > 0)
966 handshakeRequest << "Sec-WebSocket-Extensions: " % extensions;
968 if (protocols.length() > 0)
970 handshakeRequest << "Sec-WebSocket-Protocol: " % protocols;
972 handshakeRequest << "\r\n";
974 return handshakeRequest.join("\r\n");
980 QAbstractSocket::SocketState QWebSocketPrivate::state() const
982 return m_socketState;
988 bool QWebSocketPrivate::waitForConnected(int msecs)
993 retVal = m_pSocket->waitForConnected(msecs);
1001 bool QWebSocketPrivate::waitForDisconnected(int msecs)
1006 retVal = m_pSocket->waitForDisconnected(msecs);
1014 void QWebSocketPrivate::setSocketState(QAbstractSocket::SocketState state)
1016 if (m_socketState != state)
1018 m_socketState = state;
1019 Q_EMIT q_ptr->stateChanged(m_socketState);
1026 void QWebSocketPrivate::setErrorString(QString errorString)
1028 m_errorString = errorString;
1034 QHostAddress QWebSocketPrivate::localAddress() const
1036 QHostAddress address;
1039 address = m_pSocket->localAddress();
1047 quint16 QWebSocketPrivate::localPort() const
1052 port = m_pSocket->localPort();
1060 QAbstractSocket::PauseModes QWebSocketPrivate::pauseMode() const
1062 QAbstractSocket::PauseModes mode = QAbstractSocket::PauseNever;
1065 mode = m_pSocket->pauseMode();
1073 QHostAddress QWebSocketPrivate::peerAddress() const
1078 peer = m_pSocket->peerAddress();
1086 QString QWebSocketPrivate::peerName() const
1091 name = m_pSocket->peerName();
1099 quint16 QWebSocketPrivate::peerPort() const
1104 port = m_pSocket->peerPort();
1112 QNetworkProxy QWebSocketPrivate::proxy() const
1114 QNetworkProxy proxy;
1117 proxy = m_pSocket->proxy();
1125 qint64 QWebSocketPrivate::readBufferSize() const
1127 qint64 readBuffer = 0;
1130 readBuffer = m_pSocket->readBufferSize();
1138 void QWebSocketPrivate::resume()
1142 m_pSocket->resume();
1149 void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
1153 m_pSocket->setPauseMode(pauseMode);
1160 void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
1164 m_pSocket->setProxy(networkProxy);
1171 void QWebSocketPrivate::setReadBufferSize(qint64 size)
1175 m_pSocket->setReadBufferSize(size);
1182 void QWebSocketPrivate::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
1186 m_pSocket->setSocketOption(option, value);
1193 QVariant QWebSocketPrivate::socketOption(QAbstractSocket::SocketOption option)
1198 result = m_pSocket->socketOption(option);
1206 bool QWebSocketPrivate::isValid() const
1211 valid = m_pSocket->isValid();