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