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