| 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 |