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"
22 #include "qwebsocket.h"
27 #include <QTextDecoder>
31 const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
32 const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
41 Frame(const Frame &other);
43 const Frame &operator =(const Frame &other);
45 QWebSocketProtocol::CloseCode getCloseCode() const;
46 QString getCloseReason() const;
47 bool isFinalFrame() const;
48 bool isControlFrame() const;
49 bool isDataFrame() const;
50 bool isContinuationFrame() const;
52 quint32 getMask() const; //returns 0 if no mask
56 QWebSocketProtocol::OpCode getOpCode() const;
57 QByteArray getPayload() const;
59 void clear(); //resets all member variables, and invalidates the object
63 static Frame readFrame(QTcpSocket *pSocket);
66 QWebSocketProtocol::CloseCode m_closeCode;
67 QString m_closeReason;
70 int m_rsv1; //reserved field 1
71 int m_rsv2; //reserved field 2
72 int m_rsv3; //reserved field 3
73 QWebSocketProtocol::OpCode m_opCode;
75 quint8 m_length; //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
83 PS_READ_PAYLOAD_LENGTH,
84 PS_READ_BIG_PAYLOAD_LENGTH,
91 void setError(QWebSocketProtocol::CloseCode code, QString closeReason);
99 m_closeCode(QWebSocketProtocol::CC_NORMAL),
101 m_isFinalFrame(true),
106 m_opCode(QWebSocketProtocol::OC_RESERVED_V),
116 Frame::Frame(const Frame &other) :
117 m_closeCode(other.m_closeCode),
118 m_closeReason(other.m_closeReason),
119 m_isFinalFrame(other.m_isFinalFrame),
120 m_mask(other.m_mask),
121 m_rsv1(other.m_rsv1),
122 m_rsv2(other.m_rsv2),
123 m_rsv3(other.m_rsv3),
124 m_opCode(other.m_opCode),
125 m_length(other.m_length),
126 m_payload(other.m_payload),
127 m_isValid(other.m_isValid)
134 const Frame &Frame::operator =(const Frame &other)
136 m_closeCode = other.m_closeCode;
137 m_closeReason = other.m_closeReason;
138 m_isFinalFrame = other.m_isFinalFrame;
139 m_mask = other.m_mask;
140 m_rsv1 = other.m_rsv1;
141 m_rsv2 = other.m_rsv2;
142 m_rsv3 = other.m_rsv2;
143 m_opCode = other.m_opCode;
144 m_length = other.m_length;
145 m_payload = other.m_payload;
146 m_isValid = other.m_isValid;
154 QWebSocketProtocol::CloseCode Frame::getCloseCode() const
162 QString Frame::getCloseReason() const
164 return m_closeReason;
170 bool Frame::isFinalFrame() const
172 return m_isFinalFrame;
178 bool Frame::isControlFrame() const
180 return (m_opCode & 0x08) == 0x08;
186 bool Frame::isDataFrame() const
188 return !isControlFrame();
194 bool Frame::isContinuationFrame() const
196 return isDataFrame() && (m_opCode == QWebSocketProtocol::OC_CONTINUE);
202 bool Frame::hasMask() const
210 quint32 Frame::getMask() const
218 int Frame::getRsv1() const
226 int Frame::getRsv2() const
234 int Frame::getRsv3() const
242 QWebSocketProtocol::OpCode Frame::getOpCode() const
250 QByteArray Frame::getPayload() const
260 m_closeCode = QWebSocketProtocol::CC_NORMAL;
261 m_closeReason.clear();
262 m_isFinalFrame = true;
267 m_opCode = QWebSocketProtocol::OC_RESERVED_V;
276 bool Frame::isValid() const
281 #define WAIT_FOR_MORE_DATA(dataSizeInBytes) { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
286 Frame Frame::readFrame(QTcpSocket *pSocket)
289 qint64 bytesRead = 0;
291 quint64 dataWaitSize = 0;
292 ProcessingState processingState = PS_READ_HEADER;
293 ProcessingState returnState = PS_READ_HEADER;
294 bool hasMask = false;
295 quint64 payloadLength = 0;
299 switch (processingState)
301 case PS_WAIT_FOR_MORE_DATA:
303 bool ok = pSocket->waitForReadyRead(5000);
306 frame.setError(QWebSocketProtocol::CC_GOING_AWAY, QWebSocket::tr("Timeout when reading data from socket."));
311 processingState = returnState;
317 if (pSocket->bytesAvailable() >= 2)
319 //FIN, RSV1-3, Opcode
320 char header[2] = {0};
321 bytesRead = pSocket->read(header, 2);
322 frame.m_isFinalFrame = (header[0] & 0x80) != 0;
323 frame.m_rsv1 = (header[0] & 0x40);
324 frame.m_rsv2 = (header[0] & 0x20);
325 frame.m_rsv3 = (header[0] & 0x10);
326 frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
328 //Mask, PayloadLength
329 hasMask = (header[1] & 0x80) != 0;
330 frame.m_length = (header[1] & 0x7F);
332 switch (frame.m_length)
336 processingState = PS_READ_PAYLOAD_LENGTH;
341 processingState = PS_READ_BIG_PAYLOAD_LENGTH;
346 payloadLength = frame.m_length;
347 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
351 if (!frame.checkValidity())
358 WAIT_FOR_MORE_DATA(2);
363 case PS_READ_PAYLOAD_LENGTH:
365 if (pSocket->bytesAvailable() >= 2)
367 uchar length[2] = {0};
368 //TODO: Handle return value
369 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
370 payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
371 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
375 WAIT_FOR_MORE_DATA(2);
380 case PS_READ_BIG_PAYLOAD_LENGTH:
382 if (pSocket->bytesAvailable() >= 8)
384 uchar length[8] = {0};
385 //TODO: Handle return value
386 bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
387 //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
388 //TODO: Do we check for that?
389 payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
390 processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
394 WAIT_FOR_MORE_DATA(8);
402 if (pSocket->bytesAvailable() >= 4)
404 //TODO: Handle return value
405 bytesRead = pSocket->read(reinterpret_cast<char *>(&frame.m_mask), sizeof(frame.m_mask));
406 processingState = PS_READ_PAYLOAD;
410 WAIT_FOR_MORE_DATA(4);
415 case PS_READ_PAYLOAD:
419 processingState = PS_DISPATCH_RESULT;
421 else if (payloadLength > MAX_FRAME_SIZE_IN_BYTES)
423 frame.setError(QWebSocketProtocol::CC_TOO_MUCH_DATA, QWebSocket::tr("Maximum framesize exceeded."));
424 processingState = PS_DISPATCH_RESULT;
428 quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
429 if (bytesAvailable >= payloadLength)
431 frame.m_payload = pSocket->read(payloadLength);
434 QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
436 processingState = PS_DISPATCH_RESULT;
440 WAIT_FOR_MORE_DATA(payloadLength);
446 case PS_DISPATCH_RESULT:
448 processingState = PS_READ_HEADER;
455 //should not come here
456 qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
470 void Frame::setError(QWebSocketProtocol::CloseCode code, QString closeReason)
474 m_closeReason = closeReason;
481 bool Frame::checkValidity()
485 if (m_rsv1 || m_rsv2 || m_rsv3)
487 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Rsv field is non-zero"));
489 else if (QWebSocketProtocol::isOpCodeReserved(m_opCode))
491 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Used reserved opcode"));
493 else if (isControlFrame())
497 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Controle frame is larger than 125 bytes"));
499 else if (!m_isFinalFrame)
501 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Controle frames cannot be fragmented"));
519 DataProcessor::DataProcessor(QObject *parent) :
521 m_processingState(PS_READ_HEADER),
522 m_isFinalFrame(false),
523 m_isFragmented(false),
524 m_opCode(QWebSocketProtocol::OC_CLOSE),
525 m_isControlFrame(false),
531 m_pConverterState(0),
532 m_pTextCodec(QTextCodec::codecForName("UTF-8"))
540 DataProcessor::~DataProcessor()
543 if (m_pConverterState)
545 delete m_pConverterState;
546 m_pConverterState = 0;
553 void DataProcessor::process(QTcpSocket *pSocket)
559 Frame frame = Frame::readFrame(pSocket);
562 if (frame.isControlFrame())
564 Q_EMIT controlFrameReceived(frame.getOpCode(), frame.getPayload());
565 isDone = true; //exit the loop after a control frame, so we can get a chance to close the socket if necessary
567 else //we have a dataframe; opcode can be OC_CONTINUE, OC_TEXT or OC_BINARY
569 if (!m_isFragmented && frame.isContinuationFrame())
572 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Received Continuation frame /*with FIN=true*/, while there is nothing to continue."));
575 if (m_isFragmented && frame.isDataFrame() && !frame.isContinuationFrame())
578 Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("All data frames after the initial data frame must have opcode 0 (continuation)."));
581 if (!frame.isContinuationFrame())
583 m_opCode = frame.getOpCode();
584 m_isFragmented = !frame.isFinalFrame();
586 quint64 messageLength = (quint64)(m_opCode == QWebSocketProtocol::OC_TEXT) ? m_textMessage.length() : m_binaryMessage.length();
587 if ((messageLength + quint64(frame.getPayload().length())) > MAX_MESSAGE_SIZE_IN_BYTES)
590 Q_EMIT errorEncountered(QWebSocketProtocol::CC_TOO_MUCH_DATA, QWebSocket::tr("Received message is too big."));
594 if (m_opCode == QWebSocketProtocol::OC_TEXT)
596 QString frameTxt = m_pTextCodec->toUnicode(frame.getPayload().constData(), frame.getPayload().size(), m_pConverterState);
597 bool failed = (m_pConverterState->invalidChars != 0) || (frame.isFinalFrame() && (m_pConverterState->remainingChars != 0));
601 Q_EMIT errorEncountered(QWebSocketProtocol::CC_WRONG_DATATYPE, QWebSocket::tr("Invalid UTF-8 code encountered."));
606 m_textMessage.append(frameTxt);
607 Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
612 m_binaryMessage.append(frame.getPayload());
613 Q_EMIT binaryFrameReceived(frame.getPayload(), frame.isFinalFrame());
616 if (frame.isFinalFrame())
618 if (m_opCode == QWebSocketProtocol::OC_TEXT)
620 Q_EMIT textMessageReceived(m_textMessage);
624 Q_EMIT binaryMessageReceived(m_binaryMessage);
633 Q_EMIT errorEncountered(frame.getCloseCode(), frame.getCloseReason());
643 void DataProcessor::clear()
645 m_processingState = PS_READ_HEADER;
646 m_isFinalFrame = false;
647 m_isFragmented = false;
648 m_opCode = QWebSocketProtocol::OC_CLOSE;
651 m_binaryMessage.clear();
652 m_textMessage.clear();
654 if (m_pConverterState)
656 if ((m_pConverterState->remainingChars != 0) || (m_pConverterState->invalidChars != 0))
658 delete m_pConverterState;
659 m_pConverterState = 0;
662 if (!m_pConverterState)
664 m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader);