Home | History | Annotate | Download | only in http
      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