Index: net/socket_stream/socket_stream.cc |
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc |
deleted file mode 100644 |
index 422d61d45203c324fd48ed381b58dd34a3e2fd95..0000000000000000000000000000000000000000 |
--- a/net/socket_stream/socket_stream.cc |
+++ /dev/null |
@@ -1,1353 +0,0 @@ |
-// Copyright (c) 2012 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. |
-// |
-// TODO(ukai): code is similar with http_network_transaction.cc. We should |
-// think about ways to share code, if possible. |
- |
-#include "net/socket_stream/socket_stream.h" |
- |
-#include <set> |
-#include <string> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/compiler_specific.h" |
-#include "base/logging.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "net/base/auth.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/dns/host_resolver.h" |
-#include "net/http/http_auth_controller.h" |
-#include "net/http/http_network_session.h" |
-#include "net/http/http_request_headers.h" |
-#include "net/http/http_request_info.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_stream_factory.h" |
-#include "net/http/http_transaction_factory.h" |
-#include "net/http/http_util.h" |
-#include "net/socket/client_socket_factory.h" |
-#include "net/socket/client_socket_handle.h" |
-#include "net/socket/socks5_client_socket.h" |
-#include "net/socket/socks_client_socket.h" |
-#include "net/socket/ssl_client_socket.h" |
-#include "net/socket/tcp_client_socket.h" |
-#include "net/socket_stream/socket_stream_metrics.h" |
-#include "net/ssl/ssl_cert_request_info.h" |
-#include "net/ssl/ssl_info.h" |
-#include "net/url_request/url_request.h" |
-#include "net/url_request/url_request_context.h" |
- |
-static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes. |
-static const int kReadBufferSize = 4096; |
- |
-namespace net { |
- |
-int SocketStream::Delegate::OnStartOpenConnection( |
- SocketStream* socket, const CompletionCallback& callback) { |
- return OK; |
-} |
- |
-void SocketStream::Delegate::OnAuthRequired(SocketStream* socket, |
- AuthChallengeInfo* auth_info) { |
- // By default, no credential is available and close the connection. |
- socket->Close(); |
-} |
- |
-void SocketStream::Delegate::OnSSLCertificateError( |
- SocketStream* socket, |
- const SSLInfo& ssl_info, |
- bool fatal) { |
- socket->CancelWithSSLError(ssl_info); |
-} |
- |
-bool SocketStream::Delegate::CanGetCookies(SocketStream* socket, |
- const GURL& url) { |
- return true; |
-} |
- |
-bool SocketStream::Delegate::CanSetCookie(SocketStream* request, |
- const GURL& url, |
- const std::string& cookie_line, |
- CookieOptions* options) { |
- return true; |
-} |
- |
-SocketStream::ResponseHeaders::ResponseHeaders() : IOBuffer() {} |
- |
-void SocketStream::ResponseHeaders::Realloc(size_t new_size) { |
- headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size))); |
-} |
- |
-SocketStream::ResponseHeaders::~ResponseHeaders() { data_ = NULL; } |
- |
-SocketStream::SocketStream(const GURL& url, Delegate* delegate, |
- URLRequestContext* context, |
- CookieStore* cookie_store) |
- : delegate_(delegate), |
- url_(url), |
- max_pending_send_allowed_(kMaxPendingSendAllowed), |
- context_(context), |
- next_state_(STATE_NONE), |
- factory_(ClientSocketFactory::GetDefaultFactory()), |
- proxy_mode_(kDirectConnection), |
- proxy_url_(url), |
- pac_request_(NULL), |
- connection_(new ClientSocketHandle), |
- privacy_mode_(PRIVACY_MODE_DISABLED), |
- // Unretained() is required; without it, Bind() creates a circular |
- // dependency and the SocketStream object will not be freed. |
- io_callback_(base::Bind(&SocketStream::OnIOCompleted, |
- base::Unretained(this))), |
- read_buf_(NULL), |
- current_write_buf_(NULL), |
- waiting_for_write_completion_(false), |
- closing_(false), |
- server_closed_(false), |
- metrics_(new SocketStreamMetrics(url)), |
- cookie_store_(cookie_store) { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- DCHECK(delegate_); |
- |
- if (context_) { |
- if (!cookie_store_.get()) |
- cookie_store_ = context_->cookie_store(); |
- |
- net_log_ = BoundNetLog::Make( |
- context->net_log(), |
- NetLog::SOURCE_SOCKET_STREAM); |
- |
- net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE); |
- } |
-} |
- |
-SocketStream::UserData* SocketStream::GetUserData( |
- const void* key) const { |
- UserDataMap::const_iterator found = user_data_.find(key); |
- if (found != user_data_.end()) |
- return found->second.get(); |
- return NULL; |
-} |
- |
-void SocketStream::SetUserData(const void* key, UserData* data) { |
- user_data_[key] = linked_ptr<UserData>(data); |
-} |
- |
-bool SocketStream::is_secure() const { |
- return url_.SchemeIs("wss"); |
-} |
- |
-void SocketStream::DetachContext() { |
- if (!context_) |
- return; |
- |
- if (pac_request_) { |
- context_->proxy_service()->CancelPacRequest(pac_request_); |
- pac_request_ = NULL; |
- } |
- |
- net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE); |
- net_log_ = BoundNetLog(); |
- |
- context_ = NULL; |
- cookie_store_ = NULL; |
-} |
- |
-void SocketStream::CheckPrivacyMode() { |
- if (context_ && context_->network_delegate()) { |
- bool enable = context_->network_delegate()->CanEnablePrivacyMode(url_, |
- url_); |
- privacy_mode_ = enable ? PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED; |
- // Disable Channel ID if privacy mode is enabled. |
- if (enable) |
- server_ssl_config_.channel_id_enabled = false; |
- } |
-} |
- |
-void SocketStream::Connect() { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- if (context_) { |
- context_->ssl_config_service()->GetSSLConfig(&server_ssl_config_); |
- proxy_ssl_config_ = server_ssl_config_; |
- } |
- CheckPrivacyMode(); |
- |
- DCHECK_EQ(next_state_, STATE_NONE); |
- |
- AddRef(); // Released in Finish() |
- // Open a connection asynchronously, so that delegate won't be called |
- // back before returning Connect(). |
- next_state_ = STATE_BEFORE_CONNECT; |
- net_log_.BeginEvent( |
- NetLog::TYPE_SOCKET_STREAM_CONNECT, |
- NetLog::StringCallback("url", &url_.possibly_invalid_spec())); |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); |
-} |
- |
-size_t SocketStream::GetTotalSizeOfPendingWriteBufs() const { |
- size_t total_size = 0; |
- for (PendingDataQueue::const_iterator iter = pending_write_bufs_.begin(); |
- iter != pending_write_bufs_.end(); |
- ++iter) |
- total_size += (*iter)->size(); |
- return total_size; |
-} |
- |
-bool SocketStream::SendData(const char* data, int len) { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- DCHECK_GT(len, 0); |
- |
- if (!connection_->socket() || |
- !connection_->socket()->IsConnected() || next_state_ == STATE_NONE) { |
- return false; |
- } |
- |
- int total_buffered_bytes = len; |
- if (current_write_buf_.get()) { |
- // Since |
- // - the purpose of this check is to limit the amount of buffer used by |
- // this instance. |
- // - the DrainableIOBuffer doesn't release consumed memory. |
- // we need to use not BytesRemaining() but size() here. |
- total_buffered_bytes += current_write_buf_->size(); |
- } |
- total_buffered_bytes += GetTotalSizeOfPendingWriteBufs(); |
- if (total_buffered_bytes > max_pending_send_allowed_) |
- return false; |
- |
- // TODO(tyoshino): Split data into smaller chunks e.g. 8KiB to free consumed |
- // buffer progressively |
- pending_write_bufs_.push_back(make_scoped_refptr( |
- new IOBufferWithSize(len))); |
- memcpy(pending_write_bufs_.back()->data(), data, len); |
- |
- // If current_write_buf_ is not NULL, it means that a) there's ongoing write |
- // operation or b) the connection is being closed. If a), the buffer we just |
- // pushed will be automatically handled when the completion callback runs |
- // the loop, and therefore we don't need to enqueue DoLoop(). If b), it's ok |
- // to do nothing. If current_write_buf_ is NULL, to make sure DoLoop() is |
- // ran soon, enequeue it. |
- if (!current_write_buf_.get()) { |
- // Send pending data asynchronously, so that delegate won't be called |
- // back before returning from SendData(). |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); |
- } |
- |
- return true; |
-} |
- |
-void SocketStream::Close() { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- // If next_state_ is STATE_NONE, the socket was not opened, or already |
- // closed. So, return immediately. |
- // Otherwise, it might call Finish() more than once, so breaks balance |
- // of AddRef() and Release() in Connect() and Finish(), respectively. |
- if (next_state_ == STATE_NONE) |
- return; |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoClose, this)); |
-} |
- |
-void SocketStream::RestartWithAuth(const AuthCredentials& credentials) { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- DCHECK(proxy_auth_controller_.get()); |
- if (!connection_->socket()) { |
- DVLOG(1) << "Socket is closed before restarting with auth."; |
- return; |
- } |
- |
- proxy_auth_controller_->ResetAuth(credentials); |
- |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this)); |
-} |
- |
-void SocketStream::DetachDelegate() { |
- if (!delegate_) |
- return; |
- delegate_ = NULL; |
- // Prevent the rest of the function from executing if we are being called from |
- // within Finish(). |
- if (next_state_ == STATE_NONE) |
- return; |
- net_log_.AddEvent(NetLog::TYPE_CANCELLED); |
- // We don't need to send pending data when client detach the delegate. |
- pending_write_bufs_.clear(); |
- Close(); |
-} |
- |
-const ProxyServer& SocketStream::proxy_server() const { |
- return proxy_info_.proxy_server(); |
-} |
- |
-void SocketStream::SetClientSocketFactory( |
- ClientSocketFactory* factory) { |
- DCHECK(factory); |
- factory_ = factory; |
-} |
- |
-void SocketStream::CancelWithError(int error) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, error)); |
-} |
- |
-void SocketStream::CancelWithSSLError(const SSLInfo& ssl_info) { |
- CancelWithError(MapCertStatusToNetError(ssl_info.cert_status)); |
-} |
- |
-void SocketStream::ContinueDespiteError() { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); |
-} |
- |
-SocketStream::~SocketStream() { |
- DetachContext(); |
- DCHECK(!delegate_); |
- DCHECK(!pac_request_); |
-} |
- |
-SocketStream::RequestHeaders::~RequestHeaders() { data_ = NULL; } |
- |
-void SocketStream::set_addresses(const AddressList& addresses) { |
- addresses_ = addresses; |
-} |
- |
-void SocketStream::DoClose() { |
- closing_ = true; |
- // If next_state_ is: |
- // - STATE_TCP_CONNECT_COMPLETE, it's waiting other socket establishing |
- // connection. |
- // - STATE_AUTH_REQUIRED, it's waiting for restarting. |
- // - STATE_RESOLVE_PROTOCOL_COMPLETE, it's waiting for delegate_ to finish |
- // OnStartOpenConnection method call |
- // In these states, we'll close the SocketStream now. |
- if (next_state_ == STATE_TCP_CONNECT_COMPLETE || |
- next_state_ == STATE_AUTH_REQUIRED || |
- next_state_ == STATE_RESOLVE_PROTOCOL_COMPLETE) { |
- DoLoop(ERR_ABORTED); |
- return; |
- } |
- // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close |
- // the SocketStream. |
- // If it's writing now, we should defer the closing after the current |
- // writing is completed. |
- if (next_state_ == STATE_READ_WRITE && !current_write_buf_.get()) |
- DoLoop(ERR_ABORTED); |
- |
- // In other next_state_, we'll wait for callback of other APIs, such as |
- // ResolveProxy(). |
-} |
- |
-void SocketStream::Finish(int result) { |
- DCHECK(base::MessageLoop::current()) |
- << "The current base::MessageLoop must exist"; |
- DCHECK(base::MessageLoopForIO::IsCurrent()) |
- << "The current base::MessageLoop must be TYPE_IO"; |
- DCHECK_LE(result, OK); |
- if (result == OK) |
- result = ERR_CONNECTION_CLOSED; |
- DCHECK_EQ(next_state_, STATE_NONE); |
- DVLOG(1) << "Finish result=" << ErrorToString(result); |
- |
- metrics_->OnClose(); |
- |
- if (result != ERR_CONNECTION_CLOSED && delegate_) |
- delegate_->OnError(this, result); |
- if (result != ERR_PROTOCOL_SWITCHED && delegate_) |
- delegate_->OnClose(this); |
- delegate_ = NULL; |
- |
- Release(); |
-} |
- |
-int SocketStream::DidEstablishConnection() { |
- if (!connection_->socket() || !connection_->socket()->IsConnected()) { |
- next_state_ = STATE_CLOSE; |
- return ERR_CONNECTION_FAILED; |
- } |
- next_state_ = STATE_READ_WRITE; |
- metrics_->OnConnected(); |
- |
- net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT); |
- if (delegate_) |
- delegate_->OnConnected(this, max_pending_send_allowed_); |
- |
- return OK; |
-} |
- |
-int SocketStream::DidReceiveData(int result) { |
- DCHECK(read_buf_.get()); |
- DCHECK_GT(result, 0); |
- net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_RECEIVED); |
- int len = result; |
- metrics_->OnRead(len); |
- if (delegate_) { |
- // Notify recevied data to delegate. |
- delegate_->OnReceivedData(this, read_buf_->data(), len); |
- } |
- read_buf_ = NULL; |
- return OK; |
-} |
- |
-void SocketStream::DidSendData(int result) { |
- DCHECK_GT(result, 0); |
- DCHECK(current_write_buf_.get()); |
- net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_SENT); |
- |
- int bytes_sent = result; |
- |
- metrics_->OnWrite(bytes_sent); |
- |
- current_write_buf_->DidConsume(result); |
- |
- if (current_write_buf_->BytesRemaining()) |
- return; |
- |
- size_t bytes_freed = current_write_buf_->size(); |
- |
- current_write_buf_ = NULL; |
- |
- // We freed current_write_buf_ and this instance is now able to accept more |
- // data via SendData() (note that DidConsume() doesn't free consumed memory). |
- // We can tell that to delegate_ by calling OnSentData(). |
- if (delegate_) |
- delegate_->OnSentData(this, bytes_freed); |
-} |
- |
-void SocketStream::OnIOCompleted(int result) { |
- DoLoop(result); |
-} |
- |
-void SocketStream::OnReadCompleted(int result) { |
- if (result == 0) { |
- // 0 indicates end-of-file, so socket was closed. |
- // Don't close the socket if it's still writing. |
- server_closed_ = true; |
- } else if (result > 0 && read_buf_.get()) { |
- result = DidReceiveData(result); |
- } |
- DoLoop(result); |
-} |
- |
-void SocketStream::OnWriteCompleted(int result) { |
- waiting_for_write_completion_ = false; |
- if (result > 0) { |
- DidSendData(result); |
- result = OK; |
- } |
- DoLoop(result); |
-} |
- |
-void SocketStream::DoLoop(int result) { |
- if (next_state_ == STATE_NONE) |
- return; |
- |
- // If context was not set, close immediately. |
- if (!context_) |
- next_state_ = STATE_CLOSE; |
- |
- do { |
- State state = next_state_; |
- next_state_ = STATE_NONE; |
- switch (state) { |
- case STATE_BEFORE_CONNECT: |
- DCHECK_EQ(OK, result); |
- result = DoBeforeConnect(); |
- break; |
- case STATE_BEFORE_CONNECT_COMPLETE: |
- result = DoBeforeConnectComplete(result); |
- break; |
- case STATE_RESOLVE_PROXY: |
- DCHECK_EQ(OK, result); |
- result = DoResolveProxy(); |
- break; |
- case STATE_RESOLVE_PROXY_COMPLETE: |
- result = DoResolveProxyComplete(result); |
- break; |
- case STATE_RESOLVE_HOST: |
- DCHECK_EQ(OK, result); |
- result = DoResolveHost(); |
- break; |
- case STATE_RESOLVE_HOST_COMPLETE: |
- result = DoResolveHostComplete(result); |
- break; |
- case STATE_RESOLVE_PROTOCOL: |
- result = DoResolveProtocol(result); |
- break; |
- case STATE_RESOLVE_PROTOCOL_COMPLETE: |
- result = DoResolveProtocolComplete(result); |
- break; |
- case STATE_TCP_CONNECT: |
- result = DoTcpConnect(result); |
- break; |
- case STATE_TCP_CONNECT_COMPLETE: |
- result = DoTcpConnectComplete(result); |
- break; |
- case STATE_GENERATE_PROXY_AUTH_TOKEN: |
- result = DoGenerateProxyAuthToken(); |
- break; |
- case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE: |
- result = DoGenerateProxyAuthTokenComplete(result); |
- break; |
- case STATE_WRITE_TUNNEL_HEADERS: |
- DCHECK_EQ(OK, result); |
- result = DoWriteTunnelHeaders(); |
- break; |
- case STATE_WRITE_TUNNEL_HEADERS_COMPLETE: |
- result = DoWriteTunnelHeadersComplete(result); |
- break; |
- case STATE_READ_TUNNEL_HEADERS: |
- DCHECK_EQ(OK, result); |
- result = DoReadTunnelHeaders(); |
- break; |
- case STATE_READ_TUNNEL_HEADERS_COMPLETE: |
- result = DoReadTunnelHeadersComplete(result); |
- break; |
- case STATE_SOCKS_CONNECT: |
- DCHECK_EQ(OK, result); |
- result = DoSOCKSConnect(); |
- break; |
- case STATE_SOCKS_CONNECT_COMPLETE: |
- result = DoSOCKSConnectComplete(result); |
- break; |
- case STATE_SECURE_PROXY_CONNECT: |
- DCHECK_EQ(OK, result); |
- result = DoSecureProxyConnect(); |
- break; |
- case STATE_SECURE_PROXY_CONNECT_COMPLETE: |
- result = DoSecureProxyConnectComplete(result); |
- break; |
- case STATE_SECURE_PROXY_HANDLE_CERT_ERROR: |
- result = DoSecureProxyHandleCertError(result); |
- break; |
- case STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE: |
- result = DoSecureProxyHandleCertErrorComplete(result); |
- break; |
- case STATE_SSL_CONNECT: |
- DCHECK_EQ(OK, result); |
- result = DoSSLConnect(); |
- break; |
- case STATE_SSL_CONNECT_COMPLETE: |
- result = DoSSLConnectComplete(result); |
- break; |
- case STATE_SSL_HANDLE_CERT_ERROR: |
- result = DoSSLHandleCertError(result); |
- break; |
- case STATE_SSL_HANDLE_CERT_ERROR_COMPLETE: |
- result = DoSSLHandleCertErrorComplete(result); |
- break; |
- case STATE_READ_WRITE: |
- result = DoReadWrite(result); |
- break; |
- case STATE_AUTH_REQUIRED: |
- // It might be called when DoClose is called while waiting in |
- // STATE_AUTH_REQUIRED. |
- Finish(result); |
- return; |
- case STATE_CLOSE: |
- DCHECK_LE(result, OK); |
- Finish(result); |
- return; |
- default: |
- NOTREACHED() << "bad state " << state; |
- Finish(result); |
- return; |
- } |
- if (state == STATE_RESOLVE_PROTOCOL && result == ERR_PROTOCOL_SWITCHED) |
- continue; |
- // If the connection is not established yet and had actual errors, |
- // record the error. In next iteration, it will close the connection. |
- if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) { |
- net_log_.EndEventWithNetErrorCode( |
- NetLog::TYPE_SOCKET_STREAM_CONNECT, result); |
- } |
- } while (result != ERR_IO_PENDING); |
-} |
- |
-int SocketStream::DoBeforeConnect() { |
- next_state_ = STATE_BEFORE_CONNECT_COMPLETE; |
- if (!context_ || !context_->network_delegate()) |
- return OK; |
- |
- int result = context_->network_delegate()->NotifyBeforeSocketStreamConnect( |
- this, io_callback_); |
- if (result != OK && result != ERR_IO_PENDING) |
- next_state_ = STATE_CLOSE; |
- |
- return result; |
-} |
- |
-int SocketStream::DoBeforeConnectComplete(int result) { |
- DCHECK_NE(ERR_IO_PENDING, result); |
- |
- if (result == OK) |
- next_state_ = STATE_RESOLVE_PROXY; |
- else |
- next_state_ = STATE_CLOSE; |
- |
- return result; |
-} |
- |
-int SocketStream::DoResolveProxy() { |
- DCHECK(context_); |
- DCHECK(!pac_request_); |
- next_state_ = STATE_RESOLVE_PROXY_COMPLETE; |
- |
- if (!proxy_url_.is_valid()) { |
- next_state_ = STATE_CLOSE; |
- return ERR_INVALID_ARGUMENT; |
- } |
- |
- // TODO(toyoshim): Check server advertisement of SPDY through the HTTP |
- // Alternate-Protocol header, then switch to SPDY if SPDY is available. |
- // Usually we already have a session to the SPDY server because JavaScript |
- // running WebSocket itself would be served by SPDY. But, in some situation |
- // (E.g. Used by Chrome Extensions or used for cross origin connection), this |
- // connection might be the first one. At that time, we should check |
- // Alternate-Protocol header here for ws:// or TLS NPN extension for wss:// . |
- |
- return context_->proxy_service()->ResolveProxy( |
- proxy_url_, net::LOAD_NORMAL, &proxy_info_, io_callback_, &pac_request_, |
- NULL, net_log_); |
-} |
- |
-int SocketStream::DoResolveProxyComplete(int result) { |
- pac_request_ = NULL; |
- if (result != OK) { |
- DVLOG(1) << "Failed to resolve proxy: " << result; |
- if (delegate_) |
- delegate_->OnError(this, result); |
- proxy_info_.UseDirect(); |
- } |
- if (proxy_info_.is_direct()) { |
- // If proxy was not found for original URL (i.e. websocket URL), |
- // try again with https URL, like Safari implementation. |
- // Note that we don't want to use http proxy, because we'll use tunnel |
- // proxy using CONNECT method, which is used by https proxy. |
- if (!proxy_url_.SchemeIs("https")) { |
- const std::string scheme = "https"; |
- GURL::Replacements repl; |
- repl.SetSchemeStr(scheme); |
- proxy_url_ = url_.ReplaceComponents(repl); |
- DVLOG(1) << "Try https proxy: " << proxy_url_; |
- next_state_ = STATE_RESOLVE_PROXY; |
- return OK; |
- } |
- } |
- |
- if (proxy_info_.is_empty()) { |
- // No proxies/direct to choose from. This happens when we don't support any |
- // of the proxies in the returned list. |
- return ERR_NO_SUPPORTED_PROXIES; |
- } |
- |
- next_state_ = STATE_RESOLVE_HOST; |
- return OK; |
-} |
- |
-int SocketStream::DoResolveHost() { |
- next_state_ = STATE_RESOLVE_HOST_COMPLETE; |
- |
- DCHECK(!proxy_info_.is_empty()); |
- if (proxy_info_.is_direct()) |
- proxy_mode_ = kDirectConnection; |
- else if (proxy_info_.proxy_server().is_socks()) |
- proxy_mode_ = kSOCKSProxy; |
- else |
- proxy_mode_ = kTunnelProxy; |
- |
- // Determine the host and port to connect to. |
- HostPortPair host_port_pair; |
- if (proxy_mode_ != kDirectConnection) { |
- host_port_pair = proxy_info_.proxy_server().host_port_pair(); |
- } else { |
- host_port_pair = HostPortPair::FromURL(url_); |
- } |
- |
- HostResolver::RequestInfo resolve_info(host_port_pair); |
- |
- DCHECK(context_->host_resolver()); |
- resolver_.reset(new SingleRequestHostResolver(context_->host_resolver())); |
- return resolver_->Resolve(resolve_info, |
- DEFAULT_PRIORITY, |
- &addresses_, |
- base::Bind(&SocketStream::OnIOCompleted, this), |
- net_log_); |
-} |
- |
-int SocketStream::DoResolveHostComplete(int result) { |
- if (result == OK) |
- next_state_ = STATE_RESOLVE_PROTOCOL; |
- else |
- next_state_ = STATE_CLOSE; |
- // TODO(ukai): if error occured, reconsider proxy after error. |
- return result; |
-} |
- |
-int SocketStream::DoResolveProtocol(int result) { |
- DCHECK_EQ(OK, result); |
- |
- if (!delegate_) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- |
- next_state_ = STATE_RESOLVE_PROTOCOL_COMPLETE; |
- result = delegate_->OnStartOpenConnection(this, io_callback_); |
- if (result == ERR_IO_PENDING) |
- metrics_->OnWaitConnection(); |
- else if (result != OK && result != ERR_PROTOCOL_SWITCHED) |
- next_state_ = STATE_CLOSE; |
- return result; |
-} |
- |
-int SocketStream::DoResolveProtocolComplete(int result) { |
- DCHECK_NE(ERR_IO_PENDING, result); |
- |
- if (result == ERR_PROTOCOL_SWITCHED) { |
- next_state_ = STATE_CLOSE; |
- metrics_->OnCountWireProtocolType( |
- SocketStreamMetrics::WIRE_PROTOCOL_SPDY); |
- } else if (result == OK) { |
- next_state_ = STATE_TCP_CONNECT; |
- metrics_->OnCountWireProtocolType( |
- SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET); |
- } else { |
- next_state_ = STATE_CLOSE; |
- } |
- return result; |
-} |
- |
-int SocketStream::DoTcpConnect(int result) { |
- if (result != OK) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- next_state_ = STATE_TCP_CONNECT_COMPLETE; |
- DCHECK(factory_); |
- connection_->SetSocket( |
- factory_->CreateTransportClientSocket(addresses_, |
- net_log_.net_log(), |
- net_log_.source())); |
- metrics_->OnStartConnection(); |
- return connection_->socket()->Connect(io_callback_); |
-} |
- |
-int SocketStream::DoTcpConnectComplete(int result) { |
- // TODO(ukai): if error occured, reconsider proxy after error. |
- if (result != OK) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- |
- if (proxy_mode_ == kTunnelProxy) { |
- if (proxy_info_.is_https()) |
- next_state_ = STATE_SECURE_PROXY_CONNECT; |
- else |
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; |
- } else if (proxy_mode_ == kSOCKSProxy) { |
- next_state_ = STATE_SOCKS_CONNECT; |
- } else if (is_secure()) { |
- next_state_ = STATE_SSL_CONNECT; |
- } else { |
- result = DidEstablishConnection(); |
- } |
- return result; |
-} |
- |
-int SocketStream::DoGenerateProxyAuthToken() { |
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; |
- if (!proxy_auth_controller_.get()) { |
- DCHECK(context_); |
- DCHECK(context_->http_transaction_factory()); |
- DCHECK(context_->http_transaction_factory()->GetSession()); |
- HttpNetworkSession* session = |
- context_->http_transaction_factory()->GetSession(); |
- const char* scheme = proxy_info_.is_https() ? "https://" : "http://"; |
- GURL auth_url(scheme + |
- proxy_info_.proxy_server().host_port_pair().ToString()); |
- proxy_auth_controller_ = |
- new HttpAuthController(HttpAuth::AUTH_PROXY, |
- auth_url, |
- session->http_auth_cache(), |
- session->http_auth_handler_factory()); |
- } |
- HttpRequestInfo request_info; |
- request_info.url = url_; |
- request_info.method = "CONNECT"; |
- return proxy_auth_controller_->MaybeGenerateAuthToken( |
- &request_info, io_callback_, net_log_); |
-} |
- |
-int SocketStream::DoGenerateProxyAuthTokenComplete(int result) { |
- if (result != OK) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- |
- next_state_ = STATE_WRITE_TUNNEL_HEADERS; |
- return result; |
-} |
- |
-int SocketStream::DoWriteTunnelHeaders() { |
- DCHECK_EQ(kTunnelProxy, proxy_mode_); |
- |
- next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE; |
- |
- if (!tunnel_request_headers_.get()) { |
- metrics_->OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION); |
- tunnel_request_headers_ = new RequestHeaders(); |
- tunnel_request_headers_bytes_sent_ = 0; |
- } |
- if (tunnel_request_headers_->headers_.empty()) { |
- HttpRequestHeaders request_headers; |
- request_headers.SetHeader("Host", GetHostAndOptionalPort(url_)); |
- request_headers.SetHeader("Proxy-Connection", "keep-alive"); |
- if (proxy_auth_controller_.get() && proxy_auth_controller_->HaveAuth()) |
- proxy_auth_controller_->AddAuthorizationHeader(&request_headers); |
- tunnel_request_headers_->headers_ = base::StringPrintf( |
- "CONNECT %s HTTP/1.1\r\n" |
- "%s", |
- GetHostAndPort(url_).c_str(), |
- request_headers.ToString().c_str()); |
- } |
- tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_); |
- int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() - |
- tunnel_request_headers_bytes_sent_); |
- DCHECK_GT(buf_len, 0); |
- return connection_->socket()->Write( |
- tunnel_request_headers_.get(), buf_len, io_callback_); |
-} |
- |
-int SocketStream::DoWriteTunnelHeadersComplete(int result) { |
- DCHECK_EQ(kTunnelProxy, proxy_mode_); |
- |
- if (result < 0) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- |
- tunnel_request_headers_bytes_sent_ += result; |
- if (tunnel_request_headers_bytes_sent_ < |
- tunnel_request_headers_->headers_.size()) { |
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; |
- } else { |
- // Handling a cert error or a client cert request requires reconnection. |
- // DoWriteTunnelHeaders() will be called again. |
- // Thus |tunnel_request_headers_bytes_sent_| should be reset to 0 for |
- // sending |tunnel_request_headers_| correctly. |
- tunnel_request_headers_bytes_sent_ = 0; |
- next_state_ = STATE_READ_TUNNEL_HEADERS; |
- } |
- return OK; |
-} |
- |
-int SocketStream::DoReadTunnelHeaders() { |
- DCHECK_EQ(kTunnelProxy, proxy_mode_); |
- |
- next_state_ = STATE_READ_TUNNEL_HEADERS_COMPLETE; |
- |
- if (!tunnel_response_headers_.get()) { |
- tunnel_response_headers_ = new ResponseHeaders(); |
- tunnel_response_headers_capacity_ = kMaxTunnelResponseHeadersSize; |
- tunnel_response_headers_->Realloc(tunnel_response_headers_capacity_); |
- tunnel_response_headers_len_ = 0; |
- } |
- |
- int buf_len = tunnel_response_headers_capacity_ - |
- tunnel_response_headers_len_; |
- tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_); |
- CHECK(tunnel_response_headers_->data()); |
- |
- return connection_->socket()->Read( |
- tunnel_response_headers_.get(), buf_len, io_callback_); |
-} |
- |
-int SocketStream::DoReadTunnelHeadersComplete(int result) { |
- DCHECK_EQ(kTunnelProxy, proxy_mode_); |
- |
- if (result < 0) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- |
- if (result == 0) { |
- // 0 indicates end-of-file, so socket was closed. |
- next_state_ = STATE_CLOSE; |
- return ERR_CONNECTION_CLOSED; |
- } |
- |
- tunnel_response_headers_len_ += result; |
- DCHECK(tunnel_response_headers_len_ <= tunnel_response_headers_capacity_); |
- |
- int eoh = HttpUtil::LocateEndOfHeaders( |
- tunnel_response_headers_->headers(), tunnel_response_headers_len_, 0); |
- if (eoh == -1) { |
- if (tunnel_response_headers_len_ >= kMaxTunnelResponseHeadersSize) { |
- next_state_ = STATE_CLOSE; |
- return ERR_RESPONSE_HEADERS_TOO_BIG; |
- } |
- |
- next_state_ = STATE_READ_TUNNEL_HEADERS; |
- return OK; |
- } |
- // DidReadResponseHeaders |
- scoped_refptr<HttpResponseHeaders> headers; |
- headers = new HttpResponseHeaders( |
- HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh)); |
- if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) { |
- // Require the "HTTP/1.x" status line. |
- next_state_ = STATE_CLOSE; |
- return ERR_TUNNEL_CONNECTION_FAILED; |
- } |
- switch (headers->response_code()) { |
- case 200: // OK |
- if (is_secure()) { |
- DCHECK_EQ(eoh, tunnel_response_headers_len_); |
- next_state_ = STATE_SSL_CONNECT; |
- } else { |
- result = DidEstablishConnection(); |
- if (result < 0) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- if ((eoh < tunnel_response_headers_len_) && delegate_) |
- delegate_->OnReceivedData( |
- this, tunnel_response_headers_->headers() + eoh, |
- tunnel_response_headers_len_ - eoh); |
- } |
- return OK; |
- case 407: // Proxy Authentication Required. |
- if (proxy_mode_ != kTunnelProxy) |
- return ERR_UNEXPECTED_PROXY_AUTH; |
- |
- result = proxy_auth_controller_->HandleAuthChallenge( |
- headers, false, true, net_log_); |
- if (result != OK) |
- return result; |
- DCHECK(!proxy_info_.is_empty()); |
- next_state_ = STATE_AUTH_REQUIRED; |
- if (proxy_auth_controller_->HaveAuth()) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this)); |
- return ERR_IO_PENDING; |
- } |
- if (delegate_) { |
- // Wait until RestartWithAuth or Close is called. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&SocketStream::DoAuthRequired, this)); |
- return ERR_IO_PENDING; |
- } |
- break; |
- default: |
- break; |
- } |
- next_state_ = STATE_CLOSE; |
- return ERR_TUNNEL_CONNECTION_FAILED; |
-} |
- |
-int SocketStream::DoSOCKSConnect() { |
- DCHECK_EQ(kSOCKSProxy, proxy_mode_); |
- |
- next_state_ = STATE_SOCKS_CONNECT_COMPLETE; |
- |
- HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_)); |
- |
- DCHECK(!proxy_info_.is_empty()); |
- scoped_ptr<StreamSocket> s; |
- if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) { |
- s.reset(new SOCKS5ClientSocket(connection_.Pass(), req_info)); |
- } else { |
- s.reset(new SOCKSClientSocket(connection_.Pass(), |
- req_info, |
- DEFAULT_PRIORITY, |
- context_->host_resolver())); |
- } |
- connection_.reset(new ClientSocketHandle); |
- connection_->SetSocket(s.Pass()); |
- metrics_->OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION); |
- return connection_->socket()->Connect(io_callback_); |
-} |
- |
-int SocketStream::DoSOCKSConnectComplete(int result) { |
- DCHECK_EQ(kSOCKSProxy, proxy_mode_); |
- |
- if (result == OK) { |
- if (is_secure()) |
- next_state_ = STATE_SSL_CONNECT; |
- else |
- result = DidEstablishConnection(); |
- } else { |
- next_state_ = STATE_CLOSE; |
- } |
- return result; |
-} |
- |
-int SocketStream::DoSecureProxyConnect() { |
- DCHECK(factory_); |
- SSLClientSocketContext ssl_context; |
- ssl_context.cert_verifier = context_->cert_verifier(); |
- ssl_context.transport_security_state = context_->transport_security_state(); |
- ssl_context.channel_id_service = context_->channel_id_service(); |
- scoped_ptr<StreamSocket> socket(factory_->CreateSSLClientSocket( |
- connection_.Pass(), |
- proxy_info_.proxy_server().host_port_pair(), |
- proxy_ssl_config_, |
- ssl_context)); |
- connection_.reset(new ClientSocketHandle); |
- connection_->SetSocket(socket.Pass()); |
- next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE; |
- metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION); |
- return connection_->socket()->Connect(io_callback_); |
-} |
- |
-int SocketStream::DoSecureProxyConnectComplete(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- // Reconnect with client authentication. |
- if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) |
- return HandleCertificateRequest(result, &proxy_ssl_config_); |
- |
- if (IsCertificateError(result)) |
- next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR; |
- else if (result == OK) |
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; |
- else |
- next_state_ = STATE_CLOSE; |
- return result; |
-} |
- |
-int SocketStream::DoSecureProxyHandleCertError(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- DCHECK(IsCertificateError(result)); |
- result = HandleCertificateError(result); |
- if (result == ERR_IO_PENDING) |
- next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE; |
- else |
- next_state_ = STATE_CLOSE; |
- return result; |
-} |
- |
-int SocketStream::DoSecureProxyHandleCertErrorComplete(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- if (result == OK) { |
- if (!connection_->socket()->IsConnectedAndIdle()) |
- return AllowCertErrorForReconnection(&proxy_ssl_config_); |
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; |
- } else { |
- next_state_ = STATE_CLOSE; |
- } |
- return result; |
-} |
- |
-int SocketStream::DoSSLConnect() { |
- DCHECK(factory_); |
- SSLClientSocketContext ssl_context; |
- ssl_context.cert_verifier = context_->cert_verifier(); |
- ssl_context.transport_security_state = context_->transport_security_state(); |
- ssl_context.channel_id_service = context_->channel_id_service(); |
- scoped_ptr<StreamSocket> socket( |
- factory_->CreateSSLClientSocket(connection_.Pass(), |
- HostPortPair::FromURL(url_), |
- server_ssl_config_, |
- ssl_context)); |
- connection_.reset(new ClientSocketHandle); |
- connection_->SetSocket(socket.Pass()); |
- next_state_ = STATE_SSL_CONNECT_COMPLETE; |
- metrics_->OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION); |
- return connection_->socket()->Connect(io_callback_); |
-} |
- |
-int SocketStream::DoSSLConnectComplete(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- // Reconnect with client authentication. |
- if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) |
- return HandleCertificateRequest(result, &server_ssl_config_); |
- |
- if (IsCertificateError(result)) |
- next_state_ = STATE_SSL_HANDLE_CERT_ERROR; |
- else if (result == OK) |
- result = DidEstablishConnection(); |
- else |
- next_state_ = STATE_CLOSE; |
- return result; |
-} |
- |
-int SocketStream::DoSSLHandleCertError(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- DCHECK(IsCertificateError(result)); |
- result = HandleCertificateError(result); |
- if (result == OK || result == ERR_IO_PENDING) |
- next_state_ = STATE_SSL_HANDLE_CERT_ERROR_COMPLETE; |
- else |
- next_state_ = STATE_CLOSE; |
- return result; |
-} |
- |
-int SocketStream::DoSSLHandleCertErrorComplete(int result) { |
- DCHECK_EQ(STATE_NONE, next_state_); |
- // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible. |
- // If we use HTTPS and this is the first connection to the SPDY server, |
- // we should take care of TLS NPN extension here. |
- |
- if (result == OK) { |
- if (!connection_->socket()->IsConnectedAndIdle()) |
- return AllowCertErrorForReconnection(&server_ssl_config_); |
- result = DidEstablishConnection(); |
- } else { |
- next_state_ = STATE_CLOSE; |
- } |
- return result; |
-} |
- |
-int SocketStream::DoReadWrite(int result) { |
- if (result < OK) { |
- next_state_ = STATE_CLOSE; |
- return result; |
- } |
- if (!connection_->socket() || !connection_->socket()->IsConnected()) { |
- next_state_ = STATE_CLOSE; |
- return ERR_CONNECTION_CLOSED; |
- } |
- |
- // If client has requested close(), and there's nothing to write, then |
- // let's close the socket. |
- // We don't care about receiving data after the socket is closed. |
- if (closing_ && !current_write_buf_.get() && pending_write_bufs_.empty()) { |
- connection_->socket()->Disconnect(); |
- next_state_ = STATE_CLOSE; |
- return OK; |
- } |
- |
- next_state_ = STATE_READ_WRITE; |
- |
- // If server already closed the socket, we don't try to read. |
- if (!server_closed_) { |
- if (!read_buf_.get()) { |
- // No read pending and server didn't close the socket. |
- read_buf_ = new IOBuffer(kReadBufferSize); |
- result = connection_->socket()->Read( |
- read_buf_.get(), |
- kReadBufferSize, |
- base::Bind(&SocketStream::OnReadCompleted, base::Unretained(this))); |
- if (result > 0) { |
- return DidReceiveData(result); |
- } else if (result == 0) { |
- // 0 indicates end-of-file, so socket was closed. |
- next_state_ = STATE_CLOSE; |
- server_closed_ = true; |
- return ERR_CONNECTION_CLOSED; |
- } |
- // If read is pending, try write as well. |
- // Otherwise, return the result and do next loop (to close the |
- // connection). |
- if (result != ERR_IO_PENDING) { |
- next_state_ = STATE_CLOSE; |
- server_closed_ = true; |
- return result; |
- } |
- } |
- // Read is pending. |
- DCHECK(read_buf_.get()); |
- } |
- |
- if (waiting_for_write_completion_) |
- return ERR_IO_PENDING; |
- |
- if (!current_write_buf_.get()) { |
- if (pending_write_bufs_.empty()) { |
- // Nothing buffered for send. |
- return ERR_IO_PENDING; |
- } |
- |
- current_write_buf_ = new DrainableIOBuffer( |
- pending_write_bufs_.front().get(), pending_write_bufs_.front()->size()); |
- pending_write_bufs_.pop_front(); |
- } |
- |
- result = connection_->socket()->Write( |
- current_write_buf_.get(), |
- current_write_buf_->BytesRemaining(), |
- base::Bind(&SocketStream::OnWriteCompleted, base::Unretained(this))); |
- |
- if (result == ERR_IO_PENDING) { |
- waiting_for_write_completion_ = true; |
- } else if (result < 0) { |
- // Shortcut. Enter STATE_CLOSE now by changing next_state_ here than by |
- // calling DoReadWrite() again with the error code. |
- next_state_ = STATE_CLOSE; |
- } else if (result > 0) { |
- // Write is not pending. Return OK and do next loop. |
- DidSendData(result); |
- result = OK; |
- } |
- |
- return result; |
-} |
- |
-GURL SocketStream::ProxyAuthOrigin() const { |
- DCHECK(!proxy_info_.is_empty()); |
- return GURL("http://" + |
- proxy_info_.proxy_server().host_port_pair().ToString()); |
-} |
- |
-int SocketStream::HandleCertificateRequest(int result, SSLConfig* ssl_config) { |
- if (ssl_config->send_client_cert) { |
- // We already have performed SSL client authentication once and failed. |
- return result; |
- } |
- |
- DCHECK(connection_->socket()); |
- scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo; |
- SSLClientSocket* ssl_socket = |
- static_cast<SSLClientSocket*>(connection_->socket()); |
- ssl_socket->GetSSLCertRequestInfo(cert_request_info.get()); |
- |
- HttpTransactionFactory* factory = context_->http_transaction_factory(); |
- if (!factory) |
- return result; |
- scoped_refptr<HttpNetworkSession> session = factory->GetSession(); |
- if (!session.get()) |
- return result; |
- |
- // If the user selected one of the certificates in client_certs or declined |
- // to provide one for this server before, use the past decision |
- // automatically. |
- scoped_refptr<X509Certificate> client_cert; |
- if (!session->ssl_client_auth_cache()->Lookup( |
- cert_request_info->host_and_port, &client_cert)) { |
- return result; |
- } |
- |
- // Note: |client_cert| may be NULL, indicating that the caller |
- // wishes to proceed anonymously (eg: continue the handshake |
- // without sending a client cert) |
- // |
- // Check that the certificate selected is still a certificate the server |
- // is likely to accept, based on the criteria supplied in the |
- // CertificateRequest message. |
- const std::vector<std::string>& cert_authorities = |
- cert_request_info->cert_authorities; |
- if (client_cert.get() && !cert_authorities.empty() && |
- !client_cert->IsIssuedByEncoded(cert_authorities)) { |
- return result; |
- } |
- |
- ssl_config->send_client_cert = true; |
- ssl_config->client_cert = client_cert; |
- next_state_ = STATE_TCP_CONNECT; |
- return OK; |
-} |
- |
-int SocketStream::AllowCertErrorForReconnection(SSLConfig* ssl_config) { |
- DCHECK(ssl_config); |
- // The SSL handshake didn't finish, or the server closed the SSL connection. |
- // So, we should restart establishing connection with the certificate in |
- // allowed bad certificates in |ssl_config|. |
- // See also net/http/http_network_transaction.cc HandleCertificateError() and |
- // RestartIgnoringLastError(). |
- SSLClientSocket* ssl_socket = |
- static_cast<SSLClientSocket*>(connection_->socket()); |
- SSLInfo ssl_info; |
- ssl_socket->GetSSLInfo(&ssl_info); |
- if (ssl_info.cert.get() == NULL || |
- ssl_config->IsAllowedBadCert(ssl_info.cert.get(), NULL)) { |
- // If we already have the certificate in the set of allowed bad |
- // certificates, we did try it and failed again, so we should not |
- // retry again: the connection should fail at last. |
- next_state_ = STATE_CLOSE; |
- return ERR_UNEXPECTED; |
- } |
- // Add the bad certificate to the set of allowed certificates in the |
- // SSL config object. |
- SSLConfig::CertAndStatus bad_cert; |
- if (!X509Certificate::GetDEREncoded(ssl_info.cert->os_cert_handle(), |
- &bad_cert.der_cert)) { |
- next_state_ = STATE_CLOSE; |
- return ERR_UNEXPECTED; |
- } |
- bad_cert.cert_status = ssl_info.cert_status; |
- ssl_config->allowed_bad_certs.push_back(bad_cert); |
- // Restart connection ignoring the bad certificate. |
- connection_->socket()->Disconnect(); |
- connection_->SetSocket(scoped_ptr<StreamSocket>()); |
- next_state_ = STATE_TCP_CONNECT; |
- return OK; |
-} |
- |
-void SocketStream::DoAuthRequired() { |
- if (delegate_ && proxy_auth_controller_.get()) |
- delegate_->OnAuthRequired(this, proxy_auth_controller_->auth_info().get()); |
- else |
- DoLoop(ERR_UNEXPECTED); |
-} |
- |
-void SocketStream::DoRestartWithAuth() { |
- DCHECK_EQ(next_state_, STATE_AUTH_REQUIRED); |
- tunnel_request_headers_ = NULL; |
- tunnel_request_headers_bytes_sent_ = 0; |
- tunnel_response_headers_ = NULL; |
- tunnel_response_headers_capacity_ = 0; |
- tunnel_response_headers_len_ = 0; |
- |
- next_state_ = STATE_TCP_CONNECT; |
- DoLoop(OK); |
-} |
- |
-int SocketStream::HandleCertificateError(int result) { |
- DCHECK(IsCertificateError(result)); |
- SSLClientSocket* ssl_socket = |
- static_cast<SSLClientSocket*>(connection_->socket()); |
- DCHECK(ssl_socket); |
- |
- if (!context_) |
- return result; |
- |
- if (SSLClientSocket::IgnoreCertError(result, LOAD_IGNORE_ALL_CERT_ERRORS)) { |
- const HttpNetworkSession::Params* session_params = |
- context_->GetNetworkSessionParams(); |
- if (session_params && session_params->ignore_certificate_errors) |
- return OK; |
- } |
- |
- if (!delegate_) |
- return result; |
- |
- SSLInfo ssl_info; |
- ssl_socket->GetSSLInfo(&ssl_info); |
- |
- TransportSecurityState* state = context_->transport_security_state(); |
- const bool fatal = state && state->ShouldSSLErrorsBeFatal(url_.host()); |
- |
- delegate_->OnSSLCertificateError(this, ssl_info, fatal); |
- return ERR_IO_PENDING; |
-} |
- |
-CookieStore* SocketStream::cookie_store() const { |
- return cookie_store_.get(); |
-} |
- |
-} // namespace net |