• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HttpResponseBodyDrainer(HttpStream * stream)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 
~HttpResponseBodyDrainer()25 HttpResponseBodyDrainer::~HttpResponseBodyDrainer() {}
26 
Start(HttpNetworkSession * session)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 
DoLoop(int result)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 
DoDrainResponseBody()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 
DoDrainResponseBodyComplete(int result)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 
OnIOComplete(int result)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 
OnTimerFired()106 void HttpResponseBodyDrainer::OnTimerFired() {
107   Finish(ERR_TIMED_OUT);
108 }
109 
Finish(int result)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