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