Home | History | Annotate | Download | only in http
      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
      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_base.h"
     13 
     14 namespace net {
     15 
     16 HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStreamBase* stream)
     17     : stream_(stream),
     18       next_state_(STATE_NONE),
     19       total_read_(0),
     20       session_(NULL) {}
     21 
     22 HttpResponseBodyDrainer::~HttpResponseBodyDrainer() {}
     23 
     24 void HttpResponseBodyDrainer::Start(HttpNetworkSession* session) {
     25   read_buf_ = new IOBuffer(kDrainBodyBufferSize);
     26   next_state_ = STATE_DRAIN_RESPONSE_BODY;
     27   int rv = DoLoop(OK);
     28 
     29   if (rv == ERR_IO_PENDING) {
     30     timer_.Start(FROM_HERE,
     31                  base::TimeDelta::FromSeconds(kTimeoutInSeconds),
     32                  this,
     33                  &HttpResponseBodyDrainer::OnTimerFired);
     34     session_ = session;
     35     session->AddResponseDrainer(this);
     36     return;
     37   }
     38 
     39   Finish(rv);
     40 }
     41 
     42 int HttpResponseBodyDrainer::DoLoop(int result) {
     43   DCHECK_NE(next_state_, STATE_NONE);
     44 
     45   int rv = result;
     46   do {
     47     State state = next_state_;
     48     next_state_ = STATE_NONE;
     49     switch (state) {
     50       case STATE_DRAIN_RESPONSE_BODY:
     51         DCHECK_EQ(OK, rv);
     52         rv = DoDrainResponseBody();
     53         break;
     54       case STATE_DRAIN_RESPONSE_BODY_COMPLETE:
     55         rv = DoDrainResponseBodyComplete(rv);
     56         break;
     57       default:
     58         NOTREACHED() << "bad state";
     59         rv = ERR_UNEXPECTED;
     60         break;
     61     }
     62   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
     63 
     64   return rv;
     65 }
     66 
     67 int HttpResponseBodyDrainer::DoDrainResponseBody() {
     68   next_state_ = STATE_DRAIN_RESPONSE_BODY_COMPLETE;
     69 
     70   return stream_->ReadResponseBody(
     71       read_buf_.get(),
     72       kDrainBodyBufferSize - total_read_,
     73       base::Bind(&HttpResponseBodyDrainer::OnIOComplete,
     74                  base::Unretained(this)));
     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   total_read_ += result;
     84   if (stream_->IsResponseBodyComplete())
     85     return OK;
     86 
     87   DCHECK_LE(total_read_, kDrainBodyBufferSize);
     88   if (total_read_ >= kDrainBodyBufferSize)
     89     return ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN;
     90 
     91   if (result == 0)
     92     return ERR_CONNECTION_CLOSED;
     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