Changeset 128731 in webkit
- Timestamp:
- Sep 17, 2012 2:37:51 AM (12 years ago)
- Location:
- trunk/Source/WebKit/qt
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/qt/ChangeLog
r128688 r128731 1 2012-09-17 Leo Franchi <lfranchi@kde.org> 2 3 [Qt] Inspector WebSocket backend protocol update 4 https://bugs.webkit.org/show_bug.cgi?id=77031 5 6 Also adds support for multi-frame messages and non-text messages. 7 Thanks to Jocelyn Turcotte for most of the WebSocket update code! 8 9 Reviewed by Simon Hausmann. 10 11 * WebCoreSupport/InspectorServerQt.cpp: 12 (WebCore): 13 (WebCore::generateWebSocketChallengeResponse): 14 (WebCore::InspectorServerRequestHandlerQt::tcpReadyRead): 15 (WebCore::InspectorServerRequestHandlerQt::webSocketSend): 16 (WebCore::applyMask): 17 (WebCore::InspectorServerRequestHandlerQt::webSocketReadyRead): 18 * WebCoreSupport/InspectorServerQt.h: 19 (InspectorServerRequestHandlerQt): 20 1 21 2012-09-15 Pierre Rossi <pierre.rossi@gmail.com> 2 22 -
trunk/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.cpp
r119232 r128731 35 35 #include <QWidget> 36 36 #include <qendian.h> 37 #include <wtf/MD5.h> 37 #include <wtf/SHA1.h> 38 #include <wtf/text/Base64.h> 38 39 #include <wtf/text/CString.h> 39 40 … … 41 42 42 43 /*! 43 Computes the WebSocket handshake response given the two challenge numbers and key3.44 Computes the WebSocket handshake response given the input key 44 45 */ 45 static void generateWebSocketChallengeResponse(uint32_t number1, uint32_t number2, const unsigned char key3[8], unsigned char response[16]) 46 { 47 uint8_t challenge[16]; 48 qToBigEndian<qint32>(number1, &challenge[0]); 49 qToBigEndian<qint32>(number2, &challenge[4]); 50 memcpy(&challenge[8], key3, 8); 51 MD5 md5; 52 md5.addBytes(challenge, sizeof(challenge)); 53 Vector<uint8_t, 16> digest; 54 md5.checksum(digest); 55 memcpy(response, digest.data(), 16); 56 } 57 58 /*! 59 Parses and returns a WebSocket challenge number according to the 60 method specified in the WebSocket protocol. 61 62 The field contains numeric digits interspersed with spaces and 63 non-numeric digits. The protocol ignores the characters that are 64 neither digits nor spaces. The digits are concatenated and 65 interpreted as a long int. The result is this number divided by 66 the number of spaces. 67 */ 68 static quint32 parseWebSocketChallengeNumber(QString field) 69 { 70 QString nString; 71 int numSpaces = 0; 72 for (int i = 0; i < field.size(); i++) { 73 QChar c = field[i]; 74 if (c == QLatin1Char(' ')) 75 numSpaces++; 76 else if ((c >= QLatin1Char('0')) && (c <= QLatin1Char('9'))) 77 nString.append(c); 78 } 79 quint32 num = nString.toULong(); 80 quint32 result = (numSpaces ? (num / numSpaces) : num); 81 return result; 46 static QByteArray generateWebSocketChallengeResponse(const QByteArray& key) 47 { 48 SHA1 sha1; 49 Vector<uint8_t, 20> digest; 50 Vector<char> encoded; 51 QByteArray toHash("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); 52 toHash.prepend(key); 53 sha1.addBytes((uint8_t*)toHash.data(), toHash.size()); 54 sha1.computeHash(digest); 55 base64Encode((char*)digest.data(), digest.size(), encoded); 56 return QByteArray(encoded.data(), encoded.size()); 82 57 } 83 58 … … 193 168 m_contentType = header.contentType().toLatin1(); 194 169 m_contentLength = header.contentLength(); 195 if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String(" WebSocket")))170 if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String("websocket"))) 196 171 isWebSocket = true; 197 172 … … 212 187 connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(webSocketReadyRead()), Qt::QueuedConnection); 213 188 214 QByteArray key3 = m_tcpConnection->read(8); 215 216 quint32 number1 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key1"))); 217 quint32 number2 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key2"))); 218 219 char responseData[16]; 220 generateWebSocketChallengeResponse(number1, number2, (unsigned char*)key3.data(), (unsigned char*)responseData); 221 QByteArray response(responseData, sizeof(responseData)); 189 QByteArray key = header.value(QLatin1String("Sec-WebSocket-Key")).toLatin1(); 190 QString accept = QString::fromLatin1(generateWebSocketChallengeResponse(key)); 222 191 223 192 WebKit::QHttpResponseHeader responseHeader(101, QLatin1String("WebSocket Protocol Handshake"), 1, 1); 224 193 responseHeader.setValue(QLatin1String("Upgrade"), header.value(QLatin1String("Upgrade"))); 225 194 responseHeader.setValue(QLatin1String("Connection"), header.value(QLatin1String("Connection"))); 226 responseHeader.setValue(QLatin1String("Sec-WebSocket-Origin"), header.value(QLatin1String("Origin"))); 227 responseHeader.setValue(QLatin1String("Sec-WebSocket-Location"), (QLatin1String("ws://") + header.value(QLatin1String("Host")) + m_path)); 228 responseHeader.setContentLength(response.size()); 195 responseHeader.setValue(QLatin1String("Sec-WebSocket-Accept"), accept); 229 196 m_tcpConnection->write(responseHeader.toString().toLatin1()); 230 m_tcpConnection->write(response);231 197 m_tcpConnection->flush(); 232 198 … … 307 273 } 308 274 309 int InspectorServerRequestHandlerQt::webSocketSend(QByteArray payload) 275 int InspectorServerRequestHandlerQt::webSocketSend(const QString& message) 276 { 277 QByteArray payload = message.toUtf8(); 278 return webSocketSend(payload.data(), payload.size()); 279 } 280 281 int InspectorServerRequestHandlerQt::webSocketSend(const char* data, size_t length) 310 282 { 311 283 Q_ASSERT(m_tcpConnection); 312 m_tcpConnection->putChar(0x00); 313 int nBytes = m_tcpConnection->write(payload); 314 m_tcpConnection->putChar(0xFF); 284 m_tcpConnection->putChar(0x81); 285 if (length <= 125) 286 m_tcpConnection->putChar(static_cast<uint8_t>(length)); 287 else if (length <= pow(2, 16)) { 288 m_tcpConnection->putChar(126); 289 quint16 length16 = qToBigEndian<quint16>(static_cast<quint16>(length)); 290 m_tcpConnection->write(reinterpret_cast<char*>(&length16), 2); 291 } else { 292 m_tcpConnection->putChar(127); 293 quint64 length64 = qToBigEndian<quint64>(static_cast<quint64>(length)); 294 m_tcpConnection->write(reinterpret_cast<char*>(&length64), 8); 295 } 296 int nBytes = m_tcpConnection->write(data, length); 315 297 m_tcpConnection->flush(); 316 298 return nBytes; 317 299 } 318 300 319 int InspectorServerRequestHandlerQt::webSocketSend(const char* data, size_t length) 320 { 321 Q_ASSERT(m_tcpConnection); 322 m_tcpConnection->putChar(0x00); 323 int nBytes = m_tcpConnection->write(data, length); 324 m_tcpConnection->putChar(0xFF); 325 m_tcpConnection->flush(); 326 return nBytes; 301 static QByteArray applyMask(const QByteArray& payload, const QByteArray& maskingKey) 302 { 303 Q_ASSERT(maskingKey.size() == 4); 304 QByteArray unmaskedPayload; 305 for (int i = 0; i < payload.size(); ++i) { 306 char unmaskedByte = payload[i] ^ maskingKey[i % 4]; 307 unmaskedPayload.append(unmaskedByte); 308 } 309 return unmaskedPayload; 327 310 } 328 311 … … 334 317 QByteArray content = m_tcpConnection->read(m_tcpConnection->bytesAvailable()); 335 318 m_data.append(content); 336 while (m_data.size() > 0) { 337 // first byte in websocket frame should be 0 338 Q_ASSERT(!m_data[0]); 339 340 // Start of WebSocket frame is indicated by 0 341 if (m_data[0]) { 342 qCritical() << "webSocketReadyRead: unknown frame type" << m_data[0]; 343 m_data.clear(); 344 m_tcpConnection->close(); 345 return; 346 } 347 348 // End of WebSocket frame indicated by 0xff. 349 int pos = m_data.indexOf(0xff, 1); 350 if (pos < 1) 351 return; 352 353 // After above checks, length will be >= 0. 354 size_t length = pos - 1; 355 if (length <= 0) 356 return; 357 358 QByteArray payload = m_data.mid(1, length); 359 319 while (m_data.size() > 0) { 320 const bool isMasked = m_data[1] & 0x80; 321 quint64 payloadLen = m_data[1] & 0x7F; 322 int pos = 2; 323 324 if (payloadLen == 126) { 325 payloadLen = qFromBigEndian<quint16>(*reinterpret_cast<quint16*>(m_data.mid(pos, 2).data())); 326 pos = 4; 327 } else if (payloadLen == 127) { 328 payloadLen = qFromBigEndian<quint64>(*reinterpret_cast<quint64*>(m_data.mid(pos, 8).data())); 329 pos = 8; 330 } 331 332 QByteArray payload; 333 if (isMasked) { 334 QByteArray maskingKey = m_data.mid(pos, 4); 335 pos += 4; 336 payload = applyMask(m_data.mid(pos, payloadLen), maskingKey); 337 } else 338 payload = m_data.mid(pos, payloadLen); 339 340 // Handle fragmentation 341 if (!(m_data[0] & 0x80)) { // Non-last fragmented payload 342 m_fragmentedPayload.append(payload); 343 m_data = m_data.mid(pos + payloadLen); 344 continue; 345 } 346 347 if (!(m_data[0] & 0x0F)) { // Last fragment 348 m_fragmentedPayload.append(payload); 349 payload = m_fragmentedPayload; 350 m_fragmentedPayload.clear(); 351 } 352 360 353 // Remove this WebSocket message from m_data (payload, start-of-frame byte, end-of-frame byte). 361 354 // Truncate data before delivering message in case of re-entrancy. 362 m_data = m_data.mid( length + 2);355 m_data = m_data.mid(pos + payloadLen); 363 356 364 357 #if ENABLE(INSPECTOR) -
trunk/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.h
r125603 r128731 73 73 InspectorServerRequestHandlerQt(QTcpSocket *tcpConnection, InspectorServerQt *server); 74 74 virtual ~InspectorServerRequestHandlerQt(); 75 virtual int webSocketSend( QByteArray payload);75 virtual int webSocketSend(const QString& message); 76 76 virtual int webSocketSend(const char *payload, size_t length); 77 77 … … 90 90 bool m_endOfHeaders; 91 91 QByteArray m_data; 92 QByteArray m_fragmentedPayload; 92 93 InspectorClientQt* m_inspectorClient; 93 94
Note: See TracChangeset
for help on using the changeset viewer.