summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoryhirano@chromium.org <yhirano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 06:50:50 +0000
committeryhirano@chromium.org <yhirano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 06:50:50 +0000
commit3732cea41964d9db33072fafde00b95913f1c1b7 (patch)
treea9d82b879d0f5247f96802dfac2c1f959296a423 /net
parentebd73710916292f90280b4e0516045e25044e431 (diff)
downloadchromium_src-3732cea41964d9db33072fafde00b95913f1c1b7.zip
chromium_src-3732cea41964d9db33072fafde00b95913f1c1b7.tar.gz
chromium_src-3732cea41964d9db33072fafde00b95913f1c1b7.tar.bz2
Introduce RequestWebSocketStream into HttpStreamFactory
Introduce RequestWebSocketStream into HttpStreamFactory to reuse its functionality that handles socket pool, proxy and SSL. BUG=237444 Review URL: https://chromiumcodereview.appspot.com/14813024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207735 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_network_session.cc3
-rw-r--r--net/http/http_network_session.h7
-rw-r--r--net/http/http_network_session_peer.cc5
-rw-r--r--net/http/http_network_session_peer.h1
-rw-r--r--net/http/http_network_transaction.cc7
-rw-r--r--net/http/http_network_transaction.h6
-rw-r--r--net/http/http_stream_factory.h31
-rw-r--r--net/http/http_stream_factory_impl.cc76
-rw-r--r--net/http/http_stream_factory_impl.h41
-rw-r--r--net/http/http_stream_factory_impl_job.cc122
-rw-r--r--net/http/http_stream_factory_impl_job.h5
-rw-r--r--net/http/http_stream_factory_impl_request.cc98
-rw-r--r--net/http/http_stream_factory_impl_request.h24
-rw-r--r--net/http/http_stream_factory_impl_unittest.cc566
-rw-r--r--net/net.gyp1
-rw-r--r--net/socket/client_socket_pool_manager.cc27
-rw-r--r--net/socket/client_socket_pool_manager.h25
-rw-r--r--net/socket/socket_test_util.cc25
-rw-r--r--net/socket/socket_test_util.h8
-rw-r--r--net/websockets/websocket_stream.h6
-rw-r--r--net/websockets/websocket_stream_base.h55
21 files changed, 1038 insertions, 101 deletions
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 4762c71..20f71f4 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -126,7 +126,8 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
params.spdy_max_concurrent_streams_limit,
params.time_func,
params.trusted_spdy_proxy),
- http_stream_factory_(new HttpStreamFactoryImpl(this)),
+ http_stream_factory_(new HttpStreamFactoryImpl(this, false)),
+ websocket_stream_factory_(new HttpStreamFactoryImpl(this, true)),
params_(params) {
DCHECK(proxy_service_);
DCHECK(ssl_config_service_.get());
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 5e86f9c..1e1af31 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -6,6 +6,9 @@
#define NET_HTTP_HTTP_NETWORK_SESSION_H_
#include <set>
+#include <string>
+
+#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/host_port_pair.h"
@@ -136,6 +139,9 @@ class NET_EXPORT HttpNetworkSession
HttpStreamFactory* http_stream_factory() {
return http_stream_factory_.get();
}
+ HttpStreamFactory* websocket_stream_factory() {
+ return websocket_stream_factory_.get();
+ }
NetLog* net_log() {
return net_log_;
}
@@ -190,6 +196,7 @@ class NET_EXPORT HttpNetworkSession
QuicStreamFactory quic_stream_factory_;
SpdySessionPool spdy_session_pool_;
scoped_ptr<HttpStreamFactory> http_stream_factory_;
+ scoped_ptr<HttpStreamFactory> websocket_stream_factory_;
std::set<HttpResponseBodyDrainer*> response_drainers_;
Params params_;
diff --git a/net/http/http_network_session_peer.cc b/net/http/http_network_session_peer.cc
index 9fbac05..74b0d41 100644
--- a/net/http/http_network_session_peer.cc
+++ b/net/http/http_network_session_peer.cc
@@ -34,4 +34,9 @@ void HttpNetworkSessionPeer::SetHttpStreamFactory(
session_->http_stream_factory_.reset(http_stream_factory);
}
+void HttpNetworkSessionPeer::SetWebSocketStreamFactory(
+ HttpStreamFactory* http_stream_factory) {
+ session_->websocket_stream_factory_.reset(http_stream_factory);
+}
+
} // namespace net
diff --git a/net/http/http_network_session_peer.h b/net/http/http_network_session_peer.h
index 3d995cf..eeccfef 100644
--- a/net/http/http_network_session_peer.h
+++ b/net/http/http_network_session_peer.h
@@ -27,6 +27,7 @@ class NET_EXPORT_PRIVATE HttpNetworkSessionPeer {
void SetProxyService(ProxyService* proxy_service);
void SetHttpStreamFactory(HttpStreamFactory* http_stream_factory);
+ void SetWebSocketStreamFactory(HttpStreamFactory* websocket_stream_factory);
private:
const scoped_refptr<HttpNetworkSession> session_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index b59dfd1..55cfb2e 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -440,6 +440,13 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
OnIOComplete(OK);
}
+void HttpNetworkTransaction::OnWebSocketStreamReady(
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream) {
+ NOTREACHED() << "This function should never be called.";
+}
+
void HttpNetworkTransaction::OnStreamFailed(int result,
const SSLConfig& used_ssl_config) {
DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index f19b635..2e98fc2 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -24,11 +24,13 @@
namespace net {
+class ClientSocketHandle;
class HttpAuthController;
class HttpNetworkSession;
class HttpStreamBase;
class HttpStreamRequest;
class IOBuffer;
+class SpdySession;
struct HttpRequestInfo;
class NET_EXPORT_PRIVATE HttpNetworkTransaction
@@ -71,6 +73,10 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
virtual void OnStreamReady(const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
HttpStreamBase* stream) OVERRIDE;
+ virtual void OnWebSocketStreamReady(
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream) OVERRIDE;
virtual void OnStreamFailed(int status,
const SSLConfig& used_ssl_config) OVERRIDE;
virtual void OnCertificateError(int status,
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index fdcbaf0b..3fa31b8 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -18,6 +18,10 @@
#include "net/base/request_priority.h"
#include "net/http/http_server_properties.h"
#include "net/socket/ssl_client_socket.h"
+// This file can be included from net/http even though
+// it is in net/websockets because it doesn't
+// introduce any link dependency to net/websockets.
+#include "net/websockets/websocket_stream_base.h"
class GURL;
@@ -55,7 +59,7 @@ class NET_EXPORT_PRIVATE HttpStreamRequest {
public:
virtual ~Delegate() {}
- // This is the success case.
+ // This is the success case for RequestStream.
// |stream| is now owned by the delegate.
// |used_ssl_config| indicates the actual SSL configuration used for this
// stream, since the HttpStreamRequest may have modified the configuration
@@ -67,6 +71,18 @@ class NET_EXPORT_PRIVATE HttpStreamRequest {
const ProxyInfo& used_proxy_info,
HttpStreamBase* stream) = 0;
+ // This is the success case for RequestWebSocketStream.
+ // |stream| is now owned by the delegate.
+ // |used_ssl_config| indicates the actual SSL configuration used for this
+ // stream, since the HttpStreamRequest may have modified the configuration
+ // during stream processing.
+ // |used_proxy_info| indicates the actual ProxyInfo used for this stream,
+ // since the HttpStreamRequest performs the proxy resolution.
+ virtual void OnWebSocketStreamReady(
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream) = 0;
+
// This is the failure to create a stream case.
// |used_ssl_config| indicates the actual SSL configuration used for this
// stream, since the HttpStreamRequest may have modified the configuration
@@ -169,7 +185,7 @@ class NET_EXPORT HttpStreamFactory {
// Virtual interface methods.
// Request a stream.
- // Will callback to the HttpStreamRequestDelegate upon completion.
+ // Will call delegate->OnStreamReady on successful completion.
virtual HttpStreamRequest* RequestStream(
const HttpRequestInfo& info,
RequestPriority priority,
@@ -178,6 +194,17 @@ class NET_EXPORT HttpStreamFactory {
HttpStreamRequest::Delegate* delegate,
const BoundNetLog& net_log) = 0;
+ // Request a WebSocket stream.
+ // Will call delegate->OnWebSocketStreamReady on successful completion.
+ virtual HttpStreamRequest* RequestWebSocketStream(
+ const HttpRequestInfo& info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* factory,
+ const BoundNetLog& net_log) = 0;
+
// Requests that enough connections for |num_streams| be opened.
virtual void PreconnectStreams(int num_streams,
const HttpRequestInfo& info,
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index c31ba44..6c7c46b 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -4,6 +4,8 @@
#include "net/http/http_stream_factory_impl.h"
+#include <string>
+
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "googleurl/src/gurl.h"
@@ -39,11 +41,13 @@ GURL UpgradeUrlToHttps(const GURL& original_url, int port) {
} // namespace
-HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session)
+HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session,
+ bool for_websockets)
: session_(session),
http_pipelined_host_pool_(this, NULL,
session_->http_server_properties(),
- session_->force_http_pipelining()) {}
+ session_->force_http_pipelining()),
+ for_websockets_(for_websockets) {}
HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
DCHECK(request_map_.empty());
@@ -68,7 +72,48 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
const BoundNetLog& net_log) {
- Request* request = new Request(request_info.url, this, delegate, net_log);
+ DCHECK(!for_websockets_);
+ return RequestStreamInternal(request_info,
+ priority,
+ server_ssl_config,
+ proxy_ssl_config,
+ delegate,
+ NULL,
+ net_log);
+}
+
+HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketStream(
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* factory,
+ const BoundNetLog& net_log) {
+ DCHECK(for_websockets_);
+ DCHECK(factory);
+ return RequestStreamInternal(request_info,
+ priority,
+ server_ssl_config,
+ proxy_ssl_config,
+ delegate,
+ factory,
+ net_log);
+}
+
+HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal(
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* websocket_stream_factory,
+ const BoundNetLog& net_log) {
+ Request* request = new Request(request_info.url,
+ this,
+ delegate,
+ websocket_stream_factory,
+ net_log);
GURL alternate_url;
PortAlternateProtocolPair alternate =
@@ -113,6 +158,7 @@ void HttpStreamFactoryImpl::PreconnectStreams(
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config) {
+ DCHECK(!for_websockets_);
GURL alternate_url;
PortAlternateProtocolPair alternate =
GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
@@ -198,7 +244,7 @@ PortAlternateProtocolPair HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
// for the proxy to use to reach the original URL via TCP. But
// the alternate request will be going via UDP to a different port.
*alternate_url = original_url;
- }
+ }
return alternate;
}
@@ -213,7 +259,7 @@ void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
job->Orphan(request);
}
-void HttpStreamFactoryImpl::OnSpdySessionReady(
+void HttpStreamFactoryImpl::OnNewSpdySessionReady(
scoped_refptr<SpdySession> spdy_session,
bool direct,
const SSLConfig& used_ssl_config,
@@ -239,12 +285,20 @@ void HttpStreamFactoryImpl::OnSpdySessionReady(
protocol_negotiated,
using_spdy,
net_log);
- bool use_relative_url = direct || request->url().SchemeIs("https");
- request->OnStreamReady(
- NULL,
- used_ssl_config,
- used_proxy_info,
- new SpdyHttpStream(spdy_session.get(), use_relative_url));
+ if (for_websockets_) {
+ WebSocketStreamBase::Factory* factory =
+ request->websocket_stream_factory();
+ DCHECK(factory);
+ bool use_relative_url = direct || request->url().SchemeIs("wss");
+ request->OnWebSocketStreamReady(
+ NULL, used_ssl_config, used_proxy_info,
+ factory->CreateSpdyStream(spdy_session, use_relative_url));
+ } else {
+ bool use_relative_url = direct || request->url().SchemeIs("https");
+ request->OnStreamReady(NULL, used_ssl_config, used_proxy_info,
+ new SpdyHttpStream(spdy_session,
+ use_relative_url));
+ }
}
// TODO(mbelshe): Alert other valid requests.
}
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 80e96ce..3cfda3c 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -28,7 +28,9 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
public HttpStreamFactory,
public HttpPipelinedHostPool::Delegate {
public:
- explicit HttpStreamFactoryImpl(HttpNetworkSession* session);
+ // RequestStream may only be called if |for_websockets| is false.
+ // RequestWebSocketStream may only be called if |for_websockets| is true.
+ HttpStreamFactoryImpl(HttpNetworkSession* session, bool for_websockets);
virtual ~HttpStreamFactoryImpl();
// HttpStreamFactory interface
@@ -40,6 +42,15 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
HttpStreamRequest::Delegate* delegate,
const BoundNetLog& net_log) OVERRIDE;
+ virtual HttpStreamRequest* RequestWebSocketStream(
+ const HttpRequestInfo& info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* factory,
+ const BoundNetLog& net_log) OVERRIDE;
+
virtual void PreconnectStreams(int num_streams,
const HttpRequestInfo& info,
RequestPriority priority,
@@ -52,6 +63,8 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
virtual void OnHttpPipelinedHostHasAdditionalCapacity(
HttpPipelinedHost* host) OVERRIDE;
+ size_t num_orphaned_jobs() const { return orphaned_job_set_.size(); }
+
private:
class Request;
class Job;
@@ -62,6 +75,15 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
typedef std::map<HttpPipelinedHost::Key,
RequestVector> HttpPipeliningRequestMap;
+ HttpStreamRequest* RequestStreamInternal(
+ const HttpRequestInfo& info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* factory,
+ const BoundNetLog& net_log);
+
PortAlternateProtocolPair GetAlternateProtocolRequestFor(
const GURL& original_url,
GURL* alternate_url) const;
@@ -72,14 +94,14 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
// Called when a SpdySession is ready. It will find appropriate Requests and
// fulfill them. |direct| indicates whether or not |spdy_session| uses a
// proxy.
- void OnSpdySessionReady(scoped_refptr<SpdySession> spdy_session,
- bool direct,
- const SSLConfig& used_ssl_config,
- const ProxyInfo& used_proxy_info,
- bool was_npn_negotiated,
- NextProto protocol_negotiated,
- bool using_spdy,
- const BoundNetLog& net_log);
+ void OnNewSpdySessionReady(scoped_refptr<SpdySession> spdy_session,
+ bool direct,
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ bool was_npn_negotiated,
+ NextProto protocol_negotiated,
+ bool using_spdy,
+ const BoundNetLog& net_log);
// Called when the Job detects that the endpoint indicated by the
// Alternate-Protocol does not work. Lets the factory update
@@ -124,6 +146,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
// deleted when the factory is destroyed.
std::set<const Job*> preconnect_job_set_;
+ const bool for_websockets_;
DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImpl);
};
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 179d8c4..c51f1c5 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -4,6 +4,8 @@
#include "net/http/http_stream_factory_impl_job.h"
+#include <string>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
@@ -207,12 +209,22 @@ void HttpStreamFactoryImpl::Job::Resume(Job* job) {
void HttpStreamFactoryImpl::Job::Orphan(const Request* request) {
DCHECK_EQ(request_, request);
request_ = NULL;
- // We've been orphaned, but there's a job we're blocked on. Don't bother
- // racing, just cancel ourself.
if (blocking_job_) {
+ // We've been orphaned, but there's a job we're blocked on. Don't bother
+ // racing, just cancel ourself.
DCHECK(blocking_job_->waiting_job_);
blocking_job_->waiting_job_ = NULL;
blocking_job_ = NULL;
+ if (stream_factory_->for_websockets_ &&
+ connection_ && connection_->socket())
+ connection_->socket()->Disconnect();
+ stream_factory_->OnOrphanedJobComplete(this);
+ } else if (stream_factory_->for_websockets_) {
+ // We cancel this job because WebSocketStream can't be created
+ // without a WebSocketStreamBase::Factory which is stored in Request class
+ // and isn't accessible from this job.
+ if (connection_ && connection_->socket())
+ connection_->socket()->Disconnect();
stream_factory_->OnOrphanedJobComplete(this);
}
}
@@ -274,6 +286,7 @@ bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const {
// https (the normal case) or if we're connection to a SPDY proxy, or
// if we're running with force_spdy_always_. crbug.com/133176
return request_info_.url.SchemeIs("https") ||
+ request_info_.url.SchemeIs("wss") ||
proxy_info_.proxy_server().is_https() ||
force_spdy_always_;
}
@@ -281,6 +294,7 @@ bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const {
void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
DCHECK(stream_.get());
DCHECK(!IsPreconnecting());
+ DCHECK(!stream_factory_->for_websockets_);
if (IsOrphaned()) {
stream_factory_->OnOrphanedJobComplete(this);
} else {
@@ -294,7 +308,25 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
// |this| may be deleted after this call.
}
-void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() {
+void HttpStreamFactoryImpl::Job::OnWebSocketStreamReadyCallback() {
+ DCHECK(websocket_stream_);
+ DCHECK(!IsPreconnecting());
+ DCHECK(stream_factory_->for_websockets_);
+ // An orphaned WebSocket job will be closed immediately and
+ // never be ready.
+ DCHECK(!IsOrphaned());
+ request_->Complete(was_npn_negotiated(),
+ protocol_negotiated(),
+ using_spdy(),
+ net_log_);
+ request_->OnWebSocketStreamReady(this,
+ server_ssl_config_,
+ proxy_info_,
+ websocket_stream_.release());
+ // |this| may be deleted after this call.
+}
+
+void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() {
DCHECK(!stream_.get());
DCHECK(!IsPreconnecting());
DCHECK(using_spdy());
@@ -302,12 +334,12 @@ void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() {
scoped_refptr<SpdySession> spdy_session = new_spdy_session_;
new_spdy_session_ = NULL;
if (IsOrphaned()) {
- stream_factory_->OnSpdySessionReady(
+ stream_factory_->OnNewSpdySessionReady(
spdy_session, spdy_session_direct_, server_ssl_config_, proxy_info_,
was_npn_negotiated(), protocol_negotiated(), using_spdy(), net_log_);
stream_factory_->OnOrphanedJobComplete(this);
} else {
- request_->OnSpdySessionReady(this, spdy_session, spdy_session_direct_);
+ request_->OnNewSpdySessionReady(this, spdy_session, spdy_session_direct_);
}
// |this| may be deleted after this call.
}
@@ -367,15 +399,11 @@ void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback(
void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() {
DCHECK(!request_);
- if (new_spdy_session_.get()) {
- stream_factory_->OnSpdySessionReady(new_spdy_session_,
- spdy_session_direct_,
- server_ssl_config_,
- proxy_info_,
- was_npn_negotiated(),
- protocol_negotiated(),
- using_spdy(),
- net_log_);
+ if (new_spdy_session_) {
+ stream_factory_->OnNewSpdySessionReady(
+ new_spdy_session_, spdy_session_direct_, server_ssl_config_,
+ proxy_info_, was_npn_negotiated(), protocol_negotiated(), using_spdy(),
+ net_log_);
}
stream_factory_->OnPreconnectsComplete(this);
// |this| may be deleted after this call.
@@ -448,7 +476,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
- &HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback,
+ &Job::OnNeedsProxyAuthCallback,
ptr_factory_.GetWeakPtr(),
*tunnel_auth_response,
proxy_socket->GetAuthController()));
@@ -459,7 +487,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
- &HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback,
+ &Job::OnNeedsClientAuthCallback,
ptr_factory_.GetWeakPtr(),
connection_->ssl_error_response_info().cert_request_info));
return ERR_IO_PENDING;
@@ -475,7 +503,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
- &HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback,
+ &Job::OnHttpsProxyTunnelResponseCallback,
ptr_factory_.GetWeakPtr(),
*proxy_socket->GetConnectResponseInfo(),
proxy_socket->CreateConnectResponseStream()));
@@ -484,16 +512,25 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
case OK:
next_state_ = STATE_DONE;
- if (new_spdy_session_.get()) {
+ if (new_spdy_session_) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback,
- ptr_factory_.GetWeakPtr()));
+ base::Bind(
+ &Job::OnNewSpdySessionReadyCallback,
+ ptr_factory_.GetWeakPtr()));
+ } else if (stream_factory_->for_websockets_) {
+ DCHECK(websocket_stream_);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &Job::OnWebSocketStreamReadyCallback,
+ ptr_factory_.GetWeakPtr()));
} else {
+ DCHECK(stream_.get());
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
- &HttpStreamFactoryImpl::Job::OnStreamReadyCallback,
+ &Job::OnStreamReadyCallback,
ptr_factory_.GetWeakPtr()));
}
return ERR_IO_PENDING;
@@ -502,7 +539,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
- &HttpStreamFactoryImpl::Job::OnStreamFailedCallback,
+ &Job::OnStreamFailedCallback,
ptr_factory_.GetWeakPtr(),
result));
return ERR_IO_PENDING;
@@ -689,7 +726,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
DCHECK(proxy_info_.proxy_server().is_valid());
next_state_ = STATE_INIT_CONNECTION_COMPLETE;
- using_ssl_ = request_info_.url.SchemeIs("https") || ShouldForceSpdySSL();
+ using_ssl_ = request_info_.url.SchemeIs("https") ||
+ request_info_.url.SchemeIs("wss") || ShouldForceSpdySSL();
using_spdy_ = false;
if (ShouldForceQuic())
@@ -774,6 +812,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
}
if (IsPreconnecting()) {
+ DCHECK(!stream_factory_->for_websockets_);
return PreconnectSocketsForHttpRequest(
origin_url_,
request_info_.extra_headers,
@@ -795,6 +834,14 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
base::Bind(&Job::OnHostResolution, session_->spdy_session_pool(),
GetSpdySessionKey()) :
OnHostResolutionCallback();
+ if (stream_factory_->for_websockets_) {
+ return InitSocketHandleForWebSocketRequest(
+ origin_url_, request_info_.extra_headers, request_info_.load_flags,
+ priority_, session_, proxy_info_, ShouldForceSpdySSL(),
+ want_spdy_over_npn, server_ssl_config_, proxy_ssl_config_,
+ request_info_.privacy_mode, net_log_,
+ connection_.get(), resolution_callback, io_callback_);
+ }
return InitSocketHandleForHttpRequest(
origin_url_, request_info_.extra_headers, request_info_.load_flags,
priority_, session_, proxy_info_, ShouldForceSpdySSL(),
@@ -864,9 +911,9 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
SSLClientSocket::NextProtoFromString(proto);
protocol_negotiated_ = protocol_negotiated;
net_log_.AddEvent(
- NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO,
- base::Bind(&NetLogHttpStreamProtoCallback,
- status, &proto, &server_protos));
+ NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO,
+ base::Bind(&NetLogHttpStreamProtoCallback,
+ status, &proto, &server_protos));
if (ssl_socket->was_spdy_negotiated())
SwitchToSpdyMode();
}
@@ -982,10 +1029,17 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
request_info_.url.SchemeIs("ftp"));
if (stream_factory_->http_pipelined_host_pool_.
IsExistingPipelineAvailableForKey(*http_pipelining_key_.get())) {
+ DCHECK(!stream_factory_->for_websockets_);
stream_.reset(stream_factory_->http_pipelined_host_pool_.
CreateStreamOnExistingPipeline(
*http_pipelining_key_.get()));
CHECK(stream_.get());
+ } else if (stream_factory_->for_websockets_) {
+ DCHECK(request_);
+ DCHECK(request_->websocket_stream_factory());
+ websocket_stream_.reset(
+ request_->websocket_stream_factory()->CreateBasicStream(
+ connection_.release(), using_proxy));
} else if (!using_proxy && IsRequestEligibleForPipelining()) {
// TODO(simonjam): Support proxies.
stream_.reset(
@@ -1057,8 +1111,17 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
// HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it
// will know when SpdySessions become available.
- bool use_relative_url = direct || request_info_.url.SchemeIs("https");
- stream_.reset(new SpdyHttpStream(spdy_session.get(), use_relative_url));
+ if (stream_factory_->for_websockets_) {
+ DCHECK(request_);
+ DCHECK(request_->websocket_stream_factory());
+ bool use_relative_url = direct || request_info_.url.SchemeIs("wss");
+ websocket_stream_.reset(
+ request_->websocket_stream_factory()->CreateSpdyStream(
+ spdy_session, use_relative_url));
+ } else {
+ bool use_relative_url = direct || request_info_.url.SchemeIs("https");
+ stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url));
+ }
return OK;
}
@@ -1359,6 +1422,9 @@ bool HttpStreamFactoryImpl::Job::IsRequestEligibleForPipelining() {
if (IsPreconnecting() || !request_) {
return false;
}
+ if (stream_factory_->for_websockets_) {
+ return false;
+ }
if (session_->force_http_pipelining()) {
return true;
}
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index a6a3603..6e34f5f 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -127,7 +127,9 @@ class HttpStreamFactoryImpl::Job {
};
void OnStreamReadyCallback();
- void OnSpdySessionReadyCallback();
+ void OnWebSocketStreamReadyCallback();
+ // This callback function is called when a new SPDY session is created.
+ void OnNewSpdySessionReadyCallback();
void OnStreamFailedCallback(int result);
void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info);
void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info,
@@ -292,6 +294,7 @@ class HttpStreamFactoryImpl::Job {
bool establishing_tunnel_;
scoped_ptr<HttpStream> stream_;
+ scoped_ptr<WebSocketStreamBase> websocket_stream_;
// True if we negotiated NPN.
bool was_npn_negotiated_;
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index 3fcc7ae..a29e593 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -13,12 +13,15 @@
namespace net {
-HttpStreamFactoryImpl::Request::Request(const GURL& url,
- HttpStreamFactoryImpl* factory,
- HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log)
+HttpStreamFactoryImpl::Request::Request(
+ const GURL& url,
+ HttpStreamFactoryImpl* factory,
+ HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* websocket_stream_factory,
+ const BoundNetLog& net_log)
: url_(url),
factory_(factory),
+ websocket_stream_factory_(websocket_stream_factory),
delegate_(delegate),
net_log_(net_log),
completed_(false),
@@ -99,33 +102,27 @@ void HttpStreamFactoryImpl::Request::OnStreamReady(
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
HttpStreamBase* stream) {
+ DCHECK(!factory_->for_websockets_);
DCHECK(stream);
DCHECK(completed_);
- // |job| should only be NULL if we're being serviced by a late bound
- // SpdySession or HttpPipelinedConnection (one that was not created by a job
- // in our |jobs_| set).
- if (!job) {
- DCHECK(!bound_job_.get());
- DCHECK(!jobs_.empty());
- // NOTE(willchan): We do *NOT* call OrphanJobs() here. The reason is because
- // we *WANT* to cancel the unnecessary Jobs from other requests if another
- // Job completes first.
- // TODO(mbelshe): Revisit this when we implement ip connection pooling of
- // SpdySessions. Do we want to orphan the jobs for a different hostname so
- // they complete? Or do we want to prevent connecting a new SpdySession if
- // we've already got one available for a different hostname where the ip
- // address matches up?
- } else if (!bound_job_.get()) {
- // We may have other jobs in |jobs_|. For example, if we start multiple jobs
- // for Alternate-Protocol.
- OrphanJobsExcept(job);
- } else {
- DCHECK(jobs_.empty());
- }
+ OnJobSucceeded(job);
delegate_->OnStreamReady(used_ssl_config, used_proxy_info, stream);
}
+void HttpStreamFactoryImpl::Request::OnWebSocketStreamReady(
+ Job* job,
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream) {
+ DCHECK(factory_->for_websockets_);
+ DCHECK(stream);
+ DCHECK(completed_);
+
+ OnJobSucceeded(job);
+ delegate_->OnWebSocketStreamReady(used_ssl_config, used_proxy_info, stream);
+}
+
void HttpStreamFactoryImpl::Request::OnStreamFailed(
Job* job,
int status,
@@ -280,7 +277,7 @@ HttpStreamFactoryImpl::Request::RemoveRequestFromHttpPipeliningRequestMap() {
}
}
-void HttpStreamFactoryImpl::Request::OnSpdySessionReady(
+void HttpStreamFactoryImpl::Request::OnNewSpdySessionReady(
Job* job,
scoped_refptr<SpdySession> spdy_session,
bool direct) {
@@ -290,7 +287,7 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady(
// The first case is the usual case.
if (!bound_job_.get()) {
OrphanJobsExcept(job);
- } else { // This is the case for HTTPS proxy tunneling.
+ } else { // This is the case for HTTPS proxy tunneling.
DCHECK_EQ(bound_job_.get(), job);
DCHECK(jobs_.empty());
}
@@ -308,14 +305,23 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady(
// Cache this so we can still use it if the request is deleted.
HttpStreamFactoryImpl* factory = factory_;
-
- bool use_relative_url = direct || url().SchemeIs("https");
- delegate_->OnStreamReady(
- job->server_ssl_config(),
- job->proxy_info(),
- new SpdyHttpStream(spdy_session.get(), use_relative_url));
+ if (factory->for_websockets_) {
+ DCHECK(websocket_stream_factory_);
+ bool use_relative_url = direct || url().SchemeIs("wss");
+ delegate_->OnWebSocketStreamReady(
+ job->server_ssl_config(),
+ job->proxy_info(),
+ websocket_stream_factory_->CreateSpdyStream(
+ spdy_session, use_relative_url));
+ } else {
+ bool use_relative_url = direct || url().SchemeIs("https");
+ delegate_->OnStreamReady(
+ job->server_ssl_config(),
+ job->proxy_info(),
+ new SpdyHttpStream(spdy_session, use_relative_url));
+ }
// |this| may be deleted after this point.
- factory->OnSpdySessionReady(
+ factory->OnNewSpdySessionReady(
spdy_session, direct, used_ssl_config, used_proxy_info,
was_npn_negotiated, protocol_negotiated, using_spdy, net_log);
}
@@ -342,4 +348,28 @@ void HttpStreamFactoryImpl::Request::OrphanJobs() {
factory_->OrphanJob(*it, this);
}
+void HttpStreamFactoryImpl::Request::OnJobSucceeded(Job* job) {
+ // |job| should only be NULL if we're being serviced by a late bound
+ // SpdySession or HttpPipelinedConnection (one that was not created by a job
+ // in our |jobs_| set).
+ if (!job) {
+ DCHECK(!bound_job_.get());
+ DCHECK(!jobs_.empty());
+ // NOTE(willchan): We do *NOT* call OrphanJobs() here. The reason is because
+ // we *WANT* to cancel the unnecessary Jobs from other requests if another
+ // Job completes first.
+ // TODO(mbelshe): Revisit this when we implement ip connection pooling of
+ // SpdySessions. Do we want to orphan the jobs for a different hostname so
+ // they complete? Or do we want to prevent connecting a new SpdySession if
+ // we've already got one available for a different hostname where the ip
+ // address matches up?
+ } else if (!bound_job_.get()) {
+ // We may have other jobs in |jobs_|. For example, if we start multiple jobs
+ // for Alternate-Protocol.
+ OrphanJobsExcept(job);
+ } else {
+ DCHECK(jobs_.empty());
+ }
+}
+
} // namespace net
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 18633fa..ff4f8af 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -15,11 +15,15 @@
namespace net {
+class ClientSocketHandle;
+class SpdySession;
+
class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
public:
Request(const GURL& url,
HttpStreamFactoryImpl* factory,
HttpStreamRequest::Delegate* delegate,
+ WebSocketStreamBase::Factory* websocket_stream_factory,
const BoundNetLog& net_log);
virtual ~Request();
@@ -58,9 +62,13 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
void RemoveRequestFromHttpPipeliningRequestMap();
// Called by an attached Job if it sets up a SpdySession.
- void OnSpdySessionReady(Job* job,
- scoped_refptr<SpdySession> spdy_session,
- bool direct);
+ void OnNewSpdySessionReady(Job* job,
+ scoped_refptr<SpdySession> spdy_session,
+ bool direct);
+
+ WebSocketStreamBase::Factory* websocket_stream_factory() {
+ return websocket_stream_factory_;
+ }
// HttpStreamRequest::Delegate methods which we implement. Note we don't
// actually subclass HttpStreamRequest::Delegate.
@@ -69,6 +77,10 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
HttpStreamBase* stream);
+ void OnWebSocketStreamReady(Job* job,
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream);
void OnStreamFailed(Job* job, int status, const SSLConfig& used_ssl_config);
void OnCertificateError(Job* job,
int status,
@@ -106,8 +118,12 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
// Used to orphan all jobs in |jobs_|.
void OrphanJobs();
+ // Called when a Job succeeds.
+ void OnJobSucceeded(Job* job);
+
const GURL url_;
HttpStreamFactoryImpl* const factory_;
+ WebSocketStreamBase::Factory* const websocket_stream_factory_;
HttpStreamRequest::Delegate* const delegate_;
const BoundNetLog net_log_;
@@ -128,4 +144,4 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
} // namespace net
-#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_H_
+#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_REQUEST_H_
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 0200b8f..210e940 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "net/http/http_stream_factory_impl.h"
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "net/base/net_log.h"
@@ -16,26 +17,72 @@
#include "net/http/http_network_session_peer.h"
#include "net/http/http_network_transaction.h"
#include "net/http/http_request_info.h"
+#include "net/http/http_server_properties.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_stream.h"
#include "net/http/transport_security_state.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
+#include "net/socket/client_socket_handle.h"
#include "net/socket/mock_client_socket_pool_manager.h"
+#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
+#include "net/spdy/spdy_test_util_common.h"
+#include "net/ssl/ssl_config_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
+// This file can be included from net/http even though
+// it is in net/websockets because it doesn't
+// introduce any link dependency to net/websockets.
+#include "net/websockets/websocket_stream_base.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
-class MockHttpStreamFactoryImpl : public HttpStreamFactoryImpl {
+class UseAlternateProtocolsScopedSetter {
public:
- MockHttpStreamFactoryImpl(HttpNetworkSession* session)
- : HttpStreamFactoryImpl(session),
+ UseAlternateProtocolsScopedSetter(bool use_alternate_protocols)
+ : use_alternate_protocols_(HttpStreamFactory::use_alternate_protocols()) {
+ HttpStreamFactory::set_use_alternate_protocols(use_alternate_protocols);
+ }
+ ~UseAlternateProtocolsScopedSetter() {
+ HttpStreamFactory::set_use_alternate_protocols(use_alternate_protocols_);
+ }
+
+ private:
+ bool use_alternate_protocols_;
+};
+
+class MockWebSocketStream : public WebSocketStreamBase {
+ public:
+ enum StreamType {
+ kStreamTypeBasic,
+ kStreamTypeSpdy,
+ };
+
+ explicit MockWebSocketStream(StreamType type) : type_(type) {}
+
+ virtual ~MockWebSocketStream() {}
+
+ virtual WebSocketStream* AsWebSocketStream() OVERRIDE { return NULL; }
+
+ StreamType type() const {
+ return type_;
+ }
+
+ private:
+ const StreamType type_;
+};
+
+// HttpStreamFactoryImpl subclass that can wait until a preconnect is complete.
+class MockHttpStreamFactoryImplForPreconnect : public HttpStreamFactoryImpl {
+ public:
+ MockHttpStreamFactoryImplForPreconnect(HttpNetworkSession* session,
+ bool for_websockets)
+ : HttpStreamFactoryImpl(session, for_websockets),
preconnect_done_(false),
waiting_for_preconnect_(false) {}
@@ -77,6 +124,19 @@ class StreamRequestWaiter : public HttpStreamRequest::Delegate {
base::MessageLoop::current()->Quit();
stream_.reset(stream);
used_ssl_config_ = used_ssl_config;
+ used_proxy_info_ = used_proxy_info;
+ }
+
+ virtual void OnWebSocketStreamReady(
+ const SSLConfig& used_ssl_config,
+ const ProxyInfo& used_proxy_info,
+ WebSocketStreamBase* stream) OVERRIDE {
+ stream_done_ = true;
+ if (waiting_for_stream_)
+ base::MessageLoop::current()->Quit();
+ websocket_stream_.reset(stream);
+ used_ssl_config_ = used_ssl_config;
+ used_proxy_info_ = used_proxy_info;
}
virtual void OnStreamFailed(
@@ -113,20 +173,75 @@ class StreamRequestWaiter : public HttpStreamRequest::Delegate {
return used_ssl_config_;
}
+ const ProxyInfo& used_proxy_info() const {
+ return used_proxy_info_;
+ }
+
HttpStreamBase* stream() {
return stream_.get();
}
+ MockWebSocketStream* websocket_stream() {
+ return static_cast<MockWebSocketStream*>(websocket_stream_.get());
+ }
+
+ bool stream_done() const { return stream_done_; }
private:
bool waiting_for_stream_;
bool stream_done_;
scoped_ptr<HttpStreamBase> stream_;
+ scoped_ptr<WebSocketStreamBase> websocket_stream_;
SSLConfig used_ssl_config_;
+ ProxyInfo used_proxy_info_;
DISALLOW_COPY_AND_ASSIGN(StreamRequestWaiter);
};
+class WebSocketSpdyStream : public MockWebSocketStream {
+ public:
+ explicit WebSocketSpdyStream(SpdySession* spdy_session)
+ : MockWebSocketStream(kStreamTypeSpdy), spdy_session_(spdy_session) {}
+
+ virtual ~WebSocketSpdyStream() {}
+
+ SpdySession* spdy_session() { return spdy_session_.get(); }
+
+ private:
+ scoped_refptr<SpdySession> spdy_session_;
+};
+
+class WebSocketBasicStream : public MockWebSocketStream {
+ public:
+ explicit WebSocketBasicStream(ClientSocketHandle* connection)
+ : MockWebSocketStream(kStreamTypeBasic), connection_(connection) {}
+
+ virtual ~WebSocketBasicStream() {
+ connection_->socket()->Disconnect();
+ }
+
+ ClientSocketHandle* connection() { return connection_.get(); }
+
+ private:
+ scoped_ptr<ClientSocketHandle> connection_;
+};
+
+class WebSocketStreamFactory : public WebSocketStreamBase::Factory {
+ public:
+ virtual ~WebSocketStreamFactory() {}
+
+ virtual WebSocketStreamBase* CreateBasicStream(ClientSocketHandle* connection,
+ bool using_proxy) OVERRIDE {
+ return new WebSocketBasicStream(connection);
+ }
+
+ virtual WebSocketStreamBase* CreateSpdyStream(
+ SpdySession* spdy_session,
+ bool use_relative_url) OVERRIDE {
+ return new WebSocketSpdyStream(spdy_session);
+ }
+};
+
struct SessionDependencies {
// Custom proxy service dependency.
explicit SessionDependencies(ProxyService* proxy_service)
@@ -163,6 +278,7 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
session_deps->http_auth_handler_factory.get();
params.net_log = session_deps->net_log;
params.http_server_properties = &session_deps->http_server_properties;
+
return new HttpNetworkSession(params);
}
@@ -182,8 +298,8 @@ void PreconnectHelperForURL(int num_streams,
const GURL& url,
HttpNetworkSession* session) {
HttpNetworkSessionPeer peer(session);
- MockHttpStreamFactoryImpl* mock_factory =
- new MockHttpStreamFactoryImpl(session);
+ MockHttpStreamFactoryImplForPreconnect* mock_factory =
+ new MockHttpStreamFactoryImplForPreconnect(session, false);
peer.SetHttpStreamFactory(mock_factory);
SSLConfig ssl_config;
session->ssl_config_service()->GetSSLConfig(&ssl_config);
@@ -465,7 +581,7 @@ TEST(HttpStreamFactoryTest, JobNotifiesProxy) {
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- // Now request a stream. It should succeed using the second proxy in the
+ // Now request a stream. It should succeed using the second proxy in the
// list.
HttpRequestInfo request_info;
request_info.method = "GET";
@@ -537,7 +653,7 @@ int GetSocketPoolGroupCount(ClientSocketPool* pool) {
}
return count;
}
-};
+} // namespace
TEST(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
SessionDependencies session_deps(ProxyService::CreateDirect());
@@ -615,6 +731,442 @@ TEST(HttpStreamFactoryTest, GetLoadState) {
waiter.WaitForStream();
}
+TEST(HttpStreamFactoryTest, RequestHttpStream) {
+ SessionDependencies session_deps(ProxyService::CreateDirect());
+
+ StaticSocketDataProvider socket_data;
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream. It should succeed using the second proxy in the
+ // list.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ scoped_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ ASSERT_TRUE(NULL != waiter.stream());
+ EXPECT_TRUE(NULL == waiter.websocket_stream());
+ EXPECT_FALSE(waiter.stream()->IsSpdyHttpStream());
+
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetSSLSocketPool(
+ HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestHttpStreamOverSSL) {
+ SessionDependencies session_deps(ProxyService::CreateDirect());
+
+ MockRead mock_read(ASYNC, OK);
+ StaticSocketDataProvider socket_data(&mock_read, 1, NULL, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ scoped_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ ASSERT_TRUE(NULL != waiter.stream());
+ EXPECT_TRUE(NULL == waiter.websocket_stream());
+ EXPECT_FALSE(waiter.stream()->IsSpdyHttpStream());
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestHttpStreamOverProxy) {
+ SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:8888"));
+
+ StaticSocketDataProvider socket_data;
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream. It should succeed using the second proxy in the
+ // list.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ scoped_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ ASSERT_TRUE(NULL != waiter.stream());
+ EXPECT_TRUE(NULL == waiter.websocket_stream());
+ EXPECT_FALSE(waiter.stream()->IsSpdyHttpStream());
+ EXPECT_EQ(0, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetSocketPoolForHTTPProxy(
+ HttpNetworkSession::NORMAL_SOCKET_POOL,
+ HostPortPair("myproxy", 8888))));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetSocketPoolForSSLWithProxy(
+ HttpNetworkSession::NORMAL_SOCKET_POOL,
+ HostPortPair("myproxy", 8888))));
+ EXPECT_FALSE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestWebSocketBasicStream) {
+ SessionDependencies session_deps(ProxyService::CreateDirect());
+
+ StaticSocketDataProvider socket_data;
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("ws://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ WebSocketStreamFactory factory;
+ scoped_ptr<HttpStreamRequest> request(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ &factory,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ EXPECT_TRUE(NULL == waiter.stream());
+ ASSERT_TRUE(NULL != waiter.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+ waiter.websocket_stream()->type());
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestWebSocketBasicStreamOverSSL) {
+ SessionDependencies session_deps(ProxyService::CreateDirect());
+
+ MockRead mock_read(ASYNC, OK);
+ StaticSocketDataProvider socket_data(&mock_read, 1, NULL, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("wss://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ WebSocketStreamFactory factory;
+ scoped_ptr<HttpStreamRequest> request(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ &factory,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ EXPECT_TRUE(NULL == waiter.stream());
+ ASSERT_TRUE(NULL != waiter.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+ waiter.websocket_stream()->type());
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestWebSocketBasicStreamOverProxy) {
+ SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:8888"));
+
+ MockRead read(SYNCHRONOUS, "HTTP/1.0 200 Connection established\r\n\r\n");
+ StaticSocketDataProvider socket_data(&read, 1, 0, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory.AddSocketDataProvider(&socket_data);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("ws://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ WebSocketStreamFactory factory;
+ scoped_ptr<HttpStreamRequest> request(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ &factory,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ EXPECT_TRUE(NULL == waiter.stream());
+ ASSERT_TRUE(NULL != waiter.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+ waiter.websocket_stream()->type());
+ EXPECT_EQ(0, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetSocketPoolForHTTPProxy(
+ HttpNetworkSession::NORMAL_SOCKET_POOL,
+ HostPortPair("myproxy", 8888))));
+ EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetSocketPoolForSSLWithProxy(
+ HttpNetworkSession::NORMAL_SOCKET_POOL,
+ HostPortPair("myproxy", 8888))));
+ EXPECT_FALSE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestSpdyHttpStream) {
+ SpdySessionDependencies session_deps(kProtoSPDY3,
+ ProxyService::CreateDirect());
+
+ MockRead mock_read(ASYNC, OK);
+ StaticSocketDataProvider socket_data(&mock_read, 1, NULL, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory->AddSocketDataProvider(&socket_data);
+
+ SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
+ ssl_socket_data.SetNextProto(kProtoSPDY3);
+ session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
+
+ HostPortPair host_port_pair("www.google.com", 443);
+ scoped_refptr<HttpNetworkSession>
+ session(SpdySessionDependencies::SpdyCreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ scoped_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ EXPECT_TRUE(NULL == waiter.websocket_stream());
+ ASSERT_TRUE(NULL != waiter.stream());
+ EXPECT_TRUE(waiter.stream()->IsSpdyHttpStream());
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, RequestWebSocketSpdyStream) {
+ SpdySessionDependencies session_deps(kProtoSPDY3,
+ ProxyService::CreateDirect());
+
+ MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING);
+ StaticSocketDataProvider socket_data(&mock_read, 1, NULL, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory->AddSocketDataProvider(&socket_data);
+
+ SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
+ ssl_socket_data.SetNextProto(kProtoSPDY3);
+ session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
+
+ HostPortPair host_port_pair("www.google.com", 80);
+ scoped_refptr<HttpNetworkSession>
+ session(SpdySessionDependencies::SpdyCreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("wss://www.google.com");
+ request_info.load_flags = 0;
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter1;
+ WebSocketStreamFactory factory;
+ scoped_ptr<HttpStreamRequest> request1(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter1,
+ &factory,
+ BoundNetLog()));
+ waiter1.WaitForStream();
+ EXPECT_TRUE(waiter1.stream_done());
+ ASSERT_TRUE(NULL != waiter1.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+ waiter1.websocket_stream()->type());
+ EXPECT_TRUE(NULL == waiter1.stream());
+
+ StreamRequestWaiter waiter2;
+ scoped_ptr<HttpStreamRequest> request2(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter2,
+ &factory,
+ BoundNetLog()));
+ waiter2.WaitForStream();
+ EXPECT_TRUE(waiter2.stream_done());
+ ASSERT_TRUE(NULL != waiter2.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+ waiter2.websocket_stream()->type());
+ EXPECT_TRUE(NULL == waiter2.stream());
+ EXPECT_NE(waiter2.websocket_stream(), waiter1.websocket_stream());
+ EXPECT_EQ(static_cast<WebSocketSpdyStream*>(waiter2.websocket_stream())->
+ spdy_session(),
+ static_cast<WebSocketSpdyStream*>(waiter1.websocket_stream())->
+ spdy_session());
+
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter1.used_proxy_info().is_direct());
+}
+
+TEST(HttpStreamFactoryTest, OrphanedWebSocketStream) {
+ UseAlternateProtocolsScopedSetter use_alternate_protocols(true);
+ SpdySessionDependencies session_deps(kProtoSPDY3,
+ ProxyService::CreateDirect());
+
+ MockRead mock_read(ASYNC, OK);
+ StaticSocketDataProvider socket_data(&mock_read, 1, NULL, 0);
+ socket_data.set_connect_data(MockConnect(ASYNC, OK));
+ session_deps.socket_factory->AddSocketDataProvider(&socket_data);
+
+ MockRead mock_read2(ASYNC, OK);
+ StaticSocketDataProvider socket_data2(&mock_read2, 1, NULL, 0);
+ socket_data2.set_connect_data(MockConnect(ASYNC, ERR_IO_PENDING));
+ session_deps.socket_factory->AddSocketDataProvider(&socket_data2);
+
+ SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
+ ssl_socket_data.SetNextProto(kProtoSPDY3);
+ session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
+
+ scoped_refptr<HttpNetworkSession>
+ session(SpdySessionDependencies::SpdyCreateSession(&session_deps));
+
+ // Now request a stream.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("ws://www.google.com:8888");
+ request_info.load_flags = 0;
+
+ session->http_server_properties()->SetAlternateProtocol(
+ HostPortPair("www.google.com", 8888),
+ 9999,
+ NPN_SPDY_3);
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+ WebSocketStreamFactory factory;
+ scoped_ptr<HttpStreamRequest> request(
+ session->websocket_stream_factory()->RequestWebSocketStream(
+ request_info,
+ DEFAULT_PRIORITY,
+ ssl_config,
+ ssl_config,
+ &waiter,
+ &factory,
+ BoundNetLog()));
+ waiter.WaitForStream();
+ EXPECT_TRUE(waiter.stream_done());
+ EXPECT_TRUE(NULL == waiter.stream());
+ ASSERT_TRUE(NULL != waiter.websocket_stream());
+ EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+ waiter.websocket_stream()->type());
+
+ // Make sure that there was an alternative connection
+ // which consumes extra connections.
+ EXPECT_EQ(2, GetSocketPoolGroupCount(
+ session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_EQ(1, GetSocketPoolGroupCount(
+ session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+
+ // Make sure there is no orphaned job. it is already canceled.
+ ASSERT_EQ(0u, static_cast<HttpStreamFactoryImpl*>(
+ session->websocket_stream_factory())->num_orphaned_jobs());
+}
+
} // namespace
} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index e84f851..c9d37a7 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1078,6 +1078,7 @@
'websockets/websocket_net_log_params.cc',
'websockets/websocket_net_log_params.h',
'websockets/websocket_stream.h',
+ 'websockets/websocket_stream_base.h',
'websockets/websocket_throttle.cc',
'websockets/websocket_throttle.h',
],
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index 0b49b56..c00b5ec 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -88,7 +88,8 @@ int InitSocketPoolHelper(const GURL& request_url,
scoped_refptr<SOCKSSocketParams> socks_params;
scoped_ptr<HostPortPair> proxy_host_port;
- bool using_ssl = request_url.SchemeIs("https") || force_spdy_over_ssl;
+ bool using_ssl = request_url.SchemeIs("https") ||
+ request_url.SchemeIs("wss") || force_spdy_over_ssl;
HostPortPair origin_host_port =
HostPortPair(request_url.HostNoBrackets(),
@@ -393,6 +394,30 @@ int InitSocketHandleForHttpRequest(
0, socket_handle, resolution_callback, callback);
}
+int InitSocketHandleForWebSocketRequest(
+ const GURL& request_url,
+ const HttpRequestHeaders& request_extra_headers,
+ int request_load_flags,
+ RequestPriority request_priority,
+ HttpNetworkSession* session,
+ const ProxyInfo& proxy_info,
+ bool force_spdy_over_ssl,
+ bool want_spdy_over_npn,
+ const SSLConfig& ssl_config_for_origin,
+ const SSLConfig& ssl_config_for_proxy,
+ PrivacyMode privacy_mode,
+ const BoundNetLog& net_log,
+ ClientSocketHandle* socket_handle,
+ const OnHostResolutionCallback& resolution_callback,
+ const CompletionCallback& callback) {
+ DCHECK(socket_handle);
+ return InitSocketPoolHelper(
+ request_url, request_extra_headers, request_load_flags, request_priority,
+ session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn,
+ ssl_config_for_origin, ssl_config_for_proxy, true, privacy_mode, net_log,
+ 0, socket_handle, resolution_callback, callback);
+}
+
int InitSocketHandleForRawConnect(
const HostPortPair& host_port_pair,
HttpNetworkSession* session,
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
index 434a463..a514d25 100644
--- a/net/socket/client_socket_pool_manager.h
+++ b/net/socket/client_socket_pool_manager.h
@@ -108,6 +108,31 @@ int InitSocketHandleForHttpRequest(
// A helper method that uses the passed in proxy information to initialize a
// ClientSocketHandle with the relevant socket pool. Use this method for
+// HTTP/HTTPS requests for WebSocket handshake.
+// |ssl_config_for_origin| is only used if the request
+// uses SSL and |ssl_config_for_proxy| is used if the proxy server is HTTPS.
+// |resolution_callback| will be invoked after the the hostname is
+// resolved. If |resolution_callback| does not return OK, then the
+// connection will be aborted with that value.
+int InitSocketHandleForWebSocketRequest(
+ const GURL& request_url,
+ const HttpRequestHeaders& request_extra_headers,
+ int request_load_flags,
+ RequestPriority request_priority,
+ HttpNetworkSession* session,
+ const ProxyInfo& proxy_info,
+ bool force_spdy_over_ssl,
+ bool want_spdy_over_npn,
+ const SSLConfig& ssl_config_for_origin,
+ const SSLConfig& ssl_config_for_proxy,
+ PrivacyMode privacy_mode,
+ const BoundNetLog& net_log,
+ ClientSocketHandle* socket_handle,
+ const OnHostResolutionCallback& resolution_callback,
+ const CompletionCallback& callback);
+
+// A helper method that uses the passed in proxy information to initialize a
+// ClientSocketHandle with the relevant socket pool. Use this method for
// a raw socket connection to a host-port pair (that needs to tunnel through
// the proxies).
NET_EXPORT int InitSocketHandleForRawConnect(
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index a14ab2a..dbc59d7 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -877,7 +877,10 @@ int MockTCPClientSocket::Connect(const CompletionCallback& callback) {
connected_ = true;
peer_closed_connection_ = false;
if (data_->connect_data().mode == ASYNC) {
- RunCallbackAsync(callback, data_->connect_data().result);
+ if (data_->connect_data().result == ERR_IO_PENDING)
+ pending_callback_ = callback;
+ else
+ RunCallbackAsync(callback, data_->connect_data().result);
return ERR_IO_PENDING;
}
return data_->connect_data().result;
@@ -940,6 +943,11 @@ void MockTCPClientSocket::OnReadComplete(const MockRead& data) {
RunCallback(callback, rv);
}
+void MockTCPClientSocket::OnConnectComplete(const MockConnect& data) {
+ CompletionCallback callback = pending_callback_;
+ RunCallback(callback, data.result);
+}
+
int MockTCPClientSocket::CompleteRead() {
DCHECK(pending_buf_);
DCHECK(pending_buf_len_ > 0);
@@ -1171,6 +1179,10 @@ const BoundNetLog& DeterministicMockUDPClientSocket::NetLog() const {
void DeterministicMockUDPClientSocket::OnReadComplete(const MockRead& data) {}
+void DeterministicMockUDPClientSocket::OnConnectComplete(
+ const MockConnect& data) {
+ NOTIMPLEMENTED();
+}
DeterministicMockTCPClientSocket::DeterministicMockTCPClientSocket(
net::NetLog* net_log,
@@ -1261,6 +1273,9 @@ bool DeterministicMockTCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {}
+void DeterministicMockTCPClientSocket::OnConnectComplete(
+ const MockConnect& data) {}
+
// static
void MockSSLClientSocket::ConnectCallback(
MockSSLClientSocket *ssl_client_socket,
@@ -1407,6 +1422,10 @@ void MockSSLClientSocket::OnReadComplete(const MockRead& data) {
NOTIMPLEMENTED();
}
+void MockSSLClientSocket::OnConnectComplete(const MockConnect& data) {
+ NOTIMPLEMENTED();
+}
+
MockUDPClientSocket::MockUDPClientSocket(SocketDataProvider* data,
net::NetLog* net_log)
: connected_(false),
@@ -1526,6 +1545,10 @@ void MockUDPClientSocket::OnReadComplete(const MockRead& data) {
RunCallback(callback, rv);
}
+void MockUDPClientSocket::OnConnectComplete(const MockConnect& data) {
+ NOTIMPLEMENTED();
+}
+
int MockUDPClientSocket::CompleteRead() {
DCHECK(pending_buf_);
DCHECK(pending_buf_len_ > 0);
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index bab980c..6afe170 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -199,6 +199,7 @@ class AsyncSocket {
// data.async is ignored, and this read is completed synchronously as
// part of this call.
virtual void OnReadComplete(const MockRead& data) = 0;
+ virtual void OnConnectComplete(const MockConnect& data) = 0;
};
// SocketDataProvider which responds based on static tables of mock reads and
@@ -229,7 +230,7 @@ class StaticSocketDataProvider : public SocketDataProvider {
// SocketDataProvider implementation.
virtual MockRead GetNextRead() OVERRIDE;
virtual MockWriteResult OnWrite(const std::string& data) OVERRIDE;
- virtual void Reset() OVERRIDE;
+ ; virtual void Reset() OVERRIDE;
private:
MockRead* reads_;
@@ -696,6 +697,7 @@ class MockTCPClientSocket : public MockClientSocket, public AsyncSocket {
// AsyncSocket:
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
+ virtual void OnConnectComplete(const MockConnect& data) OVERRIDE;
private:
int CompleteRead();
@@ -803,6 +805,7 @@ class DeterministicMockUDPClientSocket
// AsyncSocket implementation.
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
+ virtual void OnConnectComplete(const MockConnect& data) OVERRIDE;
private:
bool connected_;
@@ -845,6 +848,7 @@ class DeterministicMockTCPClientSocket
// AsyncSocket:
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
+ virtual void OnConnectComplete(const MockConnect& data) OVERRIDE;
private:
DeterministicSocketHelper helper_;
@@ -887,6 +891,7 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket {
// This MockSocket does not implement the manual async IO feature.
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
+ virtual void OnConnectComplete(const MockConnect& data) OVERRIDE;
virtual bool WasChannelIDSent() const OVERRIDE;
virtual void set_channel_id_sent(bool channel_id_sent) OVERRIDE;
@@ -931,6 +936,7 @@ class MockUDPClientSocket
// AsyncSocket implementation.
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
+ virtual void OnConnectComplete(const MockConnect& data) OVERRIDE;
private:
int CompleteRead();
diff --git a/net/websockets/websocket_stream.h b/net/websockets/websocket_stream.h
index c69aa85..10631f4 100644
--- a/net/websockets/websocket_stream.h
+++ b/net/websockets/websocket_stream.h
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_vector.h"
#include "net/base/completion_callback.h"
+#include "net/websockets/websocket_stream_base.h"
namespace net {
@@ -30,7 +31,7 @@ struct WebSocketFrameChunk;
// |callback| will be called when the operation is finished. Non-null |callback|
// must be provided to these functions.
-class WebSocketStream {
+class WebSocketStream : public WebSocketStreamBase {
public:
WebSocketStream() {}
@@ -95,6 +96,9 @@ class WebSocketStream {
// - RenewStreamForAuth for authentication (is this necessary?)
// - GetSSLInfo, GetSSLCertRequsetInfo for SSL
+ // WebSocketStreamBase derived functions
+ virtual WebSocketStream* AsWebSocketStream() { return this; }
+
private:
DISALLOW_COPY_AND_ASSIGN(WebSocketStream);
};
diff --git a/net/websockets/websocket_stream_base.h b/net/websockets/websocket_stream_base.h
new file mode 100644
index 0000000..7786064
--- /dev/null
+++ b/net/websockets/websocket_stream_base.h
@@ -0,0 +1,55 @@
+// Copyright 2013 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.
+
+#ifndef NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_
+#define NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_
+
+// This file is included from net/http files.
+// Since net/http can be built without linking net/websockets code,
+// this file should not depend on net/websockets.
+
+#include <base/basictypes.h>
+
+namespace net {
+
+class ClientSocketHandle;
+class SpdySession;
+class WebSocketStream;
+
+// WebSocketStreamBase is the base class of WebSocketStream.
+// net/http code uses this interface to handle WebSocketStream.
+class WebSocketStreamBase {
+ public:
+ class Factory {
+ public:
+ virtual ~Factory() {}
+
+ // Create a WebSocketBasicStream.
+ // This function (or the returned object) takes the ownership
+ // of |connection|.
+ virtual WebSocketStreamBase* CreateBasicStream(
+ ClientSocketHandle* connection,
+ bool using_proxy) = 0;
+
+ // Create a WebSocketSpdyStream.
+ virtual WebSocketStreamBase* CreateSpdyStream(
+ SpdySession* session,
+ bool use_relative_url) = 0;
+ };
+
+ virtual ~WebSocketStreamBase() {}
+
+ // Return this object as a WebSocketStream.
+ virtual WebSocketStream* AsWebSocketStream() = 0;
+
+ protected:
+ WebSocketStreamBase() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebSocketStreamBase);
+};
+
+} // namespace net
+
+#endif // NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_