697f16ffa723d20ec4285a754c7e2fc65ce1d245
[contrib/qtwebsockets.git] / src / websockets / qwebsocketprotocol.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 #include "qwebsocketprotocol_p.h"
35 #include <QtCore/QString>
36 #include <QtCore/QSet>
37 #include <QtCore/QtEndian>
38
39 QT_BEGIN_NAMESPACE
40
41 /*!
42   \namespace QWebSocketProtocol
43   \inmodule QtWebSockets
44   \brief Contains constants related to the WebSocket standard.
45 */
46
47 /*!
48     \enum QWebSocketProtocol::CloseCode
49
50     \inmodule QtWebSockets
51
52     The close codes supported by WebSockets V13
53
54     \value CloseCodeNormal                  Normal closure
55     \value CloseCodeGoingAway               Going away
56     \value CloseCodeProtocolError           Protocol error
57     \value CloseCodeDatatypeNotSupported    Unsupported data
58     \value CloseCodeReserved1004            Reserved
59     \value CloseCodeMissingStatusCode       No status received
60     \value CloseCodeAbnormalDisconnection   Abnormal closure
61     \value CloseCodeWrongDatatype           Invalid frame payload data
62     \value CloseCodePolicyViolated          Policy violation
63     \value CloseCodeTooMuchData             Message too big
64     \value CloseCodeMissingExtension        Mandatory extension missing
65     \value CloseCodeBadOperation            Internal server error
66     \value CloseCodeTlsHandshakeFailed      TLS handshake failed
67
68     \sa QWebSocket::close()
69 */
70 /*!
71     \enum QWebSocketProtocol::Version
72
73     \inmodule QtWebSockets
74
75     \brief The different defined versions of the WebSocket protocol.
76
77     For an overview of the differences between the different protocols, see
78     <http://code.google.com/p/pywebsocket/wiki/WebSocketProtocolSpec>
79
80     \value VersionUnknown   Unknown or unspecified version.
81     \value Version0         hixie76:
82                             http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 &
83                             hybi-00:
84                             http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00.
85                             Works with key1, key2 and a key in the payload.
86                             Attribute: Sec-WebSocket-Draft value 0.
87                             Not supported by QtWebSockets.
88     \value Version4         hybi-04:
89                             http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-04.txt.
90                             Changed handshake: key1, key2, key3
91                             ==> Sec-WebSocket-Key, Sec-WebSocket-Nonce, Sec-WebSocket-Accept
92                             Sec-WebSocket-Draft renamed to Sec-WebSocket-Version
93                             Sec-WebSocket-Version = 4.
94                             Not supported by QtWebSockets.
95     \value Version5         hybi-05:
96                             http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-05.txt.
97                             Sec-WebSocket-Version = 5
98                             Removed Sec-WebSocket-Nonce
99                             Added Sec-WebSocket-Accept.
100                             Not supported by QtWebSockets.
101     \value Version6         Sec-WebSocket-Version = 6.
102                             Not supported by QtWebSockets.
103     \value Version7         hybi-07:
104                             http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07.
105                             Sec-WebSocket-Version = 7.
106                             Not supported by QtWebSockets.
107     \value Version8         hybi-8, hybi-9, hybi-10, hybi-11 and hybi-12.
108                             Status codes 1005 and 1006 are added and all codes are now unsigned
109                             Internal error results in 1006.
110                             Not supported by QtWebSockets.
111     \value Version13        hybi-13, hybi14, hybi-15, hybi-16, hybi-17 and RFC 6455.
112                             Sec-WebSocket-Version = 13
113                             Status code 1004 is now reserved
114                             Added 1008, 1009 and 1010
115                             Must support TLS
116                             Clarify multiple version support.
117                             Supported by QtWebSockets.
118     \value VersionLatest    Refers to the latest known version to QtWebSockets.
119 */
120
121 /*!
122     \enum QWebSocketProtocol::OpCode
123
124     \inmodule QtWebSockets
125
126     The frame opcodes as defined by the WebSockets standard
127
128     \value OpCodeContinue     Continuation frame
129     \value OpCodeText         Text frame
130     \value OpCodeBinary       Binary frame
131     \value OpCodeReserved3    Reserved
132     \value OpCodeReserved4    Reserved
133     \value OpCodeReserved5    Reserved
134     \value OpCodeReserved6    Reserved
135     \value OpCodeReserved7    Reserved
136     \value OpCodeClose        Close frame
137     \value OpCodePing         Ping frame
138     \value OpCodePong         Pong frame
139     \value OpCodeReservedB    Reserved
140     \value OpCodeReservedC    Reserved
141     \value OpCodeReservedD    Reserved
142     \value OpCodeReservedE    Reserved
143     \value OpCodeReservedF    Reserved
144
145     \internal
146 */
147
148 /*!
149   \fn QWebSocketProtocol::isOpCodeReserved(OpCode code)
150   Checks if \a code is a valid OpCode
151
152   \internal
153 */
154
155 /*!
156   \fn QWebSocketProtocol::isCloseCodeValid(int closeCode)
157   Checks if \a closeCode is a valid WebSocket close code
158
159   \internal
160 */
161
162 /*!
163   \fn QWebSocketProtocol::currentVersion()
164   Returns the latest version that WebSocket is supporting
165
166   \internal
167 */
168
169 /*!
170     Parses the \a versionString and converts it to a Version value
171
172     \internal
173 */
174 QWebSocketProtocol::Version QWebSocketProtocol::versionFromString(const QString &versionString)
175 {
176     bool ok = false;
177     Version version = VersionUnknown;
178     const int ver = versionString.toInt(&ok);
179     QSet<Version> supportedVersions;
180     supportedVersions << Version0 << Version4 << Version5 << Version6 << Version7 << Version8
181                       << Version13;
182     if (Q_LIKELY(ok) && (supportedVersions.contains(static_cast<Version>(ver))))
183         version = static_cast<Version>(ver);
184     return version;
185 }
186
187 /*!
188     Mask the \a payload with the given \a maskingKey and stores the result back in \a payload.
189
190     \internal
191 */
192 void QWebSocketProtocol::mask(QByteArray *payload, quint32 maskingKey)
193 {
194     Q_ASSERT(payload);
195     mask(payload->data(), payload->size(), maskingKey);
196 }
197
198 /*!
199     Masks the \a payload of length \a size with the given \a maskingKey and
200     stores the result back in \a payload.
201
202     \internal
203 */
204 void QWebSocketProtocol::mask(char *payload, quint64 size, quint32 maskingKey)
205 {
206     Q_ASSERT(payload);
207     const quint8 mask[] = { quint8((maskingKey & 0xFF000000u) >> 24),
208                             quint8((maskingKey & 0x00FF0000u) >> 16),
209                             quint8((maskingKey & 0x0000FF00u) >> 8),
210                             quint8((maskingKey & 0x000000FFu))
211                           };
212     int i = 0;
213     while (size-- > 0)
214         *payload++ ^= mask[i++ % 4];
215 }
216
217 QT_END_NAMESPACE