Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/websockets/websocket_handshake_handler.h" | 5 #include "net/websockets/websocket_handshake_handler.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/md5.h" | 8 #include "base/md5.h" |
| 9 #include "base/sha1.h" | 9 #include "base/sha1.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); | 259 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); |
| 260 GetKeyNumber(key, challenge); | 260 GetKeyNumber(key, challenge); |
| 261 | 261 |
| 262 challenge->append(key3_); | 262 challenge->append(key3_); |
| 263 } | 263 } |
| 264 | 264 |
| 265 return request_info; | 265 return request_info; |
| 266 } | 266 } |
| 267 | 267 |
| 268 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( | 268 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( |
| 269 const GURL& url, SpdyHeaderBlock* headers, std::string* challenge) { | 269 const GURL& url, |
| 270 SpdyHeaderBlock* headers, | |
| 271 std::string* challenge, | |
| 272 NextProto protocol_negotiated) { | |
| 270 // Construct opening handshake request headers as a SPDY header block. | 273 // Construct opening handshake request headers as a SPDY header block. |
| 271 // For details, see WebSocket Layering over SPDY/3 Draft 8. | 274 // For details, see WebSocket Layering over SPDY/3 Draft 8. |
| 272 (*headers)["path"] = url.path(); | 275 if (protocol_negotiated == kProtoSPDY2) { |
|
Yuta Kitamura
2012/08/03 07:31:51
Can we assume |protocol_negotiated| is either kPro
Takashi Toyoshima
2012/08/06 13:01:53
Good point.
It doesn't seem to be kProtoHTTP11 or
| |
| 273 (*headers)["version"] = | 276 (*headers)["path"] = url.path(); |
| 277 (*headers)["version"] = | |
| 274 base::StringPrintf("%s%d", "WebSocket/", protocol_version_); | 278 base::StringPrintf("%s%d", "WebSocket/", protocol_version_); |
| 275 (*headers)["scheme"] = url.scheme(); | 279 (*headers)["scheme"] = url.scheme(); |
| 280 } else { | |
| 281 (*headers)[":path"] = url.path(); | |
| 282 (*headers)[":version"] = | |
| 283 base::StringPrintf("%s%d", "WebSocket/", protocol_version_); | |
| 284 (*headers)[":scheme"] = url.scheme(); | |
| 285 } | |
| 276 | 286 |
| 277 HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); | 287 HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); |
| 278 while (iter.GetNext()) { | 288 while (iter.GetNext()) { |
| 279 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), "upgrade") || | 289 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), "upgrade") || |
| 280 LowerCaseEqualsASCII(iter.name_begin(), | 290 LowerCaseEqualsASCII(iter.name_begin(), |
| 281 iter.name_end(), | 291 iter.name_end(), |
| 282 "connection") || | 292 "connection") || |
| 283 LowerCaseEqualsASCII(iter.name_begin(), | 293 LowerCaseEqualsASCII(iter.name_begin(), |
| 284 iter.name_end(), | 294 iter.name_end(), |
| 285 "sec-websocket-version")) { | 295 "sec-websocket-version")) { |
| 286 // These headers must be ignored. | 296 // These headers must be ignored. |
| 287 continue; | 297 continue; |
| 288 } else if (LowerCaseEqualsASCII(iter.name_begin(), | 298 } else if (LowerCaseEqualsASCII(iter.name_begin(), |
| 289 iter.name_end(), | 299 iter.name_end(), |
| 290 "sec-websocket-key")) { | 300 "sec-websocket-key")) { |
| 291 *challenge = iter.values(); | 301 *challenge = iter.values(); |
| 292 // Sec-WebSocket-Key is not sent to a server. | 302 // Sec-WebSocket-Key is not sent to a server. |
| 293 continue; | 303 continue; |
| 304 } else if (LowerCaseEqualsASCII(iter.name_begin(), | |
| 305 iter.name_end(), | |
| 306 "host") || | |
| 307 LowerCaseEqualsASCII(iter.name_begin(), | |
| 308 iter.name_end(), | |
| 309 "origin") || | |
| 310 LowerCaseEqualsASCII(iter.name_begin(), | |
| 311 iter.name_end(), | |
| 312 "sec-websocket-protocol") || | |
| 313 LowerCaseEqualsASCII(iter.name_begin(), | |
| 314 iter.name_end(), | |
| 315 "sec-websocket-extensions")) { | |
| 316 // TODO(toyoshim): Some WebSocket extensions may be not not compatible | |
|
Yuta Kitamura
2012/08/03 07:31:51
"may be not not" -> "may not be"
Takashi Toyoshima
2012/08/06 13:01:53
Thanks.
| |
| 317 // with SPDY. We should omit them from a Sec-WebSocket-Extension header. | |
| 318 std::string name; | |
| 319 if (protocol_negotiated == kProtoSPDY2) | |
| 320 name = StringToLowerASCII(iter.name()); | |
| 321 else | |
| 322 name = ":" + StringToLowerASCII(iter.name()); | |
| 323 (*headers)[name] = iter.values(); | |
| 324 continue; | |
| 294 } | 325 } |
| 295 // Others should be sent out to |headers|. | 326 // Others should be sent out to |headers|. |
| 296 // TODO(toyoshim): Some WebSocket extensions are not compatible with SPDY. | |
| 297 // We should remove them from a Sec-WebSocket-Extension header. | |
| 298 std::string name = StringToLowerASCII(iter.name()); | 327 std::string name = StringToLowerASCII(iter.name()); |
| 299 SpdyHeaderBlock::iterator found = headers->find(name); | 328 SpdyHeaderBlock::iterator found = headers->find(name); |
| 300 if (found == headers->end()) { | 329 if (found == headers->end()) { |
| 301 (*headers)[name] = iter.values(); | 330 (*headers)[name] = iter.values(); |
| 302 } else { | 331 } else { |
| 303 // For now, websocket doesn't use multiple headers, but follows to http. | 332 // For now, websocket doesn't use multiple headers, but follows to http. |
| 304 found->second.append(1, '\0'); // +=() doesn't append 0's | 333 found->second.append(1, '\0'); // +=() doesn't append 0's |
| 305 found->second.append(iter.values()); | 334 found->second.append(iter.values()); |
| 306 } | 335 } |
| 307 } | 336 } |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 const char* digest_data = reinterpret_cast<char*>(digest.a); | 449 const char* digest_data = reinterpret_cast<char*>(digest.a); |
| 421 response_message.append(digest_data, sizeof(digest.a)); | 450 response_message.append(digest_data, sizeof(digest.a)); |
| 422 } | 451 } |
| 423 | 452 |
| 424 return ParseRawResponse(response_message.data(), | 453 return ParseRawResponse(response_message.data(), |
| 425 response_message.size()) == response_message.size(); | 454 response_message.size()) == response_message.size(); |
| 426 } | 455 } |
| 427 | 456 |
| 428 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( | 457 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( |
| 429 const SpdyHeaderBlock& headers, | 458 const SpdyHeaderBlock& headers, |
| 430 const std::string& challenge) { | 459 const std::string& challenge, |
| 431 std::string response_message; | 460 NextProto protocol_negotiated) { |
| 432 SpdyHeaderBlock::const_iterator status = headers.find("status"); | 461 SpdyHeaderBlock::const_iterator status; |
| 462 if (protocol_negotiated == kProtoSPDY2) | |
| 463 status = headers.find("status"); | |
| 464 else | |
| 465 status = headers.find(":status"); | |
| 433 if (status == headers.end()) | 466 if (status == headers.end()) |
| 434 return false; | 467 return false; |
| 468 std::string response_message; | |
| 435 response_message = | 469 response_message = |
| 436 base::StringPrintf("%s%s\r\n", "HTTP/1.1 ", status->second.c_str()); | 470 base::StringPrintf("%s%s\r\n", "HTTP/1.1 ", status->second.c_str()); |
| 437 response_message += "Upgrade: websocket\r\n"; | 471 response_message += "Upgrade: websocket\r\n"; |
| 438 response_message += "Connection: Upgrade\r\n"; | 472 response_message += "Connection: Upgrade\r\n"; |
| 439 | 473 |
| 440 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); | 474 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); |
| 441 std::string websocket_accept; | 475 std::string websocket_accept; |
| 442 bool encode_success = base::Base64Encode(hash, &websocket_accept); | 476 bool encode_success = base::Base64Encode(hash, &websocket_accept); |
| 443 DCHECK(encode_success); | 477 DCHECK(encode_success); |
| 444 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; | 478 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; |
| 445 | 479 |
| 446 for (SpdyHeaderBlock::const_iterator iter = headers.begin(); | 480 for (SpdyHeaderBlock::const_iterator iter = headers.begin(); |
| 447 iter != headers.end(); | 481 iter != headers.end(); |
| 448 ++iter) { | 482 ++iter) { |
| 449 // For each value, if the server sends a NUL-separated list of values, | 483 // For each value, if the server sends a NUL-separated list of values, |
| 450 // we separate that back out into individual headers for each value | 484 // we separate that back out into individual headers for each value |
| 451 // in the list. | 485 // in the list. |
| 452 if (LowerCaseEqualsASCII(iter->first, "status")) { | 486 if ((protocol_negotiated == kProtoSPDY2 && |
| 487 LowerCaseEqualsASCII(iter->first, "status")) || | |
|
Yuta Kitamura
2012/08/03 07:31:51
nit: This line needs to align the opening paren, i
Takashi Toyoshima
2012/08/06 13:01:53
Done.
| |
| 488 (protocol_negotiated != kProtoSPDY2 && | |
| 489 LowerCaseEqualsASCII(iter->first, ":status"))) { | |
|
Yuta Kitamura
2012/08/03 07:31:51
Ditto.
Takashi Toyoshima
2012/08/06 13:01:53
Done.
| |
| 453 // The status value is already handled as the first line of | 490 // The status value is already handled as the first line of |
| 454 // |response_message|. Just skip here. | 491 // |response_message|. Just skip here. |
| 455 continue; | 492 continue; |
| 456 } | 493 } |
| 457 const std::string& value = iter->second; | 494 const std::string& value = iter->second; |
| 458 size_t start = 0; | 495 size_t start = 0; |
| 459 size_t end = 0; | 496 size_t end = 0; |
| 460 do { | 497 do { |
| 461 end = value.find('\0', start); | 498 end = value.find('\0', start); |
| 462 std::string tval; | 499 std::string tval; |
| 463 if (end != std::string::npos) | 500 if (end != std::string::npos) |
| 464 tval = value.substr(start, (end - start)); | 501 tval = value.substr(start, (end - start)); |
| 465 else | 502 else |
| 466 tval = value.substr(start); | 503 tval = value.substr(start); |
| 467 response_message += iter->first + ": " + tval + "\r\n"; | 504 if (protocol_negotiated != kProtoSPDY2 && |
| 505 (LowerCaseEqualsASCII(iter->first, ":sec-websocket-protocol") || | |
| 506 LowerCaseEqualsASCII(iter->first, ":sec-websocket-extensions"))) | |
|
Yuta Kitamura
2012/08/03 07:31:51
Ditto.
Takashi Toyoshima
2012/08/06 13:01:53
Done.
| |
| 507 response_message += iter->first.substr(1) + ": " + tval + "\r\n"; | |
| 508 else | |
| 509 response_message += iter->first + ": " + tval + "\r\n"; | |
| 468 start = end + 1; | 510 start = end + 1; |
| 469 } while (end != std::string::npos); | 511 } while (end != std::string::npos); |
| 470 } | 512 } |
| 471 response_message += "\r\n"; | 513 response_message += "\r\n"; |
| 472 | 514 |
| 473 return ParseRawResponse(response_message.data(), | 515 return ParseRawResponse(response_message.data(), |
| 474 response_message.size()) == response_message.size(); | 516 response_message.size()) == response_message.size(); |
| 475 } | 517 } |
| 476 | 518 |
| 477 void WebSocketHandshakeResponseHandler::GetHeaders( | 519 void WebSocketHandshakeResponseHandler::GetHeaders( |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 return status_line_ + headers_ + header_separator_ + key_; | 556 return status_line_ + headers_ + header_separator_ + key_; |
| 515 } | 557 } |
| 516 | 558 |
| 517 size_t WebSocketHandshakeResponseHandler::GetResponseKeySize() const { | 559 size_t WebSocketHandshakeResponseHandler::GetResponseKeySize() const { |
| 518 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) | 560 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) |
| 519 return 0; | 561 return 0; |
| 520 return kResponseKeySize; | 562 return kResponseKeySize; |
| 521 } | 563 } |
| 522 | 564 |
| 523 } // namespace net | 565 } // namespace net |
| OLD | NEW |