Update license headers and add new license files
[contrib/qtwebsockets.git] / src / websockets / qwebsocketframe.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtWebSockets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** In addition, as a special exception, Digia gives you certain additional
27 ** rights. These rights are described in the Digia Qt LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 /*!
35     \class QWebSocketFrame
36     The class QWebSocketFrame is responsible for reading, validating and
37     interpreting frames from a WebSocket.
38     It reads data from a QIODevice, validates it against RFC 6455, and parses it into a
39     frame (data, control).
40     Whenever an error is detected, isValid() returns false.
41
42     \note The QWebSocketFrame class does not look at valid sequences of frames.
43     It processes frames one at a time.
44     \note It is the QWebSocketDataProcessor that takes the sequence into account.
45
46     \sa QWebSocketDataProcessor
47     \internal
48  */
49
50 #include "qwebsocketframe_p.h"
51 #include "qwebsocketprotocol_p.h"
52
53 #include <QtCore/QtEndian>
54 #include <QtCore/QDebug>
55
56 QT_BEGIN_NAMESPACE
57
58 /*!
59     \internal
60  */
61 QWebSocketFrame::QWebSocketFrame() :
62     m_closeCode(QWebSocketProtocol::CloseCodeNormal),
63     m_closeReason(),
64     m_isFinalFrame(true),
65     m_mask(0),
66     m_rsv1(0),
67     m_rsv2(0),
68     m_rsv3(0),
69     m_opCode(QWebSocketProtocol::OpCodeReservedC),
70     m_length(0),
71     m_payload(),
72     m_isValid(false)
73 {
74 }
75
76 /*!
77     \internal
78  */
79 QWebSocketFrame::QWebSocketFrame(const QWebSocketFrame &other) :
80     m_closeCode(other.m_closeCode),
81     m_closeReason(other.m_closeReason),
82     m_isFinalFrame(other.m_isFinalFrame),
83     m_mask(other.m_mask),
84     m_rsv1(other.m_rsv1),
85     m_rsv2(other.m_rsv2),
86     m_rsv3(other.m_rsv3),
87     m_opCode(other.m_opCode),
88     m_length(other.m_length),
89     m_payload(other.m_payload),
90     m_isValid(other.m_isValid)
91 {
92 }
93
94 /*!
95     \internal
96  */
97 QWebSocketFrame &QWebSocketFrame::operator =(const QWebSocketFrame &other)
98 {
99     m_closeCode = other.m_closeCode;
100     m_closeReason = other.m_closeReason;
101     m_isFinalFrame = other.m_isFinalFrame;
102     m_mask = other.m_mask;
103     m_rsv1 = other.m_rsv1;
104     m_rsv2 = other.m_rsv2;
105     m_rsv3 = other.m_rsv2;
106     m_opCode = other.m_opCode;
107     m_length = other.m_length;
108     m_payload = other.m_payload;
109     m_isValid = other.m_isValid;
110
111     return *this;
112 }
113
114 #ifdef Q_COMPILER_RVALUE_REFS
115 /*!
116     \internal
117  */
118 QWebSocketFrame::QWebSocketFrame(QWebSocketFrame &&other) :
119     m_closeCode(qMove(other.m_closeCode)),
120     m_closeReason(qMove(other.m_closeReason)),
121     m_isFinalFrame(qMove(other.m_isFinalFrame)),
122     m_mask(qMove(other.m_mask)),
123     m_rsv1(qMove(other.m_rsv1)),
124     m_rsv2(qMove(other.m_rsv2)),
125     m_rsv3(qMove(other.m_rsv3)),
126     m_opCode(qMove(other.m_opCode)),
127     m_length(qMove(other.m_length)),
128     m_payload(qMove(other.m_payload)),
129     m_isValid(qMove(other.m_isValid))
130 {}
131
132
133 /*!
134     \internal
135  */
136 QWebSocketFrame &QWebSocketFrame::operator =(QWebSocketFrame &&other)
137 {
138     qSwap(m_closeCode, other.m_closeCode);
139     qSwap(m_closeReason, other.m_closeReason);
140     qSwap(m_isFinalFrame, other.m_isFinalFrame);
141     qSwap(m_mask, other.m_mask);
142     qSwap(m_rsv1, other.m_rsv1);
143     qSwap(m_rsv2, other.m_rsv2);
144     qSwap(m_rsv3, other.m_rsv3);
145     qSwap(m_opCode, other.m_opCode);
146     qSwap(m_length, other.m_length);
147     qSwap(m_payload, other.m_payload);
148     qSwap(m_isValid, other.m_isValid);
149
150     return *this;
151 }
152
153 #endif
154
155 /*!
156     \internal
157  */
158 void QWebSocketFrame::swap(QWebSocketFrame &other)
159 {
160     if (&other != this) {
161         qSwap(m_closeCode, other.m_closeCode);
162         qSwap(m_closeReason, other.m_closeReason);
163         qSwap(m_isFinalFrame, other.m_isFinalFrame);
164         qSwap(m_mask, other.m_mask);
165         qSwap(m_rsv1, other.m_rsv1);
166         qSwap(m_rsv2, other.m_rsv2);
167         qSwap(m_rsv3, other.m_rsv3);
168         qSwap(m_opCode, other.m_opCode);
169         qSwap(m_length, other.m_length);
170         qSwap(m_payload, other.m_payload);
171         qSwap(m_isValid, other.m_isValid);
172     }
173 }
174
175 /*!
176     \internal
177  */
178 QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
179 {
180     return m_closeCode;
181 }
182
183 /*!
184     \internal
185  */
186 QString QWebSocketFrame::closeReason() const
187 {
188     return m_closeReason;
189 }
190
191 /*!
192     \internal
193  */
194 bool QWebSocketFrame::isFinalFrame() const
195 {
196     return m_isFinalFrame;
197 }
198
199 /*!
200     \internal
201  */
202 bool QWebSocketFrame::isControlFrame() const
203 {
204     return (m_opCode & 0x08) == 0x08;
205 }
206
207 /*!
208     \internal
209  */
210 bool QWebSocketFrame::isDataFrame() const
211 {
212     return !isControlFrame();
213 }
214
215 /*!
216     \internal
217  */
218 bool QWebSocketFrame::isContinuationFrame() const
219 {
220     return isDataFrame() && (m_opCode == QWebSocketProtocol::OpCodeContinue);
221 }
222
223 /*!
224     \internal
225  */
226 bool QWebSocketFrame::hasMask() const
227 {
228     return m_mask != 0;
229 }
230
231 /*!
232     \internal
233  */
234 quint32 QWebSocketFrame::mask() const
235 {
236     return m_mask;
237 }
238
239 /*!
240     \internal
241  */
242 int QWebSocketFrame::rsv1() const
243 {
244     return m_rsv1;
245 }
246
247 /*!
248     \internal
249  */
250 int QWebSocketFrame::rsv2() const
251 {
252     return m_rsv2;
253 }
254
255 /*!
256     \internal
257  */
258 int QWebSocketFrame::rsv3() const
259 {
260     return m_rsv3;
261 }
262
263 /*!
264     \internal
265  */
266 QWebSocketProtocol::OpCode QWebSocketFrame::opCode() const
267 {
268     return m_opCode;
269 }
270
271 /*!
272     \internal
273  */
274 QByteArray QWebSocketFrame::payload() const
275 {
276     return m_payload;
277 }
278
279 /*!
280     Resets all member variables, and invalidates the object.
281
282     \internal
283  */
284 void QWebSocketFrame::clear()
285 {
286     m_closeCode = QWebSocketProtocol::CloseCodeNormal;
287     m_closeReason.clear();
288     m_isFinalFrame = true;
289     m_mask = 0;
290     m_rsv1 = 0;
291     m_rsv2 = 0;
292     m_rsv3 = 0;
293     m_opCode = QWebSocketProtocol::OpCodeReservedC;
294     m_length = 0;
295     m_payload.clear();
296     m_isValid = false;
297 }
298
299 /*!
300     \internal
301  */
302 bool QWebSocketFrame::isValid() const
303 {
304     return m_isValid;
305 }
306
307 // The arm compiler of Visual Studio 2013 Update 3 crashes when
308 // trying to optimize QWebSocketFrame::readFrame. Hence turn
309 // those off for this snippet
310 #if defined(Q_OS_WINPHONE) && defined(__ARM__)
311 #  pragma optimize("", off)
312 #endif
313
314 #define WAIT_FOR_MORE_DATA(dataSizeInBytes)  \
315     { returnState = processingState; \
316       processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
317
318 /*!
319     \internal
320  */
321 QWebSocketFrame QWebSocketFrame::readFrame(QIODevice *pIoDevice)
322 {
323     bool isDone = false;
324     qint64 bytesRead = 0;
325     QWebSocketFrame frame;
326     quint64 dataWaitSize = 0;
327     Q_UNUSED(dataWaitSize); // value is used in MACRO, Q_UNUSED to avoid compiler warnings
328     ProcessingState processingState = PS_READ_HEADER;
329     ProcessingState returnState = PS_READ_HEADER;
330     bool hasMask = false;
331     quint64 payloadLength = 0;
332
333     while (!isDone)
334     {
335         switch (processingState) {
336         case PS_WAIT_FOR_MORE_DATA:
337             //TODO: waitForReadyRead should really be changed
338             //now, when a WebSocket is used in a GUI thread
339             //the GUI will hang for at most 5 seconds
340             //maybe, a QStateMachine should be used
341             if (!pIoDevice->waitForReadyRead(5000)) {
342                 frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
343                                QObject::tr("Timeout when reading data from socket."));
344                 processingState = PS_DISPATCH_RESULT;
345             } else {
346                 processingState = returnState;
347             }
348             break;
349
350         case PS_READ_HEADER:
351             if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
352                 //FIN, RSV1-3, Opcode
353                 char header[2] = {0};
354                 bytesRead = pIoDevice->read(header, 2);
355                 frame.m_isFinalFrame = (header[0] & 0x80) != 0;
356                 frame.m_rsv1 = (header[0] & 0x40);
357                 frame.m_rsv2 = (header[0] & 0x20);
358                 frame.m_rsv3 = (header[0] & 0x10);
359                 frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
360
361                 //Mask, PayloadLength
362                 hasMask = (header[1] & 0x80) != 0;
363                 frame.m_length = (header[1] & 0x7F);
364
365                 switch (frame.m_length)
366                 {
367                     case 126:
368                     {
369                         processingState = PS_READ_PAYLOAD_LENGTH;
370                         break;
371                     }
372                     case 127:
373                     {
374                         processingState = PS_READ_BIG_PAYLOAD_LENGTH;
375                         break;
376                     }
377                     default:
378                     {
379                         payloadLength = frame.m_length;
380                         processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
381                         break;
382                     }
383                 }
384                 if (!frame.checkValidity())
385                     processingState = PS_DISPATCH_RESULT;
386             } else {
387                 WAIT_FOR_MORE_DATA(2);
388             }
389             break;
390
391         case PS_READ_PAYLOAD_LENGTH:
392             if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
393                 uchar length[2] = {0};
394                 bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 2);
395                 if (Q_UNLIKELY(bytesRead == -1)) {
396                     frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
397                                    QObject::tr("Error occurred while reading from the network: %1")
398                                         .arg(pIoDevice->errorString()));
399                     processingState = PS_DISPATCH_RESULT;
400                 } else {
401                     payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
402                     if (Q_UNLIKELY(payloadLength < 126)) {
403                         //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
404                         //"in all cases, the minimal number of bytes MUST be used to encode
405                         //the length, for example, the length of a 124-byte-long string
406                         //can't be encoded as the sequence 126, 0, 124"
407                         frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
408                                        QObject::tr("Lengths smaller than 126 " \
409                                                    "must be expressed as one byte."));
410                         processingState = PS_DISPATCH_RESULT;
411                     } else {
412                         processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
413                     }
414                 }
415             } else {
416                 WAIT_FOR_MORE_DATA(2);
417             }
418             break;
419
420         case PS_READ_BIG_PAYLOAD_LENGTH:
421             if (Q_LIKELY(pIoDevice->bytesAvailable() >= 8)) {
422                 uchar length[8] = {0};
423                 bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 8);
424                 if (Q_UNLIKELY(bytesRead < 8)) {
425                     frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
426                                    QObject::tr("Something went wrong during "\
427                                                "reading from the network."));
428                     processingState = PS_DISPATCH_RESULT;
429                 } else {
430                     //Most significant bit must be set to 0 as
431                     //per http://tools.ietf.org/html/rfc6455#section-5.2
432                     payloadLength = qFromBigEndian<quint64>(length);
433                     if (Q_UNLIKELY(payloadLength & (quint64(1) << 63))) {
434                         frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
435                                        QObject::tr("Highest bit of payload length is not 0."));
436                         processingState = PS_DISPATCH_RESULT;
437                     } else if (Q_UNLIKELY(payloadLength <= 0xFFFFu)) {
438                         //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
439                         //"in all cases, the minimal number of bytes MUST be used to encode
440                         //the length, for example, the length of a 124-byte-long string
441                         //can't be encoded as the sequence 126, 0, 124"
442                         frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
443                                        QObject::tr("Lengths smaller than 65536 (2^16) " \
444                                                    "must be expressed as 2 bytes."));
445                         processingState = PS_DISPATCH_RESULT;
446                     } else {
447                         processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
448                     }
449                 }
450             } else {
451                 WAIT_FOR_MORE_DATA(8);
452             }
453
454             break;
455
456         case PS_READ_MASK:
457             if (Q_LIKELY(pIoDevice->bytesAvailable() >= 4)) {
458                 bytesRead = pIoDevice->read(reinterpret_cast<char *>(&frame.m_mask),
459                                             sizeof(frame.m_mask));
460                 if (bytesRead == -1) {
461                     frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
462                                    QObject::tr("Error while reading from the network: %1.")
463                                         .arg(pIoDevice->errorString()));
464                     processingState = PS_DISPATCH_RESULT;
465                 } else {
466                     frame.m_mask = qFromBigEndian(frame.m_mask);
467                     processingState = PS_READ_PAYLOAD;
468                 }
469             } else {
470                 WAIT_FOR_MORE_DATA(4);
471             }
472             break;
473
474         case PS_READ_PAYLOAD:
475             if (!payloadLength) {
476                 processingState = PS_DISPATCH_RESULT;
477             } else if (Q_UNLIKELY(payloadLength > MAX_FRAME_SIZE_IN_BYTES)) {
478                 frame.setError(QWebSocketProtocol::CloseCodeTooMuchData,
479                                QObject::tr("Maximum framesize exceeded."));
480                 processingState = PS_DISPATCH_RESULT;
481             } else {
482                 quint64 bytesAvailable = quint64(pIoDevice->bytesAvailable());
483                 if (bytesAvailable >= payloadLength) {
484                     frame.m_payload = pIoDevice->read(payloadLength);
485                     //payloadLength can be safely cast to an integer,
486                     //because MAX_FRAME_SIZE_IN_BYTES = MAX_INT
487                     if (Q_UNLIKELY(frame.m_payload.length() != int(payloadLength))) {
488                         //some error occurred; refer to the Qt documentation of QIODevice::read()
489                         frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
490                                        QObject::tr("Some serious error occurred " \
491                                                    "while reading from the network."));
492                         processingState = PS_DISPATCH_RESULT;
493                     } else {
494                         if (hasMask)
495                             QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
496                         processingState = PS_DISPATCH_RESULT;
497                     }
498                 } else {
499                     //if payload is too big, then this will timeout
500                     WAIT_FOR_MORE_DATA(payloadLength);
501                 }
502             }
503             break;
504
505         case PS_DISPATCH_RESULT:
506             processingState = PS_READ_HEADER;
507             isDone = true;
508             break;
509
510         default:
511             //should not come here
512             qWarning() << "DataProcessor::process: Found invalid state. This should not happen!";
513             frame.clear();
514             isDone = true;
515             break;
516         }       //end switch
517     }
518
519     return frame;
520 }
521
522 #if defined(Q_OS_WINPHONE) && defined(__ARM__)
523 #  pragma optimize("", on)
524 #endif
525
526 /*!
527     \internal
528  */
529 void QWebSocketFrame::setError(QWebSocketProtocol::CloseCode code, const QString &closeReason)
530 {
531     clear();
532     m_closeCode = code;
533     m_closeReason = closeReason;
534     m_isValid = false;
535 }
536
537 /*!
538     \internal
539  */
540 bool QWebSocketFrame::checkValidity()
541 {
542     if (Q_UNLIKELY(m_rsv1 || m_rsv2 || m_rsv3)) {
543         setError(QWebSocketProtocol::CloseCodeProtocolError, QObject::tr("Rsv field is non-zero"));
544     } else if (Q_UNLIKELY(QWebSocketProtocol::isOpCodeReserved(m_opCode))) {
545         setError(QWebSocketProtocol::CloseCodeProtocolError, QObject::tr("Used reserved opcode"));
546     } else if (isControlFrame()) {
547         if (Q_UNLIKELY(m_length > 125)) {
548             setError(QWebSocketProtocol::CloseCodeProtocolError,
549                      QObject::tr("Controle frame is larger than 125 bytes"));
550         } else if (Q_UNLIKELY(!m_isFinalFrame)) {
551             setError(QWebSocketProtocol::CloseCodeProtocolError,
552                      QObject::tr("Controle frames cannot be fragmented"));
553         } else {
554             m_isValid = true;
555         }
556     } else {
557         m_isValid = true;
558     }
559     return m_isValid;
560 }
561
562 QT_END_NAMESPACE