1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/basictypes.h"
6#include "base/compiler_specific.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/stl_util.h"
9#include "base/strings/string_number_conversions.h"
10#include "net/base/test_completion_callback.h"
11#include "net/base/upload_bytes_element_reader.h"
12#include "net/base/upload_data_stream.h"
13#include "net/cert/mock_cert_verifier.h"
14#include "net/dns/mapped_host_resolver.h"
15#include "net/dns/mock_host_resolver.h"
16#include "net/http/http_auth_handler_factory.h"
17#include "net/http/http_network_session.h"
18#include "net/http/http_network_transaction.h"
19#include "net/http/http_server_properties_impl.h"
20#include "net/http/http_transaction_test_util.h"
21#include "net/http/transport_security_state.h"
22#include "net/proxy/proxy_service.h"
23#include "net/quic/test_tools/quic_test_utils.h"
24#include "net/ssl/ssl_config_service_defaults.h"
25#include "net/tools/quic/quic_in_memory_cache.h"
26#include "net/tools/quic/quic_server.h"
27#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
28#include "net/tools/quic/test_tools/server_thread.h"
29#include "testing/gtest/include/gtest/gtest.h"
30#include "testing/platform_test.h"
31
32using base::StringPiece;
33using net::tools::QuicInMemoryCache;
34using net::tools::QuicServer;
35using net::tools::test::QuicInMemoryCachePeer;
36using net::tools::test::ServerThread;
37
38namespace net {
39namespace test {
40
41namespace {
42
43const char kResponseBody[] = "some arbitrary response body";
44
45// Factory for creating HttpTransactions, used by TestTransactionConsumer.
46class TestTransactionFactory : public HttpTransactionFactory {
47 public:
48  TestTransactionFactory(const HttpNetworkSession::Params& params)
49      : session_(new HttpNetworkSession(params)) {}
50
51  virtual ~TestTransactionFactory() {
52  }
53
54  // HttpTransactionFactory methods
55  virtual int CreateTransaction(RequestPriority priority,
56                                scoped_ptr<HttpTransaction>* trans) OVERRIDE {
57    trans->reset(new HttpNetworkTransaction(priority, session_.get()));
58    return OK;
59  }
60
61  virtual HttpCache* GetCache() OVERRIDE {
62    return NULL;
63  }
64
65  virtual HttpNetworkSession* GetSession() OVERRIDE { return session_.get(); };
66
67 private:
68  scoped_refptr<HttpNetworkSession> session_;
69};
70
71}  // namespace
72
73class QuicEndToEndTest : public PlatformTest {
74 protected:
75  QuicEndToEndTest()
76      : host_resolver_impl_(CreateResolverImpl()),
77        host_resolver_(host_resolver_impl_.PassAs<HostResolver>()),
78        ssl_config_service_(new SSLConfigServiceDefaults),
79        proxy_service_(ProxyService::CreateDirect()),
80        auth_handler_factory_(
81            HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
82        strike_register_no_startup_period_(false) {
83    request_.method = "GET";
84    request_.url = GURL("http://www.google.com/");
85    request_.load_flags = 0;
86
87    params_.enable_quic = true;
88    params_.quic_clock = NULL;
89    params_.quic_random = NULL;
90    params_.host_resolver = &host_resolver_;
91    params_.cert_verifier = &cert_verifier_;
92    params_.transport_security_state = &transport_security_state_;
93    params_.proxy_service = proxy_service_.get();
94    params_.ssl_config_service = ssl_config_service_.get();
95    params_.http_auth_handler_factory = auth_handler_factory_.get();
96    params_.http_server_properties = http_server_properties.GetWeakPtr();
97  }
98
99  // Creates a mock host resolver in which www.google.com
100  // resolves to localhost.
101  static MockHostResolver* CreateResolverImpl() {
102    MockHostResolver* resolver = new MockHostResolver();
103    resolver->rules()->AddRule("www.google.com", "127.0.0.1");
104    return resolver;
105  }
106
107  virtual void SetUp() {
108    QuicInMemoryCachePeer::ResetForTests();
109    StartServer();
110
111    // Use a mapped host resolver so that request for www.google.com (port 80)
112    // reach the server running on localhost.
113    std::string map_rule = "MAP www.google.com www.google.com:" +
114        base::IntToString(server_thread_->GetPort());
115    EXPECT_TRUE(host_resolver_.AddRuleFromString(map_rule));
116
117    // To simplify the test, and avoid the race with the HTTP request, we force
118    // QUIC for these requests.
119    params_.origin_to_force_quic_on =
120        HostPortPair::FromString("www.google.com:80");
121
122    transaction_factory_.reset(new TestTransactionFactory(params_));
123  }
124
125  virtual void TearDown() {
126    StopServer();
127    QuicInMemoryCachePeer::ResetForTests();
128  }
129
130  // Starts the QUIC server listening on a random port.
131  void StartServer() {
132    net::IPAddressNumber ip;
133    CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip));
134    server_address_ = IPEndPoint(ip, 0);
135    server_config_.SetDefaults();
136    server_config_.SetInitialFlowControlWindowToSend(
137        kInitialSessionFlowControlWindowForTest);
138    server_config_.SetInitialStreamFlowControlWindowToSend(
139        kInitialStreamFlowControlWindowForTest);
140    server_config_.SetInitialSessionFlowControlWindowToSend(
141        kInitialSessionFlowControlWindowForTest);
142    server_thread_.reset(new ServerThread(
143         new QuicServer(server_config_, QuicSupportedVersions()),
144         server_address_,
145         strike_register_no_startup_period_));
146    server_thread_->Initialize();
147    server_address_ = IPEndPoint(server_address_.address(),
148                                 server_thread_->GetPort());
149    server_thread_->Start();
150    server_started_ = true;
151  }
152
153  // Stops the QUIC server.
154  void StopServer() {
155    if (!server_started_) {
156      return;
157    }
158    if (server_thread_.get()) {
159      server_thread_->Quit();
160      server_thread_->Join();
161    }
162  }
163
164  // Adds an entry to the cache used by the QUIC server to serve
165  // responses.
166  void AddToCache(const StringPiece& method,
167                  const StringPiece& path,
168                  const StringPiece& version,
169                  const StringPiece& response_code,
170                  const StringPiece& response_detail,
171                  const StringPiece& body) {
172    QuicInMemoryCache::GetInstance()->AddSimpleResponse(
173        method, path, version, response_code, response_detail, body);
174  }
175
176  // Populates |request_body_| with |length_| ASCII bytes.
177  void GenerateBody(size_t length) {
178    request_body_.clear();
179    request_body_.reserve(length);
180    for (size_t i = 0; i < length; ++i) {
181      request_body_.append(1, static_cast<char>(32 + i % (126 - 32)));
182    }
183  }
184
185  // Initializes |request_| for a post of |length| bytes.
186  void InitializePostRequest(size_t length) {
187    GenerateBody(length);
188    ScopedVector<UploadElementReader> element_readers;
189    element_readers.push_back(
190        new UploadBytesElementReader(request_body_.data(),
191                                     request_body_.length()));
192    upload_data_stream_.reset(new UploadDataStream(element_readers.Pass(), 0));
193    request_.method = "POST";
194    request_.url = GURL("http://www.google.com/");
195    request_.upload_data_stream = upload_data_stream_.get();
196    ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback()));
197  }
198
199  // Checks that |consumer| completed and received |status_line| and |body|.
200  void CheckResponse(const TestTransactionConsumer& consumer,
201                     const std::string& status_line,
202                     const std::string& body) {
203    ASSERT_TRUE(consumer.is_done());
204    EXPECT_EQ(OK, consumer.error());
205    EXPECT_EQ(status_line,
206              consumer.response_info()->headers->GetStatusLine());
207    EXPECT_EQ(body, consumer.content());
208  }
209
210  scoped_ptr<MockHostResolver> host_resolver_impl_;
211  MappedHostResolver host_resolver_;
212  MockCertVerifier cert_verifier_;
213  TransportSecurityState transport_security_state_;
214  scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
215  scoped_ptr<ProxyService> proxy_service_;
216  scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
217  HttpServerPropertiesImpl http_server_properties;
218  HttpNetworkSession::Params params_;
219  scoped_ptr<TestTransactionFactory> transaction_factory_;
220  HttpRequestInfo request_;
221  std::string request_body_;
222  scoped_ptr<UploadDataStream> upload_data_stream_;
223  scoped_ptr<ServerThread> server_thread_;
224  IPEndPoint server_address_;
225  std::string server_hostname_;
226  QuicConfig server_config_;
227  bool server_started_;
228  bool strike_register_no_startup_period_;
229};
230
231TEST_F(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
232  std::string response(10 * 1024, 'x');
233
234  AddToCache("GET", request_.url.spec(),
235             "HTTP/1.1", "200", "OK",
236             response);
237
238  TestTransactionConsumer consumer(DEFAULT_PRIORITY,
239                                   transaction_factory_.get());
240  consumer.Start(&request_, BoundNetLog());
241
242  // Will terminate when the last consumer completes.
243  base::MessageLoop::current()->Run();
244
245  CheckResponse(consumer, "HTTP/1.1 200 OK", response);
246}
247
248// http://crbug.com/307284
249TEST_F(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) {
250  InitializePostRequest(10 * 1024 * 1024);
251
252  AddToCache("POST", request_.url.spec(),
253             "HTTP/1.1", "200", "OK",
254             kResponseBody);
255
256  TestTransactionConsumer consumer(DEFAULT_PRIORITY,
257                                   transaction_factory_.get());
258  consumer.Start(&request_, BoundNetLog());
259
260  // Will terminate when the last consumer completes.
261  base::MessageLoop::current()->Run();
262
263  CheckResponse(consumer, "HTTP/1.1 200 OK", kResponseBody);
264}
265
266TEST_F(QuicEndToEndTest, LargePostWithPacketLoss) {
267  // FLAGS_fake_packet_loss_percentage = 30;
268  InitializePostRequest(1024 * 1024);
269
270  const char kResponseBody[] = "some really big response body";
271  AddToCache("POST", request_.url.spec(),
272             "HTTP/1.1", "200", "OK",
273             kResponseBody);
274
275  TestTransactionConsumer consumer(DEFAULT_PRIORITY,
276                                   transaction_factory_.get());
277  consumer.Start(&request_, BoundNetLog());
278
279  // Will terminate when the last consumer completes.
280  base::MessageLoop::current()->Run();
281
282  CheckResponse(consumer, "HTTP/1.1 200 OK", kResponseBody);
283}
284
285TEST_F(QuicEndToEndTest, UberTest) {
286  // FLAGS_fake_packet_loss_percentage = 30;
287
288  const char kResponseBody[] = "some really big response body";
289  AddToCache("GET", request_.url.spec(),
290             "HTTP/1.1", "200", "OK",
291             kResponseBody);
292
293  std::vector<TestTransactionConsumer*> consumers;
294  size_t num_requests = 100;
295  for (size_t i = 0; i < num_requests; ++i) {
296      TestTransactionConsumer* consumer =
297          new TestTransactionConsumer(DEFAULT_PRIORITY,
298                                      transaction_factory_.get());
299      consumers.push_back(consumer);
300      consumer->Start(&request_, BoundNetLog());
301  }
302
303  // Will terminate when the last consumer completes.
304  base::MessageLoop::current()->Run();
305
306  for (size_t i = 0; i < num_requests; ++i) {
307    CheckResponse(*consumers[i], "HTTP/1.1 200 OK", kResponseBody);
308  }
309  STLDeleteElements(&consumers);
310}
311
312}  // namespace test
313}  // namespace net
314