There was no '?' between path and query. Bug detected by someone on the internet.
[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     \class DataProcessor
21     The class DataProcessor is responsible for reading, validating and interpreting data from a websocket.
22     It reads data from a QIODevice, validates it against RFC 6455, and parses it into frames (data, control).
23     It emits signals that correspond to the type of the frame: textFrameReceived(), binaryFrameReceived(),
24     textMessageReceived(), binaryMessageReceived(), pingReceived(), pongReceived() and closeReceived().
25     Whenever an error is detected, the errorEncountered() signal is emitted.
26     DataProcessor also checks if a frame is allowed in a sequence of frames (e.g. a continuation frame cannot follow a final frame).
27     This class is an internal class used by QWebSocketInternal for data processing and validation.
28
29     \sa Frame()
30
31     \internal
32 */
33 #include "dataprocessor_p.h"
34 #include "qwebsocketprotocol.h"
35 #include <QIODevice>
36 #include <QtEndian>
37 #include <limits.h>
38 #include <QTextCodec>
39 #include <QTextDecoder>
40 #include <QDebug>
41
42 QT_BEGIN_NAMESPACE
43
44 const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
45 const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
46
47 /*!
48     \class Frame
49     The class Frame is responsible for reading, validating and interpreting frames from a websocket.
50     It reads data from a QIODevice, validates it against RFC 6455, and parses it into a frame (data, control).
51     Whenever an error is detected, the isValid() returns false.
52
53     \note The Frame class does not look at valid sequences of frames. It processes frames one at a time.
54     \note It is the DataProcessor that takes the sequence into account.
55
56     \sa DataProcessor()
57     \internal
58  */
59 class Frame
60 {
61 public:
62     Frame();
63     Frame(const Frame &other);
64
65     const Frame &operator =(const Frame &other);
66
67     QWebSocketProtocol::CloseCode getCloseCode() const;
68     QString getCloseReason() const;
69     bool isFinalFrame() const;
70     bool isControlFrame() const;
71     bool isDataFrame() const;
72     bool isContinuationFrame() const;
73     bool hasMask() const;
74     quint32 getMask() const;    //returns 0 if no mask
75     int getRsv1() const;
76     int getRsv2() const;
77     int getRsv3() const;
78     QWebSocketProtocol::OpCode getOpCode() const;
79     QByteArray getPayload() const;
80
81     void clear();       //resets all member variables, and invalidates the object
82
83     bool isValid() const;
84
85     static Frame readFrame(QIODevice *pIoDevice);
86
87 private:
88     QWebSocketProtocol::CloseCode m_closeCode;
89     QString m_closeReason;
90     bool m_isFinalFrame;
91     quint32 m_mask;
92     int m_rsv1; //reserved field 1
93     int m_rsv2; //reserved field 2
94     int m_rsv3; //reserved field 3
95     QWebSocketProtocol::OpCode m_opCode;
96
97     quint8 m_length;        //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
98     QByteArray m_payload;
99
100     bool m_isValid;
101
102     enum ProcessingState
103     {
104         PS_READ_HEADER,
105         PS_READ_PAYLOAD_LENGTH,
106         PS_READ_BIG_PAYLOAD_LENGTH,
107         PS_READ_MASK,
108         PS_READ_PAYLOAD,
109         PS_DISPATCH_RESULT,
110         PS_WAIT_FOR_MORE_DATA
111     };
112
113     void setError(QWebSocketProtocol::CloseCode code, QString closeReason);
114     bool checkValidity();
115 };
116
117 /*!
118     \internal
119  */
120 Frame::Frame() :
121     m_closeCode(QWebSocketProtocol::CC_NORMAL),
122     m_closeReason(),
123     m_isFinalFrame(true),
124     m_mask(0),
125     m_rsv1(0),
126     m_rsv2(0),
127     m_rsv3(0),
128     m_opCode(QWebSocketProtocol::OC_RESERVED_C),
129     m_length(0),
130     m_payload(),
131     m_isValid(false)
132 {
133 }
134
135 /*!
136     \internal
137  */
138 Frame::Frame(const Frame &other) :
139     m_closeCode(other.m_closeCode),
140     m_closeReason(other.m_closeReason),
141     m_isFinalFrame(other.m_isFinalFrame),
142     m_mask(other.m_mask),
143     m_rsv1(other.m_rsv1),
144     m_rsv2(other.m_rsv2),
145     m_rsv3(other.m_rsv3),
146     m_opCode(other.m_opCode),
147     m_length(other.m_length),
148     m_payload(other.m_payload),
149     m_isValid(other.m_isValid)
150 {
151 }
152
153 /*!
154     \internal
155  */
156 const Frame &Frame::operator =(const Frame &other)
157 {
158     m_closeCode = other.m_closeCode;
159     m_closeReason = other.m_closeReason;
160     m_isFinalFrame = other.m_isFinalFrame;
161     m_mask = other.m_mask;
162     m_rsv1 = other.m_rsv1;
163     m_rsv2 = other.m_rsv2;
164     m_rsv3 = other.m_rsv2;
165     m_opCode = other.m_opCode;
166     m_length = other.m_length;
167     m_payload = other.m_payload;
168     m_isValid = other.m_isValid;
169
170     return *this;
171 }
172
173 /*!
174     \internal
175  */
176 QWebSocketProtocol::CloseCode Frame::getCloseCode() const
177 {
178     return m_closeCode;
179 }
180
181 /*!
182     \internal
183  */
184 QString Frame::getCloseReason() const
185 {
186     return m_closeReason;
187 }
188
189 /*!
190     \internal
191  */
192 bool Frame::isFinalFrame() const
193 {
194     return m_isFinalFrame;
195 }
196
197 /*!
198     \internal
199  */
200 bool Frame::isControlFrame() const
201 {
202     return (m_opCode & 0x08) == 0x08;
203 }
204
205 /*!
206     \internal
207  */
208 bool Frame::isDataFrame() const
209 {
210     return !isControlFrame();
211 }
212
213 /*!
214     \internal
215  */
216 bool Frame::isContinuationFrame() const
217 {
218     return isDataFrame() && (m_opCode == QWebSocketProtocol::OC_CONTINUE);
219 }
220
221 /*!
222     \internal
223  */
224 bool Frame::hasMask() const
225 {
226     return m_mask != 0;
227 }
228
229 /*!
230     \internal
231  */
232 quint32 Frame::getMask() const
233 {
234     return m_mask;
235 }
236
237 /*!
238     \internal
239  */
240 int Frame::getRsv1() const
241 {
242     return m_rsv1;
243 }
244
245 /*!
246     \internal
247  */
248 int Frame::getRsv2() const
249 {
250     return m_rsv2;
251 }
252
253 /*!
254     \internal
255  */
256 int Frame::getRsv3() const
257 {
258     return m_rsv3;
259 }
260
261 /*!
262     \internal
263  */
264 QWebSocketProtocol::OpCode Frame::getOpCode() const
265 {
266     return m_opCode;
267 }
268
269 /*!
270     \internal
271  */
272 QByteArray Frame::getPayload() const
273 {
274     return m_payload;
275 }
276
277 /*!
278     \internal
279  */
280 void Frame::clear()
281 {
282     m_closeCode = QWebSocketProtocol::CC_NORMAL;
283     m_closeReason.clear();
284     m_isFinalFrame = true;
285     m_mask = 0;
286     m_rsv1 = 0;
287     m_rsv2 =0;
288     m_rsv3 = 0;
289     m_opCode = QWebSocketProtocol::OC_RESERVED_C;
290     m_length = 0;
291     m_payload.clear();
292     m_isValid = false;
293 }
294
295 /*!
296     \internal
297  */
298 bool Frame::isValid() const
299 {
300     return m_isValid;
301 }
302
303 #define WAIT_FOR_MORE_DATA(dataSizeInBytes)  { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
304
305 /*!
306     \internal
307  */
308 Frame Frame::readFrame(QIODevice *pIoDevice)
309 {
310     bool isDone = false;
311     qint64 bytesRead = 0;
312     Frame frame;
313     quint64 dataWaitSize = 0;
314     ProcessingState processingState = PS_READ_HEADER;
315     ProcessingState returnState = PS_READ_HEADER;
316     bool hasMask = false;
317     quint64 payloadLength = 0;
318
319     while (!isDone)
320     {
321         switch (processingState)
322         {
323             case PS_WAIT_FOR_MORE_DATA:
324             {
325                 bool ok = pIoDevice->waitForReadyRead(5000);
326                 if (!ok)
327                 {
328                     frame.setError(QWebSocketProtocol::CC_GOING_AWAY, QObject::tr("Timeout when reading data from socket."));
329                     processingState = PS_DISPATCH_RESULT;
330                 }
331                 else
332                 {
333                     processingState = returnState;
334                 }
335                 break;
336             }
337             case PS_READ_HEADER:
338             {
339                 if (pIoDevice->bytesAvailable() >= 2)
340                 {
341                     //FIN, RSV1-3, Opcode
342                     char header[2] = {0};
343                     bytesRead = pIoDevice->read(header, 2);
344                     frame.m_isFinalFrame = (header[0] & 0x80) != 0;
345                     frame.m_rsv1 = (header[0] & 0x40);
346                     frame.m_rsv2 = (header[0] & 0x20);
347                     frame.m_rsv3 = (header[0] & 0x10);
348                     frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
349
350                     //Mask, PayloadLength
351                     hasMask = (header[1] & 0x80) != 0;
352                     frame.m_length = (header[1] & 0x7F);
353
354                     switch (frame.m_length)
355                     {
356                         case 126:
357                         {
358                             processingState = PS_READ_PAYLOAD_LENGTH;
359                             break;
360                         }
361                         case 127:
362                         {
363                             processingState = PS_READ_BIG_PAYLOAD_LENGTH;
364                             break;
365                         }
366                         default:
367                         {
368                             payloadLength = frame.m_length;
369                             processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
370                             break;
371                         }
372                     }
373                     if (!frame.checkValidity())
374                     {
375                         processingState = PS_DISPATCH_RESULT;
376                     }
377                 }
378                 else
379                 {
380                     WAIT_FOR_MORE_DATA(2);
381                 }
382                 break;
383             }
384
385             case PS_READ_PAYLOAD_LENGTH:
386             {
387                 if (pIoDevice->bytesAvailable() >= 2)
388                 {
389                     uchar length[2] = {0};
390                     bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 2);
391                     if (bytesRead == -1)
392                     {
393                         frame.setError(QWebSocketProtocol::CC_GOING_AWAY, QObject::tr("Error occurred while reading from the network: %1").arg(pIoDevice->errorString()));
394                         processingState = PS_DISPATCH_RESULT;
395                     }
396                     else
397                     {
398                         payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
399                         if (payloadLength < 126)
400                         {
401                             //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
402                             //"in all cases, the minimal number of bytes MUST be used to encode
403                             //the length, for example, the length of a 124-byte-long string
404                             //can't be encoded as the sequence 126, 0, 124"
405                             frame.setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Lengths smaller than 126 must be expressed as one byte."));
406                             processingState = PS_DISPATCH_RESULT;
407                         }
408                         else
409                         {
410                             processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
411                         }
412                     }
413                 }
414                 else
415                 {
416                     WAIT_FOR_MORE_DATA(2);
417                 }
418                 break;
419             }
420
421             case PS_READ_BIG_PAYLOAD_LENGTH:
422             {
423                 if (pIoDevice->bytesAvailable() >= 8)
424                 {
425                     uchar length[8] = {0};
426                     bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 8);
427                     if (bytesRead < 8)
428                     {
429                         frame.setError(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION, QObject::tr("Something went wrong during reading from the network."));
430                         processingState = PS_DISPATCH_RESULT;
431                     }
432                     else
433                     {
434                         //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
435                         //TODO: Do we check for that? Now we just strip off the highest bit
436                         payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
437                         if (payloadLength <= 0xFFFFu)
438                         {
439                             //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
440                             //"in all cases, the minimal number of bytes MUST be used to encode
441                             //the length, for example, the length of a 124-byte-long string
442                             //can't be encoded as the sequence 126, 0, 124"
443                             frame.setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Lengths smaller than 65536 (2^16) must be expressed as 2 bytes."));
444                             processingState = PS_DISPATCH_RESULT;
445                         }
446                         else
447                         {
448                             processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
449                         }
450                     }
451                 }
452                 else
453                 {
454                     WAIT_FOR_MORE_DATA(8);
455                 }
456
457                 break;
458             }
459
460             case PS_READ_MASK:
461             {
462                 if (pIoDevice->bytesAvailable() >= 4)
463                 {
464                     bytesRead = pIoDevice->read(reinterpret_cast<char *>(&frame.m_mask), sizeof(frame.m_mask));
465                     if (bytesRead == -1)
466                     {
467                         frame.setError(QWebSocketProtocol::CC_GOING_AWAY, QObject::tr("Error while reading from the network: %1.").arg(pIoDevice->errorString()));
468                         processingState = PS_DISPATCH_RESULT;
469                     }
470                     else
471                     {
472                         processingState = PS_READ_PAYLOAD;
473                     }
474                 }
475                 else
476                 {
477                     WAIT_FOR_MORE_DATA(4);
478                 }
479                 break;
480             }
481
482             case PS_READ_PAYLOAD:
483             {
484                 if (!payloadLength)
485                 {
486                     processingState = PS_DISPATCH_RESULT;
487                 }
488                 else if (payloadLength > MAX_FRAME_SIZE_IN_BYTES)
489                 {
490                     frame.setError(QWebSocketProtocol::CC_TOO_MUCH_DATA, QObject::tr("Maximum framesize exceeded."));
491                     processingState = PS_DISPATCH_RESULT;
492                 }
493                 else
494                 {
495                     quint64 bytesAvailable = static_cast<quint64>(pIoDevice->bytesAvailable());
496                     if (bytesAvailable >= payloadLength)
497                     {
498                         frame.m_payload = pIoDevice->read(payloadLength);
499                         //payloadLength can be safely cast to an integer, as the MAX_FRAME_SIZE_IN_BYTES = MAX_INT
500                         if (frame.m_payload.length() != static_cast<int>(payloadLength))  //some error occurred; refer to the Qt documentation
501                         {
502                             frame.setError(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION, QObject::tr("Some serious error occurred while reading from the network."));
503                             processingState = PS_DISPATCH_RESULT;
504                         }
505                         else
506                         {
507                             if (hasMask)
508                             {
509                                 QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
510                             }
511                             processingState = PS_DISPATCH_RESULT;
512                         }
513                     }
514                     else
515                     {
516                         WAIT_FOR_MORE_DATA(payloadLength);  //if payload is too big, then this will timeout
517                     }
518                 }
519                 break;
520             }
521
522             case PS_DISPATCH_RESULT:
523             {
524                 processingState = PS_READ_HEADER;
525                 isDone = true;
526                 break;
527             }
528
529             default:
530             {
531                 //should not come here
532                 qWarning() << "DataProcessor::process: Found invalid state. This should not happen!";
533                 frame.clear();
534                 isDone = true;
535                 break;
536             }
537         }       //end switch
538     }
539
540     return frame;
541 }
542
543 /*!
544     \internal
545  */
546 void Frame::setError(QWebSocketProtocol::CloseCode code, QString closeReason)
547 {
548     clear();
549     m_closeCode = code;
550     m_closeReason = closeReason;
551     m_isValid = false;
552 }
553
554 /*!
555     \internal
556  */
557 bool Frame::checkValidity()
558 {
559     if (!isValid())
560     {
561         if (m_rsv1 || m_rsv2 || m_rsv3)
562         {
563             setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Rsv field is non-zero"));
564         }
565         else if (QWebSocketProtocol::isOpCodeReserved(m_opCode))
566         {
567             setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Used reserved opcode"));
568         }
569         else if (isControlFrame())
570         {
571             if (m_length > 125)
572             {
573                 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Controle frame is larger than 125 bytes"));
574             }
575             else if (!m_isFinalFrame)
576             {
577                 setError(QWebSocketProtocol::CC_PROTOCOL_ERROR, QObject::tr("Controle frames cannot be fragmented"));
578             }
579             else
580             {
581                 m_isValid = true;
582             }
583         }
584         else
585         {
586             m_isValid = true;
587         }
588     }
589     return m_isValid;
590 }
591
592 /*!
593     \internal
594  */
595 DataProcessor::DataProcessor(QObject *parent) :
596     QObject(parent),
597     m_processingState(PS_READ_HEADER),
598     m_isFinalFrame(false),
599     m_isFragmented(false),
600     m_opCode(QWebSocketProtocol::OC_CLOSE),
601     m_isControlFrame(false),
602     m_hasMask(false),
603     m_mask(0),
604     m_binaryMessage(),
605     m_textMessage(),
606     m_payloadLength(0),
607     m_pConverterState(0),
608     m_pTextCodec(QTextCodec::codecForName("UTF-8"))
609 {
610     clear();
611 }
612
613 /*!
614     \internal
615  */
616 DataProcessor::~DataProcessor()
617 {
618     clear();
619     if (m_pConverterState)
620     {
621         delete m_pConverterState;
622         m_pConverterState = 0;
623     }
624 }
625
626 /*!
627     \internal
628  */
629 quint64 DataProcessor::maxMessageSize()
630 {
631     return MAX_MESSAGE_SIZE_IN_BYTES;
632 }
633
634 /*!
635     \internal
636  */
637 quint64 DataProcessor::maxFrameSize()
638 {
639     return MAX_FRAME_SIZE_IN_BYTES;
640 }
641
642 /*!
643     \internal
644  */
645 void DataProcessor::process(QIODevice *pIoDevice)
646 {
647     bool isDone = false;
648
649     while (!isDone)
650     {
651         Frame frame = Frame::readFrame(pIoDevice);
652         if (frame.isValid())
653         {
654             if (frame.isControlFrame())
655             {
656                 isDone = processControlFrame(frame);
657             }
658             else    //we have a dataframe; opcode can be OC_CONTINUE, OC_TEXT or OC_BINARY
659             {
660                 if (!m_isFragmented && frame.isContinuationFrame())
661                 {
662                     clear();
663                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, tr("Received Continuation frame, while there is nothing to continue."));
664                     return;
665                 }
666                 if (m_isFragmented && frame.isDataFrame() && !frame.isContinuationFrame())
667                 {
668                     clear();
669                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_PROTOCOL_ERROR, tr("All data frames after the initial data frame must have opcode 0 (continuation)."));
670                     return;
671                 }
672                 if (!frame.isContinuationFrame())
673                 {
674                     m_opCode = frame.getOpCode();
675                     m_isFragmented = !frame.isFinalFrame();
676                 }
677                 quint64 messageLength = (quint64)(m_opCode == QWebSocketProtocol::OC_TEXT) ? m_textMessage.length() : m_binaryMessage.length();
678                 if ((messageLength + quint64(frame.getPayload().length())) > MAX_MESSAGE_SIZE_IN_BYTES)
679                 {
680                     clear();
681                     Q_EMIT errorEncountered(QWebSocketProtocol::CC_TOO_MUCH_DATA, tr("Received message is too big."));
682                     return;
683                 }
684
685                 if (m_opCode == QWebSocketProtocol::OC_TEXT)
686                 {
687                     QString frameTxt = m_pTextCodec->toUnicode(frame.getPayload().constData(), frame.getPayload().size(), m_pConverterState);
688                     bool failed = (m_pConverterState->invalidChars != 0) || (frame.isFinalFrame() && (m_pConverterState->remainingChars != 0));
689                     if (failed)
690                     {
691                         clear();
692                         Q_EMIT errorEncountered(QWebSocketProtocol::CC_WRONG_DATATYPE, tr("Invalid UTF-8 code encountered."));
693                         return;
694                     }
695                     else
696                     {
697                         m_textMessage.append(frameTxt);
698                         Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
699                     }
700                 }
701                 else
702                 {
703                     m_binaryMessage.append(frame.getPayload());
704                     Q_EMIT binaryFrameReceived(frame.getPayload(), frame.isFinalFrame());
705                 }
706
707                 if (frame.isFinalFrame())
708                 {
709                     if (m_opCode == QWebSocketProtocol::OC_TEXT)
710                     {
711                         Q_EMIT textMessageReceived(m_textMessage);
712                     }
713                     else
714                     {
715                         Q_EMIT binaryMessageReceived(m_binaryMessage);
716                     }
717                     clear();
718                     isDone = true;
719                 }
720             }
721         }
722         else
723         {
724             Q_EMIT errorEncountered(frame.getCloseCode(), frame.getCloseReason());
725             clear();
726             isDone = true;
727         }
728     }
729 }
730
731 /*!
732     \internal
733  */
734 void DataProcessor::clear()
735 {
736     m_processingState = PS_READ_HEADER;
737     m_isFinalFrame = false;
738     m_isFragmented = false;
739     m_opCode = QWebSocketProtocol::OC_CLOSE;
740     m_hasMask = false;
741     m_mask = 0;
742     m_binaryMessage.clear();
743     m_textMessage.clear();
744     m_payloadLength = 0;
745     if (m_pConverterState)
746     {
747         if ((m_pConverterState->remainingChars != 0) || (m_pConverterState->invalidChars != 0))
748         {
749             delete m_pConverterState;
750             m_pConverterState = 0;
751         }
752     }
753     if (!m_pConverterState)
754     {
755         m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader);
756     }
757 }
758
759 /*!
760     \internal
761  */
762 bool DataProcessor::processControlFrame(const Frame &frame)
763 {
764     bool mustStopProcessing = false;
765     switch (frame.getOpCode())
766     {
767     case QWebSocketProtocol::OC_PING:
768     {
769         Q_EMIT pingReceived(frame.getPayload());
770         break;
771     }
772     case QWebSocketProtocol::OC_PONG:
773     {
774         Q_EMIT pongReceived(frame.getPayload());
775         break;
776     }
777     case QWebSocketProtocol::OC_CLOSE:
778     {
779         quint16 closeCode = QWebSocketProtocol::CC_NORMAL;
780         QString closeReason;
781         QByteArray payload = frame.getPayload();
782         if (payload.size() == 1)
783         {
784             closeCode = QWebSocketProtocol::CC_PROTOCOL_ERROR;
785             closeReason = tr("Payload of close frame is too small.");
786         }
787         else if (payload.size() > 1)   //close frame can have a close code and reason
788         {
789             closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(payload.constData()));
790             if (!QWebSocketProtocol::isCloseCodeValid(closeCode))
791             {
792                 closeCode = QWebSocketProtocol::CC_PROTOCOL_ERROR;
793                 closeReason = tr("Invalid close code %1 detected.").arg(closeCode);
794             }
795             else
796             {
797                 if (payload.size() > 2)
798                 {
799                     QTextCodec *tc = QTextCodec::codecForName("UTF-8");
800                     QTextCodec::ConverterState state(QTextCodec::ConvertInvalidToNull);
801                     closeReason = tc->toUnicode(payload.constData() + 2, payload.size() - 2, &state);
802                     bool failed = (state.invalidChars != 0) || (state.remainingChars != 0);
803                     if (failed)
804                     {
805                         closeCode = QWebSocketProtocol::CC_WRONG_DATATYPE;
806                         closeReason = tr("Invalid UTF-8 code encountered.");
807                     }
808                 }
809             }
810         }
811         mustStopProcessing = true;
812         Q_EMIT closeReceived(static_cast<QWebSocketProtocol::CloseCode>(closeCode), closeReason);
813         break;
814     }
815     case QWebSocketProtocol::OC_CONTINUE:
816     case QWebSocketProtocol::OC_BINARY:
817     case QWebSocketProtocol::OC_TEXT:
818     case QWebSocketProtocol::OC_RESERVED_3:
819     case QWebSocketProtocol::OC_RESERVED_4:
820     case QWebSocketProtocol::OC_RESERVED_5:
821     case QWebSocketProtocol::OC_RESERVED_6:
822     case QWebSocketProtocol::OC_RESERVED_7:
823     case QWebSocketProtocol::OC_RESERVED_C:
824     case QWebSocketProtocol::OC_RESERVED_B:
825     case QWebSocketProtocol::OC_RESERVED_D:
826     case QWebSocketProtocol::OC_RESERVED_E:
827     case QWebSocketProtocol::OC_RESERVED_F:
828     {
829         //do nothing
830         //case added to make C++ compiler happy
831         break;
832     }
833     default:
834     {
835         qDebug() << "DataProcessor::processControlFrame: Invalid opcode detected:" << static_cast<int>(frame.getOpCode());
836         //Do nothing
837         break;
838     }
839     }
840     return mustStopProcessing;
841 }
842
843 QT_END_NAMESPACE