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); | |
ukai
2011/05/06 05:02:52
here, we're checking server's response, so it is e
Yuta Kitamura
2011/05/06 08:30:32
This function is only used for a request (not for
| |
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 DCHECK(old_key1.empty()); |
263 GetKeyNumber(key2, challenge); | 318 DCHECK(old_key2.empty()); |
Yuta Kitamura
2011/05/06 08:30:32
These DCHECKs should probably be |VLOG_IF(1, !old_
| |
264 challenge->append(key3_); | 319 *challenge = new_key; |
320 } else { | |
321 DCHECK(new_key.empty()); | |
Yuta Kitamura
2011/05/06 08:30:32
Same here.
| |
322 challenge->clear(); | |
323 GetKeyNumber(old_key1, challenge); | |
324 GetKeyNumber(old_key2, challenge); | |
325 challenge->append(key3_); | |
326 } | |
265 | 327 |
266 return true; | 328 return true; |
267 } | 329 } |
268 | 330 |
269 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { | 331 std::string WebSocketHandshakeRequestHandler::GetRawRequest() { |
270 DCHECK(!status_line_.empty()); | 332 DCHECK(!status_line_.empty()); |
271 DCHECK(!headers_.empty()); | 333 DCHECK(!headers_.empty()); |
272 DCHECK_EQ(kRequestKey3Size, key3_.size()); | 334 // The following works on both hybi-04 and older handshake, |
335 // 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_; | 336 std::string raw_request = status_line_ + headers_ + "\r\n" + key3_; |
274 raw_length_ = raw_request.size(); | 337 raw_length_ = raw_request.size(); |
275 return raw_request; | 338 return raw_request; |
276 } | 339 } |
277 | 340 |
278 size_t WebSocketHandshakeRequestHandler::raw_length() const { | 341 size_t WebSocketHandshakeRequestHandler::raw_length() const { |
279 DCHECK_GT(raw_length_, 0); | 342 DCHECK_GT(raw_length_, 0); |
280 return raw_length_; | 343 return raw_length_; |
281 } | 344 } |
282 | 345 |
283 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() | 346 int WebSocketHandshakeRequestHandler::protocol_version() const { |
284 : original_header_length_(0) { | 347 DCHECK_GE(protocol_version_, 0); |
348 return protocol_version_; | |
285 } | 349 } |
286 | 350 |
351 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() | |
352 : original_header_length_(0), | |
353 protocol_version_(0) {} | |
354 | |
287 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} | 355 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} |
288 | 356 |
357 int WebSocketHandshakeResponseHandler::protocol_version() const { | |
358 DCHECK_GE(protocol_version_, 0); | |
359 return protocol_version_; | |
360 } | |
361 | |
362 void WebSocketHandshakeResponseHandler::set_protocol_version( | |
363 int protocol_version) { | |
364 DCHECK_GE(protocol_version, 0); | |
365 protocol_version_ = protocol_version; | |
366 } | |
367 | |
289 size_t WebSocketHandshakeResponseHandler::ParseRawResponse( | 368 size_t WebSocketHandshakeResponseHandler::ParseRawResponse( |
290 const char* data, int length) { | 369 const char* data, int length) { |
291 DCHECK_GT(length, 0); | 370 DCHECK_GT(length, 0); |
292 if (HasResponse()) { | 371 if (HasResponse()) { |
293 DCHECK(!status_line_.empty()); | 372 DCHECK(!status_line_.empty()); |
294 DCHECK(!headers_.empty()); | 373 DCHECK(!headers_.empty()); |
295 DCHECK_EQ(kResponseKeySize, key_.size()); | 374 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
296 return 0; | 375 return 0; |
297 } | 376 } |
298 | 377 |
299 size_t old_original_length = original_.size(); | 378 size_t old_original_length = original_.size(); |
300 | 379 |
301 original_.append(data, length); | 380 original_.append(data, length); |
302 // TODO(ukai): fail fast when response gives wrong status code. | 381 // TODO(ukai): fail fast when response gives wrong status code. |
303 original_header_length_ = HttpUtil::LocateEndOfHeaders( | 382 original_header_length_ = HttpUtil::LocateEndOfHeaders( |
304 original_.data(), original_.size(), 0); | 383 original_.data(), original_.size(), 0); |
305 if (!HasResponse()) | 384 if (!HasResponse()) |
306 return length; | 385 return length; |
307 | 386 |
308 ParseHandshakeHeader(original_.data(), | 387 ParseHandshakeHeader(original_.data(), |
309 original_header_length_, | 388 original_header_length_, |
310 &status_line_, | 389 &status_line_, |
311 &headers_); | 390 &headers_); |
312 int header_size = status_line_.size() + headers_.size(); | 391 int header_size = status_line_.size() + headers_.size(); |
313 DCHECK_GE(original_header_length_, header_size); | 392 DCHECK_GE(original_header_length_, header_size); |
314 header_separator_ = std::string(original_.data() + header_size, | 393 header_separator_ = std::string(original_.data() + header_size, |
315 original_header_length_ - header_size); | 394 original_header_length_ - header_size); |
316 key_ = std::string(original_.data() + original_header_length_, | 395 key_ = std::string(original_.data() + original_header_length_, |
317 kResponseKeySize); | 396 GetResponseKeySize()); |
318 | 397 return original_header_length_ + GetResponseKeySize() - old_original_length; |
319 return original_header_length_ + kResponseKeySize - old_original_length; | |
320 } | 398 } |
321 | 399 |
322 bool WebSocketHandshakeResponseHandler::HasResponse() const { | 400 bool WebSocketHandshakeResponseHandler::HasResponse() const { |
323 return original_header_length_ > 0 && | 401 return original_header_length_ > 0 && |
324 original_header_length_ + kResponseKeySize <= original_.size(); | 402 original_header_length_ + GetResponseKeySize() <= original_.size(); |
325 } | 403 } |
326 | 404 |
327 bool WebSocketHandshakeResponseHandler::ParseResponseInfo( | 405 bool WebSocketHandshakeResponseHandler::ParseResponseInfo( |
328 const HttpResponseInfo& response_info, | 406 const HttpResponseInfo& response_info, |
329 const std::string& challenge) { | 407 const std::string& challenge) { |
330 if (!response_info.headers.get()) | 408 if (!response_info.headers.get()) |
331 return false; | 409 return false; |
332 | 410 |
333 std::string response_message; | 411 std::string response_message; |
334 response_message = response_info.headers->GetStatusLine(); | 412 response_message = response_info.headers->GetStatusLine(); |
335 response_message += "\r\n"; | 413 response_message += "\r\n"; |
336 response_message += "Upgrade: WebSocket\r\n"; | 414 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) |
415 response_message += "Upgrade: websocket\r\n"; | |
416 else | |
417 response_message += "Upgrade: WebSocket\r\n"; | |
337 response_message += "Connection: Upgrade\r\n"; | 418 response_message += "Connection: Upgrade\r\n"; |
419 | |
420 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { | |
421 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); | |
422 std::string websocket_accept; | |
423 bool encode_success = base::Base64Encode(hash, &websocket_accept); | |
424 DCHECK(encode_success); | |
425 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; | |
426 } | |
427 | |
338 void* iter = NULL; | 428 void* iter = NULL; |
339 std::string name; | 429 std::string name; |
340 std::string value; | 430 std::string value; |
341 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { | 431 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { |
342 response_message += name + ": " + value + "\r\n"; | 432 response_message += name + ": " + value + "\r\n"; |
343 } | 433 } |
344 response_message += "\r\n"; | 434 response_message += "\r\n"; |
345 | 435 |
346 MD5Digest digest; | 436 if (protocol_version_ < kMinVersionOfHybiNewHandshake) { |
347 MD5Sum(challenge.data(), challenge.size(), &digest); | 437 MD5Digest digest; |
438 MD5Sum(challenge.data(), challenge.size(), &digest); | |
348 | 439 |
349 const char* digest_data = reinterpret_cast<char*>(digest.a); | 440 const char* digest_data = reinterpret_cast<char*>(digest.a); |
350 response_message.append(digest_data, sizeof(digest.a)); | 441 response_message.append(digest_data, sizeof(digest.a)); |
442 } | |
351 | 443 |
352 return ParseRawResponse(response_message.data(), | 444 return ParseRawResponse(response_message.data(), |
353 response_message.size()) == response_message.size(); | 445 response_message.size()) == response_message.size(); |
354 } | 446 } |
355 | 447 |
356 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( | 448 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( |
357 const spdy::SpdyHeaderBlock& headers, | 449 const spdy::SpdyHeaderBlock& headers, |
358 const std::string& challenge) { | 450 const std::string& challenge) { |
359 std::string response_message; | 451 std::string response_message; |
360 response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; | 452 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { |
361 response_message += "Upgrade: WebSocket\r\n"; | 453 response_message = "HTTP/1.1 101 Switching Protocols\r\n"; |
454 response_message += "Upgrade: websocket\r\n"; | |
455 } else { | |
456 response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; | |
457 response_message += "Upgrade: WebSocket\r\n"; | |
458 } | |
362 response_message += "Connection: Upgrade\r\n"; | 459 response_message += "Connection: Upgrade\r\n"; |
460 | |
461 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) { | |
462 std::string hash = base::SHA1HashString(challenge + kWebSocketGuid); | |
463 std::string websocket_accept; | |
464 bool encode_success = base::Base64Encode(hash, &websocket_accept); | |
465 DCHECK(encode_success); | |
466 response_message += "Sec-WebSocket-Accept: " + websocket_accept + "\r\n"; | |
467 } | |
468 | |
363 for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); | 469 for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); |
364 iter != headers.end(); | 470 iter != headers.end(); |
365 ++iter) { | 471 ++iter) { |
366 // For each value, if the server sends a NUL-separated list of values, | 472 // 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 | 473 // we separate that back out into individual headers for each value |
368 // in the list. | 474 // in the list. |
369 const std::string& value = iter->second; | 475 const std::string& value = iter->second; |
370 size_t start = 0; | 476 size_t start = 0; |
371 size_t end = 0; | 477 size_t end = 0; |
372 do { | 478 do { |
373 end = value.find('\0', start); | 479 end = value.find('\0', start); |
374 std::string tval; | 480 std::string tval; |
375 if (end != std::string::npos) | 481 if (end != std::string::npos) |
376 tval = value.substr(start, (end - start)); | 482 tval = value.substr(start, (end - start)); |
377 else | 483 else |
378 tval = value.substr(start); | 484 tval = value.substr(start); |
379 response_message += iter->first + ": " + tval + "\r\n"; | 485 response_message += iter->first + ": " + tval + "\r\n"; |
380 start = end + 1; | 486 start = end + 1; |
381 } while (end != std::string::npos); | 487 } while (end != std::string::npos); |
382 } | 488 } |
383 response_message += "\r\n"; | 489 response_message += "\r\n"; |
384 | 490 |
385 MD5Digest digest; | 491 if (protocol_version_ < kMinVersionOfHybiNewHandshake) { |
386 MD5Sum(challenge.data(), challenge.size(), &digest); | 492 MD5Digest digest; |
493 MD5Sum(challenge.data(), challenge.size(), &digest); | |
387 | 494 |
388 const char* digest_data = reinterpret_cast<char*>(digest.a); | 495 const char* digest_data = reinterpret_cast<char*>(digest.a); |
389 response_message.append(digest_data, sizeof(digest.a)); | 496 response_message.append(digest_data, sizeof(digest.a)); |
497 } | |
390 | 498 |
391 return ParseRawResponse(response_message.data(), | 499 return ParseRawResponse(response_message.data(), |
392 response_message.size()) == response_message.size(); | 500 response_message.size()) == response_message.size(); |
393 } | 501 } |
394 | 502 |
395 void WebSocketHandshakeResponseHandler::GetHeaders( | 503 void WebSocketHandshakeResponseHandler::GetHeaders( |
396 const char* const headers_to_get[], | 504 const char* const headers_to_get[], |
397 size_t headers_to_get_len, | 505 size_t headers_to_get_len, |
398 std::vector<std::string>* values) { | 506 std::vector<std::string>* values) { |
399 DCHECK(HasResponse()); | 507 DCHECK(HasResponse()); |
400 DCHECK(!status_line_.empty()); | 508 DCHECK(!status_line_.empty()); |
401 DCHECK(!headers_.empty()); | 509 DCHECK(!headers_.empty()); |
402 DCHECK_EQ(kResponseKeySize, key_.size()); | 510 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
403 | 511 |
404 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); | 512 FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); |
405 } | 513 } |
406 | 514 |
407 void WebSocketHandshakeResponseHandler::RemoveHeaders( | 515 void WebSocketHandshakeResponseHandler::RemoveHeaders( |
408 const char* const headers_to_remove[], | 516 const char* const headers_to_remove[], |
409 size_t headers_to_remove_len) { | 517 size_t headers_to_remove_len) { |
410 DCHECK(HasResponse()); | 518 DCHECK(HasResponse()); |
411 DCHECK(!status_line_.empty()); | 519 DCHECK(!status_line_.empty()); |
412 DCHECK(!headers_.empty()); | 520 DCHECK(!headers_.empty()); |
413 DCHECK_EQ(kResponseKeySize, key_.size()); | 521 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
414 | 522 |
415 headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len); | 523 headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len); |
416 } | 524 } |
417 | 525 |
418 std::string WebSocketHandshakeResponseHandler::GetRawResponse() const { | 526 std::string WebSocketHandshakeResponseHandler::GetRawResponse() const { |
419 DCHECK(HasResponse()); | 527 DCHECK(HasResponse()); |
420 return std::string(original_.data(), | 528 return std::string(original_.data(), |
421 original_header_length_ + kResponseKeySize); | 529 original_header_length_ + GetResponseKeySize()); |
422 } | 530 } |
423 | 531 |
424 std::string WebSocketHandshakeResponseHandler::GetResponse() { | 532 std::string WebSocketHandshakeResponseHandler::GetResponse() { |
425 DCHECK(HasResponse()); | 533 DCHECK(HasResponse()); |
426 DCHECK(!status_line_.empty()); | 534 DCHECK(!status_line_.empty()); |
427 // headers_ might be empty for wrong response from server. | 535 // headers_ might be empty for wrong response from server. |
428 DCHECK_EQ(kResponseKeySize, key_.size()); | 536 DCHECK_EQ(GetResponseKeySize(), key_.size()); |
429 | 537 |
430 return status_line_ + headers_ + header_separator_ + key_; | 538 return status_line_ + headers_ + header_separator_ + key_; |
431 } | 539 } |
432 | 540 |
541 size_t WebSocketHandshakeResponseHandler::GetResponseKeySize() const { | |
542 if (protocol_version_ >= kMinVersionOfHybiNewHandshake) | |
543 return 0; | |
544 return kResponseKeySize; | |
545 } | |
546 | |
433 } // namespace net | 547 } // namespace net |
OLD | NEW |