1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/http/http_response_body_drainer.h" 6 7 #include "base/compiler_specific.h" 8 #include "base/logging.h" 9 #include "net/base/io_buffer.h" 10 #include "net/base/net_errors.h" 11 #include "net/http/http_network_session.h" 12 #include "net/http/http_stream.h" 13 14 namespace net { 15 16 HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStream* stream) 17 : stream_(stream), 18 next_state_(STATE_NONE), 19 total_read_(0), 20 ALLOW_THIS_IN_INITIALIZER_LIST( 21 io_callback_(this, &HttpResponseBodyDrainer::OnIOComplete)), 22 user_callback_(NULL), 23 session_(NULL) {} 24 25 HttpResponseBodyDrainer::~HttpResponseBodyDrainer() {} 26 27 void HttpResponseBodyDrainer::Start(HttpNetworkSession* session) { 28 read_buf_ = new IOBuffer(kDrainBodyBufferSize); 29 next_state_ = STATE_DRAIN_RESPONSE_BODY; 30 int rv = DoLoop(OK); 31 32 if (rv == ERR_IO_PENDING) { 33 timer_.Start(base::TimeDelta::FromSeconds(kTimeoutInSeconds), 34 this, 35 &HttpResponseBodyDrainer::OnTimerFired); 36 session_ = session; 37 session->AddResponseDrainer(this); 38 return; 39 } 40 41 Finish(rv); 42 } 43 44 int HttpResponseBodyDrainer::DoLoop(int result) { 45 DCHECK_NE(next_state_, STATE_NONE); 46 47 int rv = result; 48 do { 49 State state = next_state_; 50 next_state_ = STATE_NONE; 51 switch (state) { 52 case STATE_DRAIN_RESPONSE_BODY: 53 DCHECK_EQ(OK, rv); 54 rv = DoDrainResponseBody(); 55 break; 56 case STATE_DRAIN_RESPONSE_BODY_COMPLETE: 57 rv = DoDrainResponseBodyComplete(rv); 58 break; 59 default: 60 NOTREACHED() << "bad state"; 61 rv = ERR_UNEXPECTED; 62 break; 63 } 64 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 65 66 return rv; 67 } 68 69 int HttpResponseBodyDrainer::DoDrainResponseBody() { 70 next_state_ = STATE_DRAIN_RESPONSE_BODY_COMPLETE; 71 72 return stream_->ReadResponseBody( 73 read_buf_, kDrainBodyBufferSize - total_read_, 74 &io_callback_); 75 } 76 77 int HttpResponseBodyDrainer::DoDrainResponseBodyComplete(int result) { 78 DCHECK_NE(ERR_IO_PENDING, result); 79 80 if (result < 0) 81 return result; 82 83 if (result == 0) 84 return ERR_CONNECTION_CLOSED; 85 86 total_read_ += result; 87 if (stream_->IsResponseBodyComplete()) 88 return OK; 89 90 DCHECK_LE(total_read_, kDrainBodyBufferSize); 91 if (total_read_ >= kDrainBodyBufferSize) 92 return ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN; 93 94 next_state_ = STATE_DRAIN_RESPONSE_BODY; 95 return OK; 96 } 97 98 void HttpResponseBodyDrainer::OnIOComplete(int result) { 99 int rv = DoLoop(result); 100 if (rv != ERR_IO_PENDING) { 101 timer_.Stop(); 102 Finish(rv); 103 } 104 } 105 106 void HttpResponseBodyDrainer::OnTimerFired() { 107 Finish(ERR_TIMED_OUT); 108 } 109 110 void HttpResponseBodyDrainer::Finish(int result) { 111 DCHECK_NE(ERR_IO_PENDING, result); 112 113 if (session_) 114 session_->RemoveResponseDrainer(this); 115 116 if (result < 0) { 117 stream_->Close(true /* no keep-alive */); 118 } else { 119 DCHECK_EQ(OK, result); 120 stream_->Close(false /* keep-alive */); 121 } 122 123 delete this; 124 } 125 126 } // namespace net 127