13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_response_body_drainer.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/compiler_specific.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/io_buffer.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/net_errors.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_network_session.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_stream.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace net {
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickHttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStream* stream)
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : stream_(stream),
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      next_state_(STATE_NONE),
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      total_read_(0),
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      ALLOW_THIS_IN_INITIALIZER_LIST(
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          io_callback_(this, &HttpResponseBodyDrainer::OnIOComplete)),
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      user_callback_(NULL),
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      session_(NULL) {}
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickHttpResponseBodyDrainer::~HttpResponseBodyDrainer() {}
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpResponseBodyDrainer::Start(HttpNetworkSession* session) {
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  read_buf_ = new IOBuffer(kDrainBodyBufferSize);
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_DRAIN_RESPONSE_BODY;
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = DoLoop(OK);
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (rv == ERR_IO_PENDING) {
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    timer_.Start(base::TimeDelta::FromSeconds(kTimeoutInSeconds),
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 this,
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 &HttpResponseBodyDrainer::OnTimerFired);
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    session_ = session;
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    session->AddResponseDrainer(this);
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Finish(rv);
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpResponseBodyDrainer::DoLoop(int result) {
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_NE(next_state_, STATE_NONE);
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = result;
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  do {
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    State state = next_state_;
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    next_state_ = STATE_NONE;
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    switch (state) {
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_DRAIN_RESPONSE_BODY:
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DCHECK_EQ(OK, rv);
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoDrainResponseBody();
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_DRAIN_RESPONSE_BODY_COMPLETE:
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoDrainResponseBodyComplete(rv);
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      default:
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NOTREACHED() << "bad state";
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = ERR_UNEXPECTED;
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return rv;
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpResponseBodyDrainer::DoDrainResponseBody() {
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_DRAIN_RESPONSE_BODY_COMPLETE;
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return stream_->ReadResponseBody(
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      read_buf_, kDrainBodyBufferSize - total_read_,
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      &io_callback_);
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpResponseBodyDrainer::DoDrainResponseBodyComplete(int result) {
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_NE(ERR_IO_PENDING, result);
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result < 0)
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result == 0)
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ERR_CONNECTION_CLOSED;
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  total_read_ += result;
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (stream_->IsResponseBodyComplete())
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return OK;
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_LE(total_read_, kDrainBodyBufferSize);
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (total_read_ >= kDrainBodyBufferSize)
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN;
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_DRAIN_RESPONSE_BODY;
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return OK;
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpResponseBodyDrainer::OnIOComplete(int result) {
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rv = DoLoop(result);
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (rv != ERR_IO_PENDING) {
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    timer_.Stop();
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Finish(rv);
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpResponseBodyDrainer::OnTimerFired() {
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Finish(ERR_TIMED_OUT);
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpResponseBodyDrainer::Finish(int result) {
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_NE(ERR_IO_PENDING, result);
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (session_)
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    session_->RemoveResponseDrainer(this);
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result < 0) {
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    stream_->Close(true /* no keep-alive */);
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK_EQ(OK, result);
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    stream_->Close(false /* keep-alive */);
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delete this;
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace net
127