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.
5 #include "net/http/http_response_body_drainer.h"
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"
16 HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStreamBase
* stream
)
19 next_state_(STATE_NONE
),
23 HttpResponseBodyDrainer::~HttpResponseBodyDrainer() {}
25 void HttpResponseBodyDrainer::Start(HttpNetworkSession
* session
) {
26 StartWithSize(session
, kDrainBodyBufferSize
);
29 void HttpResponseBodyDrainer::StartWithSize(HttpNetworkSession
* session
,
30 int num_bytes_to_drain
) {
31 DCHECK_LE(0, num_bytes_to_drain
);
32 // TODO(simonjam): Consider raising this limit if we're pipelining. If we have
33 // a bunch of responses in the pipeline, we should be less willing to give up
35 if (num_bytes_to_drain
> kDrainBodyBufferSize
) {
36 Finish(ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN
);
38 } else if (num_bytes_to_drain
== 0) {
43 read_size_
= num_bytes_to_drain
;
44 read_buf_
= new IOBuffer(read_size_
);
45 next_state_
= STATE_DRAIN_RESPONSE_BODY
;
48 if (rv
== ERR_IO_PENDING
) {
49 timer_
.Start(FROM_HERE
,
50 base::TimeDelta::FromSeconds(kTimeoutInSeconds
),
52 &HttpResponseBodyDrainer::OnTimerFired
);
54 session
->AddResponseDrainer(this);
61 int HttpResponseBodyDrainer::DoLoop(int result
) {
62 DCHECK_NE(next_state_
, STATE_NONE
);
66 State state
= next_state_
;
67 next_state_
= STATE_NONE
;
69 case STATE_DRAIN_RESPONSE_BODY
:
71 rv
= DoDrainResponseBody();
73 case STATE_DRAIN_RESPONSE_BODY_COMPLETE
:
74 rv
= DoDrainResponseBodyComplete(rv
);
77 NOTREACHED() << "bad state";
81 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
86 int HttpResponseBodyDrainer::DoDrainResponseBody() {
87 next_state_
= STATE_DRAIN_RESPONSE_BODY_COMPLETE
;
89 return stream_
->ReadResponseBody(
91 read_size_
- total_read_
,
92 base::Bind(&HttpResponseBodyDrainer::OnIOComplete
,
93 base::Unretained(this)));
96 int HttpResponseBodyDrainer::DoDrainResponseBodyComplete(int result
) {
97 DCHECK_NE(ERR_IO_PENDING
, result
);
102 total_read_
+= result
;
103 if (stream_
->IsResponseBodyComplete())
106 DCHECK_LE(total_read_
, kDrainBodyBufferSize
);
107 if (total_read_
>= kDrainBodyBufferSize
)
108 return ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN
;
111 return ERR_CONNECTION_CLOSED
;
113 next_state_
= STATE_DRAIN_RESPONSE_BODY
;
117 void HttpResponseBodyDrainer::OnIOComplete(int result
) {
118 int rv
= DoLoop(result
);
119 if (rv
!= ERR_IO_PENDING
) {
125 void HttpResponseBodyDrainer::OnTimerFired() {
126 Finish(ERR_TIMED_OUT
);
129 void HttpResponseBodyDrainer::Finish(int result
) {
130 DCHECK_NE(ERR_IO_PENDING
, result
);
133 session_
->RemoveResponseDrainer(this);
136 stream_
->Close(true /* no keep-alive */);
138 DCHECK_EQ(OK
, result
);
139 stream_
->Close(false /* keep-alive */);