Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/server/http_server.h" | 5 #include "net/server/http_server.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | |
| 7 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 9 #include "base/md5.h" | 10 #include "base/md5.h" |
| 11 #include "base/sha1.h" | |
| 10 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
| 11 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 12 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
| 13 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 14 #include "net/server/http_server_request_info.h" | 16 #include "net/server/http_server_request_info.h" |
| 17 #include "net/server/web_socket_frame.h" | |
| 15 | 18 |
| 16 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
| 17 #include <winsock2.h> | 20 #include <winsock2.h> |
| 18 #else | 21 #else |
| 19 #include <arpa/inet.h> | 22 #include <arpa/inet.h> |
| 20 #endif | 23 #endif |
| 21 | 24 |
| 22 namespace net { | 25 namespace net { |
| 23 | 26 |
| 24 int HttpServer::Connection::lastId_ = 0; | 27 int HttpServer::Connection::lastId_ = 0; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 spaces++; | 63 spaces++; |
| 61 } | 64 } |
| 62 if (spaces == 0) | 65 if (spaces == 0) |
| 63 return 0; | 66 return 0; |
| 64 int64 number = 0; | 67 int64 number = 0; |
| 65 if (!base::StringToInt64(result, &number)) | 68 if (!base::StringToInt64(result, &number)) |
| 66 return 0; | 69 return 0; |
| 67 return htonl(static_cast<uint32>(number / spaces)); | 70 return htonl(static_cast<uint32>(number / spaces)); |
| 68 } | 71 } |
| 69 | 72 |
| 70 void HttpServer::AcceptWebSocket( | 73 void HttpServer::AcceptWebSocketHixie76( |
| 71 int connection_id, | 74 HttpServer::Connection* connection, |
| 72 const HttpServerRequestInfo& request) { | 75 const HttpServerRequestInfo& request) { |
| 73 Connection* connection = FindConnection(connection_id); | |
| 74 if (connection == NULL) | |
| 75 return; | |
| 76 | |
| 77 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); | 76 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); |
| 78 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); | 77 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); |
| 79 | 78 |
| 80 uint32 fp1 = WebSocketKeyFingerprint(key1); | 79 uint32 fp1 = WebSocketKeyFingerprint(key1); |
| 81 uint32 fp2 = WebSocketKeyFingerprint(key2); | 80 uint32 fp2 = WebSocketKeyFingerprint(key2); |
| 82 | 81 |
| 83 char data[16]; | 82 char data[16]; |
| 84 memcpy(data, &fp1, 4); | 83 memcpy(data, &fp1, 4); |
| 85 memcpy(data + 4, &fp2, 4); | 84 memcpy(data + 4, &fp2, 4); |
| 86 memcpy(data + 8, &request.data[0], 8); | 85 memcpy(data + 8, &request.data[0], 8); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 97 "Upgrade: WebSocket\r\n" | 96 "Upgrade: WebSocket\r\n" |
| 98 "Connection: Upgrade\r\n" | 97 "Connection: Upgrade\r\n" |
| 99 "Sec-WebSocket-Origin: %s\r\n" | 98 "Sec-WebSocket-Origin: %s\r\n" |
| 100 "Sec-WebSocket-Location: %s\r\n" | 99 "Sec-WebSocket-Location: %s\r\n" |
| 101 "\r\n", | 100 "\r\n", |
| 102 origin.c_str(), | 101 origin.c_str(), |
| 103 location.c_str())); | 102 location.c_str())); |
| 104 connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16); | 103 connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16); |
| 105 } | 104 } |
| 106 | 105 |
| 107 void HttpServer::SendOverWebSocket(int connection_id, | 106 void HttpServer::SendOverWebSocketHixie76(HttpServer::Connection* connection, |
| 108 const std::string& data) { | 107 const std::string& data) { |
| 109 Connection* connection = FindConnection(connection_id); | |
| 110 if (connection == NULL) | |
| 111 return; | |
| 112 | |
| 113 DCHECK(connection->is_web_socket_); | |
| 114 char message_start = 0; | 108 char message_start = 0; |
| 115 char message_end = -1; | 109 char message_end = -1; |
| 116 connection->socket_->Send(&message_start, 1); | 110 connection->socket_->Send(&message_start, 1); |
| 117 connection->socket_->Send(data); | 111 connection->socket_->Send(data); |
| 118 connection->socket_->Send(&message_end, 1); | 112 connection->socket_->Send(&message_end, 1); |
| 119 } | 113 } |
| 120 | 114 |
| 121 void HttpServer::Send(int connection_id, const std::string& data) { | 115 void HttpServer::Send(int connection_id, const std::string& data) { |
| 122 Connection* connection = FindConnection(connection_id); | 116 Connection* connection = FindConnection(connection_id); |
| 123 if (connection == NULL) | 117 if (connection == NULL) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 Connection* connection = FindConnection(connection_id); | 176 Connection* connection = FindConnection(connection_id); |
| 183 if (connection == NULL) | 177 if (connection == NULL) |
| 184 return; | 178 return; |
| 185 | 179 |
| 186 connection->DetachSocket(); | 180 connection->DetachSocket(); |
| 187 } | 181 } |
| 188 | 182 |
| 189 HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock) | 183 HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock) |
| 190 : server_(server), | 184 : server_(server), |
| 191 socket_(sock), | 185 socket_(sock), |
| 192 is_web_socket_(false) { | 186 is_web_socket_(false), |
| 187 use_hixie76_web_socket_(false) { | |
| 193 id_ = lastId_++; | 188 id_ = lastId_++; |
| 194 } | 189 } |
| 195 | 190 |
| 196 HttpServer::Connection::~Connection() { | 191 HttpServer::Connection::~Connection() { |
| 197 DetachSocket(); | 192 DetachSocket(); |
| 198 server_->delegate_->OnClose(id_); | 193 server_->delegate_->OnClose(id_); |
| 199 } | 194 } |
| 200 | 195 |
| 201 void HttpServer::Connection::DetachSocket() { | 196 void HttpServer::Connection::DetachSocket() { |
| 202 socket_ = NULL; | 197 socket_ = NULL; |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 const char* data, | 364 const char* data, |
| 370 int len) { | 365 int len) { |
| 371 Connection* connection = FindConnection(socket); | 366 Connection* connection = FindConnection(socket); |
| 372 DCHECK(connection != NULL); | 367 DCHECK(connection != NULL); |
| 373 if (connection == NULL) | 368 if (connection == NULL) |
| 374 return; | 369 return; |
| 375 | 370 |
| 376 connection->recv_data_.append(data, len); | 371 connection->recv_data_.append(data, len); |
| 377 while (connection->recv_data_.length()) { | 372 while (connection->recv_data_.length()) { |
| 378 int pos = 0; | 373 int pos = 0; |
| 374 if (connection->is_web_socket_) { | |
| 375 if (connection->use_hixie76_web_socket_) { | |
| 376 HttpServerRequestInfo request; | |
| 377 if (!ParseHeaders(connection, &request, &pos)) | |
|
pfeldman
2011/07/28 14:54:18
Please add FIXME suggesting that hixie76 frames ar
| |
| 378 break; | |
| 379 delegate_->OnWebSocketMessage(connection->id_, request.data); | |
| 380 connection->Shift(pos); | |
| 381 } else { | |
| 382 std::string message; | |
| 383 if (!DidReadWebSocketHyBi10( | |
| 384 connection, | |
| 385 (char*)(connection->recv_data_.c_str() + pos), | |
| 386 connection->recv_data_.length() - pos, | |
| 387 &message)) | |
| 388 break; | |
| 389 delegate_->OnWebSocketMessage(connection->id_, message); | |
| 390 } | |
| 391 continue; | |
| 392 } | |
| 393 | |
| 379 HttpServerRequestInfo request; | 394 HttpServerRequestInfo request; |
| 380 if (!ParseHeaders(connection, &request, &pos)) | 395 if (!ParseHeaders(connection, &request, &pos)) |
| 381 break; | 396 break; |
| 382 | 397 |
| 383 if (connection->is_web_socket_) { | |
| 384 delegate_->OnWebSocketMessage(connection->id_, request.data); | |
| 385 connection->Shift(pos); | |
| 386 continue; | |
| 387 } | |
| 388 | |
| 389 std::string connection_header = GetHeaderValue(request, "Connection"); | 398 std::string connection_header = GetHeaderValue(request, "Connection"); |
| 390 if (connection_header == "Upgrade") { | 399 if (connection_header == "Upgrade") { |
| 400 std::string version = GetHeaderValue(request, "Sec-WebSocket-Version"); | |
| 401 if (version.length() && version == "8") { | |
| 402 std::string key = GetHeaderValue(request, "Sec-WebSocket-Key"); | |
| 403 if (key.empty()) { | |
| 404 Send500(connection->id_, | |
| 405 "Invalid request format. " | |
| 406 "Sec-WebSocket-Key is empty or isn't specified."); | |
| 407 connection->Shift(pos); | |
| 408 break; | |
| 409 } | |
| 410 | |
| 411 delegate_->OnWebSocketRequest(connection->id_, request); | |
| 412 connection->Shift(pos); | |
| 413 continue; | |
| 414 } | |
| 415 | |
| 391 // Is this WebSocket and if yes, upgrade the connection. | 416 // Is this WebSocket and if yes, upgrade the connection. |
| 392 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); | 417 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); |
| 393 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); | 418 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); |
| 394 | 419 |
| 395 const int websocket_handshake_body_len = 8; | 420 const int web_socket_handshake_body_len = 8; |
| 396 if (pos + websocket_handshake_body_len > | 421 if (pos + web_socket_handshake_body_len > |
| 397 static_cast<int>(connection->recv_data_.length())) { | 422 static_cast<int>(connection->recv_data_.length())) { |
| 398 // We haven't received websocket handshake body yet. Wait. | 423 // We haven't received websocket handshake body yet. Wait. |
| 399 break; | 424 break; |
| 400 } | 425 } |
| 401 | 426 |
| 402 if (!key1.empty() && !key2.empty()) { | 427 if (!key1.empty() && !key2.empty()) { |
| 403 request.data = connection->recv_data_.substr( | 428 request.data = connection->recv_data_.substr( |
| 404 pos, | 429 pos, |
| 405 pos + websocket_handshake_body_len); | 430 pos + web_socket_handshake_body_len); |
| 406 pos += websocket_handshake_body_len; | 431 pos += web_socket_handshake_body_len; |
| 432 connection->use_hixie76_web_socket_ = true; | |
| 407 delegate_->OnWebSocketRequest(connection->id_, request); | 433 delegate_->OnWebSocketRequest(connection->id_, request); |
| 408 connection->Shift(pos); | 434 connection->Shift(pos); |
| 409 continue; | 435 continue; |
| 410 } | 436 } |
| 411 } | 437 } |
| 412 // Request body is not supported. It is always empty. | 438 // Request body is not supported. It is always empty. |
| 413 delegate_->OnHttpRequest(connection->id_, request); | 439 delegate_->OnHttpRequest(connection->id_, request); |
| 414 connection->Shift(pos); | 440 connection->Shift(pos); |
| 415 } | 441 } |
| 416 } | 442 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 430 return it->second; | 456 return it->second; |
| 431 } | 457 } |
| 432 | 458 |
| 433 HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) { | 459 HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) { |
| 434 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); | 460 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); |
| 435 if (it == socket_to_connection_.end()) | 461 if (it == socket_to_connection_.end()) |
| 436 return NULL; | 462 return NULL; |
| 437 return it->second; | 463 return it->second; |
| 438 } | 464 } |
| 439 | 465 |
| 466 void HttpServer::AcceptWebSocket( | |
| 467 int connection_id, | |
| 468 const HttpServerRequestInfo& request) { | |
| 469 Connection* connection = FindConnection(connection_id); | |
| 470 if (connection == NULL) | |
| 471 return; | |
| 472 if (connection->use_hixie76_web_socket_) | |
| 473 AcceptWebSocketHixie76(connection, request); | |
| 474 else | |
| 475 AcceptWebSocketHyBi10(connection, request); | |
| 476 } | |
| 477 | |
| 478 static std::string GenerateWebSocketHyBi10AcceptKey( | |
| 479 const std::string& sec_web_socket_key) | |
| 480 { | |
| 481 static const char* const web_socket_key_GUID = | |
| 482 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | |
| 483 std::string data = base::StringPrintf("%s%s", | |
| 484 sec_web_socket_key.c_str(), | |
| 485 web_socket_key_GUID); | |
| 486 std::string encoded_hash; | |
| 487 base::Base64Encode(base::SHA1HashString(data), &encoded_hash); | |
| 488 return encoded_hash; | |
| 489 } | |
| 490 | |
| 491 void HttpServer::AcceptWebSocketHyBi10( | |
| 492 HttpServer::Connection* connection, | |
| 493 const HttpServerRequestInfo& request) { | |
| 494 std::string key = GetHeaderValue(request, "Sec-WebSocket-Key"); | |
| 495 connection->is_web_socket_ = true; | |
| 496 | |
| 497 std::string response = base::StringPrintf( | |
| 498 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
|
pfeldman
2011/07/28 14:54:18
wrong indent
| |
| 499 "Upgrade: WebSocket\r\n" | |
| 500 "Connection: Upgrade\r\n" | |
| 501 "Sec-WebSocket-Accept: %s\r\n" | |
| 502 "\r\n", | |
| 503 GenerateWebSocketHyBi10AcceptKey(key).c_str()); | |
| 504 connection->socket_->Send(response); | |
| 505 } | |
| 506 | |
| 507 void HttpServer::SendOverWebSocket(int connection_id, | |
| 508 const std::string& data) { | |
| 509 Connection* connection = FindConnection(connection_id); | |
| 510 if (connection == NULL) | |
| 511 return; | |
| 512 DCHECK(connection->is_web_socket_); | |
| 513 if (connection->use_hixie76_web_socket_) | |
|
pfeldman
2011/07/28 14:54:18
Having two web socket implementations with the sam
| |
| 514 SendOverWebSocketHixie76(connection, data); | |
| 515 else | |
| 516 SendOverWebSocketHyBi10(connection, data); | |
| 517 } | |
| 518 | |
| 519 void HttpServer::SendOverWebSocketHyBi10(HttpServer::Connection* connection, | |
| 520 const std::string& data) { | |
| 521 WebSocketFrame frame; | |
| 522 std::vector<char> buffer = frame.EncodeFrame(WebSocketFrame::kOpCodeText, | |
| 523 data.c_str(), data.length()); | |
| 524 connection->socket_->Send(&buffer[0], buffer.size()); | |
| 525 } | |
| 526 | |
| 527 bool HttpServer::DidReadWebSocketHyBi10(HttpServer::Connection* connection, | |
| 528 char* data, | |
|
pfeldman
2011/07/28 14:54:18
poor indentation.
| |
| 529 size_t length, | |
| 530 std::string* message) { | |
| 531 WebSocketFrame frame; | |
| 532 WebSocketFrame::ParseResult parse_result = frame.DecodeFrame(data, length); | |
| 533 if (parse_result == WebSocketFrame::FrameError) | |
| 534 return false; | |
| 535 | |
| 536 if (parse_result == WebSocketFrame::FrameIncomplete) | |
| 537 return false; | |
| 538 | |
| 539 CHECK(parse_result == WebSocketFrame::FrameOK); | |
| 540 *message = std::string(frame.payload_, frame.payload_length_); | |
| 541 connection->Shift(frame.frame_end_ - data); | |
| 542 | |
| 543 return true; | |
| 544 } | |
| 545 | |
| 440 } // namespace net | 546 } // namespace net |
| OLD | NEW |