• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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