There was no '?' between path and query. Bug detected by someone on the internet.
[contrib/qtwebsockets.git] / src / qwebsocketserver_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 #include <QTcpServer>
21 #include <QTcpSocket>
22 #include <QNetworkProxy>
23 #include "qwebsocketserver.h"
24 #include "qwebsocketserver_p.h"
25 #include "qwebsocketprotocol.h"
26 #include "handshakerequest_p.h"
27 #include "handshakeresponse_p.h"
28 #include "qwebsocket.h"
29 #include "qwebsocket_p.h"
30 #include "qcorsauthenticator.h"
31
32 QT_BEGIN_NAMESPACE
33
34 /*!
35     \internal
36  */
37 QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName, QWebSocketServer * const pWebSocketServer, QObject *parent) :
38     QObject(parent),
39     q_ptr(pWebSocketServer),
40     m_pTcpServer(0),
41     m_serverName(serverName),
42     m_pendingConnections()
43 {
44     Q_ASSERT(pWebSocketServer != 0);
45     m_pTcpServer = new QTcpServer(this);
46     connect(m_pTcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), q_ptr, SIGNAL(acceptError(QAbstractSocket::SocketError)));
47     connect(m_pTcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
48 }
49
50 /*!
51     \internal
52  */
53 QWebSocketServerPrivate::~QWebSocketServerPrivate()
54 {
55     while (!m_pendingConnections.isEmpty())
56     {
57         QWebSocket *pWebSocket = m_pendingConnections.dequeue();
58         pWebSocket->close(QWebSocketProtocol::CC_GOING_AWAY, tr("Server closed."));
59         pWebSocket->deleteLater();
60     }
61     m_pTcpServer->deleteLater();
62 }
63
64 /*!
65     \internal
66  */
67 void QWebSocketServerPrivate::close()
68 {
69     m_pTcpServer->close();
70 }
71
72 /*!
73     \internal
74  */
75 QString QWebSocketServerPrivate::errorString() const
76 {
77     return m_pTcpServer->errorString();
78 }
79
80 /*!
81     \internal
82  */
83 bool QWebSocketServerPrivate::hasPendingConnections() const
84 {
85     return !m_pendingConnections.isEmpty();
86 }
87
88 /*!
89     \internal
90  */
91 bool QWebSocketServerPrivate::isListening() const
92 {
93     return m_pTcpServer->isListening();
94 }
95
96 /*!
97     \internal
98  */
99 bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
100 {
101     return m_pTcpServer->listen(address, port);
102 }
103
104 /*!
105     \internal
106  */
107 int QWebSocketServerPrivate::maxPendingConnections() const
108 {
109     return m_pTcpServer->maxPendingConnections();
110 }
111
112 /*!
113     \internal
114  */
115 void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
116 {
117     if (m_pendingConnections.size() < maxPendingConnections())
118     {
119         m_pendingConnections.enqueue(pWebSocket);
120     }
121 }
122
123 /*!
124     \internal
125  */
126 QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
127 {
128     QWebSocket *pWebSocket = 0;
129     if (!m_pendingConnections.isEmpty())
130     {
131         pWebSocket = m_pendingConnections.dequeue();
132     }
133     return pWebSocket;
134 }
135
136 /*!
137     \internal
138  */
139 void QWebSocketServerPrivate::pauseAccepting()
140 {
141     m_pTcpServer->pauseAccepting();
142 }
143
144 #ifndef QT_NO_NETWORKPROXY
145 /*!
146     \internal
147  */
148 QNetworkProxy QWebSocketServerPrivate::proxy() const
149 {
150     return m_pTcpServer->proxy();
151 }
152
153 /*!
154     \internal
155  */
156 void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
157 {
158     m_pTcpServer->setProxy(networkProxy);
159 }
160 #endif
161 /*!
162     \internal
163  */
164 void QWebSocketServerPrivate::resumeAccepting()
165 {
166     m_pTcpServer->resumeAccepting();
167 }
168
169 /*!
170     \internal
171  */
172 QHostAddress QWebSocketServerPrivate::serverAddress() const
173 {
174     return m_pTcpServer->serverAddress();
175 }
176
177 /*!
178     \internal
179  */
180 QAbstractSocket::SocketError QWebSocketServerPrivate::serverError() const
181 {
182     return m_pTcpServer->serverError();
183 }
184
185 /*!
186     \internal
187  */
188 quint16 QWebSocketServerPrivate::serverPort() const
189 {
190     return m_pTcpServer->serverPort();
191 }
192
193 /*!
194     \internal
195  */
196 void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
197 {
198     m_pTcpServer->setMaxPendingConnections(numConnections);
199 }
200
201 /*!
202     \internal
203  */
204 bool QWebSocketServerPrivate::setSocketDescriptor(int socketDescriptor)
205 {
206     return m_pTcpServer->setSocketDescriptor(socketDescriptor);
207 }
208
209 /*!
210     \internal
211  */
212 int QWebSocketServerPrivate::socketDescriptor() const
213 {
214     return m_pTcpServer->socketDescriptor();
215 }
216
217 /*!
218     \internal
219  */
220 bool QWebSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut)
221 {
222     return m_pTcpServer->waitForNewConnection(msec, timedOut);
223 }
224
225 /*!
226     \internal
227  */
228 QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
229 {
230     QList<QWebSocketProtocol::Version> supportedVersions;
231     supportedVersions << QWebSocketProtocol::currentVersion();  //we only support V13
232     return supportedVersions;
233 }
234
235 /*!
236     \internal
237  */
238 QList<QString> QWebSocketServerPrivate::supportedProtocols() const
239 {
240     QList<QString> supportedProtocols;
241     return supportedProtocols;  //no protocols are currently supported
242 }
243
244 /*!
245     \internal
246  */
247 QList<QString> QWebSocketServerPrivate::supportedExtensions() const
248 {
249     QList<QString> supportedExtensions;
250     return supportedExtensions; //no extensions are currently supported
251 }
252
253 /*!
254   \internal
255  */
256 void QWebSocketServerPrivate::setServerName(const QString &serverName)
257 {
258     m_serverName = serverName;
259 }
260
261 /*!
262   \internal
263  */
264 QString QWebSocketServerPrivate::serverName() const
265 {
266     return m_serverName;
267 }
268
269 /*!
270     \internal
271  */
272 void QWebSocketServerPrivate::onNewConnection()
273 {
274     QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
275     connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(handshakeReceived()));
276 }
277
278 /*!
279     \internal
280  */
281 void QWebSocketServerPrivate::onCloseConnection()
282 {
283     QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
284     if (pTcpSocket != 0)
285     {
286         pTcpSocket->close();
287     }
288 }
289
290 /*!
291     \internal
292  */
293 void QWebSocketServerPrivate::handshakeReceived()
294 {
295     Q_Q(QWebSocketServer);
296     QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
297     if (pTcpSocket != 0)
298     {
299         bool success = false;
300         bool isSecure = false;
301         HandshakeRequest request(pTcpSocket->peerPort(), isSecure);
302         QTextStream textStream(pTcpSocket);
303         textStream >> request;
304
305         QCorsAuthenticator corsAuthenticator(request.getOrigin());
306         Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
307
308         HandshakeResponse response(request,
309                                    m_serverName,
310                                    corsAuthenticator.allowed(),
311                                    supportedVersions(),
312                                    supportedProtocols(),
313                                    supportedExtensions());
314         disconnect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(handshakeReceived()));
315
316         if (response.isValid())
317         {
318             QTextStream httpStream(pTcpSocket);
319             httpStream << response;
320             httpStream.flush();
321
322             if (response.canUpgrade())
323             {
324                 QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket, request, response);
325                 if (pWebSocket)
326                 {
327                     pWebSocket->setParent(this);
328                     addPendingConnection(pWebSocket);
329                     Q_EMIT q->newConnection();
330                     success = true;
331                 }
332                 else
333                 {
334                     //TODO: should set or emit error
335                     qDebug() << tr("Upgrading to websocket failed.");
336                 }
337             }
338             else
339             {
340                 //TODO: should set or emit error
341                 qDebug() << tr("Cannot upgrade to websocket.");
342             }
343         }
344         else
345         {
346             //TODO: should set or emit error
347             qDebug() << tr("Invalid response received.");
348         }
349         if (!success)
350         {
351             //TODO: should set or emit error
352             qDebug() << tr("Closing socket because of invalid or unsupported request.");
353             pTcpSocket->close();
354         }
355     }
356     else
357     {
358         qWarning() << "Sender socket is NULL. This should not happen, otherwise it is a Qt bug!!!";
359     }
360 }
361
362 QT_END_NAMESPACE