summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_network_transaction.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/spdy/spdy_network_transaction.cc')
-rw-r--r--net/spdy/spdy_network_transaction.cc297
1 files changed, 297 insertions, 0 deletions
diff --git a/net/spdy/spdy_network_transaction.cc b/net/spdy/spdy_network_transaction.cc
new file mode 100644
index 0000000..b578d38
--- /dev/null
+++ b/net/spdy/spdy_network_transaction.cc
@@ -0,0 +1,297 @@
+// 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/spdy/spdy_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/http/http_network_session.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_response_info.h"
+#include "net/spdy/spdy_stream.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