@@ -23,17 +23,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
23
23
#include < QCryptographicHash>
24
24
#include < QDateTime>
25
25
26
- const QString QWsServer::regExpResourceNameStr (QLatin1String(" ^GET\\ s(.*)\\ sHTTP/1.1\r\n " ));
27
- const QString QWsServer::regExpHostStr (QLatin1String(" \r\n Host:\\ s(.+(:\\ d+)?)\r\n " ));
28
- const QString QWsServer::regExpKeyStr (QLatin1String(" \r\n Sec-WebSocket-Key:\\ s(.{24})\r\n " ));
29
- const QString QWsServer::regExpKey1Str (QLatin1String(" \r\n Sec-WebSocket-Key1:\\ s(.+)\r\n " ));
30
- const QString QWsServer::regExpKey2Str (QLatin1String(" \r\n Sec-WebSocket-Key2:\\ s(.+)\r\n " ));
31
- // const QString QWsServer::regExpKey3Str(QLatin1String("\r\n(.{8})$"));
32
- const QString QWsServer::regExpVersionStr (QLatin1String(" \r\n Sec-WebSocket-Version:\\ s(\\ d+)\r\n " ));
33
- const QString QWsServer::regExpOriginStr (QLatin1String(" \r\n Sec-WebSocket-Origin:\\ s(.+)\r\n " ));
34
- const QString QWsServer::regExpOrigin2Str (QLatin1String(" \r\n Origin:\\ s(.+)\r\n " ));
35
- const QString QWsServer::regExpProtocolStr (QLatin1String(" \r\n Sec-WebSocket-Protocol:\\ s(.+)\r\n " ));
36
- const QString QWsServer::regExpExtensionsStr (QLatin1String(" \r\n Sec-WebSocket-Extensions:\\ s(.+)\r\n " ));
26
+ QRegExp QWsServer::regExpHttpRequest (QLatin1String(" ^GET\\ s(.*)\\ sHTTP/1.1\\ r\\ n" ));
27
+ QRegExp QWsServer::regExpHost (QLatin1String(" \\ r\\ nHost:\\ s(([^:]+)(:([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?)\\ r\\ n" ));
28
+ QRegExp QWsServer::regExpKey (QLatin1String(" \\ r\\ nSec-WebSocket-Key:\\ s(.{24})\\ r\\ n" ));
29
+ QRegExp QWsServer::regExpKey1 (QLatin1String(" \\ r\\ nSec-WebSocket-Key1:\\ s(.+)\\ r\\ n" ));
30
+ QRegExp QWsServer::regExpKey2 (QLatin1String(" \\ r\\ nSec-WebSocket-Key2:\\ s(.+)\\ r\\ n" ));
31
+ QRegExp QWsServer::regExpVersion (QLatin1String(" \\ r\\ nSec-WebSocket-Version:\\ s(\\ d+)\\ r\\ n" ));
32
+ QRegExp QWsServer::regExpOrigin (QLatin1String(" \\ r\\ n(Origin|Sec-WebSocket-Origin):\\ s(.+)\\ r\\ n" ));
33
+ QRegExp QWsServer::regExpProtocol (QLatin1String(" \\ r\\ nSec-WebSocket-Protocol:\\ s(.+)\\ r\\ n" ));
34
+ QRegExp QWsServer::regExpExtensions (QLatin1String(" \\ r\\ nSec-WebSocket-Extensions:\\ s(.+)\\ r\\ n" ));
37
35
38
36
QWsServer::QWsServer (QObject* parent)
39
37
: QObject(parent)
@@ -140,103 +138,108 @@ void QWsServer::dataReceived()
140
138
return ;
141
139
}
142
140
143
- QRegExp regExp;
144
- regExp.setMinimal (true );
145
-
146
- // Extract mandatory datas
141
+ // Extract mandatory fields
142
+
143
+ bool missingField = false ;
144
+
145
+ // HTTP REQUEST and Resource name
146
+ regExpHttpRequest.setMinimal (true );
147
+ if (regExpHttpRequest.indexIn (request) == -1 )
148
+ {
149
+ missingField = true ;
150
+ }
151
+ QString resourceName = regExpHttpRequest.cap (1 );
152
+
153
+ // Host (address & port)
154
+ regExpHost.setMinimal (true );
155
+ if (regExpHost.indexIn (request) == -1 )
156
+ {
157
+ missingField = true ;
158
+ }
159
+ QString host = regExpHost.cap (1 );
160
+ QString hostAddress = regExpHost.cap (2 );
161
+ QString hostPort = regExpHost.cap (4 );
162
+
147
163
// Version
148
- regExp.setPattern (QWsServer::regExpVersionStr);
149
- regExp.indexIn (request);
150
- QString versionStr = regExp.cap (1 );
151
164
QByteArray key3;
152
165
EWebsocketVersion version;
153
- if (! versionStr.isEmpty ())
154
- {
155
- version = (EWebsocketVersion)versionStr.toInt ();
156
- }
157
- else if (tcpSocket->bytesAvailable () >= 8 )
166
+ regExpVersion.setMinimal (true );
167
+ if (regExpVersion.indexIn (request) == -1 )
158
168
{
159
- version = WS_V0;
160
- key3 = tcpSocket->read (8 );
161
- request.append (key3);
169
+ if (tcpSocket->bytesAvailable () == 8 )
170
+ {
171
+ version = WS_V0;
172
+ key3 = tcpSocket->read (8 );
173
+ request += key3;
174
+ }
175
+ else
176
+ {
177
+ version = WS_VUnknow;
178
+ }
162
179
}
163
180
else
164
181
{
165
- version = WS_VUnknow ;
182
+ version = (EWebsocketVersion)regExpVersion. cap ( 1 ). toUInt () ;
166
183
}
167
184
168
- // Resource name
169
- regExp.setPattern (QWsServer::regExpResourceNameStr);
170
- regExp.indexIn (request);
171
- QString resourceName = regExp.cap (1 );
172
-
173
- // Host (address & port)
174
- regExp.setPattern (QWsServer::regExpHostStr);
175
- regExp.indexIn (request);
176
- QString host = regExp.cap (1 );
177
- QStringList hostTmp = host.split (' :' );
178
- QString hostAddress = hostTmp[0 ];
179
- QString hostPort;
180
- if (hostTmp.size () > 1 )
181
- {
182
- hostPort = hostTmp.last (); // fix for IPv6
183
- }
184
-
185
185
// Key
186
- QString key, key1, key2;
186
+ QByteArray key, key1, key2;
187
187
if (version >= WS_V4)
188
188
{
189
- regExp. setPattern (QWsServer::regExpKeyStr );
190
- regExp .indexIn (request);
191
- key = regExp .cap (1 );
189
+ regExpKey. setMinimal ( true );
190
+ regExpKey .indexIn (request);
191
+ key = regExpKey .cap (1 ). toUtf8 ( );
192
192
}
193
193
else
194
194
{
195
- regExp.setPattern (QWsServer::regExpKey1Str);
196
- regExp.indexIn (request);
197
- key1 = regExp.cap (1 );
198
- regExp.setPattern (QWsServer::regExpKey2Str);
199
- regExp.indexIn (request);
200
- key2 = regExp.cap (1 );
195
+ regExpKey1.setMinimal (true );
196
+ regExpKey1.indexIn (request);
197
+ key1 = regExpKey1.cap (1 ).toLatin1 ();
198
+
199
+ regExpKey2.setMinimal (true );
200
+ regExpKey2.indexIn (request);
201
+ key2 = regExpKey2.cap (1 ).toLatin1 ();
201
202
}
202
203
203
- // //////////////////////////////////////////////////////////////////
204
+ // //////////////////////////////////////////////////////////////
204
205
205
206
// If the mandatory fields are not specified, we abord the connection to the Websocket server
206
- if (version == WS_VUnknow || resourceName.isEmpty () || hostAddress.isEmpty () || (key.isEmpty () && (key1.isEmpty () || key2.isEmpty () || key3.isEmpty ())))
207
+ if ( missingField
208
+ || version == WS_VUnknow
209
+ || resourceName.isEmpty ()
210
+ || hostAddress.isEmpty ()
211
+ || ((key.isEmpty () && (key1.isEmpty () || key2.isEmpty () || key3.isEmpty ()))) )
207
212
{
208
213
showErrorAndClose (tcpSocket);
209
214
return ;
210
215
}
211
216
212
- // //////////////////////////////////////////////////////////////////
217
+ // //////////////////////////////////////////////////////////////
213
218
214
- QObject::disconnect (tcpSocket, SIGNAL (disconnected ()), this , SLOT (disconnected ()));
215
- headerBuffer.remove (tcpSocket);
216
-
217
- // Extract optional datas
219
+ // Extract optional fields
218
220
219
221
// Origin
220
- regExp.setPattern (QWsServer::regExpOriginStr);
221
- if (regExp.indexIn (request) == -1 )
222
- {
223
- regExp.setPattern (QWsServer::regExpOrigin2Str);
224
- regExp.indexIn (request);
225
- }
226
- QString origin = regExp.cap (1 );
222
+ regExpOrigin.setMinimal (true );
223
+ regExpOrigin.indexIn (request);
224
+ QString origin = regExpOrigin.cap (2 );
227
225
228
226
// Protocol
229
- regExp. setPattern (QWsServer::regExpProtocolStr );
230
- regExp .indexIn (request);
231
- QString protocol = regExp .cap (1 );
227
+ regExpProtocol. setMinimal ( true );
228
+ regExpProtocol .indexIn (request);
229
+ QString protocol = regExpProtocol .cap (1 );
232
230
233
231
// Extensions
234
- regExp. setPattern (QWsServer::regExpExtensionsStr );
235
- regExp .indexIn (request);
236
- QString extensions = regExp .cap (1 );
232
+ regExpExtensions. setMinimal ( true );
233
+ regExpExtensions .indexIn (request);
234
+ QString extensions = regExpExtensions .cap (1 );
237
235
238
- // //////////////////////////////////////////////////////////////////
236
+ // //////////////////////////////////////////////////////////////
239
237
238
+ // Handshake fully parsed
239
+ QObject::disconnect (tcpSocket, SIGNAL (readyRead ()), this , SLOT (dataReceived ()));
240
+ QObject::disconnect (tcpSocket, SIGNAL (disconnected ()), this , SLOT (disconnected ()));
241
+ headerBuffer.remove (tcpSocket);
242
+
240
243
// Compose opening handshake response
241
244
QString response;
242
245
@@ -257,9 +260,6 @@ void QWsServer::dataReceived()
257
260
response = QWsServer::composeOpeningHandshakeResponseV0 (accept, origin, hostAddress, hostPort, resourceName , protocol);
258
261
}
259
262
260
- // Handshake OK, disconnect readyRead
261
- QObject::disconnect (tcpSocket, SIGNAL (readyRead ()), this , SLOT (dataReceived ()));
262
-
263
263
// Send opening handshake response
264
264
if (version == WS_V0)
265
265
{
@@ -372,10 +372,10 @@ bool QWsServer::waitForNewConnection(int msec, bool* timedOut)
372
372
return tcpServer->waitForNewConnection (msec, timedOut);
373
373
}
374
374
375
- QByteArray QWsServer::computeAcceptV0 (QString key1, QString key2, QByteArray key3)
375
+ QByteArray QWsServer::computeAcceptV0 (QByteArray key1, QByteArray key2, QByteArray key3)
376
376
{
377
- quint32 key_number_1 = QString (key1).remove (QRegExp (" [^\\ d]" )).toUInt ();
378
- quint32 key_number_2 = QString (key2).remove (QRegExp (" [^\\ d]" )).toUInt ();
377
+ quint32 key_number_1 = QString::fromLatin1 (key1).remove (QRegExp (QLatin1String ( " [^\\ d]" ) )).toUInt ();
378
+ quint32 key_number_2 = QString::fromLatin1 (key2).remove (QRegExp (QLatin1String ( " [^\\ d]" ) )).toUInt ();
379
379
380
380
int spaces_1 = key1.count (' ' );
381
381
int spaces_2 = key2.count (' ' );
@@ -393,10 +393,10 @@ QByteArray QWsServer::computeAcceptV0(QString key1, QString key2, QByteArray key
393
393
return md5;
394
394
}
395
395
396
- QByteArray QWsServer::computeAcceptV4 (QString key)
396
+ QByteArray QWsServer::computeAcceptV4 (QByteArray key)
397
397
{
398
398
key += QLatin1String (" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" );
399
- QByteArray hash = QCryptographicHash::hash (key. toUtf8 () , QCryptographicHash::Sha1);
399
+ QByteArray hash = QCryptographicHash::hash (key, QCryptographicHash::Sha1);
400
400
return hash.toBase64 ();
401
401
}
402
402
@@ -405,8 +405,8 @@ QByteArray QWsServer::generateNonce()
405
405
qsrand (QDateTime::currentDateTime ().toTime_t ());
406
406
407
407
QByteArray nonce;
408
- int i = 16 ;
409
408
409
+ int i = 16 ;
410
410
while (i--)
411
411
{
412
412
nonce.append (qrand () % 0x100 );
@@ -418,85 +418,85 @@ QByteArray QWsServer::generateNonce()
418
418
QString QWsServer::composeOpeningHandshakeResponseV0 (QByteArray accept, QString origin, QString hostAddress, QString hostPort, QString resourceName, QString protocol)
419
419
{
420
420
QString response;
421
-
422
- response.append (QLatin1String (" HTTP/1.1 101 WebSocket Protocol Handshake\r\n " ));
423
- response.append (QLatin1String (" Upgrade: Websocket\r\n " ));
424
- response.append (QLatin1String (" Connection: Upgrade\r\n " ));
425
- response.append (QLatin1String (" Sec-WebSocket-Origin: " ) + origin + QLatin1String (" \r\n " ));
426
- response.append (QLatin1String (" Sec-WebSocket-Location: ws://" ) + hostAddress);
421
+ response += QLatin1String (" HTTP/1.1 101 WebSocket Protocol Handshake\r\n " );
422
+ response += QLatin1String (" Upgrade: Websocket\r\n " );
423
+ response += QLatin1String (" Connection: Upgrade\r\n " );
424
+ response += QString (" Sec-WebSocket-Origin: %1\r\n " ).arg (origin);
425
+ if (!hostAddress.startsWith (" ws://" , Qt::CaseInsensitive))
426
+ {
427
+ hostAddress.prepend (QLatin1String (" ws://" ));
428
+ }
427
429
if (!hostPort.isEmpty ())
428
430
{
429
- response. append ( QLatin1String ( " : " ) + hostPort );
431
+ hostPort. prepend ( QLatin1Char ( ' : ' ) );
430
432
}
431
- response. append (resourceName + QLatin1String ( " \r\n " ));
432
- if (! protocol.isEmpty ())
433
+ response += QString ( " Sec-WebSocket-Location: %1%2%3 \r\n " ). arg (hostAddress). arg (hostPort). arg (resourceName );
434
+ if (!protocol.isEmpty ())
433
435
{
434
- response. append ( QLatin1String ( " Sec-WebSocket-Protocol: " ) + protocol + QLatin1String ( " \r\n " ));
436
+ response += QString ( " Sec-WebSocket-Protocol: %1 \r\n " ). arg (protocol );
435
437
}
436
- response. append ( QLatin1String (" \r\n " ) );
437
- response. append ( QLatin1String (accept) );
438
+ response += QLatin1String (" \r\n " );
439
+ response += QLatin1String (accept);
438
440
439
441
return response;
440
442
}
441
443
442
444
QString QWsServer::composeOpeningHandshakeResponseV4 (QByteArray accept, QByteArray nonce, QString protocol, QString extensions)
443
445
{
444
446
QString response;
445
-
446
- response.append (QLatin1String (" HTTP/1.1 101 Switching Protocols\r\n " ));
447
- response.append (QLatin1String (" Upgrade: websocket\r\n " ));
448
- response.append (QLatin1String (" Connection: Upgrade\r\n " ));
449
- response.append (QLatin1String (" Sec-WebSocket-Accept: " ) + QLatin1String (accept) + QLatin1String (" \r\n " ));
450
- response.append (QLatin1String (" Sec-WebSocket-Nonce: " ) + QLatin1String (nonce) + QLatin1String (" \r\n " ));
451
- if (! protocol.isEmpty ())
447
+ response += QLatin1String (" HTTP/1.1 101 WebSocket Protocol Handshake\r\n " );
448
+ response += QLatin1String (" Upgrade: websocket\r\n " );
449
+ response += QLatin1String (" Connection: Upgrade\r\n " );
450
+ response += QString (" Sec-WebSocket-Accept: %1\r\n " ).arg (QLatin1String (accept));
451
+ response += QString (" Sec-WebSocket-Nonce: %1\r\n " ).arg (QLatin1String (nonce));
452
+ if (!protocol.isEmpty ())
452
453
{
453
- response. append ( QLatin1String ( " Sec-WebSocket-Protocol: " ) + protocol + QLatin1String ( " \r\n " ));
454
+ response += QString ( " Sec-WebSocket-Protocol: %1 \r\n " ). arg (protocol );
454
455
}
455
- if (! extensions.isEmpty ())
456
+ if (!extensions.isEmpty ())
456
457
{
457
- response. append ( QLatin1String ( " Sec-WebSocket-Extensions: " ) + extensions + QLatin1String ( " \r\n " ));
458
+ response += QString ( " Sec-WebSocket-Extensions: %1 \r\n " ). arg (extensions );
458
459
}
459
- response.append (QLatin1String (" \r\n " ));
460
-
460
+ response += QLatin1String (" \r\n " );
461
461
return response;
462
462
}
463
463
464
464
QString QWsServer::composeOpeningHandshakeResponseV6 (QByteArray accept, QString protocol, QString extensions)
465
465
{
466
466
QString response;
467
-
468
- response.append (QLatin1String (" HTTP/1.1 101 Switching Protocols\r\n " ));
469
- response.append (QLatin1String (" Upgrade: websocket\r\n " ));
470
- response.append (QLatin1String (" Connection: Upgrade\r\n " ));
471
- response.append (QLatin1String (" Sec-WebSocket-Accept: " ) + QLatin1String (accept) + QLatin1String (" \r\n " ));
472
- if (! protocol.isEmpty ())
467
+ response += QLatin1String (" HTTP/1.1 101 WebSocket Protocol Handshake\r\n " );
468
+ response += QLatin1String (" Upgrade: websocket\r\n " );
469
+ response += QLatin1String (" Connection: Upgrade\r\n " );
470
+ response += QString (" Sec-WebSocket-Accept: %1\r\n " ).arg (QLatin1String (accept));
471
+ if (!protocol.isEmpty ())
473
472
{
474
- response. append ( QLatin1String ( " Sec-WebSocket-Protocol: " ) + protocol + QLatin1String ( " \r\n " ));
473
+ response += QString ( " Sec-WebSocket-Protocol: %1 \r\n " ). arg (protocol );
475
474
}
476
- if (! extensions.isEmpty ())
475
+ if (!extensions.isEmpty ())
477
476
{
478
- response. append ( QLatin1String ( " Sec-WebSocket-Extensions: " ) + extensions + QLatin1String ( " \r\n " ));
477
+ response += QString ( " Sec-WebSocket-Extensions: %1 \r\n " ). arg (extensions );
479
478
}
480
- response.append (QLatin1String (" \r\n " ));
481
-
479
+ response += QLatin1String (" \r\n " );
482
480
return response;
483
481
}
484
482
485
483
QString QWsServer::composeBadRequestResponse (QList<EWebsocketVersion> versions)
486
484
{
487
485
QString response;
488
-
489
- response.append (QLatin1String (" HTTP/1.1 400 Bad Request\r\n " ));
490
- if (! versions.isEmpty ())
486
+ response += QLatin1String (" HTTP/1.1 400 Bad Request\r\n " );
487
+ if (!versions.isEmpty ())
491
488
{
492
- QString versionsStr = QString::number (( int )versions. takeLast ()) ;
489
+ QString versionsStr;
493
490
int i = versions.size ();
494
491
while (i--)
495
492
{
496
- versionsStr.append (QLatin1String (" , " ) + QString::number ((int )versions.takeLast ()));
493
+ versionsStr += QString::number ((quint16)versions.at (i));
494
+ if (i)
495
+ {
496
+ versionsStr += QLatin1String (" , " );
497
+ }
497
498
}
498
- response. append ( QLatin1String ( " Sec-WebSocket-Version: " ) + versionsStr + QLatin1String ( " \r\n " ));
499
+ response += QString ( " Sec-WebSocket-Version: %1 \r\n " ). arg (versionsStr );
499
500
}
500
-
501
501
return response;
502
502
}
0 commit comments