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 |