blob: f51edfa2c4960025f7feae84640174491d9d5832 [file] [log] [blame]
[email protected]61a527782013-02-21 03:58:001// Copyright (c) 2012 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 "net/base/mock_cert_verifier.h"
9#include "net/base/mock_host_resolver.h"
10#include "net/base/ssl_config_service_defaults.h"
11#include "net/base/test_completion_callback.h"
12#include "net/http/http_auth_handler_factory.h"
13#include "net/http/http_network_session.h"
14#include "net/http/http_network_transaction.h"
15#include "net/http/http_server_properties_impl.h"
16#include "net/http/http_stream.h"
17#include "net/http/http_stream_factory.h"
18#include "net/http/http_transaction_unittest.h"
19#include "net/proxy/proxy_config_service_fixed.h"
20#include "net/proxy/proxy_resolver.h"
21#include "net/proxy/proxy_service.h"
22#include "net/quic/crypto/quic_decrypter.h"
23#include "net/quic/crypto/quic_encrypter.h"
24#include "net/quic/quic_framer.h"
[email protected]ed3fc15d2013-03-08 18:37:4425#include "net/quic/test_tools/crypto_test_utils.h"
[email protected]61a527782013-02-21 03:58:0026#include "net/quic/test_tools/mock_clock.h"
27#include "net/quic/test_tools/mock_random.h"
28#include "net/quic/test_tools/quic_test_utils.h"
29#include "net/socket/client_socket_factory.h"
30#include "net/socket/mock_client_socket_pool_manager.h"
31#include "net/socket/socket_test_util.h"
32#include "net/socket/ssl_client_socket.h"
33#include "net/spdy/spdy_frame_builder.h"
34#include "net/spdy/spdy_framer.h"
35#include "testing/gtest/include/gtest/gtest.h"
36#include "testing/platform_test.h"
37
38//-----------------------------------------------------------------------------
39
40namespace {
41
42// This is the expected return from a current server advertising QUIC.
43static const char kQuicAlternateProtocolHttpHeader[] =
44 "Alternate-Protocol: 443:quic/1\r\n\r\n";
45
46// Returns a vector of NPN protocol strings for negotiating QUIC.
47std::vector<std::string> QuicNextProtos() {
48 std::vector<std::string> protos;
49 protos.push_back("http/1.1");
50 protos.push_back("quic/1");
51 return protos;
52}
53
54} // namespace
55
56namespace net {
57namespace test {
58
59class QuicNetworkTransactionTest : public PlatformTest {
60 protected:
[email protected]1c04f9522013-02-21 20:32:4361 QuicNetworkTransactionTest()
62 : clock_(new MockClock),
63 ssl_config_service_(new SSLConfigServiceDefaults),
64 proxy_service_(ProxyService::CreateDirect()),
65 auth_handler_factory_(
66 HttpAuthHandlerFactory::CreateDefault(&host_resolver_)) {
67 }
[email protected]61a527782013-02-21 03:58:0068
69 virtual void SetUp() {
70 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
71 MessageLoop::current()->RunUntilIdle();
72 }
73
74 virtual void TearDown() {
75 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
76 // Empty the current queue.
77 MessageLoop::current()->RunUntilIdle();
78 PlatformTest::TearDown();
79 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
80 MessageLoop::current()->RunUntilIdle();
81 HttpStreamFactory::set_use_alternate_protocols(false);
82 HttpStreamFactory::SetNextProtos(std::vector<std::string>());
83 }
84
85 // TODO(rch): factor these Construct* methods out into a test helper class.
86 scoped_ptr<QuicEncryptedPacket> ConstructChlo() {
87 const std::string host = "www.google.com";
88 scoped_ptr<QuicPacket> chlo(ConstructClientHelloPacket(0xDEADBEEF,
89 clock_,
90 &random_generator_,
91 host));
[email protected]5351cc4b2013-03-03 07:22:4192 QuicFramer framer(kQuicVersion1,
93 QuicDecrypter::Create(kNULL),
[email protected]61a527782013-02-21 03:58:0094 QuicEncrypter::Create(kNULL));
[email protected]9db443912013-02-25 05:27:0395 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo));
[email protected]61a527782013-02-21 03:58:0096 }
97
98 scoped_ptr<QuicEncryptedPacket> ConstructShlo() {
[email protected]ed3fc15d2013-03-08 18:37:4499 const std::string host = "www.google.com";
100 scoped_ptr<QuicPacket> shlo(ConstructServerHelloPacket(0xDEADBEEF,
101 clock_,
102 &random_generator_,
103 host));
[email protected]5351cc4b2013-03-03 07:22:41104 QuicFramer framer(kQuicVersion1,
105 QuicDecrypter::Create(kNULL),
[email protected]61a527782013-02-21 03:58:00106 QuicEncrypter::Create(kNULL));
[email protected]9db443912013-02-25 05:27:03107 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo));
[email protected]61a527782013-02-21 03:58:00108 }
109
110 scoped_ptr<QuicEncryptedPacket> ConstructRstPacket(
111 QuicPacketSequenceNumber num,
112 QuicStreamId stream_id) {
113 QuicPacketHeader header;
114 header.public_header.guid = 0xDEADBEEF;
[email protected]9db443912013-02-25 05:27:03115 header.public_header.reset_flag = false;
116 header.public_header.version_flag = false;
[email protected]61a527782013-02-21 03:58:00117 header.packet_sequence_number = num;
[email protected]9db443912013-02-25 05:27:03118 header.entropy_flag = false;
119 header.fec_flag = false;
120 header.fec_entropy_flag = false;
[email protected]61a527782013-02-21 03:58:00121 header.fec_group = 0;
122
[email protected]9db443912013-02-25 05:27:03123 QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR);
[email protected]61a527782013-02-21 03:58:00124 return scoped_ptr<QuicEncryptedPacket>(
125 ConstructPacket(header, QuicFrame(&rst)));
126 }
127
128 scoped_ptr<QuicEncryptedPacket> ConstructAckPacket(
129 QuicPacketSequenceNumber largest_received,
130 QuicPacketSequenceNumber least_unacked) {
131 QuicPacketHeader header;
132 header.public_header.guid = 0xDEADBEEF;
[email protected]9db443912013-02-25 05:27:03133 header.public_header.reset_flag = false;
134 header.public_header.version_flag = false;
[email protected]61a527782013-02-21 03:58:00135 header.packet_sequence_number = 3;
[email protected]9db443912013-02-25 05:27:03136 header.entropy_flag = false;
137 header.fec_flag = false;
138 header.fec_entropy_flag = false;
[email protected]61a527782013-02-21 03:58:00139 header.fec_group = 0;
140
141 QuicAckFrame ack(largest_received, least_unacked);
142
143 QuicCongestionFeedbackFrame feedback;
144 feedback.type = kTCP;
145 feedback.tcp.accumulated_number_of_lost_packets = 0;
146 feedback.tcp.receive_window = 256000;
147
[email protected]5351cc4b2013-03-03 07:22:41148 QuicFramer framer(kQuicVersion1,
149 QuicDecrypter::Create(kNULL),
[email protected]61a527782013-02-21 03:58:00150 QuicEncrypter::Create(kNULL));
151 QuicFrames frames;
152 frames.push_back(QuicFrame(&ack));
153 frames.push_back(QuicFrame(&feedback));
154 scoped_ptr<QuicPacket> packet(
[email protected]9db443912013-02-25 05:27:03155 framer.ConstructFrameDataPacket(header, frames).packet);
156 return scoped_ptr<QuicEncryptedPacket>(
157 framer.EncryptPacket(header.packet_sequence_number, *packet));
[email protected]61a527782013-02-21 03:58:00158 }
159
160 std::string GetRequestString(const std::string& method,
161 const std::string& path) {
162 SpdyHeaderBlock headers;
163 headers[":method"] = method;
164 headers[":host"] = "www.google.com";
165 headers[":path"] = path;
166 headers[":scheme"] = "http";
167 headers[":version"] = "HTTP/1.1";
168 return SerializeHeaderBlock(headers);
169 }
170
171 std::string GetResponseString(const std::string& status,
172 const std::string& body) {
173 SpdyHeaderBlock headers;
174 headers[":status"] = status;
175 headers[":version"] = "HTTP/1.1";
176 headers["content-type"] = "text/plain";
177 return SerializeHeaderBlock(headers) + body;
178 }
179
180 std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) {
181 size_t len = SpdyFramer::GetSerializedLength(3, &headers);
182 SpdyFrameBuilder builder(len);
183 SpdyFramer::WriteHeaderBlock(&builder, 3, &headers);
184 scoped_ptr<SpdyFrame> frame(builder.take());
185 return std::string(frame->data(), len);
186 }
187
188 // Returns a newly created packet to send kData on stream 1.
189 QuicEncryptedPacket* ConstructDataPacket(
190 QuicPacketSequenceNumber sequence_number,
191 bool fin,
192 QuicStreamOffset offset,
193 base::StringPiece data) {
194 InitializeHeader(sequence_number);
195 QuicStreamFrame frame(3, fin, offset, data);
196 return ConstructPacket(header_, QuicFrame(&frame)).release();
197 }
198
199 scoped_ptr<QuicEncryptedPacket> ConstructPacket(
200 const QuicPacketHeader& header,
201 const QuicFrame& frame) {
[email protected]5351cc4b2013-03-03 07:22:41202 QuicFramer framer(kQuicVersion1,
203 QuicDecrypter::Create(kNULL),
[email protected]61a527782013-02-21 03:58:00204 QuicEncrypter::Create(kNULL));
205 QuicFrames frames;
206 frames.push_back(frame);
207 scoped_ptr<QuicPacket> packet(
[email protected]9db443912013-02-25 05:27:03208 framer.ConstructFrameDataPacket(header, frames).packet);
209 return scoped_ptr<QuicEncryptedPacket>(
210 framer.EncryptPacket(header.packet_sequence_number, *packet));
[email protected]61a527782013-02-21 03:58:00211 }
212
213 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
214 header_.public_header.guid = random_generator_.RandUint64();
[email protected]9db443912013-02-25 05:27:03215 header_.public_header.reset_flag = false;
216 header_.public_header.version_flag = false;
[email protected]61a527782013-02-21 03:58:00217 header_.packet_sequence_number = sequence_number;
218 header_.fec_group = 0;
[email protected]9db443912013-02-25 05:27:03219 header_.entropy_flag = false;
220 header_.fec_flag = false;
221 header_.fec_entropy_flag = false;
[email protected]61a527782013-02-21 03:58:00222 }
223
224 void CreateSession() {
[email protected]4dca587c2013-03-07 16:54:47225 params_.enable_quic = true;
226 params_.quic_clock = clock_;
227 params_.quic_random = &random_generator_;
[email protected]61a527782013-02-21 03:58:00228 params_.client_socket_factory = &socket_factory_;
[email protected]1c04f9522013-02-21 20:32:43229 params_.host_resolver = &host_resolver_;
230 params_.cert_verifier = &cert_verifier_;
231 params_.proxy_service = proxy_service_.get();
232 params_.ssl_config_service = ssl_config_service_.get();
233 params_.http_auth_handler_factory = auth_handler_factory_.get();
[email protected]61a527782013-02-21 03:58:00234 params_.http_server_properties = &http_server_properties;
235
236 session_ = new HttpNetworkSession(params_);
237 }
238
239 QuicPacketHeader header_;
240 scoped_refptr<HttpNetworkSession> session_;
241 MockClientSocketFactory socket_factory_;
[email protected]1c04f9522013-02-21 20:32:43242 MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
243 MockHostResolver host_resolver_;
244 MockCertVerifier cert_verifier_;
245 scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
246 scoped_ptr<ProxyService> proxy_service_;
247 scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
[email protected]61a527782013-02-21 03:58:00248 MockRandom random_generator_;
249 HttpServerPropertiesImpl http_server_properties;
250 HttpNetworkSession::Params params_;
251};
252
[email protected]4dca587c2013-03-07 16:54:47253TEST_F(QuicNetworkTransactionTest, ForceQuic) {
254 params_.origin_port_to_force_quic_on = 80;
255
256 HttpRequestInfo request;
257 request.method = "GET";
258 request.url = GURL("http://www.google.com/");
259 request.load_flags = 0;
260
261 scoped_ptr<QuicEncryptedPacket> chlo(ConstructChlo());
262 scoped_ptr<QuicEncryptedPacket> data(
263 ConstructDataPacket(2, true, 0, GetRequestString("GET", "/")));
264 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(2, 1));
265
266 MockWrite quic_writes[] = {
267 MockWrite(SYNCHRONOUS, chlo->data(), chlo->length()),
268 MockWrite(SYNCHRONOUS, data->data(), data->length()),
269 MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
270 };
271
272 scoped_ptr<QuicEncryptedPacket> shlo(ConstructShlo());
273 scoped_ptr<QuicEncryptedPacket> resp(
274 ConstructDataPacket(2, true, 0, GetResponseString("200 OK", "hello!")));
275 MockRead quic_reads[] = {
276 MockRead(SYNCHRONOUS, shlo->data(), shlo->length()),
277 MockRead(SYNCHRONOUS, resp->data(), resp->length()),
278 MockRead(ASYNC, OK), // EOF
279 };
280
281 DelayedSocketData quic_data(
282 1, // wait for one write to finish before reading.
283 quic_reads, arraysize(quic_reads),
284 quic_writes, arraysize(quic_writes));
285
286 socket_factory_.AddSocketDataProvider(&quic_data);
287
288 // The non-alternate protocol job needs to hang in order to guarantee that the
289 // alternate-protocol job will "win".
290 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
291 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
292 NULL, 0, NULL, 0);
293 hanging_non_alternate_protocol_socket.set_connect_data(
294 never_finishing_connect);
295 socket_factory_.AddSocketDataProvider(
296 &hanging_non_alternate_protocol_socket);
297
298 TestCompletionCallback callback;
299
300 CreateSession();
301 scoped_ptr<HttpNetworkTransaction> trans(
302 new HttpNetworkTransaction(session_));
303
304 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
305 EXPECT_EQ(ERR_IO_PENDING, rv);
306 EXPECT_EQ(OK, callback.WaitForResult());
307
308 const HttpResponseInfo* response = trans->GetResponseInfo();
309 ASSERT_TRUE(response != NULL);
310 ASSERT_TRUE(response->headers != NULL);
311 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
312 EXPECT_TRUE(response->was_fetched_via_spdy);
313
314 std::string response_data;
315 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
316 EXPECT_EQ("hello!", response_data);
317}
318
319TEST_F(QuicNetworkTransactionTest, DoNotForceQuicForHttps) {
320 // Attempt to "force" quic on 443, which will not be honored.
321 params_.origin_port_to_force_quic_on = 443;
322
323 HttpRequestInfo request;
324 request.method = "GET";
325 request.url = GURL("https://www.google.com/");
326 request.load_flags = 0;
327
328 MockRead data_reads[] = {
329 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
330 MockRead("hello world"),
331 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
332 MockRead(ASYNC, OK)
333 };
334
335 StaticSocketDataProvider data(
336 data_reads, arraysize(data_reads), NULL, 0);
337 socket_factory_.AddSocketDataProvider(&data);
338 SSLSocketDataProvider ssl(ASYNC, OK);
339 socket_factory_.AddSSLSocketDataProvider(&ssl);
340
341 TestCompletionCallback callback;
342
343 CreateSession();
344 scoped_ptr<HttpNetworkTransaction> trans(
345 new HttpNetworkTransaction(session_));
346
347 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
348 EXPECT_EQ(ERR_IO_PENDING, rv);
349 EXPECT_EQ(OK, callback.WaitForResult());
350
351 const HttpResponseInfo* response = trans->GetResponseInfo();
352 ASSERT_TRUE(response != NULL);
353 ASSERT_TRUE(response->headers != NULL);
354 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
355
356 std::string response_data;
357 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
358 EXPECT_EQ("hello world", response_data);
359}
360
[email protected]61a527782013-02-21 03:58:00361TEST_F(QuicNetworkTransactionTest, UseAlternateProtocolForQuic) {
362 HttpStreamFactory::set_use_alternate_protocols(true);
363 HttpStreamFactory::SetNextProtos(QuicNextProtos());
[email protected]61a527782013-02-21 03:58:00364
365 HttpRequestInfo request;
366 request.method = "GET";
367 request.url = GURL("http://www.google.com/");
368 request.load_flags = 0;
369
370 MockRead data_reads[] = {
371 MockRead("HTTP/1.1 200 OK\r\n"),
372 MockRead(kQuicAlternateProtocolHttpHeader),
373 MockRead("hello world"),
374 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
375 MockRead(ASYNC, OK)
376 };
377
378 StaticSocketDataProvider first_transaction(
379 data_reads, arraysize(data_reads), NULL, 0);
380 socket_factory_.AddSocketDataProvider(&first_transaction);
381
382
383 scoped_ptr<QuicEncryptedPacket> chlo(ConstructChlo());
384 scoped_ptr<QuicEncryptedPacket> data(
385 ConstructDataPacket(2, true, 0, GetRequestString("GET", "/")));
386 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(2, 1));
387
388 MockWrite quic_writes[] = {
389 MockWrite(SYNCHRONOUS, chlo->data(), chlo->length()),
390 MockWrite(SYNCHRONOUS, data->data(), data->length()),
391 MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
392 };
393
394 scoped_ptr<QuicEncryptedPacket> shlo(ConstructShlo());
395 scoped_ptr<QuicEncryptedPacket> resp(
396 ConstructDataPacket(2, true, 0, GetResponseString("200 OK", "hello!")));
397 MockRead quic_reads[] = {
398 MockRead(SYNCHRONOUS, shlo->data(), shlo->length()),
399 MockRead(SYNCHRONOUS, resp->data(), resp->length()),
400 MockRead(ASYNC, OK), // EOF
401 };
402
403 DelayedSocketData quic_data(
404 1, // wait for one write to finish before reading.
405 quic_reads, arraysize(quic_reads),
406 quic_writes, arraysize(quic_writes));
407
408 socket_factory_.AddSocketDataProvider(&quic_data);
409
410 // The non-alternate protocol job needs to hang in order to guarantee that the
411 // alternate-protocol job will "win".
412 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
413 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
414 NULL, 0, NULL, 0);
415 hanging_non_alternate_protocol_socket.set_connect_data(
416 never_finishing_connect);
417 socket_factory_.AddSocketDataProvider(
418 &hanging_non_alternate_protocol_socket);
419
420 TestCompletionCallback callback;
421
422 CreateSession();
423 scoped_ptr<HttpNetworkTransaction> trans(
424 new HttpNetworkTransaction(session_));
425
426 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
427 EXPECT_EQ(ERR_IO_PENDING, rv);
428 EXPECT_EQ(OK, callback.WaitForResult());
429
430 const HttpResponseInfo* response = trans->GetResponseInfo();
431 ASSERT_TRUE(response != NULL);
432 ASSERT_TRUE(response->headers != NULL);
433 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
434
435 std::string response_data;
436 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
437 EXPECT_EQ("hello world", response_data);
438
439 trans.reset(new HttpNetworkTransaction(session_));
440
441 rv = trans->Start(&request, callback.callback(), BoundNetLog());
442 EXPECT_EQ(ERR_IO_PENDING, rv);
443 EXPECT_EQ(OK, callback.WaitForResult());
444
445 response = trans->GetResponseInfo();
446 ASSERT_TRUE(response != NULL);
447 ASSERT_TRUE(response->headers != NULL);
448 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
449 EXPECT_TRUE(response->was_fetched_via_spdy);
450
451 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
452 EXPECT_EQ("hello!", response_data);
453}
454
455} // namespace test
456} // namespace net