blob: b9dae536f6035f8a74273199a9e92a51bdc190b1 [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"
25#include "net/quic/quic_protocol.h"
26#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));
92 QuicFramer framer(QuicDecrypter::Create(kNULL),
93 QuicEncrypter::Create(kNULL));
94 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*chlo));
95 }
96
97 scoped_ptr<QuicEncryptedPacket> ConstructShlo() {
98 scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO));
99 QuicFramer framer(QuicDecrypter::Create(kNULL),
100 QuicEncrypter::Create(kNULL));
101 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*shlo));
102 }
103
104 scoped_ptr<QuicEncryptedPacket> ConstructRstPacket(
105 QuicPacketSequenceNumber num,
106 QuicStreamId stream_id) {
107 QuicPacketHeader header;
108 header.public_header.guid = 0xDEADBEEF;
109 header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
110 header.packet_sequence_number = num;
111 header.private_flags = PACKET_PRIVATE_FLAGS_NONE;
112 header.fec_group = 0;
113
114 QuicRstStreamFrame rst(stream_id, 0, QUIC_NO_ERROR);
115 return scoped_ptr<QuicEncryptedPacket>(
116 ConstructPacket(header, QuicFrame(&rst)));
117 }
118
119 scoped_ptr<QuicEncryptedPacket> ConstructAckPacket(
120 QuicPacketSequenceNumber largest_received,
121 QuicPacketSequenceNumber least_unacked) {
122 QuicPacketHeader header;
123 header.public_header.guid = 0xDEADBEEF;
124 header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
125 header.packet_sequence_number = 3;
126 header.private_flags = PACKET_PRIVATE_FLAGS_NONE;
127 header.fec_group = 0;
128
129 QuicAckFrame ack(largest_received, least_unacked);
130
131 QuicCongestionFeedbackFrame feedback;
132 feedback.type = kTCP;
133 feedback.tcp.accumulated_number_of_lost_packets = 0;
134 feedback.tcp.receive_window = 256000;
135
136 QuicFramer framer(QuicDecrypter::Create(kNULL),
137 QuicEncrypter::Create(kNULL));
138 QuicFrames frames;
139 frames.push_back(QuicFrame(&ack));
140 frames.push_back(QuicFrame(&feedback));
141 scoped_ptr<QuicPacket> packet(
142 framer.ConstructFrameDataPacket(header, frames));
143 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet));
144 }
145
146 std::string GetRequestString(const std::string& method,
147 const std::string& path) {
148 SpdyHeaderBlock headers;
149 headers[":method"] = method;
150 headers[":host"] = "www.google.com";
151 headers[":path"] = path;
152 headers[":scheme"] = "http";
153 headers[":version"] = "HTTP/1.1";
154 return SerializeHeaderBlock(headers);
155 }
156
157 std::string GetResponseString(const std::string& status,
158 const std::string& body) {
159 SpdyHeaderBlock headers;
160 headers[":status"] = status;
161 headers[":version"] = "HTTP/1.1";
162 headers["content-type"] = "text/plain";
163 return SerializeHeaderBlock(headers) + body;
164 }
165
166 std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) {
167 size_t len = SpdyFramer::GetSerializedLength(3, &headers);
168 SpdyFrameBuilder builder(len);
169 SpdyFramer::WriteHeaderBlock(&builder, 3, &headers);
170 scoped_ptr<SpdyFrame> frame(builder.take());
171 return std::string(frame->data(), len);
172 }
173
174 // Returns a newly created packet to send kData on stream 1.
175 QuicEncryptedPacket* ConstructDataPacket(
176 QuicPacketSequenceNumber sequence_number,
177 bool fin,
178 QuicStreamOffset offset,
179 base::StringPiece data) {
180 InitializeHeader(sequence_number);
181 QuicStreamFrame frame(3, fin, offset, data);
182 return ConstructPacket(header_, QuicFrame(&frame)).release();
183 }
184
185 scoped_ptr<QuicEncryptedPacket> ConstructPacket(
186 const QuicPacketHeader& header,
187 const QuicFrame& frame) {
188 QuicFramer framer(QuicDecrypter::Create(kNULL),
189 QuicEncrypter::Create(kNULL));
190 QuicFrames frames;
191 frames.push_back(frame);
192 scoped_ptr<QuicPacket> packet(
193 framer.ConstructFrameDataPacket(header, frames));
194 return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet));
195 }
196
197 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
198 header_.public_header.guid = random_generator_.RandUint64();
199 header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
200 header_.packet_sequence_number = sequence_number;
201 header_.fec_group = 0;
202 header_.private_flags = PACKET_PRIVATE_FLAGS_NONE;
203 }
204
205 void CreateSession() {
206 params_.client_socket_factory = &socket_factory_;
[email protected]1c04f9522013-02-21 20:32:43207 params_.host_resolver = &host_resolver_;
208 params_.cert_verifier = &cert_verifier_;
209 params_.proxy_service = proxy_service_.get();
210 params_.ssl_config_service = ssl_config_service_.get();
211 params_.http_auth_handler_factory = auth_handler_factory_.get();
[email protected]61a527782013-02-21 03:58:00212 params_.http_server_properties = &http_server_properties;
213
214 session_ = new HttpNetworkSession(params_);
215 }
216
217 QuicPacketHeader header_;
218 scoped_refptr<HttpNetworkSession> session_;
219 MockClientSocketFactory socket_factory_;
[email protected]1c04f9522013-02-21 20:32:43220 MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
221 MockHostResolver host_resolver_;
222 MockCertVerifier cert_verifier_;
223 scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
224 scoped_ptr<ProxyService> proxy_service_;
225 scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
[email protected]61a527782013-02-21 03:58:00226 MockRandom random_generator_;
227 HttpServerPropertiesImpl http_server_properties;
228 HttpNetworkSession::Params params_;
229};
230
231TEST_F(QuicNetworkTransactionTest, UseAlternateProtocolForQuic) {
232 HttpStreamFactory::set_use_alternate_protocols(true);
233 HttpStreamFactory::SetNextProtos(QuicNextProtos());
234 params_.enable_quic = true;
235 params_.quic_clock = clock_;
236 params_.use_spdy_over_quic = true;
237 params_.quic_random = &random_generator_;
238
239 HttpRequestInfo request;
240 request.method = "GET";
241 request.url = GURL("http://www.google.com/");
242 request.load_flags = 0;
243
244 MockRead data_reads[] = {
245 MockRead("HTTP/1.1 200 OK\r\n"),
246 MockRead(kQuicAlternateProtocolHttpHeader),
247 MockRead("hello world"),
248 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
249 MockRead(ASYNC, OK)
250 };
251
252 StaticSocketDataProvider first_transaction(
253 data_reads, arraysize(data_reads), NULL, 0);
254 socket_factory_.AddSocketDataProvider(&first_transaction);
255
256
257 scoped_ptr<QuicEncryptedPacket> chlo(ConstructChlo());
258 scoped_ptr<QuicEncryptedPacket> data(
259 ConstructDataPacket(2, true, 0, GetRequestString("GET", "/")));
260 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(2, 1));
261
262 MockWrite quic_writes[] = {
263 MockWrite(SYNCHRONOUS, chlo->data(), chlo->length()),
264 MockWrite(SYNCHRONOUS, data->data(), data->length()),
265 MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
266 };
267
268 scoped_ptr<QuicEncryptedPacket> shlo(ConstructShlo());
269 scoped_ptr<QuicEncryptedPacket> resp(
270 ConstructDataPacket(2, true, 0, GetResponseString("200 OK", "hello!")));
271 MockRead quic_reads[] = {
272 MockRead(SYNCHRONOUS, shlo->data(), shlo->length()),
273 MockRead(SYNCHRONOUS, resp->data(), resp->length()),
274 MockRead(ASYNC, OK), // EOF
275 };
276
277 DelayedSocketData quic_data(
278 1, // wait for one write to finish before reading.
279 quic_reads, arraysize(quic_reads),
280 quic_writes, arraysize(quic_writes));
281
282 socket_factory_.AddSocketDataProvider(&quic_data);
283
284 // The non-alternate protocol job needs to hang in order to guarantee that the
285 // alternate-protocol job will "win".
286 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
287 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
288 NULL, 0, NULL, 0);
289 hanging_non_alternate_protocol_socket.set_connect_data(
290 never_finishing_connect);
291 socket_factory_.AddSocketDataProvider(
292 &hanging_non_alternate_protocol_socket);
293
294 TestCompletionCallback callback;
295
296 CreateSession();
297 scoped_ptr<HttpNetworkTransaction> trans(
298 new HttpNetworkTransaction(session_));
299
300 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
301 EXPECT_EQ(ERR_IO_PENDING, rv);
302 EXPECT_EQ(OK, callback.WaitForResult());
303
304 const HttpResponseInfo* response = trans->GetResponseInfo();
305 ASSERT_TRUE(response != NULL);
306 ASSERT_TRUE(response->headers != NULL);
307 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
308
309 std::string response_data;
310 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
311 EXPECT_EQ("hello world", response_data);
312
313 trans.reset(new HttpNetworkTransaction(session_));
314
315 rv = trans->Start(&request, callback.callback(), BoundNetLog());
316 EXPECT_EQ(ERR_IO_PENDING, rv);
317 EXPECT_EQ(OK, callback.WaitForResult());
318
319 response = trans->GetResponseInfo();
320 ASSERT_TRUE(response != NULL);
321 ASSERT_TRUE(response->headers != NULL);
322 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
323 EXPECT_TRUE(response->was_fetched_via_spdy);
324
325 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
326 EXPECT_EQ("hello!", response_data);
327}
328
329} // namespace test
330} // namespace net