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