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_job.h" | 5 #include "net/websockets/websocket_job.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 case INITIALIZED: | 104 case INITIALIZED: |
105 return false; | 105 return false; |
106 | 106 |
107 case CONNECTING: | 107 case CONNECTING: |
108 return SendHandshakeRequest(data, len); | 108 return SendHandshakeRequest(data, len); |
109 | 109 |
110 case OPEN: | 110 case OPEN: |
111 { | 111 { |
112 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len); | 112 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len); |
113 memcpy(buffer->data(), data, len); | 113 memcpy(buffer->data(), data, len); |
114 if (current_send_buffer_ || !send_buffer_queue_.empty()) { | 114 if (current_send_buffer_.get() || !send_buffer_queue_.empty()) { |
115 send_buffer_queue_.push_back(buffer); | 115 send_buffer_queue_.push_back(buffer); |
116 return true; | 116 return true; |
117 } | 117 } |
118 current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len); | 118 current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len); |
119 return SendDataInternal(current_send_buffer_->data(), | 119 return SendDataInternal(current_send_buffer_->data(), |
120 current_send_buffer_->BytesRemaining()); | 120 current_send_buffer_->BytesRemaining()); |
121 } | 121 } |
122 | 122 |
123 case CLOSING: | 123 case CLOSING: |
124 case CLOSED: | 124 case CLOSED: |
125 return false; | 125 return false; |
126 } | 126 } |
127 return false; | 127 return false; |
128 } | 128 } |
129 | 129 |
130 void WebSocketJob::Close() { | 130 void WebSocketJob::Close() { |
131 if (state_ == CLOSED) | 131 if (state_ == CLOSED) |
132 return; | 132 return; |
133 | 133 |
134 state_ = CLOSING; | 134 state_ = CLOSING; |
135 if (current_send_buffer_) { | 135 if (current_send_buffer_.get()) { |
136 // Will close in SendPending. | 136 // Will close in SendPending. |
137 return; | 137 return; |
138 } | 138 } |
139 state_ = CLOSED; | 139 state_ = CLOSED; |
140 CloseInternal(); | 140 CloseInternal(); |
141 } | 141 } |
142 | 142 |
143 void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) { | 143 void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) { |
144 state_ = CONNECTING; | 144 state_ = CONNECTING; |
145 socket_->RestartWithAuth(credentials); | 145 socket_->RestartWithAuth(credentials); |
146 } | 146 } |
147 | 147 |
148 void WebSocketJob::DetachDelegate() { | 148 void WebSocketJob::DetachDelegate() { |
149 state_ = CLOSED; | 149 state_ = CLOSED; |
150 WebSocketThrottle::GetInstance()->RemoveFromQueue(this); | 150 WebSocketThrottle::GetInstance()->RemoveFromQueue(this); |
151 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); | 151 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); |
152 | 152 |
153 scoped_refptr<WebSocketJob> protect(this); | 153 scoped_refptr<WebSocketJob> protect(this); |
154 weak_ptr_factory_.InvalidateWeakPtrs(); | 154 weak_ptr_factory_.InvalidateWeakPtrs(); |
155 weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs(); | 155 weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs(); |
156 | 156 |
157 delegate_ = NULL; | 157 delegate_ = NULL; |
158 if (socket_) | 158 if (socket_.get()) |
159 socket_->DetachDelegate(); | 159 socket_->DetachDelegate(); |
160 socket_ = NULL; | 160 socket_ = NULL; |
161 if (!callback_.is_null()) { | 161 if (!callback_.is_null()) { |
162 waiting_ = false; | 162 waiting_ = false; |
163 callback_.Reset(); | 163 callback_.Reset(); |
164 Release(); // Balanced with OnStartOpenConnection(). | 164 Release(); // Balanced with OnStartOpenConnection(). |
165 } | 165 } |
166 } | 166 } |
167 | 167 |
168 int WebSocketJob::OnStartOpenConnection( | 168 int WebSocketJob::OnStartOpenConnection( |
(...skipping 29 matching lines...) Expand all Loading... |
198 DCHECK_NE(INITIALIZED, state_); | 198 DCHECK_NE(INITIALIZED, state_); |
199 DCHECK_GT(amount_sent, 0); | 199 DCHECK_GT(amount_sent, 0); |
200 if (state_ == CLOSED) | 200 if (state_ == CLOSED) |
201 return; | 201 return; |
202 if (state_ == CONNECTING) { | 202 if (state_ == CONNECTING) { |
203 OnSentHandshakeRequest(socket, amount_sent); | 203 OnSentHandshakeRequest(socket, amount_sent); |
204 return; | 204 return; |
205 } | 205 } |
206 if (delegate_) { | 206 if (delegate_) { |
207 DCHECK(state_ == OPEN || state_ == CLOSING); | 207 DCHECK(state_ == OPEN || state_ == CLOSING); |
208 if (!current_send_buffer_) { | 208 if (!current_send_buffer_.get()) { |
209 VLOG(1) << "OnSentData current_send_buffer=NULL amount_sent=" | 209 VLOG(1) |
210 << amount_sent; | 210 << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent; |
211 return; | 211 return; |
212 } | 212 } |
213 current_send_buffer_->DidConsume(amount_sent); | 213 current_send_buffer_->DidConsume(amount_sent); |
214 if (current_send_buffer_->BytesRemaining() > 0) | 214 if (current_send_buffer_->BytesRemaining() > 0) |
215 return; | 215 return; |
216 | 216 |
217 // We need to report amount_sent of original buffer size, instead of | 217 // We need to report amount_sent of original buffer size, instead of |
218 // amount sent to |socket|. | 218 // amount sent to |socket|. |
219 amount_sent = current_send_buffer_->size(); | 219 amount_sent = current_send_buffer_->size(); |
220 DCHECK_GT(amount_sent, 0); | 220 DCHECK_GT(amount_sent, 0); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 } | 295 } |
296 | 296 |
297 CompleteIO(result); | 297 CompleteIO(result); |
298 } | 298 } |
299 | 299 |
300 void WebSocketJob::OnSentSpdyHeaders() { | 300 void WebSocketJob::OnSentSpdyHeaders() { |
301 DCHECK_NE(INITIALIZED, state_); | 301 DCHECK_NE(INITIALIZED, state_); |
302 if (state_ != CONNECTING) | 302 if (state_ != CONNECTING) |
303 return; | 303 return; |
304 if (delegate_) | 304 if (delegate_) |
305 delegate_->OnSentData(socket_, handshake_request_->original_length()); | 305 delegate_->OnSentData(socket_.get(), handshake_request_->original_length()); |
306 handshake_request_.reset(); | 306 handshake_request_.reset(); |
307 } | 307 } |
308 | 308 |
309 int WebSocketJob::OnReceivedSpdyResponseHeader( | 309 int WebSocketJob::OnReceivedSpdyResponseHeader( |
310 const SpdyHeaderBlock& headers, int status) { | 310 const SpdyHeaderBlock& headers, int status) { |
311 DCHECK_NE(INITIALIZED, state_); | 311 DCHECK_NE(INITIALIZED, state_); |
312 if (state_ != CONNECTING) | 312 if (state_ != CONNECTING) |
313 return status; | 313 return status; |
314 if (status != OK) | 314 if (status != OK) |
315 return status; | 315 return status; |
316 // TODO(toyoshim): Fallback to non-spdy connection? | 316 // TODO(toyoshim): Fallback to non-spdy connection? |
317 handshake_response_->ParseResponseHeaderBlock(headers, | 317 handshake_response_->ParseResponseHeaderBlock(headers, |
318 challenge_, | 318 challenge_, |
319 spdy_protocol_version_); | 319 spdy_protocol_version_); |
320 | 320 |
321 SaveCookiesAndNotifyHeadersComplete(); | 321 SaveCookiesAndNotifyHeadersComplete(); |
322 return OK; | 322 return OK; |
323 } | 323 } |
324 | 324 |
325 void WebSocketJob::OnSentSpdyData(size_t bytes_sent) { | 325 void WebSocketJob::OnSentSpdyData(size_t bytes_sent) { |
326 DCHECK_NE(INITIALIZED, state_); | 326 DCHECK_NE(INITIALIZED, state_); |
327 DCHECK_NE(CONNECTING, state_); | 327 DCHECK_NE(CONNECTING, state_); |
328 if (state_ == CLOSED) | 328 if (state_ == CLOSED) |
329 return; | 329 return; |
330 if (!spdy_websocket_stream_.get()) | 330 if (!spdy_websocket_stream_.get()) |
331 return; | 331 return; |
332 OnSentData(socket_, static_cast<int>(bytes_sent)); | 332 OnSentData(socket_.get(), static_cast<int>(bytes_sent)); |
333 } | 333 } |
334 | 334 |
335 void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) { | 335 void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) { |
336 DCHECK_NE(INITIALIZED, state_); | 336 DCHECK_NE(INITIALIZED, state_); |
337 DCHECK_NE(CONNECTING, state_); | 337 DCHECK_NE(CONNECTING, state_); |
338 if (state_ == CLOSED) | 338 if (state_ == CLOSED) |
339 return; | 339 return; |
340 if (!spdy_websocket_stream_.get()) | 340 if (!spdy_websocket_stream_.get()) |
341 return; | 341 return; |
342 if (buffer) { | 342 if (buffer) { |
343 OnReceivedData(socket_, buffer->GetRemainingData(), | 343 OnReceivedData( |
344 buffer->GetRemainingSize()); | 344 socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize()); |
345 } else { | 345 } else { |
346 OnReceivedData(socket_, NULL, 0); | 346 OnReceivedData(socket_.get(), NULL, 0); |
347 } | 347 } |
348 } | 348 } |
349 | 349 |
350 void WebSocketJob::OnCloseSpdyStream() { | 350 void WebSocketJob::OnCloseSpdyStream() { |
351 spdy_websocket_stream_.reset(); | 351 spdy_websocket_stream_.reset(); |
352 OnClose(socket_); | 352 OnClose(socket_.get()); |
353 } | 353 } |
354 | 354 |
355 bool WebSocketJob::SendHandshakeRequest(const char* data, int len) { | 355 bool WebSocketJob::SendHandshakeRequest(const char* data, int len) { |
356 DCHECK_EQ(state_, CONNECTING); | 356 DCHECK_EQ(state_, CONNECTING); |
357 if (started_to_send_handshake_request_) | 357 if (started_to_send_handshake_request_) |
358 return false; | 358 return false; |
359 if (!handshake_request_->ParseRequest(data, len)) | 359 if (!handshake_request_->ParseRequest(data, len)) |
360 return false; | 360 return false; |
361 | 361 |
362 // handshake message is completed. | 362 // handshake message is completed. |
363 handshake_response_->set_protocol_version( | 363 handshake_response_->set_protocol_version( |
364 handshake_request_->protocol_version()); | 364 handshake_request_->protocol_version()); |
365 AddCookieHeaderAndSend(); | 365 AddCookieHeaderAndSend(); |
366 return true; | 366 return true; |
367 } | 367 } |
368 | 368 |
369 void WebSocketJob::AddCookieHeaderAndSend() { | 369 void WebSocketJob::AddCookieHeaderAndSend() { |
370 bool allow = true; | 370 bool allow = true; |
371 if (delegate_ && !delegate_->CanGetCookies(socket_, GetURLForCookies())) | 371 if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies())) |
372 allow = false; | 372 allow = false; |
373 | 373 |
374 if (socket_ && delegate_ && state_ == CONNECTING) { | 374 if (socket_.get() && delegate_ && state_ == CONNECTING) { |
375 handshake_request_->RemoveHeaders( | 375 handshake_request_->RemoveHeaders(kCookieHeaders, |
376 kCookieHeaders, arraysize(kCookieHeaders)); | 376 arraysize(kCookieHeaders)); |
377 if (allow && socket_->context()->cookie_store()) { | 377 if (allow && socket_->context()->cookie_store()) { |
378 // Add cookies, including HttpOnly cookies. | 378 // Add cookies, including HttpOnly cookies. |
379 CookieOptions cookie_options; | 379 CookieOptions cookie_options; |
380 cookie_options.set_include_httponly(); | 380 cookie_options.set_include_httponly(); |
381 socket_->context()->cookie_store()->GetCookiesWithOptionsAsync( | 381 socket_->context()->cookie_store()->GetCookiesWithOptionsAsync( |
382 GetURLForCookies(), cookie_options, | 382 GetURLForCookies(), cookie_options, |
383 base::Bind(&WebSocketJob::LoadCookieCallback, | 383 base::Bind(&WebSocketJob::LoadCookieCallback, |
384 weak_ptr_factory_.GetWeakPtr())); | 384 weak_ptr_factory_.GetWeakPtr())); |
385 } else { | 385 } else { |
386 DoSendData(); | 386 DoSendData(); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 received_data.insert(received_data.end(), | 490 received_data.insert(received_data.end(), |
491 received_data_after_handshake_.begin(), | 491 received_data_after_handshake_.begin(), |
492 received_data_after_handshake_.end()); | 492 received_data_after_handshake_.end()); |
493 received_data_after_handshake_.clear(); | 493 received_data_after_handshake_.clear(); |
494 | 494 |
495 state_ = OPEN; | 495 state_ = OPEN; |
496 | 496 |
497 DCHECK(!received_data.empty()); | 497 DCHECK(!received_data.empty()); |
498 if (delegate_) | 498 if (delegate_) |
499 delegate_->OnReceivedData( | 499 delegate_->OnReceivedData( |
500 socket_, &received_data.front(), received_data.size()); | 500 socket_.get(), &received_data.front(), received_data.size()); |
501 | 501 |
502 WebSocketThrottle::GetInstance()->RemoveFromQueue(this); | 502 WebSocketThrottle::GetInstance()->RemoveFromQueue(this); |
503 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); | 503 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); |
504 } | 504 } |
505 | 505 |
506 void WebSocketJob::SaveNextCookie() { | 506 void WebSocketJob::SaveNextCookie() { |
507 if (!socket_ || !delegate_ || state_ != CONNECTING) | 507 if (!socket_.get() || !delegate_ || state_ != CONNECTING) |
508 return; | 508 return; |
509 | 509 |
510 callback_pending_ = false; | 510 callback_pending_ = false; |
511 save_next_cookie_running_ = true; | 511 save_next_cookie_running_ = true; |
512 | 512 |
513 if (socket_->context()->cookie_store()) { | 513 if (socket_->context()->cookie_store()) { |
514 GURL url_for_cookies = GetURLForCookies(); | 514 GURL url_for_cookies = GetURLForCookies(); |
515 | 515 |
516 CookieOptions options; | 516 CookieOptions options; |
517 options.set_include_httponly(); | 517 options.set_include_httponly(); |
518 | 518 |
519 // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since | 519 // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since |
520 // CookieMonster's asynchronous operation APIs queue the callback to run it | 520 // CookieMonster's asynchronous operation APIs queue the callback to run it |
521 // on the thread where the API was called, there won't be race. I.e. unless | 521 // on the thread where the API was called, there won't be race. I.e. unless |
522 // the callback is run synchronously, it won't be run in parallel with this | 522 // the callback is run synchronously, it won't be run in parallel with this |
523 // method. | 523 // method. |
524 while (!callback_pending_ && | 524 while (!callback_pending_ && |
525 response_cookies_save_index_ < response_cookies_.size()) { | 525 response_cookies_save_index_ < response_cookies_.size()) { |
526 std::string cookie = response_cookies_[response_cookies_save_index_]; | 526 std::string cookie = response_cookies_[response_cookies_save_index_]; |
527 response_cookies_save_index_++; | 527 response_cookies_save_index_++; |
528 | 528 |
529 if (!delegate_->CanSetCookie(socket_, url_for_cookies, cookie, &options)) | 529 if (!delegate_->CanSetCookie( |
| 530 socket_.get(), url_for_cookies, cookie, &options)) |
530 continue; | 531 continue; |
531 | 532 |
532 callback_pending_ = true; | 533 callback_pending_ = true; |
533 socket_->context()->cookie_store()->SetCookieWithOptionsAsync( | 534 socket_->context()->cookie_store()->SetCookieWithOptionsAsync( |
534 url_for_cookies, cookie, options, | 535 url_for_cookies, cookie, options, |
535 base::Bind(&WebSocketJob::OnCookieSaved, | 536 base::Bind(&WebSocketJob::OnCookieSaved, |
536 weak_ptr_factory_.GetWeakPtr())); | 537 weak_ptr_factory_.GetWeakPtr())); |
537 } | 538 } |
538 } | 539 } |
539 | 540 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 SSLInfo ssl_info; | 607 SSLInfo ssl_info; |
607 bool was_npn_negotiated; | 608 bool was_npn_negotiated; |
608 NextProto protocol_negotiated = kProtoUnknown; | 609 NextProto protocol_negotiated = kProtoUnknown; |
609 bool use_ssl = spdy_session->GetSSLInfo( | 610 bool use_ssl = spdy_session->GetSSLInfo( |
610 &ssl_info, &was_npn_negotiated, &protocol_negotiated); | 611 &ssl_info, &was_npn_negotiated, &protocol_negotiated); |
611 if (socket_->is_secure() && !use_ssl) | 612 if (socket_->is_secure() && !use_ssl) |
612 return OK; | 613 return OK; |
613 | 614 |
614 // Create SpdyWebSocketStream. | 615 // Create SpdyWebSocketStream. |
615 spdy_protocol_version_ = spdy_session->GetProtocolVersion(); | 616 spdy_protocol_version_ = spdy_session->GetProtocolVersion(); |
616 spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this)); | 617 spdy_websocket_stream_.reset( |
| 618 new SpdyWebSocketStream(spdy_session.get(), this)); |
617 | 619 |
618 int result = spdy_websocket_stream_->InitializeStream( | 620 int result = spdy_websocket_stream_->InitializeStream( |
619 socket_->url(), MEDIUM, *socket_->net_log()); | 621 socket_->url(), MEDIUM, *socket_->net_log()); |
620 if (result == OK) { | 622 if (result == OK) { |
621 OnConnected(socket_, kMaxPendingSendAllowed); | 623 OnConnected(socket_.get(), kMaxPendingSendAllowed); |
622 return ERR_PROTOCOL_SWITCHED; | 624 return ERR_PROTOCOL_SWITCHED; |
623 } | 625 } |
624 if (result != ERR_IO_PENDING) { | 626 if (result != ERR_IO_PENDING) { |
625 spdy_websocket_stream_.reset(); | 627 spdy_websocket_stream_.reset(); |
626 return OK; | 628 return OK; |
627 } | 629 } |
628 | 630 |
629 return ERR_IO_PENDING; | 631 return ERR_IO_PENDING; |
630 } | 632 } |
631 | 633 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 } | 678 } |
677 | 679 |
678 void WebSocketJob::CloseInternal() { | 680 void WebSocketJob::CloseInternal() { |
679 if (spdy_websocket_stream_.get()) | 681 if (spdy_websocket_stream_.get()) |
680 spdy_websocket_stream_->Close(); | 682 spdy_websocket_stream_->Close(); |
681 if (socket_.get()) | 683 if (socket_.get()) |
682 socket_->Close(); | 684 socket_->Close(); |
683 } | 685 } |
684 | 686 |
685 void WebSocketJob::SendPending() { | 687 void WebSocketJob::SendPending() { |
686 if (current_send_buffer_) | 688 if (current_send_buffer_.get()) |
687 return; | 689 return; |
688 | 690 |
689 // Current buffer has been sent. Try next if any. | 691 // Current buffer has been sent. Try next if any. |
690 if (send_buffer_queue_.empty()) { | 692 if (send_buffer_queue_.empty()) { |
691 // No more data to send. | 693 // No more data to send. |
692 if (state_ == CLOSING) | 694 if (state_ == CLOSING) |
693 CloseInternal(); | 695 CloseInternal(); |
694 return; | 696 return; |
695 } | 697 } |
696 | 698 |
697 scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front(); | 699 scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front(); |
698 send_buffer_queue_.pop_front(); | 700 send_buffer_queue_.pop_front(); |
699 current_send_buffer_ = new DrainableIOBuffer(next_buffer, | 701 current_send_buffer_ = |
700 next_buffer->size()); | 702 new DrainableIOBuffer(next_buffer.get(), next_buffer->size()); |
701 SendDataInternal(current_send_buffer_->data(), | 703 SendDataInternal(current_send_buffer_->data(), |
702 current_send_buffer_->BytesRemaining()); | 704 current_send_buffer_->BytesRemaining()); |
703 } | 705 } |
704 | 706 |
705 } // namespace net | 707 } // namespace net |
OLD | NEW |