| OLD | NEW |
| 1 // Copyright (c) 2011 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/http/http_pipelined_connection_impl.h" | 5 #include "net/http/http_pipelined_connection_impl.h" |
| 6 | 6 |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "net/base/io_buffer.h" | 9 #include "net/base/io_buffer.h" |
| 10 #include "net/http/http_pipelined_stream.h" | 10 #include "net/http/http_pipelined_stream.h" |
| 11 #include "net/http/http_request_info.h" | 11 #include "net/http/http_request_info.h" |
| 12 #include "net/http/http_response_body_drainer.h" | 12 #include "net/http/http_response_body_drainer.h" |
| 13 #include "net/http/http_response_headers.h" | 13 #include "net/http/http_response_headers.h" |
| 14 #include "net/http/http_stream_parser.h" | 14 #include "net/http/http_stream_parser.h" |
| 15 #include "net/http/http_version.h" |
| 15 #include "net/socket/client_socket_handle.h" | 16 #include "net/socket/client_socket_handle.h" |
| 16 | 17 |
| 17 namespace net { | 18 namespace net { |
| 18 | 19 |
| 19 HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl( | 20 HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl( |
| 20 ClientSocketHandle* connection, | 21 ClientSocketHandle* connection, |
| 21 HttpPipelinedConnection::Delegate* delegate, | 22 HttpPipelinedConnection::Delegate* delegate, |
| 22 const SSLConfig& used_ssl_config, | 23 const SSLConfig& used_ssl_config, |
| 23 const ProxyInfo& used_proxy_info, | 24 const ProxyInfo& used_proxy_info, |
| 24 const BoundNetLog& net_log, | 25 const BoundNetLog& net_log, |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 case SEND_STATE_SEND_ACTIVE_REQUEST: | 161 case SEND_STATE_SEND_ACTIVE_REQUEST: |
| 161 rv = DoSendActiveRequest(rv); | 162 rv = DoSendActiveRequest(rv); |
| 162 break; | 163 break; |
| 163 case SEND_STATE_COMPLETE: | 164 case SEND_STATE_COMPLETE: |
| 164 rv = DoSendComplete(rv); | 165 rv = DoSendComplete(rv); |
| 165 break; | 166 break; |
| 166 case SEND_STATE_EVICT_PENDING_REQUESTS: | 167 case SEND_STATE_EVICT_PENDING_REQUESTS: |
| 167 rv = DoEvictPendingSendRequests(rv); | 168 rv = DoEvictPendingSendRequests(rv); |
| 168 break; | 169 break; |
| 169 default: | 170 default: |
| 170 NOTREACHED() << "bad send state: " << state; | 171 CHECK(false) << "bad send state: " << state; |
| 171 rv = ERR_FAILED; | 172 rv = ERR_FAILED; |
| 172 break; | 173 break; |
| 173 } | 174 } |
| 174 } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE); | 175 } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE); |
| 175 send_still_on_call_stack_ = false; | 176 send_still_on_call_stack_ = false; |
| 176 return rv; | 177 return rv; |
| 177 } | 178 } |
| 178 | 179 |
| 179 void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) { | 180 void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) { |
| 180 CHECK(active_send_request_.get()); | 181 CHECK(active_send_request_.get()); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 return rv; | 331 return rv; |
| 331 case READ_STATE_STREAM_CLOSED: | 332 case READ_STATE_STREAM_CLOSED: |
| 332 rv = DoReadStreamClosed(); | 333 rv = DoReadStreamClosed(); |
| 333 break; | 334 break; |
| 334 case READ_STATE_EVICT_PENDING_READS: | 335 case READ_STATE_EVICT_PENDING_READS: |
| 335 rv = DoEvictPendingReadHeaders(rv); | 336 rv = DoEvictPendingReadHeaders(rv); |
| 336 break; | 337 break; |
| 337 case READ_STATE_NONE: | 338 case READ_STATE_NONE: |
| 338 break; | 339 break; |
| 339 default: | 340 default: |
| 340 NOTREACHED() << "bad read state"; | 341 CHECK(false) << "bad read state"; |
| 341 rv = ERR_FAILED; | 342 rv = ERR_FAILED; |
| 342 break; | 343 break; |
| 343 } | 344 } |
| 344 } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE); | 345 } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE); |
| 345 read_still_on_call_stack_ = false; | 346 read_still_on_call_stack_ = false; |
| 346 return rv; | 347 return rv; |
| 347 } | 348 } |
| 348 | 349 |
| 349 void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) { | 350 void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) { |
| 350 DoReadHeadersLoop(result); | 351 DoReadHeadersLoop(result); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 // Since nobody will read whatever data is on the pipeline associated with | 388 // Since nobody will read whatever data is on the pipeline associated with |
| 388 // this closed request, we must shut down the rest of the pipeline. | 389 // this closed request, we must shut down the rest of the pipeline. |
| 389 read_next_state_ = READ_STATE_EVICT_PENDING_READS; | 390 read_next_state_ = READ_STATE_EVICT_PENDING_READS; |
| 390 break; | 391 break; |
| 391 | 392 |
| 392 case STREAM_SENT: | 393 case STREAM_SENT: |
| 393 read_next_state_ = READ_STATE_NONE; | 394 read_next_state_ = READ_STATE_NONE; |
| 394 break; | 395 break; |
| 395 | 396 |
| 396 default: | 397 default: |
| 397 NOTREACHED() << "Unexpected read state: " | 398 CHECK(false) << "Unexpected read state: " |
| 398 << stream_info_map_[next_id].state; | 399 << stream_info_map_[next_id].state; |
| 399 } | 400 } |
| 400 | 401 |
| 401 return OK; | 402 return OK; |
| 402 } | 403 } |
| 403 | 404 |
| 404 int HttpPipelinedConnectionImpl::DoReadHeaders(int result) { | 405 int HttpPipelinedConnectionImpl::DoReadHeaders(int result) { |
| 405 CHECK(active_read_id_); | 406 CHECK(active_read_id_); |
| 406 CHECK(ContainsKey(stream_info_map_, active_read_id_)); | 407 CHECK(ContainsKey(stream_info_map_, active_read_id_)); |
| 407 CHECK_EQ(STREAM_READ_PENDING, stream_info_map_[active_read_id_].state); | 408 CHECK_EQ(STREAM_READ_PENDING, stream_info_map_[active_read_id_].state); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 418 CHECK_EQ(STREAM_ACTIVE, stream_info_map_[active_read_id_].state); | 419 CHECK_EQ(STREAM_ACTIVE, stream_info_map_[active_read_id_].state); |
| 419 | 420 |
| 420 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 421 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| 421 if (result < OK) { | 422 if (result < OK) { |
| 422 if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) { | 423 if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) { |
| 423 result = ERR_PIPELINE_EVICTION; | 424 result = ERR_PIPELINE_EVICTION; |
| 424 } | 425 } |
| 425 usable_ = false; | 426 usable_ = false; |
| 426 } | 427 } |
| 427 | 428 |
| 429 CheckHeadersForPipelineCompatibility(result, active_read_id_); |
| 430 |
| 428 if (!read_still_on_call_stack_) { | 431 if (!read_still_on_call_stack_) { |
| 429 QueueUserCallback(active_read_id_, | 432 QueueUserCallback(active_read_id_, |
| 430 stream_info_map_[active_read_id_].read_headers_callback, | 433 stream_info_map_[active_read_id_].read_headers_callback, |
| 431 result, FROM_HERE); | 434 result, FROM_HERE); |
| 432 } | 435 } |
| 433 | 436 |
| 434 return result; | 437 return result; |
| 435 } | 438 } |
| 436 | 439 |
| 437 int HttpPipelinedConnectionImpl::DoReadWaitForClose(int result) { | 440 int HttpPipelinedConnectionImpl::DoReadWaitForClose(int result) { |
| 438 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 441 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| 439 return result; | 442 return result; |
| 440 } | 443 } |
| 441 | 444 |
| 442 int HttpPipelinedConnectionImpl::DoReadStreamClosed() { | 445 int HttpPipelinedConnectionImpl::DoReadStreamClosed() { |
| 443 CHECK(active_read_id_); | 446 CHECK(active_read_id_); |
| 444 CHECK(ContainsKey(stream_info_map_, active_read_id_)); | 447 CHECK(ContainsKey(stream_info_map_, active_read_id_)); |
| 445 CHECK_EQ(stream_info_map_[active_read_id_].state, STREAM_CLOSED); | 448 CHECK_EQ(stream_info_map_[active_read_id_].state, STREAM_CLOSED); |
| 446 active_read_id_ = 0; | 449 active_read_id_ = 0; |
| 447 if (!usable_) { | 450 if (!usable_) { |
| 451 // TODO(simonjam): Don't wait this long to evict. |
| 448 read_next_state_ = READ_STATE_EVICT_PENDING_READS; | 452 read_next_state_ = READ_STATE_EVICT_PENDING_READS; |
| 449 return OK; | 453 return OK; |
| 450 } | 454 } |
| 451 completed_one_request_ = true; | 455 completed_one_request_ = true; |
| 452 MessageLoop::current()->PostTask( | 456 MessageLoop::current()->PostTask( |
| 453 FROM_HERE, | 457 FROM_HERE, |
| 454 method_factory_.NewRunnableMethod( | 458 method_factory_.NewRunnableMethod( |
| 455 &HttpPipelinedConnectionImpl::StartNextDeferredRead)); | 459 &HttpPipelinedConnectionImpl::StartNextDeferredRead)); |
| 456 read_next_state_ = READ_STATE_NONE; | 460 read_next_state_ = READ_STATE_NONE; |
| 457 return OK; | 461 return OK; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 case STREAM_READ_EVICTED: | 524 case STREAM_READ_EVICTED: |
| 521 stream_info_map_[pipeline_id].state = STREAM_CLOSED; | 525 stream_info_map_[pipeline_id].state = STREAM_CLOSED; |
| 522 break; | 526 break; |
| 523 | 527 |
| 524 case STREAM_CLOSED: | 528 case STREAM_CLOSED: |
| 525 case STREAM_UNUSED: | 529 case STREAM_UNUSED: |
| 526 // TODO(simonjam): Why is Close() sometimes called twice? | 530 // TODO(simonjam): Why is Close() sometimes called twice? |
| 527 break; | 531 break; |
| 528 | 532 |
| 529 default: | 533 default: |
| 530 NOTREACHED(); | 534 CHECK(false); |
| 531 break; | 535 break; |
| 532 } | 536 } |
| 533 } | 537 } |
| 534 | 538 |
| 535 int HttpPipelinedConnectionImpl::ReadResponseBody( | 539 int HttpPipelinedConnectionImpl::ReadResponseBody( |
| 536 int pipeline_id, | 540 int pipeline_id, |
| 537 IOBuffer* buf, | 541 IOBuffer* buf, |
| 538 int buf_len, | 542 int buf_len, |
| 539 OldCompletionCallback* callback) { | 543 OldCompletionCallback* callback) { |
| 540 CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 544 CHECK(ContainsKey(stream_info_map_, pipeline_id)); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 // common. | 621 // common. |
| 618 stream->Close(true); | 622 stream->Close(true); |
| 619 delete stream; | 623 delete stream; |
| 620 return; | 624 return; |
| 621 } | 625 } |
| 622 HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(stream); | 626 HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(stream); |
| 623 drainer->StartWithSize(session, headers->GetContentLength()); | 627 drainer->StartWithSize(session, headers->GetContentLength()); |
| 624 // |drainer| will delete itself when done. | 628 // |drainer| will delete itself when done. |
| 625 } | 629 } |
| 626 | 630 |
| 631 void HttpPipelinedConnectionImpl::CheckHeadersForPipelineCompatibility( |
| 632 int result, |
| 633 int pipeline_id) { |
| 634 if (result < OK) { |
| 635 switch (result) { |
| 636 // TODO(simonjam): Ignoring specific errors like this may not work. |
| 637 // Collect metrics to see if this code is useful. |
| 638 case ERR_ABORTED: |
| 639 case ERR_INTERNET_DISCONNECTED: |
| 640 // These errors are no fault of the server. |
| 641 break; |
| 642 |
| 643 default: |
| 644 delegate_->OnPipelineFeedback(this, PIPELINE_SOCKET_ERROR); |
| 645 return; |
| 646 } |
| 647 } |
| 648 HttpResponseInfo* info = GetResponseInfo(pipeline_id); |
| 649 const HttpVersion required_version(1, 1); |
| 650 if (info->headers->GetParsedHttpVersion() < required_version) { |
| 651 delegate_->OnPipelineFeedback(this, OLD_HTTP_VERSION); |
| 652 return; |
| 653 } |
| 654 if (!info->headers->IsKeepAlive() || !CanFindEndOfResponse(pipeline_id)) { |
| 655 usable_ = false; |
| 656 delegate_->OnPipelineFeedback(this, MUST_CLOSE_CONNECTION); |
| 657 return; |
| 658 } |
| 659 // TODO(simonjam): We should also check for, and work around, authentication. |
| 660 delegate_->OnPipelineFeedback(this, OK); |
| 661 } |
| 662 |
| 627 void HttpPipelinedConnectionImpl::QueueUserCallback( | 663 void HttpPipelinedConnectionImpl::QueueUserCallback( |
| 628 int pipeline_id, | 664 int pipeline_id, |
| 629 OldCompletionCallback* callback, | 665 OldCompletionCallback* callback, |
| 630 int rv, | 666 int rv, |
| 631 const tracked_objects::Location& from_here) { | 667 const tracked_objects::Location& from_here) { |
| 632 CHECK(!stream_info_map_[pipeline_id].pending_user_callback); | 668 CHECK(!stream_info_map_[pipeline_id].pending_user_callback); |
| 633 stream_info_map_[pipeline_id].pending_user_callback = callback; | 669 stream_info_map_[pipeline_id].pending_user_callback = callback; |
| 634 MessageLoop::current()->PostTask( | 670 MessageLoop::current()->PostTask( |
| 635 from_here, | 671 from_here, |
| 636 method_factory_.NewRunnableMethod( | 672 method_factory_.NewRunnableMethod( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 HttpPipelinedConnectionImpl::StreamInfo::StreamInfo() | 723 HttpPipelinedConnectionImpl::StreamInfo::StreamInfo() |
| 688 : read_headers_callback(NULL), | 724 : read_headers_callback(NULL), |
| 689 pending_user_callback(NULL), | 725 pending_user_callback(NULL), |
| 690 state(STREAM_CREATED) { | 726 state(STREAM_CREATED) { |
| 691 } | 727 } |
| 692 | 728 |
| 693 HttpPipelinedConnectionImpl::StreamInfo::~StreamInfo() { | 729 HttpPipelinedConnectionImpl::StreamInfo::~StreamInfo() { |
| 694 } | 730 } |
| 695 | 731 |
| 696 } // namespace net | 732 } // namespace net |
| OLD | NEW |