blob: 8f3bdde566bcc6d54825d8a85a7be14ad9bb21f3 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_stream_factory.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "net/base/test_data_directory.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"
#include "net/http/http_util.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_http_stream.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/quic/test_tools/quic_test_packet_maker.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/socket/socket_test_util.h"
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
using std::string;
using std::vector;
namespace net {
namespace test {
namespace {
const char kDefaultServerHostName[] = "www.google.com";
const int kDefaultServerPort = 443;
} // namespace anonymous
class QuicStreamFactoryPeer {
public:
static QuicCryptoClientConfig* GetOrCreateCryptoConfig(
QuicStreamFactory* factory,
const HostPortProxyPair& host_port_proxy_pair) {
return factory->GetOrCreateCryptoConfig(host_port_proxy_pair);
}
static bool HasActiveSession(QuicStreamFactory* factory,
const HostPortProxyPair& host_port_proxy_pair) {
return factory->HasActiveSession(host_port_proxy_pair);
}
static QuicClientSession* GetActiveSession(
QuicStreamFactory* factory,
const HostPortProxyPair& host_port_proxy_pair) {
DCHECK(factory->HasActiveSession(host_port_proxy_pair));
return factory->active_sessions_[host_port_proxy_pair];
}
static bool IsLiveSession(QuicStreamFactory* factory,
QuicClientSession* session) {
for (QuicStreamFactory::SessionSet::iterator it =
factory->all_sessions_.begin();
it != factory->all_sessions_.end(); ++it) {
if (*it == session)
return true;
}
return false;
}
};
class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicStreamFactoryTest()
: random_generator_(0),
maker_(GetParam(), 0),
clock_(new MockClock()),
factory_(&host_resolver_, &socket_factory_,
base::WeakPtr<HttpServerProperties>(),
&crypto_client_stream_factory_,
&random_generator_, clock_, kDefaultMaxPacketSize,
SupportedVersions(GetParam())),
host_port_proxy_pair_(HostPortPair(kDefaultServerHostName,
kDefaultServerPort),
ProxyServer::Direct()),
is_https_(false),
cert_verifier_(CertVerifier::CreateDefault()) {
factory_.set_require_confirmation(false);
}
int GetSourcePortForNewSession(const HostPortProxyPair& destination) {
// Should only be called if there is no active session for this destination.
EXPECT_EQ(NULL, factory_.CreateIfSessionExists(destination,
net_log_).get());
size_t socket_count = socket_factory_.udp_client_sockets().size();
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_data.StopAfter(1);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(destination, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
stream.reset();
QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
&factory_, destination);
if (socket_count + 1 != socket_factory_.udp_client_sockets().size()) {
EXPECT_TRUE(false);
return 0;
}
IPEndPoint endpoint;
socket_factory_.
udp_client_sockets()[socket_count]->GetLocalAddress(&endpoint);
int port = endpoint.port();
factory_.OnSessionClosed(session);
EXPECT_EQ(NULL, factory_.CreateIfSessionExists(destination,
net_log_).get());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
return port;
}
MockHostResolver host_resolver_;
DeterministicMockClientSocketFactory socket_factory_;
MockCryptoClientStreamFactory crypto_client_stream_factory_;
MockRandom random_generator_;
QuicTestPacketMaker maker_;
MockClock* clock_; // Owned by factory_.
QuicStreamFactory factory_;
HostPortProxyPair host_port_proxy_pair_;
bool is_https_;
scoped_ptr<CertVerifier> cert_verifier_;
BoundNetLog net_log_;
TestCompletionCallback callback_;
};
INSTANTIATE_TEST_CASE_P(Version, QuicStreamFactoryTest,
::testing::ValuesIn(QuicSupportedVersions()));
TEST_P(QuicStreamFactoryTest, CreateIfSessionExists) {
EXPECT_EQ(NULL, factory_.CreateIfSessionExists(host_port_proxy_pair_,
net_log_).get());
}
TEST_P(QuicStreamFactoryTest, Create) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
// Will reset stream 3.
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_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
stream = request2.ReleaseStream(); // Will reset stream 5.
stream.reset(); // Will reset stream 7.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, Pooling) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
HostPortProxyPair server2 = HostPortProxyPair(
HostPortPair("mail.google.com", kDefaultServerPort),
host_port_proxy_pair_.second);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(
kDefaultServerHostName, "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(
"mail.google.com", "192.168.0.1", "");
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_,
cert_verifier_.get(), net_log_,
callback.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
EXPECT_EQ(
QuicStreamFactoryPeer::GetActiveSession(&factory_, host_port_proxy_pair_),
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2));
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data1.StopAfter(1);
socket_data2.StopAfter(1);
HostPortProxyPair server2 = HostPortProxyPair(
HostPortPair("mail.google.com", kDefaultServerPort),
host_port_proxy_pair_.second);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(
kDefaultServerHostName, "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(
"mail.google.com", "192.168.0.1", "");
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_,
cert_verifier_.get(), net_log_,
callback.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
factory_.OnSessionGoingAway(
QuicStreamFactoryPeer::GetActiveSession(&factory_,
host_port_proxy_pair_));
EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(&factory_,
host_port_proxy_pair_));
EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(&factory_, server2));
TestCompletionCallback callback3;
QuicStreamRequest request3(&factory_);
EXPECT_EQ(OK, request3.Request(server2, is_https_,
cert_verifier_.get(), net_log_,
callback3.callback()));
scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
EXPECT_TRUE(stream3.get());
EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(&factory_, server2));
EXPECT_TRUE(socket_data1.at_read_eof());
EXPECT_TRUE(socket_data1.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, HttpsPooling) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
HostPortProxyPair server1(HostPortPair("www.example.org", 443),
ProxyServer::Direct());
HostPortProxyPair server2(HostPortPair("mail.example.org", 443),
ProxyServer::Direct());
// Load a cert that is valid for:
// www.example.org (server1)
// mail.example.org (server2)
// www.example.com
base::FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
SSLInfo ssl_info;
ssl_info.cert = test_cert.get();
crypto_client_stream_factory_.set_ssl_info(&ssl_info);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(
server1.first.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(
server2.first.host(), "192.168.0.1", "");
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, cert_verifier_.get(),
net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, cert_verifier_.get(),
net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
EXPECT_EQ(QuicStreamFactoryPeer::GetActiveSession(&factory_, server1),
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2));
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithCertMismatch) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data1.StopAfter(1);
socket_data2.StopAfter(1);
HostPortProxyPair server1(HostPortPair("www.example.org", 443),
ProxyServer::Direct());
HostPortProxyPair server2(HostPortPair("mail.google.com", 443),
ProxyServer::Direct());
// Load a cert that is valid for:
// www.example.org (server1)
// mail.example.org
// www.example.com
// But is not valid for mail.google.com (server2).
base::FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
SSLInfo ssl_info;
ssl_info.cert = test_cert.get();
crypto_client_stream_factory_.set_ssl_info(&ssl_info);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(
server1.first.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(
server2.first.host(), "192.168.0.1", "");
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, cert_verifier_.get(),
net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, cert_verifier_.get(),
net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(&factory_, server1),
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2));
EXPECT_TRUE(socket_data1.at_read_eof());
EXPECT_TRUE(socket_data1.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, Goaway) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_data.StopAfter(1);
socket_factory_.AddSocketDataProvider(&socket_data);
DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
socket_data2.StopAfter(1);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
// Mark the session as going away. Ensure that while it is still alive
// that it is no longer active.
QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
&factory_, host_port_proxy_pair_);
factory_.OnSessionGoingAway(session);
EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(&factory_, session));
EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(&factory_,
host_port_proxy_pair_));
EXPECT_EQ(NULL, factory_.CreateIfSessionExists(host_port_proxy_pair_,
net_log_).get());
// Create a new request for the same destination and verify that a
// new session is created.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(&factory_,
host_port_proxy_pair_));
EXPECT_NE(session,
QuicStreamFactoryPeer::GetActiveSession(
&factory_, host_port_proxy_pair_));
EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(&factory_, session));
stream2.reset();
stream.reset();
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
QuicStreamId stream_id = GetParam() > QUIC_VERSION_12 ? 5 : 3;
scoped_ptr<QuicEncryptedPacket> rst(
maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(ASYNC, rst->data(), rst->length(), 1),
};
DeterministicSocketData socket_data(reads, arraysize(reads),
writes, arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
HttpRequestInfo request_info;
std::vector<QuicHttpStream*> streams;
// The MockCryptoClientStream sets max_open_streams to be
// 2 * kDefaultMaxStreamsPerConnection.
for (size_t i = 0; i < 2 * kDefaultMaxStreamsPerConnection; i++) {
QuicStreamRequest request(&factory_);
int rv = request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback());
if (i == 0) {
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, callback_.WaitForResult());
} else {
EXPECT_EQ(OK, rv);
}
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream);
EXPECT_EQ(OK, stream->InitializeStream(
&request_info, DEFAULT_PRIORITY, net_log_, CompletionCallback()));
streams.push_back(stream.release());
}
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
CompletionCallback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream);
EXPECT_EQ(ERR_IO_PENDING, stream->InitializeStream(
&request_info, DEFAULT_PRIORITY, net_log_, callback_.callback()));
// Close the first stream.
streams.front()->Close(false);
ASSERT_TRUE(callback_.have_result());
EXPECT_EQ(OK, callback_.WaitForResult());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
STLDeleteElements(&streams);
}
TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
DeterministicSocketData socket_data(NULL, 0, NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
host_resolver_.rules()->AddSimulatedFailure(kDefaultServerHostName);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
MockConnect connect(SYNCHRONOUS, ERR_ADDRESS_IN_USE);
DeterministicSocketData socket_data(NULL, 0, NULL, 0);
socket_data.set_connect_data(connect);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(ERR_ADDRESS_IN_USE, callback_.WaitForResult());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, CancelCreate) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
{
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
}
socket_data.StopAfter(1);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
scoped_ptr<QuicHttpStream> stream(
factory_.CreateIfSessionExists(host_port_proxy_pair_, net_log_));
EXPECT_TRUE(stream.get());
stream.reset();
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
// Sequentially connect to the default host, then another host, and then the
// default host. Verify that the default host gets a consistent ephemeral
// port, that is different from the other host's connection.
std::string other_server_name = "other.google.com";
EXPECT_NE(kDefaultServerHostName, other_server_name);
HostPortPair host_port_pair2(other_server_name, kDefaultServerPort);
HostPortProxyPair host_port_proxy_pair2(host_port_pair2,
host_port_proxy_pair_.second);
int original_port = GetSourcePortForNewSession(host_port_proxy_pair_);
EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_proxy_pair2));
EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_proxy_pair_));
}
TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
MockRead reads[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
MockRead reads2[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info,
DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Close the session and verify that stream saw the error.
factory_.CloseAllSessions(ERR_INTERNET_DISCONNECTED);
EXPECT_EQ(ERR_INTERNET_DISCONNECTED,
stream->ReadResponseHeaders(callback_.callback()));
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
MockRead reads[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
MockRead reads2[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info,
DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Change the IP address and verify that stream saw the error.
factory_.OnIPAddressChanged();
EXPECT_EQ(ERR_NETWORK_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_TRUE(factory_.require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, OnCertAdded) {
MockRead reads[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
MockRead reads2[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info,
DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Add a cert and verify that stream saw the event.
factory_.OnCertAdded(NULL);
EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_FALSE(factory_.require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
MockRead reads[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
MockRead reads2[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data2(reads2, arraysize(reads2), NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info,
DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Change the CA cert and verify that stream saw the event.
factory_.OnCACertChanged(NULL);
EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_FALSE(factory_.require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request2.Request(host_port_proxy_pair_, is_https_,
cert_verifier_.get(), net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_TRUE(socket_data2.at_read_eof());
EXPECT_TRUE(socket_data2.at_write_eof());
}
TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) {
vector<string> cannoncial_suffixes;
cannoncial_suffixes.push_back(string(".c.youtube.com"));
cannoncial_suffixes.push_back(string(".googlevideo.com"));
for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
string r1_host_name("r1");
string r2_host_name("r2");
r1_host_name.append(cannoncial_suffixes[i]);
r2_host_name.append(cannoncial_suffixes[i]);
HostPortProxyPair host_port_proxy_pair1(HostPortPair(r1_host_name, 80),
ProxyServer::Direct());
QuicCryptoClientConfig* crypto_config1 =
QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
host_port_proxy_pair1);
DCHECK(crypto_config1);
QuicCryptoClientConfig::CachedState* cached1 =
crypto_config1->LookupOrCreate(host_port_proxy_pair1.first.host());
EXPECT_FALSE(cached1->proof_valid());
EXPECT_TRUE(cached1->source_address_token().empty());
// Mutate the cached1 to have different data.
// TODO(rtenneti): mutate other members of CachedState.
cached1->set_source_address_token(r1_host_name);
cached1->SetProofValid();
HostPortProxyPair host_port_proxy_pair2(HostPortPair(r2_host_name, 80),
ProxyServer::Direct());
QuicCryptoClientConfig* crypto_config2 =
QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
host_port_proxy_pair2);
DCHECK(crypto_config2);
QuicCryptoClientConfig::CachedState* cached2 =
crypto_config2->LookupOrCreate(host_port_proxy_pair2.first.host());
EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token());
EXPECT_TRUE(cached2->proof_valid());
}
}
TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
vector<string> cannoncial_suffixes;
cannoncial_suffixes.push_back(string(".c.youtube.com"));
cannoncial_suffixes.push_back(string(".googlevideo.com"));
for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
string r3_host_name("r3");
string r4_host_name("r4");
r3_host_name.append(cannoncial_suffixes[i]);
r4_host_name.append(cannoncial_suffixes[i]);
HostPortProxyPair host_port_proxy_pair1(HostPortPair(r3_host_name, 80),
ProxyServer::Direct());
QuicCryptoClientConfig* crypto_config1 =
QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
host_port_proxy_pair1);
DCHECK(crypto_config1);
QuicCryptoClientConfig::CachedState* cached1 =
crypto_config1->LookupOrCreate(host_port_proxy_pair1.first.host());
EXPECT_FALSE(cached1->proof_valid());
EXPECT_TRUE(cached1->source_address_token().empty());
// Mutate the cached1 to have different data.
// TODO(rtenneti): mutate other members of CachedState.
cached1->set_source_address_token(r3_host_name);
cached1->SetProofInvalid();
HostPortProxyPair host_port_proxy_pair2(HostPortPair(r4_host_name, 80),
ProxyServer::Direct());
QuicCryptoClientConfig* crypto_config2 =
QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
host_port_proxy_pair2);
DCHECK(crypto_config2);
QuicCryptoClientConfig::CachedState* cached2 =
crypto_config2->LookupOrCreate(host_port_proxy_pair2.first.host());
EXPECT_NE(cached1->source_address_token(), cached2->source_address_token());
EXPECT_TRUE(cached2->source_address_token().empty());
EXPECT_FALSE(cached2->proof_valid());
}
}
} // namespace test
} // namespace net