OLD | NEW |
| (Empty) |
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.h" | |
13 | |
14 namespace net { | |
15 | |
16 HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStream* 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 | |
OLD | NEW |