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 #ifndef QT_NONETWORKPROXY
33 #include <QNetworkProxy>
42 const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2; //maximum size of a frame when sending a message
47 QWebSocketPrivate::QWebSocketPrivate(QString origin, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent) :
50 m_pSocket(new QTcpSocket(this)),
58 m_socketState(QAbstractSocket::UnconnectedState),
61 m_isClosingHandshakeSent(false),
62 m_isClosingHandshakeReceived(false),
66 Q_ASSERT(pWebSocket != 0);
67 makeConnections(m_pSocket);
68 qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
74 QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent) :
77 m_pSocket(pTcpSocket),
78 m_errorString(pTcpSocket->errorString()),
85 m_socketState(pTcpSocket->state()),
88 m_isClosingHandshakeSent(false),
89 m_isClosingHandshakeReceived(false),
93 Q_ASSERT(pWebSocket != 0);
94 makeConnections(m_pSocket);
100 QWebSocketPrivate::~QWebSocketPrivate()
102 if (state() == QAbstractSocket::ConnectedState)
104 close(QWebSocketProtocol::CC_GOING_AWAY, "Connection closed");
106 releaseConnections(m_pSocket);
107 m_pSocket->deleteLater();
114 void QWebSocketPrivate::abort()
122 QAbstractSocket::SocketError QWebSocketPrivate::error() const
124 return m_pSocket->error();
130 QString QWebSocketPrivate::errorString() const
132 if (!m_errorString.isEmpty())
134 return m_errorString;
138 return m_pSocket->errorString();
145 bool QWebSocketPrivate::flush()
147 return m_pSocket->flush();
153 qint64 QWebSocketPrivate::write(const char *message)
155 return write(QString::fromUtf8(message));
161 qint64 QWebSocketPrivate::write(const char *message, qint64 maxSize)
163 return write(QString::fromUtf8(message, static_cast<int>(maxSize)));
169 qint64 QWebSocketPrivate::write(const QString &message)
171 return doWriteData(message.toUtf8(), false);
177 qint64 QWebSocketPrivate::write(const QByteArray &data)
179 return doWriteData(data, true);
185 QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket,
186 const HandshakeRequest &request,
187 const HandshakeResponse &response,
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
204 void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString reason)
206 if (!m_isClosingHandshakeSent)
208 quint32 maskingKey = 0;
211 maskingKey = generateMaskingKey();
213 quint16 code = qToBigEndian<quint16>(closeCode);
215 payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
216 if (!reason.isEmpty())
218 payload.append(reason.toUtf8());
222 QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
224 QByteArray frame = getFrameHeader(QWebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
225 frame.append(payload);
226 m_pSocket->write(frame);
229 m_isClosingHandshakeSent = true;
231 Q_EMIT q_ptr->aboutToClose();
239 void QWebSocketPrivate::open(const QUrl &url, bool mask)
241 m_dataProcessor.clear();
242 m_isClosingHandshakeReceived = false;
243 m_isClosingHandshakeSent = false;
246 QString resourceName = url.path() + url.query();
247 if (resourceName.isEmpty())
251 setResourceName(resourceName);
254 setSocketState(QAbstractSocket::ConnectingState);
256 m_pSocket->connectToHost(url.host(), url.port(80));
262 void QWebSocketPrivate::ping()
264 m_pingTimer.restart();
265 QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OC_PING, 0, 0, true);
266 writeFrame(pingFrame);
271 Sets the version to use for the websocket protocol; this must be set before the socket is opened.
273 void QWebSocketPrivate::setVersion(QWebSocketProtocol::Version version)
280 Sets the resource name of the connection; must be set before the socket is openend
282 void QWebSocketPrivate::setResourceName(QString resourceName)
284 m_resourceName = resourceName;
290 void QWebSocketPrivate::setRequestUrl(QUrl requestUrl)
292 m_requestUrl = requestUrl;
298 void QWebSocketPrivate::setOrigin(QString origin)
306 void QWebSocketPrivate::setProtocol(QString protocol)
308 m_protocol = protocol;
314 void QWebSocketPrivate::setExtension(QString extension)
316 m_extension = extension;
322 void QWebSocketPrivate::enableMasking(bool enable)
330 qint64 QWebSocketPrivate::doWriteData(const QByteArray &data, bool isBinary)
332 return doWriteFrames(data, isBinary);
338 void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
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)));
348 connect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
349 connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
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)));
362 void QWebSocketPrivate::releaseConnections(const QTcpSocket *pTcpSocket)
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)));
374 disconnect(pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(processStateChanged(QAbstractSocket::SocketState)));
375 disconnect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
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)));
388 QWebSocketProtocol::Version QWebSocketPrivate::version()
396 QString QWebSocketPrivate::resourceName()
398 return m_resourceName;
404 QUrl QWebSocketPrivate::requestUrl()
412 QString QWebSocketPrivate::origin()
420 QString QWebSocketPrivate::protocol()
428 QString QWebSocketPrivate::extension()
436 QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength, quint32 maskingKey, bool lastFrame) const
440 bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL;
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));
449 //Now write the masking bit and the payload length byte
455 if (payloadLength <= 125)
457 byte |= static_cast<quint8>(payloadLength);
458 header.append(static_cast<char>(byte));
460 else if (payloadLength <= 0xFFFFU)
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);
467 else if (payloadLength <= 0x7FFFFFFFFFFFFFFFULL)
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);
478 header.append(static_cast<const char *>(static_cast<const void *>(&maskingKey)), sizeof(quint32));
483 //setErrorString("WebSocket::getHeader: payload too big!");
484 //Q_EMIT q_ptr->error(QAbstractSocket::DatagramTooLargeError);
485 qDebug() << "WebSocket::getHeader: payload too big!";
494 qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
496 const QWebSocketProtocol::OpCode firstOpCode = isBinary ? QWebSocketProtocol::OC_BINARY : QWebSocketProtocol::OC_TEXT;
498 int numFrames = data.size() / FRAME_SIZE_IN_BYTES;
499 QByteArray tmpData(data);
501 char *payload = tmpData.data();
502 quint64 sizeLeft = static_cast<quint64>(data.size()) % FRAME_SIZE_IN_BYTES;
507 if (numFrames == 0) //catch the case where the payload is zero bytes; in that case, we still need to send a frame
511 quint64 currentPosition = 0;
512 qint64 bytesWritten = 0;
513 qint64 payloadWritten = 0;
514 quint64 bytesLeft = data.size();
516 for (int i = 0; i < numFrames; ++i)
518 quint32 maskingKey = 0;
521 maskingKey = generateMaskingKey();
524 bool isLastFrame = (i == (numFrames - 1));
525 bool isFirstFrame = (i == 0);
527 quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
528 QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode : QWebSocketProtocol::OC_CONTINUE;
531 bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
536 char *currentData = payload + currentPosition;
539 QWebSocketProtocol::mask(currentData, size, maskingKey);
541 qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
544 bytesWritten += written;
545 payloadWritten += written;
549 setErrorString("WebSocket::doWriteFrames: Error writing bytes to socket: " + m_pSocket->errorString());
550 qDebug() << errorString();
552 Q_EMIT q_ptr->error(QAbstractSocket::NetworkError);
556 currentPosition += size;
559 if (payloadWritten != data.size())
561 setErrorString("Bytes written " + QString::number(payloadWritten) + " != " + QString::number(data.size()));
562 qDebug() << errorString();
563 Q_EMIT q_ptr->error(QAbstractSocket::NetworkError);
565 return payloadWritten;
571 quint32 QWebSocketPrivate::generateRandomNumber() const
573 return static_cast<quint32>((static_cast<double>(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
579 quint32 QWebSocketPrivate::generateMaskingKey() const
581 return generateRandomNumber();
587 QByteArray QWebSocketPrivate::generateKey() const
591 for (int i = 0; i < 4; ++i)
593 quint32 tmp = generateRandomNumber();
594 key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
597 return key.toBase64();
604 QString QWebSocketPrivate::calculateAcceptKey(const QString &key) const
606 QString tmpKey = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
607 QByteArray hash = QCryptographicHash::hash(tmpKey.toLatin1(), QCryptographicHash::Sha1);
608 return QString(hash.toBase64());
614 qint64 QWebSocketPrivate::writeFrames(const QList<QByteArray> &frames)
617 for (int i = 0; i < frames.size(); ++i)
619 written += writeFrame(frames[i]);
627 qint64 QWebSocketPrivate::writeFrame(const QByteArray &frame)
629 return m_pSocket->write(frame);
635 QString readLine(QTcpSocket *pSocket)
639 while (pSocket->getChar(&c))
643 pSocket->getChar(&c);
648 line.append(QChar(c));
654 //called on the client for a server handshake response
658 void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
666 QString errorDescription;
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;
673 QString httpStatusMessage;
674 QRegularExpressionMatch match = regExp.match(statusLine);
675 if (match.hasMatch())
677 QStringList tokens = match.capturedTexts();
678 tokens.removeFirst(); //remove the search string
679 if (tokens.length() == 3)
681 httpProtocol = tokens[0];
682 httpStatusCode = tokens[1].toInt();
683 httpStatusMessage = tokens[2].trimmed();
689 errorDescription = "WebSocket::processHandshake: Invalid statusline in response: " + statusLine;
693 QString headerLine = readLine(pSocket);
694 QMap<QString, QString> headers;
695 while (!headerLine.isEmpty())
697 QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
698 headers.insertMulti(headerField[0], headerField[1]);
699 headerLine = readLine(pSocket);
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", "");
710 if (httpStatusCode == 101) //HTTP/x.y 101 Switching Protocols
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"));
721 QString accept = calculateAcceptKey(m_key);
722 ok = (accept == acceptKey);
725 errorDescription = "WebSocket::processHandshake: Accept-Key received from server " + acceptKey + " does not match the client key " + accept;
730 errorDescription = "WebSocket::processHandshake: Invalid statusline in response: " + statusLine;
733 else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
735 if (!version.isEmpty())
737 QStringList versions = version.split(", ", QString::SkipEmptyParts);
738 if (!versions.contains(QString::number(QWebSocketProtocol::currentVersion())))
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(", ");
747 //we tried v13, but something different went wrong
748 errorDescription = "WebSocket::processHandshake: Unknown error condition encountered. Aborting connection.";
755 errorDescription = "WebSocket::processHandshake: Unhandled http status code " + QString::number(httpStatusCode);
761 qDebug() << errorDescription;
762 setErrorString(errorDescription);
763 Q_EMIT q_ptr->error(QAbstractSocket::ConnectionRefusedError);
767 //handshake succeeded
768 setSocketState(QAbstractSocket::ConnectedState);
769 Q_EMIT q_ptr->connected();
777 void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketState)
779 QAbstractSocket::SocketState webSocketState = this->state();
782 case QAbstractSocket::ConnectedState:
784 if (webSocketState == QAbstractSocket::ConnectingState)
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());
792 case QAbstractSocket::ClosingState:
794 if (webSocketState == QAbstractSocket::ConnectedState)
796 setSocketState(QAbstractSocket::ClosingState);
800 case QAbstractSocket::UnconnectedState:
802 if (webSocketState != QAbstractSocket::UnconnectedState)
804 setSocketState(QAbstractSocket::UnconnectedState);
805 Q_EMIT q_ptr->disconnected();
809 case QAbstractSocket::HostLookupState:
810 case QAbstractSocket::ConnectingState:
811 case QAbstractSocket::BoundState:
812 case QAbstractSocket::ListeningState:
815 //to make C++ compiler happy;
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
837 void QWebSocketPrivate::processData()
839 while (m_pSocket->bytesAvailable())
841 if (state() == QAbstractSocket::ConnectingState)
843 processHandshake(m_pSocket);
847 m_dataProcessor.process(m_pSocket);
855 void QWebSocketPrivate::processControlFrame(QWebSocketProtocol::OpCode opCode, QByteArray frame)
859 case QWebSocketProtocol::OC_PING:
861 quint32 maskingKey = 0;
864 maskingKey = generateMaskingKey();
866 m_pSocket->write(getFrameHeader(QWebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
867 if (frame.size() > 0)
871 QWebSocketProtocol::mask(&frame, maskingKey);
873 m_pSocket->write(frame);
877 case QWebSocketProtocol::OC_PONG:
879 Q_EMIT q_ptr->pong(static_cast<quint64>(m_pingTimer.elapsed()));
882 case QWebSocketProtocol::OC_CLOSE:
884 quint16 closeCode = QWebSocketProtocol::CC_NORMAL;
886 if (frame.size() > 0) //close frame can have a close code and reason
888 closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
889 if (!QWebSocketProtocol::isCloseCodeValid(closeCode))
891 closeCode = QWebSocketProtocol::CC_PROTOCOL_ERROR;
892 closeReason = QString("Invalid close code %1 detected").arg(closeCode);
896 if (frame.size() > 2)
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);
904 closeCode = QWebSocketProtocol::CC_WRONG_DATATYPE;
905 closeReason = "Invalid UTF-8 code encountered.";
910 m_isClosingHandshakeReceived = true;
911 close(static_cast<QWebSocketProtocol::CloseCode>(closeCode), closeReason);
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:
929 //case added to make C++ compiler happy
934 qDebug() << "WebSocket::processData: Invalid opcode detected:" << static_cast<int>(opCode);
944 QString QWebSocketPrivate::createHandShakeRequest(QString resourceName,
951 QStringList handshakeRequest;
953 handshakeRequest << "GET " + resourceName + " HTTP/1.1" <<
955 "Upgrade: websocket" <<
956 "Connection: Upgrade" <<
957 "Sec-WebSocket-Key: " + QString(key);
958 if (!origin.isEmpty())
960 handshakeRequest << "Origin: " + origin;
962 handshakeRequest << "Sec-WebSocket-Version: " + QString::number(QWebSocketProtocol::currentVersion());
963 if (extensions.length() > 0)
965 handshakeRequest << "Sec-WebSocket-Extensions: " + extensions;
967 if (protocols.length() > 0)
969 handshakeRequest << "Sec-WebSocket-Protocol: " + protocols;
971 handshakeRequest << "\r\n";
973 return handshakeRequest.join("\r\n");
979 QAbstractSocket::SocketState QWebSocketPrivate::state() const
981 return m_socketState;
987 bool QWebSocketPrivate::waitForConnected(int msecs)
992 retVal = m_pSocket->waitForConnected(msecs);
1000 bool QWebSocketPrivate::waitForDisconnected(int msecs)
1005 retVal = m_pSocket->waitForDisconnected(msecs);
1013 void QWebSocketPrivate::setSocketState(QAbstractSocket::SocketState state)
1015 if (m_socketState != state)
1017 m_socketState = state;
1018 Q_EMIT q_ptr->stateChanged(m_socketState);
1025 void QWebSocketPrivate::setErrorString(QString errorString)
1027 m_errorString = errorString;
1033 QHostAddress QWebSocketPrivate::localAddress() const
1035 QHostAddress address;
1038 address = m_pSocket->localAddress();
1046 quint16 QWebSocketPrivate::localPort() const
1051 port = m_pSocket->localPort();
1059 QAbstractSocket::PauseModes QWebSocketPrivate::pauseMode() const
1061 QAbstractSocket::PauseModes mode = QAbstractSocket::PauseNever;
1064 mode = m_pSocket->pauseMode();
1072 QHostAddress QWebSocketPrivate::peerAddress() const
1077 peer = m_pSocket->peerAddress();
1085 QString QWebSocketPrivate::peerName() const
1090 name = m_pSocket->peerName();
1098 quint16 QWebSocketPrivate::peerPort() const
1103 port = m_pSocket->peerPort();
1111 QNetworkProxy QWebSocketPrivate::proxy() const
1113 QNetworkProxy proxy;
1116 proxy = m_pSocket->proxy();
1124 qint64 QWebSocketPrivate::readBufferSize() const
1126 qint64 readBuffer = 0;
1129 readBuffer = m_pSocket->readBufferSize();
1137 void QWebSocketPrivate::resume()
1141 m_pSocket->resume();
1148 void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
1152 m_pSocket->setPauseMode(pauseMode);
1159 void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
1163 m_pSocket->setProxy(networkProxy);
1170 void QWebSocketPrivate::setReadBufferSize(qint64 size)
1174 m_pSocket->setReadBufferSize(size);
1181 void QWebSocketPrivate::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
1185 m_pSocket->setSocketOption(option, value);
1192 QVariant QWebSocketPrivate::socketOption(QAbstractSocket::SocketOption option)
1197 result = m_pSocket->socketOption(option);
1205 bool QWebSocketPrivate::isValid()
1210 valid = m_pSocket->isValid();