Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Side by Side Diff: net/quic/quic_http_stream_test.cc

Issue 11364068: Add a QuicHttpStream class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: NET_EXPORT_PRIVATE Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/quic/quic_http_stream.cc ('k') | net/quic/quic_protocol.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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"
11 #include "net/base/upload_data.h"
12 #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
24 using testing::_;
25
26 namespace net {
27
28 class QuicConnectionPeer {
29 public:
30 static void SetScheduler(QuicConnection* connection,
31 QuicSendScheduler* scheduler) {
32 connection->scheduler_.reset(scheduler);
33 }
34 };
35
36 namespace test {
37
38 namespace {
39
40 const char kUploadData[] = "hello world!";
41
42 class TestQuicConnection : public QuicConnection {
43 public:
44 TestQuicConnection(QuicGuid guid,
45 IPEndPoint address,
46 QuicConnectionHelper* helper)
47 : QuicConnection(guid, address, helper) {
48 }
49
50 void SetScheduler(QuicSendScheduler* scheduler) {
51 QuicConnectionPeer::SetScheduler(this, scheduler);
52 }
53 };
54
55 } // namespace
56
57 class QuicHttpStreamTest : public ::testing::Test {
58 protected:
59 const static bool kFin = true;
60 const static bool kNoFin = false;
61 // Holds a packet to be written to the wire, and the IO mode that should
62 // be used by the mock socket when performing the write.
63 struct PacketToWrite {
64 PacketToWrite(IoMode mode, QuicEncryptedPacket* packet)
65 : mode(mode),
66 packet(packet) {
67 }
68 IoMode mode;
69 QuicEncryptedPacket* packet;
70 };
71
72 QuicHttpStreamTest()
73 : net_log_(BoundNetLog()),
74 read_buffer_(new IOBufferWithSize(4096)),
75 guid_(2),
76 framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
77 creator_(guid_, &framer_) {
78 IPAddressNumber ip;
79 CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
80 peer_addr_ = IPEndPoint(ip, 443);
81 self_addr_ = IPEndPoint(ip, 8435);
82 // Do null initialization for simple tests.
83 Initialize();
84 }
85
86 ~QuicHttpStreamTest() {
87 for (size_t i = 0; i < writes_.size(); i++) {
88 delete writes_[i].packet;
89 }
90 }
91
92 // Adds a packet to the list of expected writes.
93 void AddWrite(IoMode mode, QuicEncryptedPacket* packet) {
94 writes_.push_back(PacketToWrite(mode, packet));
95 }
96
97 // Returns the packet to be written at position |pos|.
98 QuicEncryptedPacket* GetWrite(size_t pos) {
99 return writes_[pos].packet;
100 }
101
102 bool AtEof() {
103 return socket_data_->at_read_eof() && socket_data_->at_write_eof();
104 }
105
106 void ProcessPacket(const QuicEncryptedPacket& packet) {
107 connection_->ProcessUdpPacket(self_addr_, peer_addr_, packet);
108 }
109
110 // Configures the test fixture to use the list of expected writes.
111 void Initialize() {
112 mock_writes_.reset(new MockWrite[writes_.size()]);
113 for (size_t i = 0; i < writes_.size(); i++) {
114 mock_writes_[i] = MockWrite(writes_[i].mode,
115 writes_[i].packet->data(),
116 writes_[i].packet->length());
117 };
118
119 socket_data_.reset(new StaticSocketDataProvider(NULL, 0, mock_writes_.get(),
120 writes_.size()));
121
122 socket_.reset(new MockUDPClientSocket(socket_data_.get(),
123 net_log_.net_log()));
124 socket_->Connect(peer_addr_);
125 runner_ = new TestTaskRunner(&clock_);
126 scheduler_ = new MockScheduler();
127 EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
128 WillRepeatedly(testing::Return(QuicTime::Delta()));
129 connection_ = new TestQuicConnection(
130 guid_, peer_addr_, new QuicConnectionHelper(
131 runner_.get(), &clock_, socket_.get()));
132 connection_->set_visitor(&visitor_);
133 connection_->SetScheduler(scheduler_);
134 session_.reset(new QuicClientSession(connection_));
135 CryptoHandshakeMessage message;
136 message.tag = kSHLO;
137 session_->GetCryptoStream()->OnHandshakeMessage(message);
138 EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
139 stream_.reset(new QuicHttpStream(session_->CreateOutgoingReliableStream()));
140 }
141
142 // Returns a newly created packet to send kData on stream 1.
143 QuicEncryptedPacket* ConstructDataPacket(
144 QuicPacketSequenceNumber sequence_number,
145 bool fin,
146 QuicStreamOffset offset,
147 base::StringPiece data) {
148 InitializeHeader(sequence_number);
149 QuicStreamFrame frame(3, fin, offset, data);
150 return ConstructPacket(header_, QuicFrame(&frame));
151 }
152
153 // Returns a newly created packet to send ack data.
154 QuicEncryptedPacket* ConstructAckPacket(
155 QuicPacketSequenceNumber sequence_number,
156 QuicPacketSequenceNumber largest_received,
157 QuicPacketSequenceNumber least_unacked) {
158 InitializeHeader(sequence_number);
159
160 QuicAckFrame ack(largest_received, QuicTime(), least_unacked);
161 ack.congestion_info.type = kFixRate;
162 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
163
164 return ConstructPacket(header_, QuicFrame(&ack));
165 }
166
167 // Returns a newly created packet to send a connection close frame.
168 QuicEncryptedPacket* ConstructClosePacket(
169 QuicPacketSequenceNumber sequence_number,
170 bool with_congestion_info) {
171 InitializeHeader(sequence_number);
172
173 QuicFrames frames;
174 QuicAckFrame ack(0, QuicTime(), 0);
175 if (with_congestion_info) {
176 ack.congestion_info.type = kFixRate;
177 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
178 } else {
179 ack.congestion_info.type = kNone;
180 }
181 QuicConnectionCloseFrame close;
182 close.error_code = QUIC_CONNECTION_TIMED_OUT;
183 close.ack_frame = ack;
184
185 return ConstructPacket(header_, QuicFrame(&close));
186 }
187
188 BoundNetLog net_log_;
189 MockScheduler* scheduler_;
190 scoped_refptr<TestTaskRunner> runner_;
191 scoped_array<MockWrite> mock_writes_;
192 MockClock clock_;
193 TestQuicConnection* connection_;
194 testing::StrictMock<MockConnectionVisitor> visitor_;
195 scoped_ptr<QuicHttpStream> stream_;
196 scoped_ptr<QuicClientSession> session_;
197 TestCompletionCallback callback_;
198 HttpRequestInfo request_;
199 HttpRequestHeaders headers_;
200 HttpResponseInfo response_;
201 scoped_refptr<IOBufferWithSize> read_buffer_;
202
203 private:
204 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
205 header_.guid = guid_;
206 header_.packet_sequence_number = sequence_number;
207 header_.flags = PACKET_FLAGS_NONE;
208 header_.fec_group = 0;
209 }
210
211 QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header,
212 const QuicFrame& frame) {
213 QuicFrames frames;
214 frames.push_back(frame);
215 QuicPacket* packet;
216 framer_.ConstructFrameDataPacket(header_, frames, &packet);
217 QuicEncryptedPacket* encrypted = framer_.EncryptPacket(*packet);
218 delete packet;
219 return encrypted;
220 }
221
222 const QuicGuid guid_;
223 QuicFramer framer_;
224 IPEndPoint self_addr_;
225 IPEndPoint peer_addr_;
226 QuicPacketCreator creator_;
227 QuicPacketHeader header_;
228 scoped_ptr<MockUDPClientSocket> socket_;
229 scoped_ptr<StaticSocketDataProvider> socket_data_;
230 std::vector<PacketToWrite> writes_;
231 };
232
233 TEST_F(QuicHttpStreamTest, RenewStreamForAuth) {
234 EXPECT_EQ(NULL, stream_->RenewStreamForAuth());
235 }
236
237 TEST_F(QuicHttpStreamTest, CanFindEndOfResponse) {
238 EXPECT_TRUE(stream_->CanFindEndOfResponse());
239 }
240
241 TEST_F(QuicHttpStreamTest, IsMoreDataBuffered) {
242 EXPECT_FALSE(stream_->IsMoreDataBuffered());
243 }
244
245 TEST_F(QuicHttpStreamTest, IsConnectionReusable) {
246 EXPECT_FALSE(stream_->IsConnectionReusable());
247 }
248
249 TEST_F(QuicHttpStreamTest, GetRequest) {
250 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
251 "GET / HTTP/1.1\r\n\r\n"));
252 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 0));
253 Initialize();
254
255 request_.method = "GET";
256 request_.url = GURL("http://www.google.com/");
257
258 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
259 callback_.callback()));
260 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
261 callback_.callback()));
262 EXPECT_EQ(&response_, stream_->GetResponseInfo());
263
264 // Ack the request.
265 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1, 0));
266 ProcessPacket(*ack);
267
268 EXPECT_EQ(ERR_IO_PENDING,
269 stream_->ReadResponseHeaders(callback_.callback()));
270
271 // Send the response without a body.
272 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
273 "Content-Type: text/plain\r\n\r\n";
274 scoped_ptr<QuicEncryptedPacket> resp(
275 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
276 ProcessPacket(*resp);
277
278 // Now that the headers have been processed, the callback will return.
279 EXPECT_EQ(OK, callback_.WaitForResult());
280 ASSERT_TRUE(response_.headers != NULL);
281 EXPECT_EQ(404, response_.headers->response_code());
282 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
283
284 // There is no body, so this should return immediately.
285 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(),
286 read_buffer_->size(),
287 callback_.callback()));
288 EXPECT_TRUE(stream_->IsResponseBodyComplete());
289 EXPECT_TRUE(AtEof());
290 }
291
292 TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
293 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
294 "GET / HTTP/1.1\r\n\r\n"));
295 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 0));
296 Initialize();
297
298 request_.method = "GET";
299 request_.url = GURL("http://www.google.com/");
300
301 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
302 callback_.callback()));
303 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
304 callback_.callback()));
305 EXPECT_EQ(&response_, stream_->GetResponseInfo());
306
307 // Ack the request.
308 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1, 0));
309 ProcessPacket(*ack);
310
311 EXPECT_EQ(ERR_IO_PENDING,
312 stream_->ReadResponseHeaders(callback_.callback()));
313
314 // Send the response with a body.
315 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
316 "Content-Type: text/plain\r\n\r\nhello world!";
317 scoped_ptr<QuicEncryptedPacket> resp(
318 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
319 ProcessPacket(*resp);
320
321 // Now that the headers have been processed, the callback will return.
322 EXPECT_EQ(OK, callback_.WaitForResult());
323 ASSERT_TRUE(response_.headers != NULL);
324 EXPECT_EQ(404, response_.headers->response_code());
325 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
326
327 // There is no body, so this should return immediately.
328 // Since the body has already arrived, this should return immediately.
329 EXPECT_EQ(12, stream_->ReadResponseBody(read_buffer_.get(),
330 read_buffer_->size(),
331 callback_.callback()));
332 EXPECT_TRUE(stream_->IsResponseBodyComplete());
333 EXPECT_TRUE(AtEof());
334 }
335
336 TEST_F(QuicHttpStreamTest, SendPostRequest) {
337 const char kRequestData[] = "POST / HTTP/1.1\r\n\r\n";
338 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kNoFin, 0, kRequestData));
339 AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, strlen(kRequestData),
340 kUploadData));
341 AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 0));
342 AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 3, 0));
343
344 Initialize();
345
346 UploadData* upload_data = new UploadData();
347 upload_data->AppendBytes(kUploadData, strlen(kUploadData));
348 UploadDataStream upload_data_stream(upload_data);
349 request_.method = "POST";
350 request_.url = GURL("http://www.google.com/");
351 request_.upload_data_stream = &upload_data_stream;
352 ASSERT_EQ(OK, request_.upload_data_stream->InitSync());
353
354 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
355 callback_.callback()));
356 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
357 callback_.callback()));
358 EXPECT_EQ(&response_, stream_->GetResponseInfo());
359
360 // Ack both packets in the request.
361 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 2, 1));
362 ProcessPacket(*ack);
363
364 // Send the response headers (but not the body).
365 const char kResponseHeaders[] = "HTTP/1.1 200 OK\r\n"
366 "Content-Type: text/plain\r\n\r\n";
367 scoped_ptr<QuicEncryptedPacket> resp(
368 ConstructDataPacket(2, kNoFin, 0, kResponseHeaders));
369 ProcessPacket(*resp);
370
371 // Since the headers have already arrived, this should return immediately.
372 EXPECT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback()));
373 ASSERT_TRUE(response_.headers != NULL);
374 EXPECT_EQ(200, response_.headers->response_code());
375 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
376
377 // Send the response body.
378 const char kResponseBody[] = "Hello world!";
379 scoped_ptr<QuicEncryptedPacket> resp_body(
380 ConstructDataPacket(3, kFin, strlen(kResponseHeaders), kResponseBody));
381 ProcessPacket(*resp_body);
382
383 // Since the body has already arrived, this should return immediately.
384 EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
385 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
386 callback_.callback()));
387
388 EXPECT_TRUE(stream_->IsResponseBodyComplete());
389 EXPECT_TRUE(AtEof());
390 }
391
392 } // namespace test
393
394 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_http_stream.cc ('k') | net/quic/quic_protocol.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698