blob: 00a3adea6331be0c05baf224a90026ef42973296 [file] [log] [blame]
// 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.
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/test_completion_callback.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/dns/mapped_host_resolver.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_transaction_test_util.h"
#include "net/http/transport_security_state.h"
#include "net/proxy/proxy_service.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
#include "net/tools/quic/test_tools/server_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
using base::StringPiece;
using net::tools::QuicInMemoryCache;
using net::tools::QuicServer;
using net::tools::test::QuicInMemoryCachePeer;
using net::tools::test::ServerThread;
namespace net {
namespace test {
namespace {
const char kResponseBody[] = "some arbitrary response body";
// Factory for creating HttpTransactions, used by TestTransactionConsumer.
class TestTransactionFactory : public HttpTransactionFactory {
public:
TestTransactionFactory(const HttpNetworkSession::Params& params)
: session_(new HttpNetworkSession(params)) {}
virtual ~TestTransactionFactory() {
}
// HttpTransactionFactory methods
virtual int CreateTransaction(RequestPriority priority,
scoped_ptr<HttpTransaction>* trans) OVERRIDE {
trans->reset(new HttpNetworkTransaction(priority, session_.get()));
return OK;
}
virtual HttpCache* GetCache() OVERRIDE {
return NULL;
}
virtual HttpNetworkSession* GetSession() OVERRIDE { return session_.get(); };
private:
scoped_refptr<HttpNetworkSession> session_;
};
} // namespace
class QuicEndToEndTest : public PlatformTest {
protected:
QuicEndToEndTest()
: host_resolver_impl_(CreateResolverImpl()),
host_resolver_(host_resolver_impl_.PassAs<HostResolver>()),
ssl_config_service_(new SSLConfigServiceDefaults),
proxy_service_(ProxyService::CreateDirect()),
auth_handler_factory_(
HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
strike_register_no_startup_period_(false) {
request_.method = "GET";
request_.url = GURL("http://www.google.com/");
request_.load_flags = 0;
params_.enable_quic = true;
params_.quic_clock = NULL;
params_.quic_random = NULL;
params_.host_resolver = &host_resolver_;
params_.cert_verifier = &cert_verifier_;
params_.transport_security_state = &transport_security_state_;
params_.proxy_service = proxy_service_.get();
params_.ssl_config_service = ssl_config_service_.get();
params_.http_auth_handler_factory = auth_handler_factory_.get();
params_.http_server_properties = http_server_properties.GetWeakPtr();
}
// Creates a mock host resolver in which www.google.com
// resolves to localhost.
static MockHostResolver* CreateResolverImpl() {
MockHostResolver* resolver = new MockHostResolver();
resolver->rules()->AddRule("www.google.com", "127.0.0.1");
return resolver;
}
virtual void SetUp() {
QuicInMemoryCachePeer::ResetForTests();
StartServer();
// Use a mapped host resolver so that request for www.google.com (port 80)
// reach the server running on localhost.
std::string map_rule = "MAP www.google.com www.google.com:" +
base::IntToString(server_thread_->GetPort());
EXPECT_TRUE(host_resolver_.AddRuleFromString(map_rule));
// To simplify the test, and avoid the race with the HTTP request, we force
// QUIC for these requests.
params_.origin_to_force_quic_on =
HostPortPair::FromString("www.google.com:80");
transaction_factory_.reset(new TestTransactionFactory(params_));
}
virtual void TearDown() {
StopServer();
QuicInMemoryCachePeer::ResetForTests();
}
// Starts the QUIC server listening on a random port.
void StartServer() {
net::IPAddressNumber ip;
CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip));
server_address_ = IPEndPoint(ip, 0);
server_config_.SetDefaults();
server_config_.SetInitialFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
server_config_.SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
server_config_.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
server_thread_.reset(new ServerThread(
new QuicServer(server_config_, QuicSupportedVersions()),
server_address_,
strike_register_no_startup_period_));
server_thread_->Initialize();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
server_thread_->Start();
server_started_ = true;
}
// Stops the QUIC server.
void StopServer() {
if (!server_started_) {
return;
}
if (server_thread_.get()) {
server_thread_->Quit();
server_thread_->Join();
}
}
// Adds an entry to the cache used by the QUIC server to serve
// responses.
void AddToCache(const StringPiece& method,
const StringPiece& path,
const StringPiece& version,
const StringPiece& response_code,
const StringPiece& response_detail,
const StringPiece& body) {
QuicInMemoryCache::GetInstance()->AddSimpleResponse(
method, path, version, response_code, response_detail, body);
}
// Populates |request_body_| with |length_| ASCII bytes.
void GenerateBody(size_t length) {
request_body_.clear();
request_body_.reserve(length);
for (size_t i = 0; i < length; ++i) {
request_body_.append(1, static_cast<char>(32 + i % (126 - 32)));
}
}
// Initializes |request_| for a post of |length| bytes.
void InitializePostRequest(size_t length) {
GenerateBody(length);
ScopedVector<UploadElementReader> element_readers;
element_readers.push_back(
new UploadBytesElementReader(request_body_.data(),
request_body_.length()));
upload_data_stream_.reset(new UploadDataStream(element_readers.Pass(), 0));
request_.method = "POST";
request_.url = GURL("http://www.google.com/");
request_.upload_data_stream = upload_data_stream_.get();
ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback()));
}
// Checks that |consumer| completed and received |status_line| and |body|.
void CheckResponse(const TestTransactionConsumer& consumer,
const std::string& status_line,
const std::string& body) {
ASSERT_TRUE(consumer.is_done());
EXPECT_EQ(OK, consumer.error());
EXPECT_EQ(status_line,
consumer.response_info()->headers->GetStatusLine());
EXPECT_EQ(body, consumer.content());
}
scoped_ptr<MockHostResolver> host_resolver_impl_;
MappedHostResolver host_resolver_;
MockCertVerifier cert_verifier_;
TransportSecurityState transport_security_state_;
scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
scoped_ptr<ProxyService> proxy_service_;
scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
HttpServerPropertiesImpl http_server_properties;
HttpNetworkSession::Params params_;
scoped_ptr<TestTransactionFactory> transaction_factory_;
HttpRequestInfo request_;
std::string request_body_;
scoped_ptr<UploadDataStream> upload_data_stream_;
scoped_ptr<ServerThread> server_thread_;
IPEndPoint server_address_;
std::string server_hostname_;
QuicConfig server_config_;
bool server_started_;
bool strike_register_no_startup_period_;
};
TEST_F(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
std::string response(10 * 1024, 'x');
AddToCache("GET", request_.url.spec(),
"HTTP/1.1", "200", "OK",
response);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
consumer.Start(&request_, BoundNetLog());
// Will terminate when the last consumer completes.
base::MessageLoop::current()->Run();
CheckResponse(consumer, "HTTP/1.1 200 OK", response);
}
// http://crbug.com/307284
TEST_F(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) {
InitializePostRequest(10 * 1024 * 1024);
AddToCache("POST", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
consumer.Start(&request_, BoundNetLog());
// Will terminate when the last consumer completes.
base::MessageLoop::current()->Run();
CheckResponse(consumer, "HTTP/1.1 200 OK", kResponseBody);
}
TEST_F(QuicEndToEndTest, LargePostWithPacketLoss) {
// FLAGS_fake_packet_loss_percentage = 30;
InitializePostRequest(1024 * 1024);
const char kResponseBody[] = "some really big response body";
AddToCache("POST", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
consumer.Start(&request_, BoundNetLog());
// Will terminate when the last consumer completes.
base::MessageLoop::current()->Run();
CheckResponse(consumer, "HTTP/1.1 200 OK", kResponseBody);
}
TEST_F(QuicEndToEndTest, UberTest) {
// FLAGS_fake_packet_loss_percentage = 30;
const char kResponseBody[] = "some really big response body";
AddToCache("GET", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
std::vector<TestTransactionConsumer*> consumers;
size_t num_requests = 100;
for (size_t i = 0; i < num_requests; ++i) {
TestTransactionConsumer* consumer =
new TestTransactionConsumer(DEFAULT_PRIORITY,
transaction_factory_.get());
consumers.push_back(consumer);
consumer->Start(&request_, BoundNetLog());
}
// Will terminate when the last consumer completes.
base::MessageLoop::current()->Run();
for (size_t i = 0; i < num_requests; ++i) {
CheckResponse(*consumers[i], "HTTP/1.1 200 OK", kResponseBody);
}
STLDeleteElements(&consumers);
}
} // namespace test
} // namespace net