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 "dataprocessor_p.h"
21 #include "qwebsocketprotocol.h"
26 #include <QTextDecoder>
30 const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
31 const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
40 Frame(const Frame &other);
42 const Frame &operator =(const Frame &other);
44 QWebSocketProtocol::CloseCode getCloseCode() const;
45 QString getCloseReason() const;
46 bool isFinalFrame() const;
47 bool isControlFrame() const;
48 bool isDataFrame() const;
49 bool isContinuationFrame() const;
51 quint32 getMask() const; //returns 0 if no mask
55 QWebSocketProtocol::OpCode getOpCode() const;
56 QByteArray getPayload() const;
58 void clear(); //resets all member variables, and invalidates the object
62 static Frame readFrame(QTcpSocket *pSocket);
65 QWebSocketProtocol::CloseCode m_closeCode;
66 QString m_closeReason;
69 int m_rsv1; //reserved field 1
70 int m_rsv2; //reserved field 2
71 int m_rsv3; //reserved field 3
72 QWebSocketProtocol::OpCode m_opCode;
74 quint8 m_length; //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
82 PS_READ_PAYLOAD_LENGTH,
83 PS_READ_BIG_PAYLOAD_LENGTH,
90 void setError(QWebSocketProtocol::CloseCode code, QString closeReason);
98 m_closeCode(QWebSocketProtocol::CC_NORMAL),
100 m_isFinalFrame(true),
105 m_opCode(QWebSocketProtocol::OC_RESERVED_V),
115 Frame::Frame(const Frame &other) :
116 m_closeCode(other.m_closeCode),
117 m_closeReason(other.m_closeReason),
118 m_isFinalFrame(other.m_isFinalFrame),
119 m_mask(other.m_mask),
120 m_rsv1(other.m_rsv1),
121 m_rsv2(other.m_rsv2),
122 m_rsv3(other.m_rsv3),
123 m_opCode(other.m_opCode),
124 m_length(other.m_length),
125 m_payload(other.m_payload),
126 m_isValid(other.m_isValid)
133 const Frame &Frame::operator =(const Frame &other)
135 m_closeCode = other.m_closeCode;
136 m_closeReason = other.m_closeReason;
137 m_isFinalFrame = other.m_isFinalFrame;
138 m_mask = other.m_mask;
139 m_rsv1 = other.m_rsv1;
140 m_rsv2 = other.m_rsv2;
141 m_rsv3 = other.m_rsv2;
142 m_opCode = other.m_opCode;
143 m_length = other.m_length;
144 m_payload = other.m_payload;
145 m_isValid = other.m_isValid;
153 QWebSocketProtocol::CloseCode Frame::getCloseCode() const
161 QString Frame::getCloseReason() const
163 return m_closeReason;
169 bool Frame::isFinalFrame() const
171 return m_isFinalFrame;
177 bool Frame::isControlFrame() const
179 return (m_opCode & 0x08) == 0x08;
185 bool Frame::isDataFrame() const
187 return !isControlFrame();
193 bool Frame::isContinuationFrame() const
195 return isDataFrame() && (m_opCode == QWebSocketProtocol::OC_CONTINUE);
201 bool Frame::hasMask() const
209 quint32 Frame::getMask() const
217 int Frame::getRsv1() const
225 int Frame::getRsv2() const
233 int Frame::getRsv3() const
241 QWebSocketProtocol::OpCode Frame::getOpCode() const
249 QByteArray Frame::getPayload() const
259 m_closeCode = QWebSocketProtocol::CC_NORMAL;
260 m_closeReason.clear();
261 m_isFinalFrame = true;
266 m_opCode = QWebSocketProtocol::OC_RESERVED_V;
275 bool Frame::isValid() const
280 #define WAIT_FOR_MORE_DATA(dataSizeInBytes) { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
285 Frame Frame::readFrame(QTcpSocket *pSocket)
288 qint64 bytesRead = 0;
290 quint64 dataWaitSize = 0;
291 ProcessingState processingState = PS_READ_HEADER;
292 ProcessingState returnState = PS_READ_HEADER;
293 bool hasMask = false;
294 quint64 payloadLength = 0;
298 switch (processingState)
300 case PS_WAIT_FOR_MORE_DATA:
302 bool ok = pSocket->waitForReadyRead(5000);
305 frame.setError(QWebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
310 processingState = returnState;
316 if (pSocket->bytesAvailable() >= 2)
318 //FIN, RSV1-3, Opcode
319 char header[2] = {0};
320 bytesRead = pSocket->read(header, 2);
321 frame.m_isFinalFrame = (header[0] & 0x80) != 0;
322 frame.m_rsv1 = (header[0] & 0x40);
323 frame.m_rsv2 = (header[0] & 0x20);
324 frame.m_rsv3 = (header[0] & 0x10);
325 frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
327 //Mask, PayloadLength
328 hasMask = (header[1] & 0x80) != 0;
329 frame.m_length = (header[1] & 0x7F);
331 switch (frame.m_length)
335 processingState = PS_READ_PAYLOAD_LENGTH;
340 processingState = PS_READ_BIG_PAYLOAD_LENGTH;
345 payloadLength = frame.m_length;
346 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
350 if (!frame.checkValidity())
357 WAIT_FOR_MORE_DATA(2);
362 case PS_READ_PAYLOAD_LENGTH:
364 if (pSocket->bytesAvailable() >= 2)
366 uchar length[2] = {0};
367 //TODO: Handle return value
368 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
369 payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
370 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
374 WAIT_FOR_MORE_DATA(2);
379 case PS_READ_BIG_PAYLOAD_LENGTH:
381 if (pSocket->bytesAvailable() >= 8)
383 uchar length[8] = {0};
384 //TODO: Handle return value
385 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
386 //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
387 //TODO: Do we check for that?
388 payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
389 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
393 WAIT_FOR_MORE_DATA(8);
401 if (pSocket->bytesAvailable() >= 4)
403 //TODO: Handle return value
404 bytesRead = pSocket->read(reinterpret_cast<char *>(&frame.m_mask), sizeof(frame.m_mask));
405 processingState = PS_READ_PAYLOAD;
409 WAIT_FOR_MORE_DATA(4);
414 case PS_READ_PAYLOAD:
418 processingState = PS_DISPATCH_RESULT;
420 else if (payloadLength > MAX_FRAME_SIZE_IN_BYTES)
422 frame.setError(QWebSocketProtocol::CC_TOO_MUCH_DATA, "Maximum framesize exceeded.");
423 processingState = PS_DISPATCH_RESULT;
427 quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
428 if (bytesAvailable >= payloadLength)
430 frame.m_payload = pSocket->read(payloadLength);
433 QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
435 processingState = PS_DISPATCH_RESULT;
439 WAIT_FOR_MORE_DATA(payloadLength);
445 case PS_DISPATCH_RESULT:
447 processingState = PS_READ_HEADER;
454 //should not come here
455 qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
469 void Frame::setError(QWebSocketProtocol::CloseCode code, QString closeReason)
473 m_closeReason = closeReason;
480 bool Frame::checkValidity()
484 if (m_rsv1 || m_rsv2 || m_rsv3)
486 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
488 else if (QWebSocketProtocol::isOpCodeReserved(m_opCode))
490 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
492 else if (isControlFrame())
496 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
498 else if (!m_isFinalFrame)
500 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
518 DataProcessor::DataProcessor(QObject *parent) :
520 m_processingState(PS_READ_HEADER),
521 m_isFinalFrame(false),
522 m_isFragmented(false),
523 m_opCode(QWebSocketProtocol::OC_CLOSE),
524 m_isControlFrame(false),
530 m_pConverterState(0),
531 m_pTextCodec(QTextCodec::codecForName("UTF-8"))
539 DataProcessor::~DataProcessor()
542 if (m_pConverterState)
544 delete m_pConverterState;
545 m_pConverterState = 0;
552 void DataProcessor::process(QTcpSocket *pSocket)
558 Frame frame = Frame::readFrame(pSocket);
561 if (frame.isControlFrame())
563 Q_EMIT controlFrameReceived(frame.getOpCode(), frame.getPayload());
564 isDone = true; //exit the loop after a control frame, so we can get a chance to close the socket if necessary
566 else //we have a dataframe; opcode can be OC_CONTINUE, OC_TEXT or OC_BINARY
568 if (!m_isFragmented && frame.isContinuationFrame())
571 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
574 if (m_isFragmented && frame.isDataFrame() && !frame.isContinuationFrame())
577 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0 (continuation).");
580 if (!frame.isContinuationFrame())
582 m_opCode = frame.getOpCode();
583 m_isFragmented = !frame.isFinalFrame();
585 quint64 messageLength = (quint64)(m_opCode == QWebSocketProtocol::OC_TEXT) ? m_textMessage.length() : m_binaryMessage.length();
586 if ((messageLength + quint64(frame.getPayload().length())) > MAX_MESSAGE_SIZE_IN_BYTES)
589 Q_EMIT errorEncountered(QWebSocketProtocol::CC_TOO_MUCH_DATA, "Received message is too big.");
593 if (m_opCode == QWebSocketProtocol::OC_TEXT)
595 QString frameTxt = m_pTextCodec->toUnicode(frame.getPayload().constData(), frame.getPayload().size(), m_pConverterState);
596 bool failed = (m_pConverterState->invalidChars != 0) || (frame.isFinalFrame() && (m_pConverterState->remainingChars != 0));
600 Q_EMIT errorEncountered(QWebSocketProtocol::CC_WRONG_DATATYPE, "Invalid UTF-8 code encountered.");
605 m_textMessage.append(frameTxt);
606 Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
611 m_binaryMessage.append(frame.getPayload());
612 Q_EMIT binaryFrameReceived(frame.getPayload(), frame.isFinalFrame());
615 if (frame.isFinalFrame())
617 if (m_opCode == QWebSocketProtocol::OC_TEXT)
619 Q_EMIT textMessageReceived(m_textMessage);
623 Q_EMIT binaryMessageReceived(m_binaryMessage);
632 Q_EMIT errorEncountered(frame.getCloseCode(), frame.getCloseReason());
642 void DataProcessor::clear()
644 m_processingState = PS_READ_HEADER;
645 m_isFinalFrame = false;
646 m_isFragmented = false;
647 m_opCode = QWebSocketProtocol::OC_CLOSE;
650 m_binaryMessage.clear();
651 m_textMessage.clear();
653 if (m_pConverterState)
655 if ((m_pConverterState->remainingChars != 0) || (m_pConverterState->invalidChars != 0))
657 delete m_pConverterState;
658 m_pConverterState = 0;
661 if (!m_pConverterState)
663 m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader);