| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/flip/flip_network_transaction.h" |
| |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/scoped_ptr.h" |
| #include "base/stats_counters.h" |
| #include "net/base/host_resolver.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/net_util.h" |
| #include "net/base/upload_data_stream.h" |
| #include "net/flip/flip_stream.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_request_info.h" |
| #include "net/http/http_response_info.h" |
| |
| using base::Time; |
| |
| namespace net { |
| |
| //----------------------------------------------------------------------------- |
| |
| FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session) |
| : ALLOW_THIS_IN_INITIALIZER_LIST( |
| io_callback_(this, &FlipNetworkTransaction::OnIOComplete)), |
| user_callback_(NULL), |
| user_buffer_len_(0), |
| session_(session), |
| request_(NULL), |
| next_state_(STATE_NONE), |
| stream_(NULL) { |
| } |
| |
| FlipNetworkTransaction::~FlipNetworkTransaction() { |
| LOG(INFO) << "FlipNetworkTransaction dead. " << this; |
| if (stream_.get()) |
| stream_->Cancel(); |
| } |
| |
| int FlipNetworkTransaction::Start(const HttpRequestInfo* request_info, |
| CompletionCallback* callback, |
| LoadLog* load_log) { |
| CHECK(request_info); |
| CHECK(callback); |
| |
| SIMPLE_STATS_COUNTER("FlipNetworkTransaction.Count"); |
| |
| load_log_ = load_log; |
| request_ = request_info; |
| start_time_ = base::TimeTicks::Now(); |
| |
| next_state_ = STATE_INIT_CONNECTION; |
| int rv = DoLoop(OK); |
| if (rv == ERR_IO_PENDING) |
| user_callback_ = callback; |
| return rv; |
| } |
| |
| int FlipNetworkTransaction::RestartIgnoringLastError( |
| CompletionCallback* callback) { |
| // TODO(mbelshe): implement me. |
| NOTIMPLEMENTED(); |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| int FlipNetworkTransaction::RestartWithCertificate( |
| X509Certificate* client_cert, CompletionCallback* callback) { |
| // TODO(mbelshe): implement me. |
| NOTIMPLEMENTED(); |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| int FlipNetworkTransaction::RestartWithAuth( |
| const std::wstring& username, |
| const std::wstring& password, |
| CompletionCallback* callback) { |
| // TODO(mbelshe): implement me. |
| NOTIMPLEMENTED(); |
| return 0; |
| } |
| |
| int FlipNetworkTransaction::Read(IOBuffer* buf, int buf_len, |
| CompletionCallback* callback) { |
| DCHECK(buf); |
| DCHECK_GT(buf_len, 0); |
| DCHECK(callback); |
| |
| user_buffer_ = buf; |
| user_buffer_len_ = buf_len; |
| |
| next_state_ = STATE_READ_BODY; |
| int rv = DoLoop(OK); |
| if (rv == ERR_IO_PENDING) |
| user_callback_ = callback; |
| return rv; |
| } |
| |
| const HttpResponseInfo* FlipNetworkTransaction::GetResponseInfo() const { |
| return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL; |
| } |
| |
| LoadState FlipNetworkTransaction::GetLoadState() const { |
| switch (next_state_) { |
| case STATE_INIT_CONNECTION_COMPLETE: |
| if (flip_.get()) |
| return flip_->GetLoadState(); |
| return LOAD_STATE_CONNECTING; |
| case STATE_SEND_REQUEST_COMPLETE: |
| return LOAD_STATE_SENDING_REQUEST; |
| case STATE_READ_HEADERS_COMPLETE: |
| return LOAD_STATE_WAITING_FOR_RESPONSE; |
| case STATE_READ_BODY_COMPLETE: |
| return LOAD_STATE_READING_RESPONSE; |
| default: |
| return LOAD_STATE_IDLE; |
| } |
| } |
| |
| uint64 FlipNetworkTransaction::GetUploadProgress() const { |
| if (!stream_.get()) |
| return 0; |
| |
| return stream_->GetUploadProgress(); |
| } |
| |
| void FlipNetworkTransaction::DoCallback(int rv) { |
| CHECK(rv != ERR_IO_PENDING); |
| CHECK(user_callback_); |
| |
| // Since Run may result in Read being called, clear user_callback_ up front. |
| CompletionCallback* c = user_callback_; |
| user_callback_ = NULL; |
| c->Run(rv); |
| } |
| |
| void FlipNetworkTransaction::OnIOComplete(int result) { |
| int rv = DoLoop(result); |
| if (rv != ERR_IO_PENDING) |
| DoCallback(rv); |
| } |
| |
| int FlipNetworkTransaction::DoLoop(int result) { |
| DCHECK(next_state_ != STATE_NONE); |
| DCHECK(request_); |
| |
| if (!request_) |
| return 0; |
| |
| int rv = result; |
| do { |
| State state = next_state_; |
| next_state_ = STATE_NONE; |
| switch (state) { |
| case STATE_INIT_CONNECTION: |
| DCHECK_EQ(OK, rv); |
| LoadLog::BeginEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION); |
| rv = DoInitConnection(); |
| break; |
| case STATE_INIT_CONNECTION_COMPLETE: |
| LoadLog::EndEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION); |
| rv = DoInitConnectionComplete(rv); |
| break; |
| case STATE_SEND_REQUEST: |
| DCHECK_EQ(OK, rv); |
| LoadLog::BeginEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST); |
| rv = DoSendRequest(); |
| break; |
| case STATE_SEND_REQUEST_COMPLETE: |
| LoadLog::EndEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST); |
| rv = DoSendRequestComplete(rv); |
| break; |
| case STATE_READ_HEADERS: |
| DCHECK_EQ(OK, rv); |
| LoadLog::BeginEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS); |
| rv = DoReadHeaders(); |
| break; |
| case STATE_READ_HEADERS_COMPLETE: |
| LoadLog::EndEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS); |
| rv = DoReadHeadersComplete(rv); |
| break; |
| case STATE_READ_BODY: |
| DCHECK_EQ(OK, rv); |
| LoadLog::BeginEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY); |
| rv = DoReadBody(); |
| break; |
| case STATE_READ_BODY_COMPLETE: |
| LoadLog::EndEvent(load_log_, |
| LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY); |
| rv = DoReadBodyComplete(rv); |
| break; |
| case STATE_NONE: |
| rv = ERR_FAILED; |
| break; |
| default: |
| NOTREACHED() << "bad state"; |
| rv = ERR_FAILED; |
| break; |
| } |
| } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| |
| return rv; |
| } |
| |
| int FlipNetworkTransaction::DoInitConnection() { |
| next_state_ = STATE_INIT_CONNECTION_COMPLETE; |
| |
| std::string host = request_->url.HostNoBrackets(); |
| int port = request_->url.EffectiveIntPort(); |
| |
| // Use the fixed testing ports if they've been provided. This is useful for |
| // debugging. |
| if (FlipSession::SSLMode()) { |
| if (session_->fixed_https_port() != 0) |
| port = session_->fixed_https_port(); |
| } else if (session_->fixed_http_port() != 0) { |
| port = session_->fixed_http_port(); |
| } |
| |
| std::string connection_group = "flip."; |
| connection_group.append(host); |
| |
| HostResolver::RequestInfo resolve_info(host, port); |
| |
| flip_ = session_->flip_session_pool()->Get(resolve_info, session_); |
| DCHECK(flip_); |
| |
| return flip_->Connect( |
| connection_group, resolve_info, request_->priority, load_log_); |
| } |
| |
| int FlipNetworkTransaction::DoInitConnectionComplete(int result) { |
| if (result < 0) |
| return result; |
| |
| next_state_ = STATE_SEND_REQUEST; |
| return OK; |
| } |
| |
| int FlipNetworkTransaction::DoSendRequest() { |
| next_state_ = STATE_SEND_REQUEST_COMPLETE; |
| CHECK(!stream_.get()); |
| UploadDataStream* upload_data = request_->upload_data ? |
| new UploadDataStream(request_->upload_data) : NULL; |
| stream_ = flip_->GetOrCreateStream(*request_, upload_data, load_log_.get()); |
| // Release the reference to |flip_| since we don't need it anymore. |
| flip_ = NULL; |
| return stream_->SendRequest(upload_data, &response_, &io_callback_); |
| } |
| |
| int FlipNetworkTransaction::DoSendRequestComplete(int result) { |
| if (result < 0) |
| return result; |
| |
| next_state_ = STATE_READ_HEADERS; |
| return OK; |
| } |
| |
| int FlipNetworkTransaction::DoReadHeaders() { |
| next_state_ = STATE_READ_HEADERS_COMPLETE; |
| return stream_->ReadResponseHeaders(&io_callback_); |
| } |
| |
| int FlipNetworkTransaction::DoReadHeadersComplete(int result) { |
| // TODO(willchan): Flesh out the support for HTTP authentication here. |
| return result; |
| } |
| |
| int FlipNetworkTransaction::DoReadBody() { |
| next_state_ = STATE_READ_BODY_COMPLETE; |
| |
| return stream_->ReadResponseBody( |
| user_buffer_, user_buffer_len_, &io_callback_); |
| } |
| |
| int FlipNetworkTransaction::DoReadBodyComplete(int result) { |
| user_buffer_ = NULL; |
| user_buffer_len_ = 0; |
| |
| if (result <= 0) |
| stream_ = NULL; |
| |
| return result; |
| } |
| |
| } // namespace net |