diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-10 03:57:54 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-10 03:57:54 +0000 |
commit | 6d1b4ed17cbad3f89394490b287a29108037567b (patch) | |
tree | 5ee638a15ff19160b26decc8d8a2f46f02ad9ef5 /net | |
parent | 929fb4e415bec4565b9eea7254f5ac019c7648b5 (diff) | |
download | chromium_src-6d1b4ed17cbad3f89394490b287a29108037567b.zip chromium_src-6d1b4ed17cbad3f89394490b287a29108037567b.tar.gz chromium_src-6d1b4ed17cbad3f89394490b287a29108037567b.tar.bz2 |
First step at enabling QUIC over HTTPS.
- Added code to enable proof verifier and integrated CertVerifier.
TODO:
- Make ProofVerifier work with multiple verifications at the same time.
- Use the correct NPN for NextProto instead of kProtoSPDY3.
- Write unit tests for QUIC over HTTPS.
R=rch@chromium.org
Review URL: https://chromiumcodereview.appspot.com/18084015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@210732 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_network_session.cc | 1 | ||||
-rw-r--r-- | net/http/http_network_session.h | 1 | ||||
-rw-r--r-- | net/http/http_stream_factory.cc | 8 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl.cc | 6 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.cc | 44 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.cc | 4 | ||||
-rw-r--r-- | net/quic/quic_http_stream.cc | 2 | ||||
-rw-r--r-- | net/quic/quic_network_transaction_unittest.cc | 98 | ||||
-rw-r--r-- | net/quic/quic_session.cc | 10 | ||||
-rw-r--r-- | net/quic/quic_session.h | 10 | ||||
-rw-r--r-- | net/quic/quic_stream_factory.cc | 33 | ||||
-rw-r--r-- | net/quic/quic_stream_factory.h | 21 | ||||
-rw-r--r-- | net/quic/quic_stream_factory_test.cc | 33 | ||||
-rw-r--r-- | net/socket/next_proto.h | 4 | ||||
-rw-r--r-- | net/socket/ssl_client_socket.cc | 4 | ||||
-rw-r--r-- | net/spdy/spdy_network_transaction_unittest.cc | 2 | ||||
-rw-r--r-- | net/spdy/spdy_test_util_common.cc | 2 |
17 files changed, 183 insertions, 100 deletions
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 7c64d1d..208e95b 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -81,6 +81,7 @@ HttpNetworkSession::Params::Params() spdy_max_concurrent_streams_limit(0), time_func(&base::TimeTicks::Now), enable_quic(false), + enable_quic_https(false), quic_clock(NULL), quic_random(NULL), enable_user_alternate_protocol_ports(false), diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 3ca928e..09ced59 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -85,6 +85,7 @@ class NET_EXPORT HttpNetworkSession SpdySessionPool::TimeFunc time_func; std::string trusted_spdy_proxy; bool enable_quic; + bool enable_quic_https; HostPortPair origin_to_force_quic_on; QuicClock* quic_clock; // Will be owned by QuicStreamFactory. QuicRandom* quic_random; diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index 1c707f2..89ba518 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc @@ -143,7 +143,7 @@ void HttpStreamFactory::EnableNpnSpdy() { set_use_alternate_protocols(true); std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); - next_protos.push_back("quic"); + next_protos.push_back("quic/1+spdy/3"); next_protos.push_back("spdy/2"); SetNextProtos(next_protos); } @@ -164,7 +164,7 @@ void HttpStreamFactory::EnableNpnSpdy3() { set_use_alternate_protocols(true); std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); - next_protos.push_back("quic"); + next_protos.push_back("quic/1+spdy/3"); next_protos.push_back("spdy/2"); next_protos.push_back("spdy/3"); SetNextProtos(next_protos); @@ -175,7 +175,7 @@ void HttpStreamFactory::EnableNpnSpdy31() { set_use_alternate_protocols(true); std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); - next_protos.push_back("quic"); + next_protos.push_back("quic/1+spdy/3"); next_protos.push_back("spdy/2"); next_protos.push_back("spdy/3"); next_protos.push_back("spdy/3.1"); @@ -217,7 +217,7 @@ void HttpStreamFactory::SetNextProtos(const std::vector<std::string>& value) { enabled_protocols_[NPN_SPDY_3_1] = true; } else if (value[i] == "spdy/4a2") { enabled_protocols_[NPN_SPDY_4A2] = true; - } else if (value[i] == "quic") { + } else if (value[i] == "quic/1+spdy/3") { enabled_protocols_[QUIC] = true; } } diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index 8094f4b..7ee16d8 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc @@ -238,8 +238,10 @@ PortAlternateProtocolPair HttpStreamFactoryImpl::GetAlternateProtocolRequestFor( } else { DCHECK_EQ(QUIC, alternate.protocol); if (!session_->params().enable_quic || - !original_url.SchemeIs("http")) - return kNoAlternateProtocol; + !(original_url.SchemeIs("http") || + session_->params().enable_quic_https)) { + return kNoAlternateProtocol; + } // TODO(rch): Figure out how to make QUIC iteract with PAC // scripts. By not re-writing the URL, we will query the PAC script // for the proxy to use to reach the original URL via TCP. But diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index b6226ae..da0b456 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -705,9 +705,9 @@ bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const { } bool HttpStreamFactoryImpl::Job::ShouldForceQuic() const { - return session_->params().enable_quic && request_info_.url.SchemeIs("http") && - session_->params().origin_to_force_quic_on.Equals(origin_) && - proxy_info_.is_direct(); + return session_->params().enable_quic && + session_->params().origin_to_force_quic_on.Equals(origin_) && + proxy_info_.is_direct(); } int HttpStreamFactoryImpl::Job::DoWaitForJob() { @@ -746,6 +746,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() { next_state_ = STATE_INIT_CONNECTION_COMPLETE; const ProxyServer& proxy_server = proxy_info_.proxy_server(); int rv = quic_request_.Request(HostPortProxyPair(origin_, proxy_server), + using_ssl_, session_->cert_verifier(), net_log_, io_callback_); if (rv != OK) { // OK, there's no available QUIC session. Let |waiting_job_| resume @@ -913,26 +914,33 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { connection_->is_ssl_error()); if (ssl_started && (result == OK || IsCertificateError(result))) { - SSLClientSocket* ssl_socket = - static_cast<SSLClientSocket*>(connection_->socket()); - if (ssl_socket->WasNpnNegotiated()) { + if (using_quic_ && result == OK) { was_npn_negotiated_ = true; - std::string proto; - std::string server_protos; - SSLClientSocket::NextProtoStatus status = - ssl_socket->GetNextProto(&proto, &server_protos); NextProto protocol_negotiated = - SSLClientSocket::NextProtoFromString(proto); + SSLClientSocket::NextProtoFromString("quic/1+spdy/3"); protocol_negotiated_ = protocol_negotiated; - net_log_.AddEvent( - NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO, - base::Bind(&NetLogHttpStreamProtoCallback, - status, &proto, &server_protos)); - if (ssl_socket->was_spdy_negotiated()) + } else { + SSLClientSocket* ssl_socket = + static_cast<SSLClientSocket*>(connection_->socket()); + if (ssl_socket->WasNpnNegotiated()) { + was_npn_negotiated_ = true; + std::string proto; + std::string server_protos; + SSLClientSocket::NextProtoStatus status = + ssl_socket->GetNextProto(&proto, &server_protos); + NextProto protocol_negotiated = + SSLClientSocket::NextProtoFromString(proto); + protocol_negotiated_ = protocol_negotiated; + net_log_.AddEvent( + NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO, + base::Bind(&NetLogHttpStreamProtoCallback, + status, &proto, &server_protos)); + if (ssl_socket->was_spdy_negotiated()) + SwitchToSpdyMode(); + } + if (ShouldForceSpdySSL()) SwitchToSpdyMode(); } - if (ShouldForceSpdySSL()) - SwitchToSpdyMode(); } else if (proxy_info_.is_https() && connection_->socket() && result == OK) { ProxyClientSocket* proxy_socket = diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 7b6eb7a..ab548b2 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -148,7 +148,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( return; } if (!cached->proof_valid()) { - ProofVerifier* verifier = session()->proof_verifier(); + ProofVerifier* verifier = crypto_config_->proof_verifier(); if (!verifier) { // If no verifier is set then we don't check the certificates. cached->SetProofValid(); @@ -160,7 +160,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( next_state_ = STATE_SEND_CHLO; break; case STATE_VERIFY_PROOF: { - ProofVerifier* verifier = session()->proof_verifier(); + ProofVerifier* verifier = crypto_config_->proof_verifier(); DCHECK(verifier); next_state_ = STATE_VERIFY_PROOF_COMPLETE; generation_counter_ = cached->generation_counter(); diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index c7a5827..5976c79 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -48,7 +48,7 @@ int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, if (!stream_) return ERR_SOCKET_NOT_CONNECTED; - DCHECK_EQ("http", request_info->url.scheme()); + //DCHECK_EQ("http", request_info->url.scheme()); stream_net_log_ = stream_net_log; request_info_ = request_info; diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 53e69ee..69ac658 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -47,7 +47,8 @@ namespace { // This is the expected return from a current server advertising QUIC. static const char kQuicAlternateProtocolHttpHeader[] = "Alternate-Protocol: 80:quic\r\n\r\n"; - +static const char kQuicAlternateProtocolHttpsHeader[] = + "Alternate-Protocol: 443:quic\r\n\r\n"; } // namespace namespace net { @@ -151,12 +152,13 @@ class QuicNetworkTransactionTest : public PlatformTest { } std::string GetRequestString(const std::string& method, + const std::string& scheme, const std::string& path) { SpdyHeaderBlock headers; headers[":method"] = method; headers[":host"] = "www.google.com"; headers[":path"] = path; - headers[":scheme"] = "http"; + headers[":scheme"] = scheme; headers[":version"] = "HTTP/1.1"; return SerializeHeaderBlock(headers); } @@ -333,7 +335,7 @@ TEST_F(QuicNetworkTransactionTest, ForceQuic) { QuicStreamId stream_id = 3; scoped_ptr<QuicEncryptedPacket> req( ConstructDataPacket(1, stream_id, true, true, 0, - GetRequestString("GET", "/"))); + GetRequestString("GET", "http", "/"))); scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0)); MockWrite quic_writes[] = { @@ -459,7 +461,8 @@ TEST_F(QuicNetworkTransactionTest, UseAlternateProtocolForQuic) { socket_factory_.AddSocketDataProvider(&http_data); scoped_ptr<QuicEncryptedPacket> req( - ConstructDataPacket(1, 3, true, true, 0, GetRequestString("GET", "/"))); + ConstructDataPacket(1, 3, true, true, 0, + GetRequestString("GET", "http", "/"))); scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0)); MockWrite quic_writes[] = { @@ -492,6 +495,59 @@ TEST_F(QuicNetworkTransactionTest, UseAlternateProtocolForQuic) { SendRequestAndExpectQuicResponse("hello!"); } +TEST_F(QuicNetworkTransactionTest, UseAlternateProtocolForQuicForHttps) { + params_.origin_to_force_quic_on = + HostPortPair::FromString("www.google.com:443"); + params_.enable_quic_https = true; + HttpStreamFactory::EnableNpnSpdy(); // Enables QUIC too. + + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead(kQuicAlternateProtocolHttpsHeader), + MockRead("hello world"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK) + }; + + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), + NULL, 0); + socket_factory_.AddSocketDataProvider(&http_data); + + scoped_ptr<QuicEncryptedPacket> req( + ConstructDataPacket(1, 3, true, true, 0, + GetRequestString("GET", "https", "/"))); + scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0)); + + MockWrite quic_writes[] = { + MockWrite(SYNCHRONOUS, req->data(), req->length()), + MockWrite(SYNCHRONOUS, ack->data(), ack->length()), + }; + + scoped_ptr<QuicEncryptedPacket> resp( + ConstructDataPacket( + 1, 3, false, true, 0, GetResponseString("200 OK", "hello!"))); + MockRead quic_reads[] = { + MockRead(SYNCHRONOUS, resp->data(), resp->length()), + MockRead(ASYNC, OK), // EOF + }; + + DelayedSocketData quic_data( + 1, // wait for one write to finish before reading. + quic_reads, arraysize(quic_reads), + quic_writes, arraysize(quic_writes)); + + socket_factory_.AddSocketDataProvider(&quic_data); + + // The non-alternate protocol job needs to hang in order to guarantee that + // the alternate-protocol job will "win". + AddHangingNonAlternateProtocolSocketData(); + + CreateSession(); + + // TODO(rtenneti): Test QUIC over HTTPS, GetSSLInfo(). + SendRequestAndExpectHttpResponse("hello world"); +} + TEST_F(QuicNetworkTransactionTest, HungAlternateProtocol) { HttpStreamFactory::EnableNpnSpdy(); // Enables QUIC too. crypto_client_stream_factory_.set_handshake_mode( @@ -551,39 +607,12 @@ TEST_F(QuicNetworkTransactionTest, HungAlternateProtocol) { ASSERT_TRUE(!quic_data.at_write_eof()); } -TEST_F(QuicNetworkTransactionTest, DontUseAlternateProtocolForQuicHttps) { - HttpStreamFactory::EnableNpnSpdy(); // Enables QUIC too. - - MockRead http_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-length: 11\r\n"), - MockRead(kQuicAlternateProtocolHttpHeader), - MockRead("hello world"), - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-length: 6\r\n"), - MockRead(kQuicAlternateProtocolHttpHeader), - MockRead("hello!"), - }; - - StaticSocketDataProvider data(http_reads, arraysize(http_reads), NULL, 0); - socket_factory_.AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(ASYNC, OK); - socket_factory_.AddSSLSocketDataProvider(&ssl); - - request_.url = GURL("https://www.google.com/"); - - CreateSession(); - - SendRequestAndExpectHttpResponse("hello world"); - SendRequestAndExpectHttpResponse("hello!"); -} - TEST_F(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) { HttpStreamFactory::EnableNpnSpdy(); // Enables QUIC too. scoped_ptr<QuicEncryptedPacket> req( - ConstructDataPacket(1, 3, true, true, 0, GetRequestString("GET", "/"))); + ConstructDataPacket(1, 3, true, true, 0, + GetRequestString("GET", "http", "/"))); scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0)); MockWrite quic_writes[] = { @@ -619,7 +648,8 @@ TEST_F(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) { HttpStreamFactory::EnableNpnSpdy(); // Enables QUIC too. scoped_ptr<QuicEncryptedPacket> req( - ConstructDataPacket(1, 3, true, true, 0, GetRequestString("GET", "/"))); + ConstructDataPacket(1, 3, true, true, 0, + GetRequestString("GET", "http", "/"))); scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0)); MockWrite quic_writes[] = { diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 10cad83..e3bb136 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -258,16 +258,6 @@ void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { } } -// TODO(rtenneti): Don't port proof_verifier code back to google3 until we have -// a way to have single ProofVerifier that can handle multiple requests. -ProofVerifier* QuicSession::proof_verifier() const { - return proof_verifier_.get(); -} - -void QuicSession::set_proof_verifier(ProofVerifier* verifier) { - proof_verifier_.reset(verifier); -} - QuicConfig* QuicSession::config() { return &config_; } diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index f70ebb2..31a05fe 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -23,7 +23,6 @@ namespace net { -class ProofVerifier; class QuicCryptoStream; class ReliableQuicStream; class VisitorShim; @@ -105,14 +104,6 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // Servers will simply call it once with HANDSHAKE_CONFIRMED. virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event); - virtual ProofVerifier* proof_verifier() const; - - // set_proof_verifier takes ownership of a |ProofVerifier| that clients are - // free to use in order to verify certificate chains from servers. If a - // ProofVerifier is set then the client will request a certificate chain from - // the server. - virtual void set_proof_verifier(ProofVerifier* verifier); - // Returns mutable config for this session. Returned config is owned // by QuicSession. QuicConfig* config(); @@ -223,7 +214,6 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { QuicSpdyCompressor compressor_; QuicConfig config_; - scoped_ptr<ProofVerifier> proof_verifier_; // Returns the maximum number of streams this connection can open. size_t max_open_streams_; diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index c4e695f..619c125 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc @@ -13,8 +13,10 @@ #include "base/stl_util.h" #include "base/values.h" #include "net/base/net_errors.h" +#include "net/cert/cert_verifier.h" #include "net/dns/host_resolver.h" #include "net/dns/single_request_host_resolver.h" +#include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_client_session.h" #include "net/quic/quic_clock.h" @@ -34,6 +36,8 @@ class QuicStreamFactory::Job { Job(QuicStreamFactory* factory, HostResolver* host_resolver, const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log); ~Job(); @@ -69,6 +73,8 @@ class QuicStreamFactory::Job { QuicStreamFactory* factory_; SingleRequestHostResolver host_resolver_; const HostPortProxyPair host_port_proxy_pair_; + bool is_https_; + CertVerifier* cert_verifier_; const BoundNetLog net_log_; QuicClientSession* session_; CompletionCallback callback_; @@ -80,10 +86,14 @@ QuicStreamFactory::Job::Job( QuicStreamFactory* factory, HostResolver* host_resolver, const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log) : factory_(factory), host_resolver_(host_resolver), host_port_proxy_pair_(host_port_proxy_pair), + is_https_(is_https), + cert_verifier_(cert_verifier), net_log_(net_log) { } @@ -172,13 +182,18 @@ QuicStreamRequest::~QuicStreamRequest() { int QuicStreamRequest::Request( const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log, const CompletionCallback& callback) { DCHECK(!stream_); DCHECK(callback_.is_null()); - int rv = factory_->Create(host_port_proxy_pair, net_log, this); + int rv = factory_->Create(host_port_proxy_pair, is_https, cert_verifier, + net_log, this); if (rv == ERR_IO_PENDING) { host_port_proxy_pair_ = host_port_proxy_pair; + is_https_ = is_https; + cert_verifier_ = cert_verifier; net_log_ = net_log; callback_ = callback; } else { @@ -207,8 +222,8 @@ scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() { int QuicStreamFactory::Job::DoConnect() { io_state_ = STATE_CONNECT_COMPLETE; - session_ = factory_->CreateSession(host_port_proxy_pair_, address_list_, - net_log_); + session_ = factory_->CreateSession(host_port_proxy_pair_, is_https_, + cert_verifier_, address_list_, net_log_); session_->StartReading(); int rv = session_->CryptoConnect( base::Bind(&QuicStreamFactory::Job::OnIOComplete, @@ -251,6 +266,8 @@ QuicStreamFactory::~QuicStreamFactory() { } int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log, QuicStreamRequest* request) { if (HasActiveSession(host_port_proxy_pair)) { @@ -265,8 +282,8 @@ int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair, return ERR_IO_PENDING; } - scoped_ptr<Job> job( - new Job(this, host_resolver_, host_port_proxy_pair, net_log)); + scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_proxy_pair, + is_https, cert_verifier, net_log)); int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete, base::Unretained(this), job.get())); @@ -386,6 +403,8 @@ bool QuicStreamFactory::HasActiveSession( QuicClientSession* QuicStreamFactory::CreateSession( const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const AddressList& address_list, const BoundNetLog& net_log) { QuicGuid guid = random_generator_->RandUint64(); @@ -433,6 +452,10 @@ QuicClientSession* QuicStreamFactory::CreateSession( host_port_proxy_pair.first.host(), config_, crypto_config, net_log.net_log()); all_sessions_.insert(session); // owning pointer + if (is_https) { + crypto_config->SetProofVerifier( + new ProofVerifierChromium(cert_verifier, net_log)); + } return session; } diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index db3e7ac..963a603 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h @@ -22,8 +22,9 @@ namespace net { -class HostResolver; +class CertVerifier; class ClientSocketFactory; +class HostResolver; class QuicClock; class QuicClientSession; class QuicCryptoClientStreamFactory; @@ -38,7 +39,10 @@ class NET_EXPORT_PRIVATE QuicStreamRequest { explicit QuicStreamRequest(QuicStreamFactory* factory); ~QuicStreamRequest(); + // For http, |is_https| is false and |cert_verifier| can be null. int Request(const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log, const CompletionCallback& callback); @@ -55,6 +59,8 @@ class NET_EXPORT_PRIVATE QuicStreamRequest { private: QuicStreamFactory* factory_; HostPortProxyPair host_port_proxy_pair_; + bool is_https_; + CertVerifier* cert_verifier_; BoundNetLog net_log_; CompletionCallback callback_; scoped_ptr<QuicHttpStream> stream_; @@ -76,10 +82,15 @@ class NET_EXPORT_PRIVATE QuicStreamFactory virtual ~QuicStreamFactory(); // Creates a new QuicHttpStream to |host_port_proxy_pair| which will be - // owned by |request|. If a matching session already exists, this - // method will return OK. If no matching session exists, this will - // return ERR_IO_PENDING and will invoke OnRequestComplete asynchronously. + // owned by |request|. |is_https| specifies if the protocol is https or not. + // |cert_verifier| is used by ProofVerifier for verifying the certificate + // chain and signature. For http, this can be null. If a matching session + // already exists, this method will return OK. If no matching session exists, + // this will return ERR_IO_PENDING and will invoke OnRequestComplete + // asynchronously. int Create(const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const BoundNetLog& net_log, QuicStreamRequest* request); @@ -127,6 +138,8 @@ class NET_EXPORT_PRIVATE QuicStreamFactory bool HasActiveJob(const HostPortProxyPair& host_port_proxy_pair); QuicClientSession* CreateSession( const HostPortProxyPair& host_port_proxy_pair, + bool is_https, + CertVerifier* cert_verifier, const AddressList& address_list, const BoundNetLog& net_log); void ActivateSession(const HostPortProxyPair& host_port_proxy_pair, diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index afa8bf6..8fdc27b 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -6,6 +6,7 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" +#include "net/cert/cert_verifier.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" @@ -31,7 +32,9 @@ class QuicStreamFactoryTest : public ::testing::Test { &crypto_client_stream_factory_, &random_generator_, clock_), host_port_proxy_pair_(HostPortPair("www.google.com", 443), - ProxyServer::Direct()) { + ProxyServer::Direct()), + is_https_(false), + cert_verifier_(CertVerifier::CreateDefault()) { } scoped_ptr<QuicEncryptedPacket> ConstructRstPacket( @@ -119,6 +122,8 @@ class QuicStreamFactoryTest : public ::testing::Test { MockClock* clock_; // Owned by factory_. QuicStreamFactory factory_; HostPortProxyPair host_port_proxy_pair_; + bool is_https_; + CertVerifier* cert_verifier_; BoundNetLog net_log_; TestCompletionCallback callback_; }; @@ -137,7 +142,8 @@ TEST_F(QuicStreamFactoryTest, Create) { socket_data.StopAfter(1); QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(OK, callback_.WaitForResult()); @@ -148,8 +154,11 @@ TEST_F(QuicStreamFactoryTest, Create) { stream = factory_.CreateIfSessionExists(host_port_proxy_pair_, net_log_); EXPECT_TRUE(stream.get()); + // TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result + // in streams on different sessions. QuicStreamRequest request2(&factory_); - EXPECT_EQ(OK, request2.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(OK, request2.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); stream = request2.ReleaseStream(); // Will reset stream 5. stream.reset(); // Will reset stream 7. @@ -165,7 +174,8 @@ TEST_F(QuicStreamFactoryTest, CreateError) { host_resolver_.rules()->AddSimulatedFailure("www.google.com"); QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult()); @@ -182,7 +192,8 @@ TEST_F(QuicStreamFactoryTest, CancelCreate) { socket_factory_.AddSocketDataProvider(&socket_data); { QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); } @@ -215,7 +226,8 @@ TEST_F(QuicStreamFactoryTest, CloseAllSessions) { socket_data2.StopAfter(1); QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(OK, callback_.WaitForResult()); @@ -230,7 +242,8 @@ TEST_F(QuicStreamFactoryTest, CloseAllSessions) { // a new session. QuicStreamRequest request2(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(OK, callback_.WaitForResult()); @@ -259,7 +272,8 @@ TEST_F(QuicStreamFactoryTest, OnIPAddressChanged) { socket_data2.StopAfter(1); QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(OK, callback_.WaitForResult()); @@ -274,7 +288,8 @@ TEST_F(QuicStreamFactoryTest, OnIPAddressChanged) { // a new session. QuicStreamRequest request2(&factory_); - EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, net_log_, + EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_, + cert_verifier_, net_log_, callback_.callback())); EXPECT_EQ(OK, callback_.WaitForResult()); diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h index f9c1659..00cec80 100644 --- a/net/socket/next_proto.h +++ b/net/socket/next_proto.h @@ -27,7 +27,9 @@ enum NextProto { kProtoSPDY4a2 = 7, kProtoSPDYMaximumVersion = kProtoSPDY4a2, - kProtoMaximumVersion = kProtoSPDYMaximumVersion, + kProtoQUIC1SPDY3 = 8, + + kProtoMaximumVersion = kProtoQUIC1SPDY3, }; } // namespace net diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc index 2b73a1b..70b2a87 100644 --- a/net/socket/ssl_client_socket.cc +++ b/net/socket/ssl_client_socket.cc @@ -30,6 +30,8 @@ NextProto SSLClientSocket::NextProtoFromString( return kProtoSPDY31; } else if (proto_string == "spdy/4a2") { return kProtoSPDY4a2; + } else if (proto_string == "quic/1+spdy/3") { + return kProtoQUIC1SPDY3; } else { return kProtoUnknown; } @@ -50,6 +52,8 @@ const char* SSLClientSocket::NextProtoToString(NextProto next_proto) { return "spdy/3.1"; case kProtoSPDY4a2: return "spdy/4a2"; + case kProtoQUIC1SPDY3: + return "quic/1+spdy/3"; default: break; } diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index e0e9cfc..db1dc7d 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -71,6 +71,8 @@ HttpResponseInfo::ConnectionInfo NextProtoToConnectionInfo( return HttpResponseInfo::CONNECTION_INFO_SPDY3; case kProtoSPDY4a2: return HttpResponseInfo::CONNECTION_INFO_SPDY4; + case kProtoQUIC1SPDY3: + return HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3; case kProtoUnknown: case kProtoHTTP11: diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 54982b9..1574c87 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc @@ -690,6 +690,8 @@ AlternateProtocol AlternateProtocolFromNextProto(NextProto next_proto) { return NPN_SPDY_3_1; case kProtoSPDY4a2: return NPN_SPDY_4A2; + case kProtoQUIC1SPDY3: + return QUIC; case kProtoUnknown: case kProtoHTTP11: |