2 QWebSockets implements the WebSocket protocol as defined in RFC 6455.
3 Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com)
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.
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.
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
20 #include "handshakerequest_p.h"
23 #include <QTextStream>
26 #include <QStringList>
27 #include "qwebsocketprotocol.h"
34 HandshakeRequest::HandshakeRequest(int port, bool isSecure) :
51 HandshakeRequest::~HandshakeRequest()
58 void HandshakeRequest::clear()
75 int HandshakeRequest::getPort() const
77 return m_requestUrl.port(m_port);
83 bool HandshakeRequest::isSecure() const
91 bool HandshakeRequest::isValid() const
99 QMap<QString, QString> HandshakeRequest::getHeaders() const
107 QList<QWebSocketProtocol::Version> HandshakeRequest::getVersions() const
115 QString HandshakeRequest::getResourceName() const
117 return m_requestUrl.path();
123 QString HandshakeRequest::getKey() const
131 QString HandshakeRequest::getHost() const
133 return m_requestUrl.host();
139 QString HandshakeRequest::getOrigin() const
147 QList<QString> HandshakeRequest::getProtocols() const
155 QList<QString> HandshakeRequest::getExtensions() const
163 QUrl HandshakeRequest::getRequestUrl() const
171 QTextStream &HandshakeRequest::readFromStream(QTextStream &textStream)
175 if (textStream.status() == QTextStream::Ok)
177 QString requestLine = textStream.readLine();
178 QStringList tokens = requestLine.split(' ', QString::SkipEmptyParts);
179 QString verb = tokens[0];
180 QString resourceName = tokens[1];
181 QString httpProtocol = tokens[2];
182 bool conversionOk = false;
183 float httpVersion = httpProtocol.midRef(5).toFloat(&conversionOk);
185 QString headerLine = textStream.readLine();
187 while (!headerLine.isEmpty())
189 QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
190 m_headers.insertMulti(headerField[0], headerField[1]);
191 headerLine = textStream.readLine();
194 QString host = m_headers.value("Host", "");
195 m_requestUrl = QUrl::fromEncoded(resourceName.toLatin1());
196 if (m_requestUrl.isRelative())
198 m_requestUrl.setHost(host);
200 if (m_requestUrl.scheme().isEmpty())
202 QString scheme = isSecure() ? "wss://" : "ws://";
203 m_requestUrl.setScheme(scheme);
206 QStringList versionLines = m_headers.values("Sec-WebSocket-Version");
207 Q_FOREACH(QString versionLine, versionLines)
209 QStringList versions = versionLine.split(",", QString::SkipEmptyParts);
210 Q_FOREACH(QString version, versions)
212 QWebSocketProtocol::Version ver = QWebSocketProtocol::versionFromString(version.trimmed());
216 qStableSort(m_versions.begin(), m_versions.end(), qGreater<QWebSocketProtocol::Version>()); //sort in descending order
217 m_key = m_headers.value("Sec-WebSocket-Key", "");
218 QString upgrade = m_headers.value("Upgrade", ""); //must be equal to "websocket", case-insensitive
219 QString connection = m_headers.value("Connection", ""); //must contain "Upgrade", case-insensitive
220 QStringList connectionLine = connection.split(",", QString::SkipEmptyParts);
221 QStringList connectionValues;
222 Q_FOREACH(QString connection, connectionLine)
224 connectionValues << connection.trimmed();
228 m_origin = m_headers.value("Sec-WebSocket-Origin", "");
229 QStringList protocolLines = m_headers.values("Sec-WebSocket-Protocol");
230 Q_FOREACH(QString protocolLine, protocolLines)
232 QStringList protocols = protocolLine.split(",", QString::SkipEmptyParts);
233 Q_FOREACH(QString protocol, protocols)
235 m_protocols << protocol.trimmed();
238 QStringList extensionLines = m_headers.values("Sec-WebSocket-Extensions");
239 Q_FOREACH(QString extensionLine, extensionLines)
241 QStringList extensions = extensionLine.split(",", QString::SkipEmptyParts);
242 Q_FOREACH(QString extension, extensions)
244 m_extensions << extension.trimmed();
247 //TODO: authentication field
249 m_isValid = !(host.isEmpty() ||
250 resourceName.isEmpty() ||
251 m_versions.isEmpty() ||
254 (!conversionOk || (httpVersion < 1.1f)) ||
255 (upgrade.toLower() != "websocket") ||
256 (!connectionValues.contains("upgrade", Qt::CaseInsensitive)));
264 QTextStream &operator >>(QTextStream &stream, HandshakeRequest &request)
266 return request.readFromStream(stream);