blob: 53ed8ebcd032d49097b3a64ff2f9c3a422fc00b8 [file] [log] [blame]
[email protected]f702d572012-12-04 15:56:201// 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 "net/quic/quic_http_stream.h"
6
7#include <vector>
8
9#include "net/base/net_errors.h"
10#include "net/base/test_completion_callback.h"
[email protected]b2d26cfd2012-12-11 10:36:0611#include "net/base/upload_bytes_element_reader.h"
[email protected]f702d572012-12-04 15:56:2012#include "net/base/upload_data_stream.h"
13#include "net/http/http_response_headers.h"
14#include "net/quic/quic_client_session.h"
15#include "net/quic/quic_connection.h"
16#include "net/quic/quic_connection_helper.h"
17#include "net/quic/test_tools/mock_clock.h"
18#include "net/quic/test_tools/quic_test_utils.h"
19#include "net/quic/test_tools/test_task_runner.h"
20#include "net/socket/socket_test_util.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using testing::_;
25
26namespace net {
27
28class QuicConnectionPeer {
29 public:
30 static void SetScheduler(QuicConnection* connection,
31 QuicSendScheduler* scheduler) {
32 connection->scheduler_.reset(scheduler);
33 }
[email protected]26f3f8e2012-12-13 21:07:1934
35 static void SetCollector(QuicConnection* connection,
36 QuicReceiptMetricsCollector* collector) {
37 connection->collector_.reset(collector);
38 }
[email protected]f702d572012-12-04 15:56:2039};
40
41namespace test {
42
43namespace {
44
45const char kUploadData[] = "hello world!";
46
47class TestQuicConnection : public QuicConnection {
48 public:
49 TestQuicConnection(QuicGuid guid,
50 IPEndPoint address,
51 QuicConnectionHelper* helper)
52 : QuicConnection(guid, address, helper) {
53 }
54
55 void SetScheduler(QuicSendScheduler* scheduler) {
56 QuicConnectionPeer::SetScheduler(this, scheduler);
57 }
[email protected]26f3f8e2012-12-13 21:07:1958
59 void SetCollector(QuicReceiptMetricsCollector* collector) {
60 QuicConnectionPeer::SetCollector(this, collector);
61 }
62};
63
64class TestCollector : public QuicReceiptMetricsCollector {
65 public:
66 explicit TestCollector(QuicCongestionFeedbackFrame* feedback)
67 : QuicReceiptMetricsCollector(&clock_, kFixRate),
68 feedback_(feedback) {
69 }
70
71 bool GenerateCongestionFeedback(
72 QuicCongestionFeedbackFrame* congestion_feedback) {
73 if (feedback_ == NULL) {
74 return false;
75 }
76 *congestion_feedback = *feedback_;
77 return true;
78 }
79
80 MOCK_METHOD4(RecordIncomingPacket,
81 void(size_t, QuicPacketSequenceNumber, QuicTime, bool));
82
83 private:
84 MockClock clock_;
85 QuicCongestionFeedbackFrame* feedback_;
86
87 DISALLOW_COPY_AND_ASSIGN(TestCollector);
[email protected]f702d572012-12-04 15:56:2088};
89
90} // namespace
91
92class QuicHttpStreamTest : public ::testing::Test {
93 protected:
94 const static bool kFin = true;
95 const static bool kNoFin = false;
96 // Holds a packet to be written to the wire, and the IO mode that should
97 // be used by the mock socket when performing the write.
98 struct PacketToWrite {
99 PacketToWrite(IoMode mode, QuicEncryptedPacket* packet)
100 : mode(mode),
101 packet(packet) {
102 }
103 IoMode mode;
104 QuicEncryptedPacket* packet;
105 };
106
107 QuicHttpStreamTest()
108 : net_log_(BoundNetLog()),
109 read_buffer_(new IOBufferWithSize(4096)),
110 guid_(2),
111 framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
112 creator_(guid_, &framer_) {
113 IPAddressNumber ip;
114 CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
115 peer_addr_ = IPEndPoint(ip, 443);
116 self_addr_ = IPEndPoint(ip, 8435);
117 // Do null initialization for simple tests.
118 Initialize();
119 }
120
121 ~QuicHttpStreamTest() {
122 for (size_t i = 0; i < writes_.size(); i++) {
123 delete writes_[i].packet;
124 }
125 }
126
127 // Adds a packet to the list of expected writes.
128 void AddWrite(IoMode mode, QuicEncryptedPacket* packet) {
129 writes_.push_back(PacketToWrite(mode, packet));
130 }
131
132 // Returns the packet to be written at position |pos|.
133 QuicEncryptedPacket* GetWrite(size_t pos) {
134 return writes_[pos].packet;
135 }
136
137 bool AtEof() {
138 return socket_data_->at_read_eof() && socket_data_->at_write_eof();
139 }
140
141 void ProcessPacket(const QuicEncryptedPacket& packet) {
142 connection_->ProcessUdpPacket(self_addr_, peer_addr_, packet);
143 }
144
145 // Configures the test fixture to use the list of expected writes.
146 void Initialize() {
147 mock_writes_.reset(new MockWrite[writes_.size()]);
148 for (size_t i = 0; i < writes_.size(); i++) {
149 mock_writes_[i] = MockWrite(writes_[i].mode,
150 writes_[i].packet->data(),
151 writes_[i].packet->length());
152 };
153
154 socket_data_.reset(new StaticSocketDataProvider(NULL, 0, mock_writes_.get(),
155 writes_.size()));
156
[email protected]e13201d82012-12-12 05:00:32157 MockUDPClientSocket* socket = new MockUDPClientSocket(socket_data_.get(),
158 net_log_.net_log());
159 socket->Connect(peer_addr_);
[email protected]f702d572012-12-04 15:56:20160 runner_ = new TestTaskRunner(&clock_);
161 scheduler_ = new MockScheduler();
[email protected]26f3f8e2012-12-13 21:07:19162 collector_ = new TestCollector(NULL);
[email protected]f702d572012-12-04 15:56:20163 EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
164 WillRepeatedly(testing::Return(QuicTime::Delta()));
[email protected]e13201d82012-12-12 05:00:32165 helper_ = new QuicConnectionHelper(runner_.get(), &clock_, socket);
166 connection_ = new TestQuicConnection(guid_, peer_addr_, helper_);
[email protected]f702d572012-12-04 15:56:20167 connection_->set_visitor(&visitor_);
168 connection_->SetScheduler(scheduler_);
[email protected]26f3f8e2012-12-13 21:07:19169 connection_->SetCollector(collector_);
[email protected]e13201d82012-12-12 05:00:32170 session_.reset(new QuicClientSession(connection_, helper_, NULL));
[email protected]f702d572012-12-04 15:56:20171 CryptoHandshakeMessage message;
172 message.tag = kSHLO;
173 session_->GetCryptoStream()->OnHandshakeMessage(message);
174 EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
175 stream_.reset(new QuicHttpStream(session_->CreateOutgoingReliableStream()));
176 }
177
178 // Returns a newly created packet to send kData on stream 1.
179 QuicEncryptedPacket* ConstructDataPacket(
180 QuicPacketSequenceNumber sequence_number,
181 bool fin,
182 QuicStreamOffset offset,
183 base::StringPiece data) {
184 InitializeHeader(sequence_number);
185 QuicStreamFrame frame(3, fin, offset, data);
186 return ConstructPacket(header_, QuicFrame(&frame));
187 }
188
189 // Returns a newly created packet to send ack data.
190 QuicEncryptedPacket* ConstructAckPacket(
191 QuicPacketSequenceNumber sequence_number,
[email protected]e537f742012-12-07 15:33:53192 QuicPacketSequenceNumber largest_received) {
[email protected]f702d572012-12-04 15:56:20193 InitializeHeader(sequence_number);
194
[email protected]e537f742012-12-07 15:33:53195 QuicAckFrame ack(largest_received, QuicTime(), sequence_number);
[email protected]e537f742012-12-07 15:33:53196 // TODO(rch): remove this grotty hack once we move the packet times
197 // out of the ack frame.
198 if (sequence_number == 4) {
199 ack.received_info.ClearAckTimes();
200 ack.received_info.received_packet_times[3] = QuicTime();
201 }
[email protected]f702d572012-12-04 15:56:20202
203 return ConstructPacket(header_, QuicFrame(&ack));
204 }
205
[email protected]f702d572012-12-04 15:56:20206 BoundNetLog net_log_;
207 MockScheduler* scheduler_;
[email protected]26f3f8e2012-12-13 21:07:19208 TestCollector* collector_;
[email protected]f702d572012-12-04 15:56:20209 scoped_refptr<TestTaskRunner> runner_;
210 scoped_array<MockWrite> mock_writes_;
211 MockClock clock_;
212 TestQuicConnection* connection_;
[email protected]e13201d82012-12-12 05:00:32213 QuicConnectionHelper* helper_;
[email protected]f702d572012-12-04 15:56:20214 testing::StrictMock<MockConnectionVisitor> visitor_;
215 scoped_ptr<QuicHttpStream> stream_;
216 scoped_ptr<QuicClientSession> session_;
217 TestCompletionCallback callback_;
218 HttpRequestInfo request_;
219 HttpRequestHeaders headers_;
220 HttpResponseInfo response_;
221 scoped_refptr<IOBufferWithSize> read_buffer_;
222
223 private:
224 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
225 header_.guid = guid_;
226 header_.packet_sequence_number = sequence_number;
227 header_.flags = PACKET_FLAGS_NONE;
228 header_.fec_group = 0;
229 }
230
231 QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header,
232 const QuicFrame& frame) {
233 QuicFrames frames;
234 frames.push_back(frame);
235 QuicPacket* packet;
236 framer_.ConstructFrameDataPacket(header_, frames, &packet);
237 QuicEncryptedPacket* encrypted = framer_.EncryptPacket(*packet);
238 delete packet;
239 return encrypted;
240 }
241
242 const QuicGuid guid_;
243 QuicFramer framer_;
244 IPEndPoint self_addr_;
245 IPEndPoint peer_addr_;
246 QuicPacketCreator creator_;
247 QuicPacketHeader header_;
[email protected]f702d572012-12-04 15:56:20248 scoped_ptr<StaticSocketDataProvider> socket_data_;
249 std::vector<PacketToWrite> writes_;
250};
251
252TEST_F(QuicHttpStreamTest, RenewStreamForAuth) {
253 EXPECT_EQ(NULL, stream_->RenewStreamForAuth());
254}
255
256TEST_F(QuicHttpStreamTest, CanFindEndOfResponse) {
257 EXPECT_TRUE(stream_->CanFindEndOfResponse());
258}
259
260TEST_F(QuicHttpStreamTest, IsMoreDataBuffered) {
261 EXPECT_FALSE(stream_->IsMoreDataBuffered());
262}
263
264TEST_F(QuicHttpStreamTest, IsConnectionReusable) {
265 EXPECT_FALSE(stream_->IsConnectionReusable());
266}
267
268TEST_F(QuicHttpStreamTest, GetRequest) {
269 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
270 "GET / HTTP/1.1\r\n\r\n"));
[email protected]e537f742012-12-07 15:33:53271 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2));
[email protected]f702d572012-12-04 15:56:20272 Initialize();
273
274 request_.method = "GET";
275 request_.url = GURL("http://www.google.com/");
276
277 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
278 callback_.callback()));
279 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
280 callback_.callback()));
281 EXPECT_EQ(&response_, stream_->GetResponseInfo());
282
283 // Ack the request.
[email protected]e537f742012-12-07 15:33:53284 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1));
[email protected]f702d572012-12-04 15:56:20285 ProcessPacket(*ack);
286
287 EXPECT_EQ(ERR_IO_PENDING,
288 stream_->ReadResponseHeaders(callback_.callback()));
289
290 // Send the response without a body.
291 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
292 "Content-Type: text/plain\r\n\r\n";
293 scoped_ptr<QuicEncryptedPacket> resp(
294 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
295 ProcessPacket(*resp);
296
297 // Now that the headers have been processed, the callback will return.
298 EXPECT_EQ(OK, callback_.WaitForResult());
299 ASSERT_TRUE(response_.headers != NULL);
300 EXPECT_EQ(404, response_.headers->response_code());
301 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
302
303 // There is no body, so this should return immediately.
304 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(),
305 read_buffer_->size(),
306 callback_.callback()));
307 EXPECT_TRUE(stream_->IsResponseBodyComplete());
308 EXPECT_TRUE(AtEof());
309}
310
311TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
312 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
313 "GET / HTTP/1.1\r\n\r\n"));
[email protected]e537f742012-12-07 15:33:53314 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2));
[email protected]f702d572012-12-04 15:56:20315 Initialize();
316
317 request_.method = "GET";
318 request_.url = GURL("http://www.google.com/");
319
320 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
321 callback_.callback()));
322 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
323 callback_.callback()));
324 EXPECT_EQ(&response_, stream_->GetResponseInfo());
325
326 // Ack the request.
[email protected]e537f742012-12-07 15:33:53327 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1));
[email protected]f702d572012-12-04 15:56:20328 ProcessPacket(*ack);
329
330 EXPECT_EQ(ERR_IO_PENDING,
331 stream_->ReadResponseHeaders(callback_.callback()));
332
333 // Send the response with a body.
334 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
335 "Content-Type: text/plain\r\n\r\nhello world!";
336 scoped_ptr<QuicEncryptedPacket> resp(
337 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
338 ProcessPacket(*resp);
339
340 // Now that the headers have been processed, the callback will return.
341 EXPECT_EQ(OK, callback_.WaitForResult());
342 ASSERT_TRUE(response_.headers != NULL);
343 EXPECT_EQ(404, response_.headers->response_code());
344 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
345
346 // There is no body, so this should return immediately.
347 // Since the body has already arrived, this should return immediately.
348 EXPECT_EQ(12, stream_->ReadResponseBody(read_buffer_.get(),
349 read_buffer_->size(),
350 callback_.callback()));
351 EXPECT_TRUE(stream_->IsResponseBodyComplete());
352 EXPECT_TRUE(AtEof());
353}
354
355TEST_F(QuicHttpStreamTest, SendPostRequest) {
356 const char kRequestData[] = "POST / HTTP/1.1\r\n\r\n";
357 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kNoFin, 0, kRequestData));
358 AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, strlen(kRequestData),
359 kUploadData));
[email protected]e537f742012-12-07 15:33:53360 AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2));
361 AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 3));
[email protected]f702d572012-12-04 15:56:20362
363 Initialize();
364
[email protected]b2d26cfd2012-12-11 10:36:06365 ScopedVector<UploadElementReader> element_readers;
366 element_readers.push_back(
367 new UploadBytesElementReader(kUploadData, strlen(kUploadData)));
368 UploadDataStream upload_data_stream(&element_readers, 0);
[email protected]f702d572012-12-04 15:56:20369 request_.method = "POST";
370 request_.url = GURL("http://www.google.com/");
371 request_.upload_data_stream = &upload_data_stream;
372 ASSERT_EQ(OK, request_.upload_data_stream->InitSync());
373
374 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
375 callback_.callback()));
376 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
377 callback_.callback()));
378 EXPECT_EQ(&response_, stream_->GetResponseInfo());
379
380 // Ack both packets in the request.
[email protected]e537f742012-12-07 15:33:53381 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 2));
[email protected]f702d572012-12-04 15:56:20382 ProcessPacket(*ack);
383
384 // Send the response headers (but not the body).
385 const char kResponseHeaders[] = "HTTP/1.1 200 OK\r\n"
386 "Content-Type: text/plain\r\n\r\n";
387 scoped_ptr<QuicEncryptedPacket> resp(
388 ConstructDataPacket(2, kNoFin, 0, kResponseHeaders));
389 ProcessPacket(*resp);
390
391 // Since the headers have already arrived, this should return immediately.
392 EXPECT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback()));
393 ASSERT_TRUE(response_.headers != NULL);
394 EXPECT_EQ(200, response_.headers->response_code());
395 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
396
397 // Send the response body.
398 const char kResponseBody[] = "Hello world!";
399 scoped_ptr<QuicEncryptedPacket> resp_body(
400 ConstructDataPacket(3, kFin, strlen(kResponseHeaders), kResponseBody));
401 ProcessPacket(*resp_body);
402
403 // Since the body has already arrived, this should return immediately.
404 EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
405 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
406 callback_.callback()));
407
408 EXPECT_TRUE(stream_->IsResponseBodyComplete());
409 EXPECT_TRUE(AtEof());
410}
411
412} // namespace test
413
414} // namespace net