| OLD | NEW |
| 1 // Copyright (c) 2010 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/websockets/websocket_handshake_handler.h" | 5 #include "net/websockets/websocket_handshake_handler.h" |
| 6 | 6 |
| 7 #include "base/base64.h" |
| 7 #include "base/md5.h" | 8 #include "base/md5.h" |
| 9 #include "base/sha1.h" |
| 10 #include "base/string_number_conversions.h" |
| 8 #include "base/string_piece.h" | 11 #include "base/string_piece.h" |
| 9 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 10 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
| 11 #include "net/http/http_response_headers.h" | 14 #include "net/http/http_response_headers.h" |
| 12 #include "net/http/http_util.h" | 15 #include "net/http/http_util.h" |
| 13 | 16 |
| 14 namespace { | 17 namespace { |
| 15 | 18 |
| 16 const size_t kRequestKey3Size = 8U; | 19 const size_t kRequestKey3Size = 8U; |
| 17 const size_t kResponseKeySize = 16U; | 20 const size_t kResponseKeySize = 16U; |
| 18 | 21 |
| 22 // First version that introduced new WebSocket handshake which does not |
| 23 // require sending "key3" or "response key" data after headers. |
| 24 const int kMinVersionOfHybiNewHandshake = 4; |
| 25 |
| 26 // Used when we calculate the value of Sec-WebSocket-Accept. |
| 27 const char* const kWebSocketGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
| 28 |
| 19 void ParseHandshakeHeader( | 29 void ParseHandshakeHeader( |
| 20 const char* handshake_message, int len, | 30 const char* handshake_message, int len, |
| 21 std::string* status_line, | 31 std::string* status_line, |
| 22 std::string* headers) { | 32 std::string* headers) { |
| 23 size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n"); | 33 size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n"); |
| 24 if (i == base::StringPiece::npos) { | 34 if (i == base::StringPiece::npos) { |
| 25 *status_line = std::string(handshake_message, len); | 35 *status_line = std::string(handshake_message, len); |
| 26 *headers = ""; | 36 *headers = ""; |
| 27 return; | 37 return; |
| 28 } | 38 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 key_number /= spaces; | 133 key_number /= spaces; |
| 124 | 134 |
| 125 char part[4]; | 135 char part[4]; |
| 126 for (int i = 0; i < 4; i++) { | 136 for (int i = 0; i < 4; i++) { |
| 127 part[3 - i] = key_number & 0xFF; | 137 part[3 - i] = key_number & 0xFF; |
| 128 key_number >>= 8; | 138 key_number >>= 8; |
| 129 } | 139 } |
| 130 challenge->append(part, 4); | 140 challenge->append(part, 4); |
| 131 } | 141 } |
| 132 | 142 |
| 143 int GetVersionFromRequest(const std::string& request_headers) { |
| 144 std::vector<std::string> values; |
| 145 const char* const headers_to_get[2] = { "sec-websocket-version", |
| 146 "sec-websocket-draft" }; |
| 147 FetchHeaders(request_headers, headers_to_get, 2, &values); |
| 148 DCHECK_LE(values.size(), 1U); |
| 149 if (values.empty()) |
| 150 return 0; |
| 151 int version; |
| 152 bool conversion_success = base::StringToInt(values[0], &version); |
| 153 DCHECK(conversion_success); |
| 154 DCHECK_GE(version, 1); |
| 155 return version; |
| 156 } |
| 157 |
| 133 } // anonymous namespace | 158 } // anonymous namespace |
| 134 | 159 |
| 135 namespace net { | 160 namespace net { |
| 136 | 161 |
| 137 WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler() | 162 WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler() |
| 138 : original_length_(0), | 163 : original_length_(0), |
| 139 raw_length_(0) {} | 164 raw_length_(0), |
| 165 protocol_version_(-1) {} |
| 140 | 166 |
| 141 bool WebSocketHandshakeRequestHandler::ParseRequest( | 167 bool WebSocketHandshakeRequestHandler::ParseRequest( |
| 142 const char* data, int length) { | 168 const char* data, int length) { |
| 143 DCHECK_GT(length, 0); | 169 DCHECK_GT(length, 0); |
| 144 std::string input(data, length); | 170 std::string input(data, length); |
| 145 int input_header_length = | 171 int input_header_length = |
| 146 HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0); | 172 HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0); |
| 147 if (input_header_length <= 0 || | 173 if (input_header_length <= 0) |
| 148 input_header_length + kRequestKey3Size > input.size()) | |
| 149 return false; | 174 return false; |
| 150 | 175 |
| 151 ParseHandshakeHeader(input.data(), | 176 ParseHandshakeHeader(input.data(), |
| 152 input_header_length, | 177 input_header_length, |
| 153 &status_line_, | 178 &status_line_, |
| 154 &headers_); | 179 &headers_); |
| 155 | 180 |
| 156 // draft-hixie-thewebsocketprotocol-76 or later will send /key3/ | 181 // WebSocket protocol drafts hixie-76 (hybi-00), hybi-01, 02 and 03 require |
| 157 // after handshake request header. | 182 // the clients to send key3 after the handshake request header fields. |
| 183 // Hybi-04 and later drafts, on the other hand, no longer have key3 |
| 184 // in the handshake format. |
| 185 protocol_version_ = GetVersionFromRequest(headers_); |
| 186 DCHECK_GE(protocol_version_, 0); |
| 187 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 188 key3_ = ""; |
| 189 original_length_ = input_header_length; |
| 190 return true; |
| 191 } |
| 192 |
| 193 if (input_header_length + kRequestKey3Size > input.size()) |
| 194 return false; |
| 195 |
| 158 // Assumes WebKit doesn't send any data after handshake request message | 196 // Assumes WebKit doesn't send any data after handshake request message |
| 159 // until handshake is finished. | 197 // until handshake is finished. |
| 160 // Thus, |key3_| is part of handshake message, and not in part | 198 // Thus, |key3_| is part of handshake message, and not in part |
| 161 // of WebSocket frame stream. | 199 // of WebSocket frame stream. |
| 162 DCHECK_EQ(kRequestKey3Size, | 200 DCHECK_EQ(kRequestKey3Size, input.size() - input_header_length); |
| 163 input.size() - | |
| 164 input_header_length); | |
| 165 key3_ = std::string(input.data() + input_header_length, | 201 key3_ = std::string(input.data() + input_header_length, |
| 166 input.size() - input_header_length); | 202 input.size() - input_header_length); |
| 167 original_length_ = input.size(); | 203 original_length_ = input.size(); |
| 168 return true; | 204 return true; |
| 169 } | 205 } |
| 170 | 206 |
| 171 size_t WebSocketHandshakeRequestHandler::original_length() const { | 207 size_t WebSocketHandshakeRequestHandler::original_length() const { |
| 172 return original_length_; | 208 return original_length_; |
| 173 } | 209 } |
| 174 | 210 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 195 status_line_.data(), status_line_.size()).find_first_of(" "); | 231 status_line_.data(), status_line_.size()).find_first_of(" "); |
| 196 if (method_end != base::StringPiece::npos) | 232 if (method_end != base::StringPiece::npos) |
| 197 request_info.method = std::string(status_line_.data(), method_end); | 233 request_info.method = std::string(status_line_.data(), method_end); |
| 198 | 234 |
| 199 request_info.extra_headers.Clear(); | 235 request_info.extra_headers.Clear(); |
| 200 request_info.extra_headers.AddHeadersFromString(headers_); | 236 request_info.extra_headers.AddHeadersFromString(headers_); |
| 201 | 237 |
| 202 request_info.extra_headers.RemoveHeader("Upgrade"); | 238 request_info.extra_headers.RemoveHeader("Upgrade"); |
| 203 request_info.extra_headers.RemoveHeader("Connection"); | 239 request_info.extra_headers.RemoveHeader("Connection"); |
| 204 | 240 |
| 205 challenge->clear(); | 241 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 206 std::string key; | 242 std::string key; |
| 207 request_info.extra_headers.GetHeader("Sec-WebSocket-Key1", &key); | 243 bool header_present = |
| 208 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key1"); | 244 request_info.extra_headers.GetHeader("Sec-WebSocket-Key", &key); |
| 209 GetKeyNumber(key, challenge); | 245 DCHECK(header_present); |
| 246 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key"); |
| 247 *challenge = key; |
| 248 } else { |
| 249 challenge->clear(); |
| 250 std::string key; |
| 251 bool header_present = |
| 252 request_info.extra_headers.GetHeader("Sec-WebSocket-Key1", &key); |
| 253 DCHECK(header_present); |
| 254 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key1"); |
| 255 GetKeyNumber(key, challenge); |
| 210 | 256 |
| 211 request_info.extra_headers.GetHeader("Sec-WebSocket-Key2", &key); | 257 header_present = |
| 212 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); | 258 request_info.extra_headers.GetHeader("Sec-WebSocket-Key2", &key); |
| 213 GetKeyNumber(key, challenge); | 259 DCHECK(header_present); |
| 260 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); |
| 261 GetKeyNumber(key, challenge); |
| 214 | 262 |
| 215 challenge->append(key3_); | 263 challenge->append(key3_); |
| 264 } |
| 216 | 265 |
| 217 return request_info; | 266 return request_info; |
| 218 } | 267 } |
| 219 | 268 |
| 220 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( | 269 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( |
| 221 const GURL& url, spdy::SpdyHeaderBlock* headers, std::string* challenge) { | 270 const GURL& url, spdy::SpdyHeaderBlock* headers, std::string* challenge) { |
| 222 // We don't set "method" and "version". These are fixed value in WebSocket | 271 // We don't set "method" and "version". These are fixed value in WebSocket |
| 223 // protocol. | 272 // protocol. |
| 224 (*headers)["url"] = url.spec(); | 273 (*headers)["url"] = url.spec(); |
| 225 | 274 |
| 226 std::string key1; | 275 std::string new_key; // For protocols hybi-04 and newer. |
| 227 std::string key2; | 276 std::string old_key1; // For protocols hybi-03 and older. |
| 277 std::string old_key2; // Ditto. |
| 228 HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); | 278 HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); |
| 229 while (iter.GetNext()) { | 279 while (iter.GetNext()) { |
| 230 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), | 280 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 231 "connection")) { | 281 "connection")) { |
| 232 // Ignore "Connection" header. | 282 // Ignore "Connection" header. |
| 233 continue; | 283 continue; |
| 234 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), | 284 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 235 "upgrade")) { | 285 "upgrade")) { |
| 236 // Ignore "Upgrade" header. | 286 // Ignore "Upgrade" header. |
| 237 continue; | 287 continue; |
| 238 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), | 288 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 239 "sec-websocket-key1")) { | 289 "sec-websocket-key1")) { |
| 240 // Use only for generating challenge. | 290 // Only used for generating challenge. |
| 241 key1 = iter.values(); | 291 old_key1 = iter.values(); |
| 242 continue; | 292 continue; |
| 243 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), | 293 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 244 "sec-websocket-key2")) { | 294 "sec-websocket-key2")) { |
| 245 // Use only for generating challenge. | 295 // Only used for generating challenge. |
| 246 key2 = iter.values(); | 296 old_key2 = iter.values(); |
| 297 continue; |
| 298 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 299 "sec-websocket-key")) { |
| 300 // Only used for generating challenge. |
| 301 new_key = iter.values(); |
| 247 continue; | 302 continue; |
| 248 } | 303 } |
| 249 // Others should be sent out to |headers|. | 304 // Others should be sent out to |headers|. |
| 250 std::string name = StringToLowerASCII(iter.name()); | 305 std::string name = StringToLowerASCII(iter.name()); |
| 251 spdy::SpdyHeaderBlock::iterator found = headers->find(name); | 306 spdy::SpdyHeaderBlock::iterator found = headers->find(name); |
| 252 if (found == headers->end()) { | 307 if (found == headers->end()) { |
| 253 (*headers)[name] = iter.values(); | 308 (*headers)[name] = iter.values(); |
| 254 } else { | 309 } else { |
| 255 // For now, websocket doesn't use multiple headers, but follows to http. | 310 // For now, websocket doesn't use multiple headers, but follows to http. |
| 256 found->second.append(1, '\0'); // +=() doesn't append 0's | 311 found->second.append(1, '\0'); // +=() doesn't append 0's |
| 257 found->second.append(iter.values()); | 312 found->second.append(iter.values()); |
| 258 } | 313 } |
| 259 } | 314 } |
| 260 | 315 |
| 261 challenge->clear(); | 316 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 262 GetKeyNumber(key1, challenge); | 317 DVLOG_IF(1, !old_key1.empty()) |
| 263 GetKeyNumber(key2, challenge); | 318 << "Server sent unexpected Sec-WebSocket-Key1 header."; |
| 264 challenge->append(key3_); | 319 DVLOG_IF(1, !old_key2.empty()) |
| 320 << "Server sent unexpected Sec-WebSocket-Key2 header."; |
| 321 *challenge = new_key; |
| 322 } else { |
| 323 DVLOG_IF(1, !new_key.empty()) |
| 324 << "Server sent unexpected Sec-WebSocket-Key header."; |
| 325 challenge->clear(); |
| 326 GetKeyNumber(old_key1, challenge); |
| 327 GetKeyNumber(old_key2, challenge); |
| 328 challenge->append(key3_); |
| 329 } |
| 265 | 330 |
| 266 return true; | 331 return true; |
| 267 } | 332 } |
| 268 | 333 |
| 269 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { | 334 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { |
| 270 DCHECK(!status_line_.empty()); | 335 DCHECK(!status_line_.empty()); |
| 271 DCHECK(!headers_.empty()); | 336 DCHECK(!headers_.empty()); |
| 272 DCHECK_EQ(kRequestKey3Size, key3_.size()); | 337 // The following works on both hybi-04 and older handshake, |
| 338 // because |key3_| is guaranteed to be empty if the handshake was hybi-04's. |
| 273 std::string raw_request = status_line_ + headers_ + "\r\n" + key3_; | 339 std::string raw_request = status_line_ + headers_ + "\r\n" + key3_; |
| 274 raw_length_ = raw_request.size(); | 340 raw_length_ = raw_request.size(); |
| 275 return raw_request; | 341 return raw_request; |
| 276 } | 342 } |
| 277 | 343 |
| 278 size_t WebSocketHandshakeRequestHandler::raw_length() const { | 344 size_t WebSocketHandshakeRequestHandler::raw_length() const { |
| 279 DCHECK_GT(raw_length_, 0); | 345 DCHECK_GT(raw_length_, 0); |
| 280 return raw_length_; | 346 return raw_length_; |
| 281 } | 347 } |
| 282 | 348 |
| 283 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() | 349 int WebSocketHandshakeRequestHandler::protocol_version() const { |
| 284 : original_header_length_(0) { | 350 DCHECK_GE(protocol_version_, 0); |
| 351 return protocol_version_; |
| 285 } | 352 } |
| 286 | 353 |
| 354 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() |
| 355 : original_header_length_(0), |
| 356 protocol_version_(0) {} |
| 357 |
| 287 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} | 358 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} |
| 288 | 359 |
| 360 int WebSocketHandshakeResponseHandler::protocol_version() const { |
| 361 DCHECK_GE(protocol_version_, 0); |
| 362 return protocol_version_; |
| 363 } |
| 364 |
| 365 void WebSocketHandshakeResponseHandler::set_protocol_version( |
| 366 int protocol_version) { |
| 367 DCHECK_GE(protocol_version, 0); |
| 368 protocol_version_ = protocol_version; |
| 369 } |
| 370 |
| 289 size_t WebSocketHandshakeResponseHandler::ParseRawResponse( | 371 size_t WebSocketHandshakeResponseHandler::ParseRawResponse( |
| 290 const char* data, int length) { | 372 const char* data, int length) { |
| 291 DCHECK_GT(length, 0); | 373 DCHECK_GT(length, 0); |
| 292 if (HasResponse()) { | 374 if (HasResponse()) { |
| 293 DCHECK(!status_line_.empty()); | 375 DCHECK(!status_line_.empty()); |
| 294 DCHECK(!headers_.empty()); | 376 DCHECK(!headers_.empty()); |
| 295 DCHECK_EQ(kResponseKeySize, key_.size()); | 377 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
| 296 return 0; | 378 return 0; |
| 297 } | 379 } |
| 298 | 380 |
| 299 size_t old_original_length = original_.size(); | 381 size_t old_original_length = original_.size(); |
| 300 | 382 |
| 301 original_.append(data, length); | 383 original_.append(data, length); |
| 302 // TODO(ukai): fail fast when response gives wrong status code. | 384 // TODO(ukai): fail fast when response gives wrong status code. |
| 303 original_header_length_ = HttpUtil::LocateEndOfHeaders( | 385 original_header_length_ = HttpUtil::LocateEndOfHeaders( |
| 304 original_.data(), original_.size(), 0); | 386 original_.data(), original_.size(), 0); |
| 305 if (!HasResponse()) | 387 if (!HasResponse()) |
| 306 return length; | 388 return length; |
| 307 | 389 |
| 308 ParseHandshakeHeader(original_.data(), | 390 ParseHandshakeHeader(original_.data(), |
| 309 original_header_length_, | 391 original_header_length_, |
| 310 &status_line_, | 392 &status_line_, |
| 311 &headers_); | 393 &headers_); |
| 312 int header_size = status_line_.size() + headers_.size(); | 394 int header_size = status_line_.size() + headers_.size(); |
| 313 DCHECK_GE(original_header_length_, header_size); | 395 DCHECK_GE(original_header_length_, header_size); |
| 314 header_separator_ = std::string(original_.data() + header_size, | 396 header_separator_ = std::string(original_.data() + header_size, |
| 315 original_header_length_ - header_size); | 397 original_header_length_ - header_size); |
| 316 key_ = std::string(original_.data() + original_header_length_, | 398 key_ = std::string(original_.data() + original_header_length_, |
| 317 kResponseKeySize); | 399 GetResponseKeySize()); |
| 318 | 400 return original_header_length_ + GetResponseKeySize() - old_original_length; |
| 319 return original_header_length_ + kResponseKeySize - old_original_length; | |
| 320 } | 401 } |
| 321 | 402 |
| 322 bool WebSocketHandshakeResponseHandler::HasResponse() const { | 403 bool WebSocketHandshakeResponseHandler::HasResponse() const { |
| 323 return original_header_length_ > 0 && | 404 return original_header_length_ > 0 && |
| 324 original_header_length_ + kResponseKeySize <= original_.size(); | 405 original_header_length_ + GetResponseKeySize() <= original_.size(); |
| 325 } | 406 } |
| 326 | 407 |
| 327 bool WebSocketHandshakeResponseHandler::ParseResponseInfo( | 408 bool WebSocketHandshakeResponseHandler::ParseResponseInfo( |
| 328 const HttpResponseInfo& response_info, | 409 const HttpResponseInfo& response_info, |
| 329 const std::string& challenge) { | 410 const std::string& challenge) { |
| 330 if (!response_info.headers.get()) | 411 if (!response_info.headers.get()) |
| 331 return false; | 412 return false; |
| 332 | 413 |
| 333 std::string response_message; | 414 std::string response_message; |
| 334 response_message = response_info.headers->GetStatusLine(); | 415 response_message = response_info.headers->GetStatusLine(); |
| 335 response_message += "\r\n"; | 416 response_message += "\r\n"; |
| 336 response_message += "Upgrade: WebSocket\r\n"; | 417 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) |
| 418 response_message += "Upgrade: websocket\r\n"; |
| 419 else |
| 420 response_message += "Upgrade: WebSocket\r\n"; |
| 337 response_message += "Connection: Upgrade\r\n"; | 421 response_message += "Connection: Upgrade\r\n"; |
| 422 |
| 423 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 424 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); |
| 425 std::string websocket_accept; |
| 426 bool encode_success = base::Base64Encode(hash, &websocket_accept); |
| 427 DCHECK(encode_success); |
| 428 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; |
| 429 } |
| 430 |
| 338 void* iter = NULL; | 431 void* iter = NULL; |
| 339 std::string name; | 432 std::string name; |
| 340 std::string value; | 433 std::string value; |
| 341 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { | 434 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { |
| 342 response_message += name + ": " + value + "\r\n"; | 435 response_message += name + ": " + value + "\r\n"; |
| 343 } | 436 } |
| 344 response_message += "\r\n"; | 437 response_message += "\r\n"; |
| 345 | 438 |
| 346 MD5Digest digest; | 439 if (protocol_version_ < kMinVersionOfHybiNewHandshake) { |
| 347 MD5Sum(challenge.data(), challenge.size(), &digest); | 440 MD5Digest digest; |
| 441 MD5Sum(challenge.data(), challenge.size(), &digest); |
| 348 | 442 |
| 349 const char* digest_data = reinterpret_cast<char*>(digest.a); | 443 const char* digest_data = reinterpret_cast<char*>(digest.a); |
| 350 response_message.append(digest_data, sizeof(digest.a)); | 444 response_message.append(digest_data, sizeof(digest.a)); |
| 445 } |
| 351 | 446 |
| 352 return ParseRawResponse(response_message.data(), | 447 return ParseRawResponse(response_message.data(), |
| 353 response_message.size()) == response_message.size(); | 448 response_message.size()) == response_message.size(); |
| 354 } | 449 } |
| 355 | 450 |
| 356 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( | 451 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( |
| 357 const spdy::SpdyHeaderBlock& headers, | 452 const spdy::SpdyHeaderBlock& headers, |
| 358 const std::string& challenge) { | 453 const std::string& challenge) { |
| 359 std::string response_message; | 454 std::string response_message; |
| 360 response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; | 455 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 361 response_message += "Upgrade: WebSocket\r\n"; | 456 response_message = "HTTP/1.1 101 Switching Protocols\r\n"; |
| 457 response_message += "Upgrade: websocket\r\n"; |
| 458 } else { |
| 459 response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; |
| 460 response_message += "Upgrade: WebSocket\r\n"; |
| 461 } |
| 362 response_message += "Connection: Upgrade\r\n"; | 462 response_message += "Connection: Upgrade\r\n"; |
| 463 |
| 464 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
| 465 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); |
| 466 std::string websocket_accept; |
| 467 bool encode_success = base::Base64Encode(hash, &websocket_accept); |
| 468 DCHECK(encode_success); |
| 469 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; |
| 470 } |
| 471 |
| 363 for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); | 472 for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); |
| 364 iter != headers.end(); | 473 iter != headers.end(); |
| 365 ++iter) { | 474 ++iter) { |
| 366 // For each value, if the server sends a NUL-separated list of values, | 475 // For each value, if the server sends a NUL-separated list of values, |
| 367 // we separate that back out into individual headers for each value | 476 // we separate that back out into individual headers for each value |
| 368 // in the list. | 477 // in the list. |
| 369 const std::string& value = iter->second; | 478 const std::string& value = iter->second; |
| 370 size_t start = 0; | 479 size_t start = 0; |
| 371 size_t end = 0; | 480 size_t end = 0; |
| 372 do { | 481 do { |
| 373 end = value.find('\0', start); | 482 end = value.find('\0', start); |
| 374 std::string tval; | 483 std::string tval; |
| 375 if (end != std::string::npos) | 484 if (end != std::string::npos) |
| 376 tval = value.substr(start, (end - start)); | 485 tval = value.substr(start, (end - start)); |
| 377 else | 486 else |
| 378 tval = value.substr(start); | 487 tval = value.substr(start); |
| 379 response_message += iter->first + ": " + tval + "\r\n"; | 488 response_message += iter->first + ": " + tval + "\r\n"; |
| 380 start = end + 1; | 489 start = end + 1; |
| 381 } while (end != std::string::npos); | 490 } while (end != std::string::npos); |
| 382 } | 491 } |
| 383 response_message += "\r\n"; | 492 response_message += "\r\n"; |
| 384 | 493 |
| 385 MD5Digest digest; | 494 if (protocol_version_ < kMinVersionOfHybiNewHandshake) { |
| 386 MD5Sum(challenge.data(), challenge.size(), &digest); | 495 MD5Digest digest; |
| 496 MD5Sum(challenge.data(), challenge.size(), &digest); |
| 387 | 497 |
| 388 const char* digest_data = reinterpret_cast<char*>(digest.a); | 498 const char* digest_data = reinterpret_cast<char*>(digest.a); |
| 389 response_message.append(digest_data, sizeof(digest.a)); | 499 response_message.append(digest_data, sizeof(digest.a)); |
| 500 } |
| 390 | 501 |
| 391 return ParseRawResponse(response_message.data(), | 502 return ParseRawResponse(response_message.data(), |
| 392 response_message.size()) == response_message.size(); | 503 response_message.size()) == response_message.size(); |
| 393 } | 504 } |
| 394 | 505 |
| 395 void WebSocketHandshakeResponseHandler::GetHeaders( | 506 void WebSocketHandshakeResponseHandler::GetHeaders( |
| 396 const char* const headers_to_get[], | 507 const char* const headers_to_get[], |
| 397 size_t headers_to_get_len, | 508 size_t headers_to_get_len, |
| 398 std::vector<std::string>* values) { | 509 std::vector<std::string>* values) { |
| 399 DCHECK(HasResponse()); | 510 DCHECK(HasResponse()); |
| 400 DCHECK(!status_line_.empty()); | 511 DCHECK(!status_line_.empty()); |
| 401 DCHECK(!headers_.empty()); | 512 DCHECK(!headers_.empty()); |
| 402 DCHECK_EQ(kResponseKeySize, key_.size()); | 513 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
| 403 | 514 |
| 404 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); | 515 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); |
| 405 } | 516 } |
| 406 | 517 |
| 407 void WebSocketHandshakeResponseHandler::RemoveHeaders( | 518 void WebSocketHandshakeResponseHandler::RemoveHeaders( |
| 408 const char* const headers_to_remove[], | 519 const char* const headers_to_remove[], |
| 409 size_t headers_to_remove_len) { | 520 size_t headers_to_remove_len) { |
| 410 DCHECK(HasResponse()); | 521 DCHECK(HasResponse()); |
| 411 DCHECK(!status_line_.empty()); | 522 DCHECK(!status_line_.empty()); |
| 412 DCHECK(!headers_.empty()); | 523 DCHECK(!headers_.empty()); |
| 413 DCHECK_EQ(kResponseKeySize, key_.size()); | 524 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
| 414 | 525 |
| 415 headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len); | 526 headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len); |
| 416 } | 527 } |
| 417 | 528 |
| 418 std::string WebSocketHandshakeResponseHandler::GetRawResponse() const { | 529 std::string WebSocketHandshakeResponseHandler::GetRawResponse() const { |
| 419 DCHECK(HasResponse()); | 530 DCHECK(HasResponse()); |
| 420 return std::string(original_.data(), | 531 return std::string(original_.data(), |
| 421 original_header_length_ + kResponseKeySize); | 532 original_header_length_ + GetResponseKeySize()); |
| 422 } | 533 } |
| 423 | 534 |
| 424 std::string WebSocketHandshakeResponseHandler::GetResponse() { | 535 std::string WebSocketHandshakeResponseHandler::GetResponse() { |
| 425 DCHECK(HasResponse()); | 536 DCHECK(HasResponse()); |
| 426 DCHECK(!status_line_.empty()); | 537 DCHECK(!status_line_.empty()); |
| 427 // headers_ might be empty for wrong response from server. | 538 // headers_ might be empty for wrong response from server. |
| 428 DCHECK_EQ(kResponseKeySize, key_.size()); | 539 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
| 429 | 540 |
| 430 return status_line_ + headers_ + header_separator_ + key_; | 541 return status_line_ + headers_ + header_separator_ + key_; |
| 431 } | 542 } |
| 432 | 543 |
| 544 size_t WebSocketHandshakeResponseHandler::GetResponseKeySize() const { |
| 545 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) |
| 546 return 0; |
| 547 return kResponseKeySize; |
| 548 } |
| 549 |
| 433 } // namespace net | 550 } // namespace net |
| OLD | NEW |