1 #include "dataprocessor_p.h"
2 #include "qwebsocketprotocol.h"
7 #include <QTextDecoder>
11 const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
12 const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
21 Frame(const Frame &other);
23 const Frame &operator =(const Frame &other);
25 QWebSocketProtocol::CloseCode getCloseCode() const;
26 QString getCloseReason() const;
27 bool isFinalFrame() const;
28 bool isControlFrame() const;
29 bool isDataFrame() const;
30 bool isContinuationFrame() const;
32 quint32 getMask() const; //returns 0 if no mask
36 QWebSocketProtocol::OpCode getOpCode() const;
37 QByteArray getPayload() const;
39 void clear(); //resets all member variables, and invalidates the object
43 static Frame readFrame(QTcpSocket *pSocket);
46 QWebSocketProtocol::CloseCode m_closeCode;
47 QString m_closeReason;
50 int m_rsv1; //reserved field 1
51 int m_rsv2; //reserved field 2
52 int m_rsv3; //reserved field 3
53 QWebSocketProtocol::OpCode m_opCode;
55 quint8 m_length; //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
63 PS_READ_PAYLOAD_LENGTH,
64 PS_READ_BIG_PAYLOAD_LENGTH,
71 void setError(QWebSocketProtocol::CloseCode code, QString closeReason);
79 m_closeCode(QWebSocketProtocol::CC_NORMAL),
86 m_opCode(QWebSocketProtocol::OC_RESERVED_V),
96 Frame::Frame(const Frame &other) :
97 m_closeCode(other.m_closeCode),
98 m_closeReason(other.m_closeReason),
99 m_isFinalFrame(other.m_isFinalFrame),
100 m_mask(other.m_mask),
101 m_rsv1(other.m_rsv1),
102 m_rsv2(other.m_rsv2),
103 m_rsv3(other.m_rsv3),
104 m_opCode(other.m_opCode),
105 m_length(other.m_length),
106 m_payload(other.m_payload),
107 m_isValid(other.m_isValid)
114 const Frame &Frame::operator =(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_rsv2;
123 m_opCode = other.m_opCode;
124 m_length = other.m_length;
125 m_payload = other.m_payload;
126 m_isValid = other.m_isValid;
134 QWebSocketProtocol::CloseCode Frame::getCloseCode() const
142 QString Frame::getCloseReason() const
144 return m_closeReason;
150 bool Frame::isFinalFrame() const
152 return m_isFinalFrame;
158 bool Frame::isControlFrame() const
160 return (m_opCode & 0x08) == 0x08;
166 bool Frame::isDataFrame() const
168 return !isControlFrame();
174 bool Frame::isContinuationFrame() const
176 return isDataFrame() && (m_opCode == QWebSocketProtocol::OC_CONTINUE);
182 bool Frame::hasMask() const
190 quint32 Frame::getMask() const
198 int Frame::getRsv1() const
206 int Frame::getRsv2() const
214 int Frame::getRsv3() const
222 QWebSocketProtocol::OpCode Frame::getOpCode() const
230 QByteArray Frame::getPayload() const
240 m_closeCode = QWebSocketProtocol::CC_NORMAL;
241 m_closeReason.clear();
242 m_isFinalFrame = true;
247 m_opCode = QWebSocketProtocol::OC_RESERVED_V;
256 bool Frame::isValid() const
261 #define WAIT_FOR_MORE_DATA(dataSizeInBytes) { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
266 Frame Frame::readFrame(QTcpSocket *pSocket)
269 qint64 bytesRead = 0;
271 quint64 dataWaitSize = 0;
272 ProcessingState processingState = PS_READ_HEADER;
273 ProcessingState returnState = PS_READ_HEADER;
274 bool hasMask = false;
275 quint64 payloadLength = 0;
279 switch (processingState)
281 case PS_WAIT_FOR_MORE_DATA:
283 bool ok = pSocket->waitForReadyRead(5000);
286 frame.setError(QWebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
291 processingState = returnState;
297 if (pSocket->bytesAvailable() >= 2)
299 //FIN, RSV1-3, Opcode
300 char header[2] = {0};
301 bytesRead = pSocket->read(header, 2);
302 frame.m_isFinalFrame = (header[0] & 0x80) != 0;
303 frame.m_rsv1 = (header[0] & 0x40);
304 frame.m_rsv2 = (header[0] & 0x20);
305 frame.m_rsv3 = (header[0] & 0x10);
306 frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
308 //Mask, PayloadLength
309 hasMask = (header[1] & 0x80) != 0;
310 frame.m_length = (header[1] & 0x7F);
312 switch (frame.m_length)
316 processingState = PS_READ_PAYLOAD_LENGTH;
321 processingState = PS_READ_BIG_PAYLOAD_LENGTH;
326 payloadLength = frame.m_length;
327 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
331 if (!frame.checkValidity())
338 WAIT_FOR_MORE_DATA(2);
343 case PS_READ_PAYLOAD_LENGTH:
345 if (pSocket->bytesAvailable() >= 2)
347 uchar length[2] = {0};
348 //TODO: Handle return value
349 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
350 payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
351 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
355 WAIT_FOR_MORE_DATA(2);
360 case PS_READ_BIG_PAYLOAD_LENGTH:
362 if (pSocket->bytesAvailable() >= 8)
364 uchar length[8] = {0};
365 //TODO: Handle return value
366 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
367 //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
368 //TODO: Do we check for that?
369 payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
370 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
374 WAIT_FOR_MORE_DATA(8);
382 if (pSocket->bytesAvailable() >= 4)
384 //TODO: Handle return value
385 bytesRead = pSocket->read(reinterpret_cast<char *>(&frame.m_mask), sizeof(frame.m_mask));
386 processingState = PS_READ_PAYLOAD;
390 WAIT_FOR_MORE_DATA(4);
395 case PS_READ_PAYLOAD:
399 processingState = PS_DISPATCH_RESULT;
401 else if (payloadLength > MAX_FRAME_SIZE_IN_BYTES)
403 frame.setError(QWebSocketProtocol::CC_TOO_MUCH_DATA, "Maximum framesize exceeded.");
404 processingState = PS_DISPATCH_RESULT;
408 quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
409 if (bytesAvailable >= payloadLength)
411 frame.m_payload = pSocket->read(payloadLength);
414 QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
416 processingState = PS_DISPATCH_RESULT;
420 WAIT_FOR_MORE_DATA(payloadLength);
426 case PS_DISPATCH_RESULT:
428 processingState = PS_READ_HEADER;
435 //should not come here
436 qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
450 void Frame::setError(QWebSocketProtocol::CloseCode code, QString closeReason)
454 m_closeReason = closeReason;
461 bool Frame::checkValidity()
465 if (m_rsv1 || m_rsv2 || m_rsv3)
467 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
469 else if (QWebSocketProtocol::isOpCodeReserved(m_opCode))
471 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
473 else if (isControlFrame())
477 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
479 else if (!m_isFinalFrame)
481 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
499 DataProcessor::DataProcessor(QObject *parent) :
501 m_processingState(PS_READ_HEADER),
502 m_isFinalFrame(false),
503 m_isFragmented(false),
504 m_opCode(QWebSocketProtocol::OC_CLOSE),
505 m_isControlFrame(false),
511 m_pConverterState(0),
512 m_pTextCodec(QTextCodec::codecForName("UTF-8"))
520 DataProcessor::~DataProcessor()
523 if (m_pConverterState)
525 delete m_pConverterState;
526 m_pConverterState = 0;
533 void DataProcessor::process(QTcpSocket *pSocket)
539 Frame frame = Frame::readFrame(pSocket);
542 if (frame.isControlFrame())
544 Q_EMIT controlFrameReceived(frame.getOpCode(), frame.getPayload());
545 isDone = true; //exit the loop after a control frame, so we can get a chance to close the socket if necessary
547 else //we have a dataframe; opcode can be OC_CONTINUE, OC_TEXT or OC_BINARY
549 if (!m_isFragmented && frame.isContinuationFrame())
552 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
555 if (m_isFragmented && frame.isDataFrame() && !frame.isContinuationFrame())
558 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0 (continuation).");
561 if (!frame.isContinuationFrame())
563 m_opCode = frame.getOpCode();
564 m_isFragmented = !frame.isFinalFrame();
566 quint64 messageLength = (quint64)(m_opCode == QWebSocketProtocol::OC_TEXT) ? m_textMessage.length() : m_binaryMessage.length();
567 if ((messageLength + quint64(frame.getPayload().length())) > MAX_MESSAGE_SIZE_IN_BYTES)
570 Q_EMIT errorEncountered(QWebSocketProtocol::CC_TOO_MUCH_DATA, "Received message is too big.");
574 if (m_opCode == QWebSocketProtocol::OC_TEXT)
576 QString frameTxt = m_pTextCodec->toUnicode(frame.getPayload().constData(), frame.getPayload().size(), m_pConverterState);
577 bool failed = (m_pConverterState->invalidChars != 0) || (frame.isFinalFrame() && (m_pConverterState->remainingChars != 0));
581 Q_EMIT errorEncountered(QWebSocketProtocol::CC_WRONG_DATATYPE, "Invalid UTF-8 code encountered.");
586 m_textMessage.append(frameTxt);
587 Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
592 m_binaryMessage.append(frame.getPayload());
593 Q_EMIT binaryFrameReceived(frame.getPayload(), frame.isFinalFrame());
596 if (frame.isFinalFrame())
598 if (m_opCode == QWebSocketProtocol::OC_TEXT)
600 Q_EMIT textMessageReceived(m_textMessage);
604 Q_EMIT binaryMessageReceived(m_binaryMessage);
613 Q_EMIT errorEncountered(frame.getCloseCode(), frame.getCloseReason());
623 void DataProcessor::clear()
625 m_processingState = PS_READ_HEADER;
626 m_isFinalFrame = false;
627 m_isFragmented = false;
628 m_opCode = QWebSocketProtocol::OC_CLOSE;
631 m_binaryMessage.clear();
632 m_textMessage.clear();
634 if (m_pConverterState)
636 if ((m_pConverterState->remainingChars != 0) || (m_pConverterState->invalidChars != 0))
638 delete m_pConverterState;
639 m_pConverterState = 0;
642 if (!m_pConverterState)
644 m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader);