1 // Copyright (c) 2009 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/flip/flip_network_transaction.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/scoped_ptr.h"
10 #include "base/stats_counters.h"
11 #include "net/base/host_resolver.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_util.h"
16 #include "net/base/upload_data_stream.h"
17 #include "net/flip/flip_stream.h"
18 #include "net/http/http_network_session.h"
19 #include "net/http/http_request_info.h"
20 #include "net/http/http_response_info.h"
21
22 using base::Time;
23
24 namespace net {
25
26 //-----------------------------------------------------------------------------
27
FlipNetworkTransaction(HttpNetworkSession * session)28 FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session)
29 : ALLOW_THIS_IN_INITIALIZER_LIST(
30 io_callback_(this, &FlipNetworkTransaction::OnIOComplete)),
31 user_callback_(NULL),
32 user_buffer_len_(0),
33 session_(session),
34 request_(NULL),
35 next_state_(STATE_NONE),
36 stream_(NULL) {
37 }
38
~FlipNetworkTransaction()39 FlipNetworkTransaction::~FlipNetworkTransaction() {
40 LOG(INFO) << "FlipNetworkTransaction dead. " << this;
41 if (stream_.get())
42 stream_->Cancel();
43 }
44
Start(const HttpRequestInfo * request_info,CompletionCallback * callback,LoadLog * load_log)45 int FlipNetworkTransaction::Start(const HttpRequestInfo* request_info,
46 CompletionCallback* callback,
47 LoadLog* load_log) {
48 CHECK(request_info);
49 CHECK(callback);
50
51 SIMPLE_STATS_COUNTER("FlipNetworkTransaction.Count");
52
53 load_log_ = load_log;
54 request_ = request_info;
55 start_time_ = base::TimeTicks::Now();
56
57 next_state_ = STATE_INIT_CONNECTION;
58 int rv = DoLoop(OK);
59 if (rv == ERR_IO_PENDING)
60 user_callback_ = callback;
61 return rv;
62 }
63
RestartIgnoringLastError(CompletionCallback * callback)64 int FlipNetworkTransaction::RestartIgnoringLastError(
65 CompletionCallback* callback) {
66 // TODO(mbelshe): implement me.
67 NOTIMPLEMENTED();
68 return ERR_NOT_IMPLEMENTED;
69 }
70
RestartWithCertificate(X509Certificate * client_cert,CompletionCallback * callback)71 int FlipNetworkTransaction::RestartWithCertificate(
72 X509Certificate* client_cert, CompletionCallback* callback) {
73 // TODO(mbelshe): implement me.
74 NOTIMPLEMENTED();
75 return ERR_NOT_IMPLEMENTED;
76 }
77
RestartWithAuth(const std::wstring & username,const std::wstring & password,CompletionCallback * callback)78 int FlipNetworkTransaction::RestartWithAuth(
79 const std::wstring& username,
80 const std::wstring& password,
81 CompletionCallback* callback) {
82 // TODO(mbelshe): implement me.
83 NOTIMPLEMENTED();
84 return 0;
85 }
86
Read(IOBuffer * buf,int buf_len,CompletionCallback * callback)87 int FlipNetworkTransaction::Read(IOBuffer* buf, int buf_len,
88 CompletionCallback* callback) {
89 DCHECK(buf);
90 DCHECK_GT(buf_len, 0);
91 DCHECK(callback);
92
93 user_buffer_ = buf;
94 user_buffer_len_ = buf_len;
95
96 next_state_ = STATE_READ_BODY;
97 int rv = DoLoop(OK);
98 if (rv == ERR_IO_PENDING)
99 user_callback_ = callback;
100 return rv;
101 }
102
GetResponseInfo() const103 const HttpResponseInfo* FlipNetworkTransaction::GetResponseInfo() const {
104 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
105 }
106
GetLoadState() const107 LoadState FlipNetworkTransaction::GetLoadState() const {
108 switch (next_state_) {
109 case STATE_INIT_CONNECTION_COMPLETE:
110 if (flip_.get())
111 return flip_->GetLoadState();
112 return LOAD_STATE_CONNECTING;
113 case STATE_SEND_REQUEST_COMPLETE:
114 return LOAD_STATE_SENDING_REQUEST;
115 case STATE_READ_HEADERS_COMPLETE:
116 return LOAD_STATE_WAITING_FOR_RESPONSE;
117 case STATE_READ_BODY_COMPLETE:
118 return LOAD_STATE_READING_RESPONSE;
119 default:
120 return LOAD_STATE_IDLE;
121 }
122 }
123
GetUploadProgress() const124 uint64 FlipNetworkTransaction::GetUploadProgress() const {
125 if (!stream_.get())
126 return 0;
127
128 return stream_->GetUploadProgress();
129 }
130
DoCallback(int rv)131 void FlipNetworkTransaction::DoCallback(int rv) {
132 CHECK(rv != ERR_IO_PENDING);
133 CHECK(user_callback_);
134
135 // Since Run may result in Read being called, clear user_callback_ up front.
136 CompletionCallback* c = user_callback_;
137 user_callback_ = NULL;
138 c->Run(rv);
139 }
140
OnIOComplete(int result)141 void FlipNetworkTransaction::OnIOComplete(int result) {
142 int rv = DoLoop(result);
143 if (rv != ERR_IO_PENDING)
144 DoCallback(rv);
145 }
146
DoLoop(int result)147 int FlipNetworkTransaction::DoLoop(int result) {
148 DCHECK(next_state_ != STATE_NONE);
149 DCHECK(request_);
150
151 if (!request_)
152 return 0;
153
154 int rv = result;
155 do {
156 State state = next_state_;
157 next_state_ = STATE_NONE;
158 switch (state) {
159 case STATE_INIT_CONNECTION:
160 DCHECK_EQ(OK, rv);
161 LoadLog::BeginEvent(load_log_,
162 LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION);
163 rv = DoInitConnection();
164 break;
165 case STATE_INIT_CONNECTION_COMPLETE:
166 LoadLog::EndEvent(load_log_,
167 LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION);
168 rv = DoInitConnectionComplete(rv);
169 break;
170 case STATE_SEND_REQUEST:
171 DCHECK_EQ(OK, rv);
172 LoadLog::BeginEvent(load_log_,
173 LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST);
174 rv = DoSendRequest();
175 break;
176 case STATE_SEND_REQUEST_COMPLETE:
177 LoadLog::EndEvent(load_log_,
178 LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST);
179 rv = DoSendRequestComplete(rv);
180 break;
181 case STATE_READ_HEADERS:
182 DCHECK_EQ(OK, rv);
183 LoadLog::BeginEvent(load_log_,
184 LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS);
185 rv = DoReadHeaders();
186 break;
187 case STATE_READ_HEADERS_COMPLETE:
188 LoadLog::EndEvent(load_log_,
189 LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS);
190 rv = DoReadHeadersComplete(rv);
191 break;
192 case STATE_READ_BODY:
193 DCHECK_EQ(OK, rv);
194 LoadLog::BeginEvent(load_log_,
195 LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY);
196 rv = DoReadBody();
197 break;
198 case STATE_READ_BODY_COMPLETE:
199 LoadLog::EndEvent(load_log_,
200 LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY);
201 rv = DoReadBodyComplete(rv);
202 break;
203 case STATE_NONE:
204 rv = ERR_FAILED;
205 break;
206 default:
207 NOTREACHED() << "bad state";
208 rv = ERR_FAILED;
209 break;
210 }
211 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
212
213 return rv;
214 }
215
DoInitConnection()216 int FlipNetworkTransaction::DoInitConnection() {
217 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
218
219 std::string host = request_->url.HostNoBrackets();
220 int port = request_->url.EffectiveIntPort();
221
222 // Use the fixed testing ports if they've been provided. This is useful for
223 // debugging.
224 if (FlipSession::SSLMode()) {
225 if (session_->fixed_https_port() != 0)
226 port = session_->fixed_https_port();
227 } else if (session_->fixed_http_port() != 0) {
228 port = session_->fixed_http_port();
229 }
230
231 std::string connection_group = "flip.";
232 connection_group.append(host);
233
234 HostResolver::RequestInfo resolve_info(host, port);
235
236 flip_ = session_->flip_session_pool()->Get(resolve_info, session_);
237 DCHECK(flip_);
238
239 return flip_->Connect(
240 connection_group, resolve_info, request_->priority, load_log_);
241 }
242
DoInitConnectionComplete(int result)243 int FlipNetworkTransaction::DoInitConnectionComplete(int result) {
244 if (result < 0)
245 return result;
246
247 next_state_ = STATE_SEND_REQUEST;
248 return OK;
249 }
250
DoSendRequest()251 int FlipNetworkTransaction::DoSendRequest() {
252 next_state_ = STATE_SEND_REQUEST_COMPLETE;
253 CHECK(!stream_.get());
254 UploadDataStream* upload_data = request_->upload_data ?
255 new UploadDataStream(request_->upload_data) : NULL;
256 stream_ = flip_->GetOrCreateStream(*request_, upload_data, load_log_.get());
257 // Release the reference to |flip_| since we don't need it anymore.
258 flip_ = NULL;
259 return stream_->SendRequest(upload_data, &response_, &io_callback_);
260 }
261
DoSendRequestComplete(int result)262 int FlipNetworkTransaction::DoSendRequestComplete(int result) {
263 if (result < 0)
264 return result;
265
266 next_state_ = STATE_READ_HEADERS;
267 return OK;
268 }
269
DoReadHeaders()270 int FlipNetworkTransaction::DoReadHeaders() {
271 next_state_ = STATE_READ_HEADERS_COMPLETE;
272 return stream_->ReadResponseHeaders(&io_callback_);
273 }
274
DoReadHeadersComplete(int result)275 int FlipNetworkTransaction::DoReadHeadersComplete(int result) {
276 // TODO(willchan): Flesh out the support for HTTP authentication here.
277 return result;
278 }
279
DoReadBody()280 int FlipNetworkTransaction::DoReadBody() {
281 next_state_ = STATE_READ_BODY_COMPLETE;
282
283 return stream_->ReadResponseBody(
284 user_buffer_, user_buffer_len_, &io_callback_);
285 }
286
DoReadBodyComplete(int result)287 int FlipNetworkTransaction::DoReadBodyComplete(int result) {
288 user_buffer_ = NULL;
289 user_buffer_len_ = 0;
290
291 if (result <= 0)
292 stream_ = NULL;
293
294 return result;
295 }
296
297 } // namespace net
298