OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/md5.h" | 7 #include "base/md5.h" |
8 #include "base/string_piece.h" | 8 #include "base/string_piece.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "googleurl/src/gurl.h" | 10 #include "googleurl/src/gurl.h" |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 } | 87 } |
88 } | 88 } |
89 if (!should_remove) { | 89 if (!should_remove) { |
90 filtered_headers.append(line_begin, line_end); | 90 filtered_headers.append(line_begin, line_end); |
91 filtered_headers.append("\r\n"); | 91 filtered_headers.append("\r\n"); |
92 } | 92 } |
93 } | 93 } |
94 return filtered_headers; | 94 return filtered_headers; |
95 } | 95 } |
96 | 96 |
97 // Gets a key number for |key_name| in |headers| and appends the number to | 97 // Gets a key number from |key| and appends the number to |challenge|. |
98 // |challenge|. | |
99 // The key number (/part_N/) is extracted as step 4.-8. in | 98 // The key number (/part_N/) is extracted as step 4.-8. in |
100 // 5.2. Sending the server's opening handshake of | 99 // 5.2. Sending the server's opening handshake of |
101 // http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt | 100 // http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt |
102 void GetKeyNumber(net::HttpRequestHeaders* headers, const char* key_name, | 101 void GetKeyNumber(const std::string& key, std::string* challenge) { |
103 std::string* challenge) { | |
104 std::string key; | |
105 headers->GetHeader(key_name, &key); | |
106 headers->RemoveHeader(key_name); | |
107 | |
108 uint32 key_number = 0; | 102 uint32 key_number = 0; |
109 uint32 spaces = 0; | 103 uint32 spaces = 0; |
110 for (size_t i = 0; i < key.size(); ++i) { | 104 for (size_t i = 0; i < key.size(); ++i) { |
111 if (isdigit(key[i])) | 105 if (isdigit(key[i])) { |
| 106 // key_number should not overflow. (it comes from |
| 107 // WebCore/websockets/WebSocketHandshake.cpp). |
112 key_number = key_number * 10 + key[i] - '0'; | 108 key_number = key_number * 10 + key[i] - '0'; |
113 else if (key[i] == ' ') | 109 } else if (key[i] == ' ') { |
114 ++spaces; | 110 ++spaces; |
| 111 } |
115 } | 112 } |
116 // spaces should not be zero in valid handshake request. | 113 // spaces should not be zero in valid handshake request. |
117 if (spaces == 0) | 114 if (spaces == 0) |
118 return; | 115 return; |
119 key_number /= spaces; | 116 key_number /= spaces; |
120 | 117 |
121 char part[4]; | 118 char part[4]; |
122 for (int i = 0; i < 4; i++) { | 119 for (int i = 0; i < 4; i++) { |
123 part[3 - i] = key_number & 0xFF; | 120 part[3 - i] = key_number & 0xFF; |
124 key_number >>= 8; | 121 key_number >>= 8; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 if (method_end != base::StringPiece::npos) | 189 if (method_end != base::StringPiece::npos) |
193 request_info.method = std::string(status_line_.data(), method_end); | 190 request_info.method = std::string(status_line_.data(), method_end); |
194 | 191 |
195 request_info.extra_headers.Clear(); | 192 request_info.extra_headers.Clear(); |
196 request_info.extra_headers.AddHeadersFromString(headers_); | 193 request_info.extra_headers.AddHeadersFromString(headers_); |
197 | 194 |
198 request_info.extra_headers.RemoveHeader("Upgrade"); | 195 request_info.extra_headers.RemoveHeader("Upgrade"); |
199 request_info.extra_headers.RemoveHeader("Connection"); | 196 request_info.extra_headers.RemoveHeader("Connection"); |
200 | 197 |
201 challenge->clear(); | 198 challenge->clear(); |
202 GetKeyNumber(&request_info.extra_headers, "Sec-WebSocket-Key1", challenge); | 199 std::string key; |
203 GetKeyNumber(&request_info.extra_headers, "Sec-WebSocket-Key2", challenge); | 200 request_info.extra_headers.GetHeader("Sec-WebSocket-Key1", &key); |
| 201 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key1"); |
| 202 GetKeyNumber(key, challenge); |
| 203 |
| 204 request_info.extra_headers.GetHeader("Sec-WebSocket-Key2", &key); |
| 205 request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); |
| 206 GetKeyNumber(key, challenge); |
| 207 |
204 challenge->append(key3_); | 208 challenge->append(key3_); |
205 | 209 |
206 return request_info; | 210 return request_info; |
207 } | 211 } |
208 | 212 |
| 213 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( |
| 214 const GURL& url, spdy::SpdyHeaderBlock* headers, std::string* challenge) { |
| 215 // We don't set "method" and "version". These are fixed value in WebSocket |
| 216 // protocol. |
| 217 (*headers)["url"] = url.spec(); |
| 218 |
| 219 std::string key1; |
| 220 std::string key2; |
| 221 HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); |
| 222 while (iter.GetNext()) { |
| 223 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 224 "connection")) { |
| 225 // Ignore "Connection" header. |
| 226 continue; |
| 227 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 228 "upgrade")) { |
| 229 // Ignore "Upgrade" header. |
| 230 continue; |
| 231 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 232 "sec-websocket-key1")) { |
| 233 // Use only for generating challenge. |
| 234 key1 = iter.values(); |
| 235 continue; |
| 236 } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
| 237 "sec-websocket-key2")) { |
| 238 // Use only for generating challenge. |
| 239 key2 = iter.values(); |
| 240 continue; |
| 241 } |
| 242 // Others should be sent out to |headers|. |
| 243 std::string name = StringToLowerASCII(iter.name()); |
| 244 spdy::SpdyHeaderBlock::iterator found = headers->find(name); |
| 245 if (found == headers->end()) { |
| 246 (*headers)[name] = iter.values(); |
| 247 } else { |
| 248 // For now, websocket doesn't use multiple headers, but follows to http. |
| 249 found->second.append(1, '\0'); // +=() doesn't append 0's |
| 250 found->second.append(iter.values()); |
| 251 } |
| 252 } |
| 253 |
| 254 challenge->clear(); |
| 255 GetKeyNumber(key1, challenge); |
| 256 GetKeyNumber(key2, challenge); |
| 257 challenge->append(key3_); |
| 258 |
| 259 return true; |
| 260 } |
| 261 |
209 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { | 262 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { |
210 DCHECK(status_line_.size() > 0); | 263 DCHECK(status_line_.size() > 0); |
211 DCHECK(headers_.size() > 0); | 264 DCHECK(headers_.size() > 0); |
212 DCHECK_EQ(kRequestKey3Size, key3_.size()); | 265 DCHECK_EQ(kRequestKey3Size, key3_.size()); |
213 std::string raw_request = status_line_ + headers_ + "\r\n" + key3_; | 266 std::string raw_request = status_line_ + headers_ + "\r\n" + key3_; |
214 raw_length_ = raw_request.size(); | 267 raw_length_ = raw_request.size(); |
215 return raw_request; | 268 return raw_request; |
216 } | 269 } |
217 | 270 |
218 size_t WebSocketHandshakeRequestHandler::raw_length() const { | 271 size_t WebSocketHandshakeRequestHandler::raw_length() const { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 MD5Digest digest; | 333 MD5Digest digest; |
281 MD5Sum(challenge.data(), challenge.size(), &digest); | 334 MD5Sum(challenge.data(), challenge.size(), &digest); |
282 | 335 |
283 const char* digest_data = reinterpret_cast<char*>(digest.a); | 336 const char* digest_data = reinterpret_cast<char*>(digest.a); |
284 response_message.append(digest_data, sizeof(digest.a)); | 337 response_message.append(digest_data, sizeof(digest.a)); |
285 | 338 |
286 return ParseRawResponse(response_message.data(), | 339 return ParseRawResponse(response_message.data(), |
287 response_message.size()) == response_message.size(); | 340 response_message.size()) == response_message.size(); |
288 } | 341 } |
289 | 342 |
| 343 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( |
| 344 const spdy::SpdyHeaderBlock& headers, |
| 345 const std::string& challenge) { |
| 346 std::string response_message; |
| 347 response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; |
| 348 response_message += "Upgrade: WebSocket\r\n"; |
| 349 response_message += "Connection: Upgrade\r\n"; |
| 350 for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); |
| 351 iter != headers.end(); |
| 352 ++iter) { |
| 353 // For each value, if the server sends a NUL-separated list of values, |
| 354 // we separate that back out into individual headers for each value |
| 355 // in the list. |
| 356 const std::string& value = iter->second; |
| 357 size_t start = 0; |
| 358 size_t end = 0; |
| 359 do { |
| 360 end = value.find('\0', start); |
| 361 std::string tval; |
| 362 if (end != std::string::npos) |
| 363 tval = value.substr(start, (end - start)); |
| 364 else |
| 365 tval = value.substr(start); |
| 366 response_message += iter->first + ": " + tval + "\r\n"; |
| 367 start = end + 1; |
| 368 } while (end != std::string::npos); |
| 369 } |
| 370 response_message += "\r\n"; |
| 371 |
| 372 MD5Digest digest; |
| 373 MD5Sum(challenge.data(), challenge.size(), &digest); |
| 374 |
| 375 const char* digest_data = reinterpret_cast<char*>(digest.a); |
| 376 response_message.append(digest_data, sizeof(digest.a)); |
| 377 |
| 378 return ParseRawResponse(response_message.data(), |
| 379 response_message.size()) == response_message.size(); |
| 380 } |
| 381 |
290 void WebSocketHandshakeResponseHandler::GetHeaders( | 382 void WebSocketHandshakeResponseHandler::GetHeaders( |
291 const char* const headers_to_get[], | 383 const char* const headers_to_get[], |
292 size_t headers_to_get_len, | 384 size_t headers_to_get_len, |
293 std::vector<std::string>* values) { | 385 std::vector<std::string>* values) { |
294 DCHECK(HasResponse()); | 386 DCHECK(HasResponse()); |
295 DCHECK(status_line_.size() > 0); | 387 DCHECK(status_line_.size() > 0); |
296 DCHECK(headers_.size() > 0); | 388 DCHECK(headers_.size() > 0); |
297 DCHECK_EQ(kResponseKeySize, key_.size()); | 389 DCHECK_EQ(kResponseKeySize, key_.size()); |
298 | 390 |
299 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); | 391 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); |
(...skipping 13 matching lines...) Expand all Loading... |
313 std::string WebSocketHandshakeResponseHandler::GetResponse() { | 405 std::string WebSocketHandshakeResponseHandler::GetResponse() { |
314 DCHECK(HasResponse()); | 406 DCHECK(HasResponse()); |
315 DCHECK(status_line_.size() > 0); | 407 DCHECK(status_line_.size() > 0); |
316 DCHECK(headers_.size() > 0); | 408 DCHECK(headers_.size() > 0); |
317 DCHECK_EQ(kResponseKeySize, key_.size()); | 409 DCHECK_EQ(kResponseKeySize, key_.size()); |
318 | 410 |
319 return status_line_ + headers_ + "\r\n" + key_; | 411 return status_line_ + headers_ + "\r\n" + key_; |
320 } | 412 } |
321 | 413 |
322 } // namespace net | 414 } // namespace net |
OLD | NEW |