Made parameters const references
[contrib/qtwebsockets.git] / src / dataprocessor_p.cpp
1 /*
2 QWebSockets implements the WebSocket protocol as defined in RFC 6455.
3 Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com)
4
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.
9
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.
14
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
18 */
19
20 #include "dataprocessor_p.h"
21 #include "qwebsocketprotocol.h"
22 #include "qwebsocket.h"
23 #include <QTcpSocket>
24 #include <QtEndian>
25 #include <limits.h>
26 #include <QTextCodec>
27 #include <QTextDecoder>
28
29 QT_BEGIN_NAMESPACE
30
31 const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
32 const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
33
34 /*!
35     \internal
36  */
37 class Frame
38 {
39 public:
40     Frame();
41     Frame(const Frame &other);
42
43     const Frame &operator =(const Frame &other);
44
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;
51     bool hasMask() const;
52     quint32 getMask() const;    //returns 0 if no mask
53     int getRsv1() const;
54     int getRsv2() const;
55     int getRsv3() const;
56     QWebSocketProtocol::OpCode getOpCode() const;
57     QByteArray getPayload() const;
58
59     void clear();       //resets all member variables, and invalidates the object
60
61     bool isValid() const;
62
63     static Frame readFrame(QTcpSocket *pSocket);
64
65 private:
66     QWebSocketProtocol::CloseCode m_closeCode;
67     QString m_closeReason;
68     bool m_isFinalFrame;
69     quint32 m_mask;
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;
74
75     quint8 m_length;        //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
76     QByteArray m_payload;
77
78     bool m_isValid;
79
80     enum ProcessingState
81     {
82         PS_READ_HEADER,
83         PS_READ_PAYLOAD_LENGTH,
84         PS_READ_BIG_PAYLOAD_LENGTH,
85         PS_READ_MASK,
86         PS_READ_PAYLOAD,
87         PS_DISPATCH_RESULT,
88         PS_WAIT_FOR_MORE_DATA
89     };
90
91     void setError(QWebSocketProtocol::CloseCode code, QString closeReason);
92     bool checkValidity();
93 };
94
95 /*!
96     \internal
97  */
98 Frame::Frame() :
99     m_closeCode(QWebSocketProtocol::CC_NORMAL),
100     m_closeReason(),
101     m_isFinalFrame(true),
102     m_mask(0),
103     m_rsv1(0),
104     m_rsv2(0),
105     m_rsv3(0),
106     m_opCode(QWebSocketProtocol::OC_RESERVED_V),
107     m_length(0),
108     m_payload(),
109     m_isValid(false)
110 {
111 }
112
113 /*!
114     \internal
115  */
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)
128 {
129 }
130
131 /*!
132     \internal
133  */
134 const Frame &Frame::operator =(const Frame &other)
135 {
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;
147
148     return *this;
149 }
150
151 /*!
152     \internal
153  */
154 QWebSocketProtocol::CloseCode Frame::getCloseCode() const
155 {
156     return m_closeCode;
157 }
158
159 /*!
160     \internal
161  */
162 QString Frame::getCloseReason() const
163 {
164     return m_closeReason;
165 }
166
167 /*!
168     \internal
169  */
170 bool Frame::isFinalFrame() const
171 {
172     return m_isFinalFrame;
173 }
174
175 /*!
176     \internal
177  */
178 bool Frame::isControlFrame() const
179 {
180     return (m_opCode & 0x08) == 0x08;
181 }
182
183 /*!
184     \internal
185  */
186 bool Frame::isDataFrame() const
187 {
188     return !isControlFrame();
189 }
190
191 /*!
192     \internal
193  */
194 bool Frame::isContinuationFrame() const
195 {
196     return isDataFrame() && (m_opCode == QWebSocketProtocol::OC_CONTINUE);
197 }
198
199 /*!
200     \internal
201  */
202 bool Frame::hasMask() const
203 {
204     return m_mask != 0;
205 }
206
207 /*!
208     \internal
209  */
210 quint32 Frame::getMask() const
211 {
212     return m_mask;
213 }
214
215 /*!
216     \internal
217  */
218 int Frame::getRsv1() const
219 {
220     return m_rsv1;
221 }
222
223 /*!
224     \internal
225  */
226 int Frame::getRsv2() const
227 {
228     return m_rsv2;
229 }
230
231 /*!
232     \internal
233  */
234 int Frame::getRsv3() const
235 {
236     return m_rsv3;
237 }
238
239 /*!
240     \internal
241  */
242 QWebSocketProtocol::OpCode Frame::getOpCode() const
243 {
244     return m_opCode;
245 }
246
247 /*!
248     \internal
249  */
250 QByteArray Frame::getPayload() const
251 {
252     return m_payload;
253 }
254
255 /*!
256     \internal
257  */
258 void Frame::clear()
259 {
260     m_closeCode = QWebSocketProtocol::CC_NORMAL;
261     m_closeReason.clear();
262     m_isFinalFrame = true;
263     m_mask = 0;
264     m_rsv1 = 0;
265     m_rsv2 =0;
266     m_rsv3 = 0;
267     m_opCode = QWebSocketProtocol::OC_RESERVED_V;
268     m_length = 0;
269     m_payload.clear();
270     m_isValid = false;
271 }
272
273 /*!
274     \internal
275  */
276 bool Frame::isValid() const
277 {
278     return m_isValid;
279 }
280
281 #define WAIT_FOR_MORE_DATA(dataSizeInBytes)  { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
282
283 /*!
284     \internal
285  */
286 Frame Frame::readFrame(QTcpSocket *pSocket)
287 {
288     bool isDone = false;
289     qint64 bytesRead = 0;
290     Frame frame;
291     quint64 dataWaitSize = 0;
292     ProcessingState processingState = PS_READ_HEADER;
293     ProcessingState returnState = PS_READ_HEADER;
294     bool hasMask = false;
295     quint64 payloadLength = 0;
296
297     while (!isDone)
298     {
299         switch (processingState)
300         {
301             case PS_WAIT_FOR_MORE_DATA:
302             {
303                 bool ok = pSocket->waitForReadyRead(5000);
304                 if (!ok)
305                 {
306                     frame.setError(QWebSocketProtocol::CC_GOING_AWAY, QWebSocket::tr("Timeout when reading data from socket."));
307                     isDone = true;
308                 }
309                 else
310                 {
311                     processingState = returnState;
312                 }
313                 break;
314             }
315             case PS_READ_HEADER:
316             {
317                 if (pSocket->bytesAvailable() >= 2)
318                 {
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);
327
328                     //Mask, PayloadLength
329                     hasMask = (header[1] & 0x80) != 0;
330                     frame.m_length = (header[1] & 0x7F);
331
332                     switch (frame.m_length)
333                     {
334                         case 126:
335                         {
336                             processingState = PS_READ_PAYLOAD_LENGTH;
337                             break;
338                         }
339                         case 127:
340                         {
341                             processingState = PS_READ_BIG_PAYLOAD_LENGTH;
342                             break;
343                         }
344                         default:
345                         {
346                             payloadLength = frame.m_length;
347                             processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
348                             break;
349                         }
350                     }
351                     if (!frame.checkValidity())
352                     {
353                         isDone = true;
354                     }
355                 }
356                 else
357                 {
358                     WAIT_FOR_MORE_DATA(2);
359                 }
360                 break;
361             }
362
363             case PS_READ_PAYLOAD_LENGTH:
364             {
365                 if (pSocket->bytesAvailable() >= 2)
366                 {
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;
372                 }
373                 else
374                 {
375                     WAIT_FOR_MORE_DATA(2);
376                 }
377                 break;
378             }
379
380             case PS_READ_BIG_PAYLOAD_LENGTH:
381             {
382                 if (pSocket->bytesAvailable() >= 8)
383                 {
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;
391                 }
392                 else
393                 {
394                     WAIT_FOR_MORE_DATA(8);
395                 }
396
397                 break;
398             }
399
400             case PS_READ_MASK:
401             {
402                 if (pSocket->bytesAvailable() >= 4)
403                 {
404                     //TODO: Handle return value
405                     bytesRead = pSocket->read(reinterpret_cast<char *>(&frame.m_mask), sizeof(frame.m_mask));
406                     processingState = PS_READ_PAYLOAD;
407                 }
408                 else
409                 {
410                     WAIT_FOR_MORE_DATA(4);
411                 }
412                 break;
413             }
414
415             case PS_READ_PAYLOAD:
416             {
417                 if (!payloadLength)
418                 {
419                     processingState = PS_DISPATCH_RESULT;
420                 }
421                 else if (payloadLength > MAX_FRAME_SIZE_IN_BYTES)
422                 {
423                     frame.setError(QWebSocketProtocol::CC_TOO_MUCH_DATA, QWebSocket::tr("Maximum framesize exceeded."));
424                     processingState = PS_DISPATCH_RESULT;
425                 }
426                 else
427                 {
428                     quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
429                     if (bytesAvailable >= payloadLength)
430                     {
431                         frame.m_payload = pSocket->read(payloadLength);
432                         if (hasMask)
433                         {
434                             QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
435                         }
436                         processingState = PS_DISPATCH_RESULT;
437                     }
438                     else
439                     {
440                         WAIT_FOR_MORE_DATA(payloadLength);
441                     }
442                 }
443                 break;
444             }
445
446             case PS_DISPATCH_RESULT:
447             {
448                 processingState = PS_READ_HEADER;
449                 isDone = true;
450                 break;
451             }
452
453             default:
454             {
455                 //should not come here
456                 qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
457                 frame.clear();
458                 isDone = true;
459                 break;
460             }
461         }       //end switch
462     }
463
464     return frame;
465 }
466
467 /*!
468     \internal
469  */
470 void Frame::setError(QWebSocketProtocol::CloseCode code, QString closeReason)
471 {
472     clear();
473     m_closeCode = code;
474     m_closeReason = closeReason;
475     m_isValid = false;
476 }
477
478 /*!
479     \internal
480  */
481 bool Frame::checkValidity()
482 {
483     if (!isValid())
484     {
485         if (m_rsv1 || m_rsv2 || m_rsv3)
486         {
487             setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Rsv field is non-zero"));
488         }
489         else if (QWebSocketProtocol::isOpCodeReserved(m_opCode))
490         {
491             setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Used reserved opcode"));
492         }
493         else if (isControlFrame())
494         {
495             if (m_length > 125)
496             {
497                 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Controle frame is larger than 125 bytes"));
498             }
499             else if (!m_isFinalFrame)
500             {
501                 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Controle frames cannot be fragmented"));
502             }
503             else
504             {
505                 m_isValid = true;
506             }
507         }
508         else
509         {
510             m_isValid = true;
511         }
512     }
513     return m_isValid;
514 }
515
516 /*!
517     \internal
518  */
519 DataProcessor::DataProcessor(QObject *parent) :
520     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),
526     m_hasMask(false),
527     m_mask(0),
528     m_binaryMessage(),
529     m_textMessage(),
530     m_payloadLength(0),
531     m_pConverterState(0),
532     m_pTextCodec(QTextCodec::codecForName("UTF-8"))
533 {
534     clear();
535 }
536
537 /*!
538     \internal
539  */
540 DataProcessor::~DataProcessor()
541 {
542     clear();
543     if (m_pConverterState)
544     {
545         delete m_pConverterState;
546         m_pConverterState = 0;
547     }
548 }
549
550 /*!
551     \internal
552  */
553 void DataProcessor::process(QTcpSocket *pSocket)
554 {
555     bool isDone = false;
556
557     while (!isDone)
558     {
559         Frame frame = Frame::readFrame(pSocket);
560         if (frame.isValid())
561         {
562             if (frame.isControlFrame())
563             {
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
566             }
567             else    //we have a dataframe; opcode can be OC_CONTINUE, OC_TEXT or OC_BINARY
568             {
569                 if (!m_isFragmented && frame.isContinuationFrame())
570                 {
571                     clear();
572                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("Received Continuation frame /*with FIN=true*/, while there is nothing to continue."));
573                     return;
574                 }
575                 if (m_isFragmented && frame.isDataFrame() && !frame.isContinuationFrame())
576                 {
577                     clear();
578                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, QWebSocket::tr("All data frames after the initial data frame must have opcode 0 (continuation)."));
579                     return;
580                 }
581                 if (!frame.isContinuationFrame())
582                 {
583                     m_opCode = frame.getOpCode();
584                     m_isFragmented = !frame.isFinalFrame();
585                 }
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)
588                 {
589                     clear();
590                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_TOO_MUCH_DATA, QWebSocket::tr("Received message is too big."));
591                     return;
592                 }
593
594                 if (m_opCode == QWebSocketProtocol::OC_TEXT)
595                 {
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));
598                     if (failed)
599                     {
600                         clear();
601                         Q_EMIT errorEncountered(QWebSocketProtocol::CC_WRONG_DATATYPE, QWebSocket::tr("Invalid UTF-8 code encountered."));
602                         return;
603                     }
604                     else
605                     {
606                         m_textMessage.append(frameTxt);
607                         Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
608                     }
609                 }
610                 else
611                 {
612                     m_binaryMessage.append(frame.getPayload());
613                     Q_EMIT binaryFrameReceived(frame.getPayload(), frame.isFinalFrame());
614                 }
615
616                 if (frame.isFinalFrame())
617                 {
618                     if (m_opCode == QWebSocketProtocol::OC_TEXT)
619                     {
620                         Q_EMIT textMessageReceived(m_textMessage);
621                     }
622                     else
623                     {
624                         Q_EMIT binaryMessageReceived(m_binaryMessage);
625                     }
626                     clear();
627                     isDone = true;
628                 }
629             }
630         }
631         else
632         {
633             Q_EMIT errorEncountered(frame.getCloseCode(), frame.getCloseReason());
634             clear();
635             isDone = true;
636         }
637     }
638 }
639
640 /*!
641     \internal
642  */
643 void DataProcessor::clear()
644 {
645     m_processingState = PS_READ_HEADER;
646     m_isFinalFrame = false;
647     m_isFragmented = false;
648     m_opCode = QWebSocketProtocol::OC_CLOSE;
649     m_hasMask = false;
650     m_mask = 0;
651     m_binaryMessage.clear();
652     m_textMessage.clear();
653     m_payloadLength = 0;
654     if (m_pConverterState)
655     {
656         if ((m_pConverterState->remainingChars != 0) || (m_pConverterState->invalidChars != 0))
657         {
658             delete m_pConverterState;
659             m_pConverterState = 0;
660         }
661     }
662     if (!m_pConverterState)
663     {
664         m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader);
665     }
666 }
667
668 QT_END_NAMESPACE