OLD | NEW |
| (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/chunked_upload_data_stream.h" | |
10 #include "net/base/elements_upload_data_stream.h" | |
11 #include "net/base/net_errors.h" | |
12 #include "net/base/test_completion_callback.h" | |
13 #include "net/base/upload_bytes_element_reader.h" | |
14 #include "net/http/http_response_headers.h" | |
15 #include "net/http/transport_security_state.h" | |
16 #include "net/quic/congestion_control/send_algorithm_interface.h" | |
17 #include "net/quic/crypto/crypto_protocol.h" | |
18 #include "net/quic/crypto/quic_decrypter.h" | |
19 #include "net/quic/crypto/quic_encrypter.h" | |
20 #include "net/quic/crypto/quic_server_info.h" | |
21 #include "net/quic/quic_client_session.h" | |
22 #include "net/quic/quic_connection.h" | |
23 #include "net/quic/quic_connection_helper.h" | |
24 #include "net/quic/quic_default_packet_writer.h" | |
25 #include "net/quic/quic_http_utils.h" | |
26 #include "net/quic/quic_reliable_client_stream.h" | |
27 #include "net/quic/quic_write_blocked_list.h" | |
28 #include "net/quic/spdy_utils.h" | |
29 #include "net/quic/test_tools/mock_clock.h" | |
30 #include "net/quic/test_tools/mock_crypto_client_stream_factory.h" | |
31 #include "net/quic/test_tools/mock_random.h" | |
32 #include "net/quic/test_tools/quic_connection_peer.h" | |
33 #include "net/quic/test_tools/quic_test_packet_maker.h" | |
34 #include "net/quic/test_tools/quic_test_utils.h" | |
35 #include "net/quic/test_tools/test_task_runner.h" | |
36 #include "net/socket/socket_test_util.h" | |
37 #include "net/spdy/spdy_frame_builder.h" | |
38 #include "net/spdy/spdy_framer.h" | |
39 #include "net/spdy/spdy_http_utils.h" | |
40 #include "net/spdy/spdy_protocol.h" | |
41 #include "testing/gmock/include/gmock/gmock.h" | |
42 #include "testing/gtest/include/gtest/gtest.h" | |
43 | |
44 using testing::_; | |
45 using testing::AnyNumber; | |
46 using testing::Return; | |
47 | |
48 namespace net { | |
49 namespace test { | |
50 namespace { | |
51 | |
52 const char kUploadData[] = "Really nifty data!"; | |
53 const char kServerHostname[] = "www.google.com"; | |
54 const uint16 kServerPort = 80; | |
55 | |
56 class TestQuicConnection : public QuicConnection { | |
57 public: | |
58 TestQuicConnection(const QuicVersionVector& versions, | |
59 QuicConnectionId connection_id, | |
60 IPEndPoint address, | |
61 QuicConnectionHelper* helper, | |
62 const QuicConnection::PacketWriterFactory& writer_factory) | |
63 : QuicConnection(connection_id, | |
64 address, | |
65 helper, | |
66 writer_factory, | |
67 true /* owns_writer */, | |
68 false /* is_server */, | |
69 false /* is_secure */, | |
70 versions) { | |
71 } | |
72 | |
73 void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { | |
74 QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); | |
75 } | |
76 }; | |
77 | |
78 // Subclass of QuicHttpStream that closes itself when the first piece of data | |
79 // is received. | |
80 class AutoClosingStream : public QuicHttpStream { | |
81 public: | |
82 explicit AutoClosingStream(const base::WeakPtr<QuicClientSession>& session) | |
83 : QuicHttpStream(session) { | |
84 } | |
85 | |
86 int OnDataReceived(const char* data, int length) override { | |
87 Close(false); | |
88 return OK; | |
89 } | |
90 }; | |
91 | |
92 class TestPacketWriterFactory : public QuicConnection::PacketWriterFactory { | |
93 public: | |
94 explicit TestPacketWriterFactory(DatagramClientSocket* socket) | |
95 : socket_(socket) {} | |
96 ~TestPacketWriterFactory() override {} | |
97 | |
98 QuicPacketWriter* Create(QuicConnection* connection) const override { | |
99 return new QuicDefaultPacketWriter(socket_); | |
100 } | |
101 | |
102 private: | |
103 DatagramClientSocket* socket_; | |
104 }; | |
105 | |
106 } // namespace | |
107 | |
108 class QuicHttpStreamPeer { | |
109 public: | |
110 static QuicReliableClientStream* GetQuicReliableClientStream( | |
111 QuicHttpStream* stream) { | |
112 return stream->stream_; | |
113 } | |
114 }; | |
115 | |
116 class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { | |
117 protected: | |
118 static const bool kFin = true; | |
119 static const bool kIncludeVersion = true; | |
120 static const bool kIncludeCongestionFeedback = true; | |
121 | |
122 // Holds a packet to be written to the wire, and the IO mode that should | |
123 // be used by the mock socket when performing the write. | |
124 struct PacketToWrite { | |
125 PacketToWrite(IoMode mode, QuicEncryptedPacket* packet) | |
126 : mode(mode), | |
127 packet(packet) { | |
128 } | |
129 IoMode mode; | |
130 QuicEncryptedPacket* packet; | |
131 }; | |
132 | |
133 QuicHttpStreamTest() | |
134 : net_log_(BoundNetLog()), | |
135 use_closing_stream_(false), | |
136 read_buffer_(new IOBufferWithSize(4096)), | |
137 connection_id_(2), | |
138 stream_id_(kClientDataStreamId1), | |
139 maker_(GetParam(), connection_id_, &clock_), | |
140 random_generator_(0) { | |
141 IPAddressNumber ip; | |
142 CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); | |
143 peer_addr_ = IPEndPoint(ip, 443); | |
144 self_addr_ = IPEndPoint(ip, 8435); | |
145 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); | |
146 } | |
147 | |
148 ~QuicHttpStreamTest() { | |
149 session_->CloseSessionOnError(ERR_ABORTED); | |
150 for (size_t i = 0; i < writes_.size(); i++) { | |
151 delete writes_[i].packet; | |
152 } | |
153 } | |
154 | |
155 // Adds a packet to the list of expected writes. | |
156 void AddWrite(scoped_ptr<QuicEncryptedPacket> packet) { | |
157 writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release())); | |
158 } | |
159 | |
160 // Returns the packet to be written at position |pos|. | |
161 QuicEncryptedPacket* GetWrite(size_t pos) { | |
162 return writes_[pos].packet; | |
163 } | |
164 | |
165 bool AtEof() { | |
166 return socket_data_->at_read_eof() && socket_data_->at_write_eof(); | |
167 } | |
168 | |
169 void ProcessPacket(scoped_ptr<QuicEncryptedPacket> packet) { | |
170 connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet); | |
171 } | |
172 | |
173 // Configures the test fixture to use the list of expected writes. | |
174 void Initialize() { | |
175 mock_writes_.reset(new MockWrite[writes_.size()]); | |
176 for (size_t i = 0; i < writes_.size(); i++) { | |
177 mock_writes_[i] = MockWrite(writes_[i].mode, | |
178 writes_[i].packet->data(), | |
179 writes_[i].packet->length()); | |
180 }; | |
181 | |
182 socket_data_.reset(new StaticSocketDataProvider( | |
183 nullptr, 0, mock_writes_.get(), writes_.size())); | |
184 | |
185 MockUDPClientSocket* socket = new MockUDPClientSocket(socket_data_.get(), | |
186 net_log_.net_log()); | |
187 socket->Connect(peer_addr_); | |
188 runner_ = new TestTaskRunner(&clock_); | |
189 send_algorithm_ = new MockSendAlgorithm(); | |
190 EXPECT_CALL(*send_algorithm_, | |
191 OnPacketSent(_, _, _, _, _)).WillRepeatedly(Return(true)); | |
192 EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( | |
193 Return(QuicTime::Delta::Zero())); | |
194 EXPECT_CALL(*send_algorithm_, GetCongestionWindow()).WillRepeatedly( | |
195 Return(kMaxPacketSize)); | |
196 EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)). | |
197 WillRepeatedly(Return(QuicTime::Delta::Zero())); | |
198 EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly( | |
199 Return(QuicBandwidth::Zero())); | |
200 EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber()); | |
201 helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_, | |
202 &random_generator_)); | |
203 TestPacketWriterFactory writer_factory(socket); | |
204 connection_ = new TestQuicConnection(SupportedVersions(GetParam()), | |
205 connection_id_, peer_addr_, | |
206 helper_.get(), writer_factory); | |
207 connection_->set_visitor(&visitor_); | |
208 connection_->SetSendAlgorithm(send_algorithm_); | |
209 session_.reset( | |
210 new QuicClientSession(connection_, | |
211 scoped_ptr<DatagramClientSocket>(socket), | |
212 nullptr, | |
213 &transport_security_state_, | |
214 make_scoped_ptr((QuicServerInfo*)nullptr), | |
215 DefaultQuicConfig(), | |
216 base::MessageLoop::current()-> | |
217 message_loop_proxy().get(), | |
218 nullptr)); | |
219 session_->InitializeSession(QuicServerId(kServerHostname, kServerPort, | |
220 /*is_secure=*/false, | |
221 PRIVACY_MODE_DISABLED), | |
222 &crypto_config_, | |
223 &crypto_client_stream_factory_); | |
224 session_->GetCryptoStream()->CryptoConnect(); | |
225 EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed()); | |
226 stream_.reset(use_closing_stream_ ? | |
227 new AutoClosingStream(session_->GetWeakPtr()) : | |
228 new QuicHttpStream(session_->GetWeakPtr())); | |
229 } | |
230 | |
231 void SetRequest(const std::string& method, | |
232 const std::string& path, | |
233 RequestPriority priority) { | |
234 request_headers_ = maker_.GetRequestHeaders(method, "http", path); | |
235 } | |
236 | |
237 void SetResponse(const std::string& status, const std::string& body) { | |
238 response_headers_ = maker_.GetResponseHeaders(status); | |
239 response_data_ = body; | |
240 } | |
241 | |
242 scoped_ptr<QuicEncryptedPacket> ConstructDataPacket( | |
243 QuicPacketSequenceNumber sequence_number, | |
244 bool should_include_version, | |
245 bool fin, | |
246 QuicStreamOffset offset, | |
247 base::StringPiece data) { | |
248 return maker_.MakeDataPacket(sequence_number, stream_id_, | |
249 should_include_version, fin, offset, data); | |
250 } | |
251 | |
252 scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( | |
253 QuicPacketSequenceNumber sequence_number, | |
254 bool fin, | |
255 RequestPriority request_priority) { | |
256 QuicPriority priority = | |
257 ConvertRequestPriorityToQuicPriority(request_priority); | |
258 return maker_.MakeRequestHeadersPacket(sequence_number, stream_id_, | |
259 kIncludeVersion, fin, priority, | |
260 request_headers_); | |
261 } | |
262 | |
263 scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( | |
264 QuicPacketSequenceNumber sequence_number, | |
265 bool fin) { | |
266 return maker_.MakeResponseHeadersPacket( | |
267 sequence_number, stream_id_, !kIncludeVersion, fin, response_headers_); | |
268 } | |
269 | |
270 scoped_ptr<QuicEncryptedPacket> ConstructRstStreamPacket( | |
271 QuicPacketSequenceNumber sequence_number) { | |
272 return maker_.MakeRstPacket( | |
273 sequence_number, true, stream_id_, | |
274 AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam())); | |
275 } | |
276 | |
277 scoped_ptr<QuicEncryptedPacket> ConstructAckAndRstStreamPacket( | |
278 QuicPacketSequenceNumber sequence_number) { | |
279 return maker_.MakeAckAndRstPacket( | |
280 sequence_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED, | |
281 2, 1, !kIncludeCongestionFeedback); | |
282 } | |
283 | |
284 scoped_ptr<QuicEncryptedPacket> ConstructAckPacket( | |
285 QuicPacketSequenceNumber sequence_number, | |
286 QuicPacketSequenceNumber largest_received, | |
287 QuicPacketSequenceNumber least_unacked) { | |
288 return maker_.MakeAckPacket(sequence_number, largest_received, | |
289 least_unacked, !kIncludeCongestionFeedback); | |
290 } | |
291 | |
292 BoundNetLog net_log_; | |
293 bool use_closing_stream_; | |
294 MockSendAlgorithm* send_algorithm_; | |
295 scoped_refptr<TestTaskRunner> runner_; | |
296 scoped_ptr<MockWrite[]> mock_writes_; | |
297 MockClock clock_; | |
298 TestQuicConnection* connection_; | |
299 scoped_ptr<QuicConnectionHelper> helper_; | |
300 testing::StrictMock<MockConnectionVisitor> visitor_; | |
301 scoped_ptr<QuicHttpStream> stream_; | |
302 TransportSecurityState transport_security_state_; | |
303 scoped_ptr<QuicClientSession> session_; | |
304 QuicCryptoClientConfig crypto_config_; | |
305 TestCompletionCallback callback_; | |
306 HttpRequestInfo request_; | |
307 HttpRequestHeaders headers_; | |
308 HttpResponseInfo response_; | |
309 scoped_refptr<IOBufferWithSize> read_buffer_; | |
310 SpdyHeaderBlock request_headers_; | |
311 SpdyHeaderBlock response_headers_; | |
312 std::string request_data_; | |
313 std::string response_data_; | |
314 | |
315 private: | |
316 const QuicConnectionId connection_id_; | |
317 const QuicStreamId stream_id_; | |
318 QuicTestPacketMaker maker_; | |
319 IPEndPoint self_addr_; | |
320 IPEndPoint peer_addr_; | |
321 MockRandom random_generator_; | |
322 MockCryptoClientStreamFactory crypto_client_stream_factory_; | |
323 scoped_ptr<StaticSocketDataProvider> socket_data_; | |
324 std::vector<PacketToWrite> writes_; | |
325 }; | |
326 | |
327 INSTANTIATE_TEST_CASE_P(Version, QuicHttpStreamTest, | |
328 ::testing::ValuesIn(QuicSupportedVersions())); | |
329 | |
330 TEST_P(QuicHttpStreamTest, RenewStreamForAuth) { | |
331 Initialize(); | |
332 EXPECT_EQ(nullptr, stream_->RenewStreamForAuth()); | |
333 } | |
334 | |
335 TEST_P(QuicHttpStreamTest, CanFindEndOfResponse) { | |
336 Initialize(); | |
337 EXPECT_TRUE(stream_->CanFindEndOfResponse()); | |
338 } | |
339 | |
340 TEST_P(QuicHttpStreamTest, IsConnectionReusable) { | |
341 Initialize(); | |
342 EXPECT_FALSE(stream_->IsConnectionReusable()); | |
343 } | |
344 | |
345 TEST_P(QuicHttpStreamTest, GetRequest) { | |
346 SetRequest("GET", "/", DEFAULT_PRIORITY); | |
347 AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY)); | |
348 Initialize(); | |
349 | |
350 request_.method = "GET"; | |
351 request_.url = GURL("http://www.google.com/"); | |
352 | |
353 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
354 net_log_, callback_.callback())); | |
355 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
356 callback_.callback())); | |
357 | |
358 // Ack the request. | |
359 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
360 | |
361 EXPECT_EQ(ERR_IO_PENDING, | |
362 stream_->ReadResponseHeaders(callback_.callback())); | |
363 | |
364 SetResponse("404 Not Found", std::string()); | |
365 ProcessPacket(ConstructResponseHeadersPacket(2, kFin)); | |
366 | |
367 // Now that the headers have been processed, the callback will return. | |
368 EXPECT_EQ(OK, callback_.WaitForResult()); | |
369 ASSERT_TRUE(response_.headers.get()); | |
370 EXPECT_EQ(404, response_.headers->response_code()); | |
371 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
372 EXPECT_FALSE(response_.response_time.is_null()); | |
373 EXPECT_FALSE(response_.request_time.is_null()); | |
374 | |
375 // There is no body, so this should return immediately. | |
376 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(), | |
377 read_buffer_->size(), | |
378 callback_.callback())); | |
379 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
380 EXPECT_TRUE(AtEof()); | |
381 } | |
382 | |
383 // Regression test for http://crbug.com/288128 | |
384 TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) { | |
385 SetRequest("GET", "/", DEFAULT_PRIORITY); | |
386 AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY)); | |
387 Initialize(); | |
388 | |
389 request_.method = "GET"; | |
390 request_.url = GURL("http://www.google.com/"); | |
391 | |
392 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
393 net_log_, callback_.callback())); | |
394 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
395 callback_.callback())); | |
396 | |
397 // Ack the request. | |
398 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
399 | |
400 EXPECT_EQ(ERR_IO_PENDING, | |
401 stream_->ReadResponseHeaders(callback_.callback())); | |
402 | |
403 SpdyHeaderBlock headers; | |
404 headers[":status"] = "200 OK"; | |
405 headers[":version"] = "HTTP/1.1"; | |
406 headers["content-type"] = "text/plain"; | |
407 headers["big6"] = std::string(10000, 'x'); // Lots of x's. | |
408 | |
409 std::string response = SpdyUtils::SerializeUncompressedHeaders(headers); | |
410 EXPECT_LT(4096u, response.length()); | |
411 stream_->OnDataReceived(response.data(), response.length()); | |
412 stream_->OnClose(QUIC_NO_ERROR); | |
413 | |
414 // Now that the headers have been processed, the callback will return. | |
415 EXPECT_EQ(OK, callback_.WaitForResult()); | |
416 ASSERT_TRUE(response_.headers.get()); | |
417 EXPECT_EQ(200, response_.headers->response_code()); | |
418 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
419 | |
420 // There is no body, so this should return immediately. | |
421 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(), | |
422 read_buffer_->size(), | |
423 callback_.callback())); | |
424 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
425 EXPECT_TRUE(AtEof()); | |
426 } | |
427 | |
428 // Regression test for http://crbug.com/409101 | |
429 TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendRequest) { | |
430 SetRequest("GET", "/", DEFAULT_PRIORITY); | |
431 Initialize(); | |
432 | |
433 request_.method = "GET"; | |
434 request_.url = GURL("http://www.google.com/"); | |
435 | |
436 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
437 net_log_, callback_.callback())); | |
438 | |
439 session_->connection()->CloseConnection(QUIC_NO_ERROR, true); | |
440 | |
441 EXPECT_EQ(ERR_CONNECTION_CLOSED, | |
442 stream_->SendRequest(headers_, &response_, | |
443 callback_.callback())); | |
444 } | |
445 | |
446 // Regression test for http://crbug.com/409871 | |
447 TEST_P(QuicHttpStreamTest, SessionClosedBeforeReadResponseHeaders) { | |
448 SetRequest("GET", "/", DEFAULT_PRIORITY); | |
449 AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY)); | |
450 Initialize(); | |
451 | |
452 request_.method = "GET"; | |
453 request_.url = GURL("http://www.google.com/"); | |
454 | |
455 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
456 net_log_, callback_.callback())); | |
457 | |
458 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
459 callback_.callback())); | |
460 | |
461 session_->connection()->CloseConnection(QUIC_NO_ERROR, true); | |
462 | |
463 EXPECT_NE(OK, stream_->ReadResponseHeaders(callback_.callback())); | |
464 } | |
465 | |
466 TEST_P(QuicHttpStreamTest, SendPostRequest) { | |
467 SetRequest("POST", "/", DEFAULT_PRIORITY); | |
468 AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY)); | |
469 AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData)); | |
470 AddWrite(ConstructAckPacket(3, 3, 1)); | |
471 | |
472 Initialize(); | |
473 | |
474 ScopedVector<UploadElementReader> element_readers; | |
475 element_readers.push_back( | |
476 new UploadBytesElementReader(kUploadData, strlen(kUploadData))); | |
477 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
478 request_.method = "POST"; | |
479 request_.url = GURL("http://www.google.com/"); | |
480 request_.upload_data_stream = &upload_data_stream; | |
481 ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback())); | |
482 | |
483 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
484 net_log_, callback_.callback())); | |
485 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
486 callback_.callback())); | |
487 | |
488 // Ack both packets in the request. | |
489 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
490 | |
491 // Send the response headers (but not the body). | |
492 SetResponse("200 OK", std::string()); | |
493 ProcessPacket(ConstructResponseHeadersPacket(2, !kFin)); | |
494 | |
495 // Since the headers have already arrived, this should return immediately. | |
496 EXPECT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback())); | |
497 ASSERT_TRUE(response_.headers.get()); | |
498 EXPECT_EQ(200, response_.headers->response_code()); | |
499 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
500 | |
501 // Send the response body. | |
502 const char kResponseBody[] = "Hello world!"; | |
503 ProcessPacket(ConstructDataPacket(3, false, kFin, 0, kResponseBody)); | |
504 // Since the body has already arrived, this should return immediately. | |
505 EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), | |
506 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(), | |
507 callback_.callback())); | |
508 | |
509 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
510 EXPECT_TRUE(AtEof()); | |
511 } | |
512 | |
513 TEST_P(QuicHttpStreamTest, SendChunkedPostRequest) { | |
514 SetRequest("POST", "/", DEFAULT_PRIORITY); | |
515 size_t chunk_size = strlen(kUploadData); | |
516 AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY)); | |
517 AddWrite(ConstructDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData)); | |
518 AddWrite(ConstructDataPacket(3, kIncludeVersion, kFin, chunk_size, | |
519 kUploadData)); | |
520 AddWrite(ConstructAckPacket(4, 3, 1)); | |
521 Initialize(); | |
522 | |
523 ChunkedUploadDataStream upload_data_stream(0); | |
524 upload_data_stream.AppendData(kUploadData, chunk_size, false); | |
525 | |
526 request_.method = "POST"; | |
527 request_.url = GURL("http://www.google.com/"); | |
528 request_.upload_data_stream = &upload_data_stream; | |
529 ASSERT_EQ(OK, request_.upload_data_stream->Init( | |
530 TestCompletionCallback().callback())); | |
531 | |
532 ASSERT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
533 net_log_, callback_.callback())); | |
534 ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, | |
535 callback_.callback())); | |
536 | |
537 upload_data_stream.AppendData(kUploadData, chunk_size, true); | |
538 | |
539 // Ack both packets in the request. | |
540 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
541 | |
542 // Send the response headers (but not the body). | |
543 SetResponse("200 OK", std::string()); | |
544 ProcessPacket(ConstructResponseHeadersPacket(2, !kFin)); | |
545 | |
546 // Since the headers have already arrived, this should return immediately. | |
547 ASSERT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback())); | |
548 ASSERT_TRUE(response_.headers.get()); | |
549 EXPECT_EQ(200, response_.headers->response_code()); | |
550 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
551 | |
552 // Send the response body. | |
553 const char kResponseBody[] = "Hello world!"; | |
554 ProcessPacket(ConstructDataPacket(3, false, kFin, response_data_.length(), | |
555 kResponseBody)); | |
556 | |
557 // Since the body has already arrived, this should return immediately. | |
558 ASSERT_EQ(static_cast<int>(strlen(kResponseBody)), | |
559 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(), | |
560 callback_.callback())); | |
561 | |
562 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
563 EXPECT_TRUE(AtEof()); | |
564 } | |
565 | |
566 TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithFinalEmptyDataPacket) { | |
567 SetRequest("POST", "/", DEFAULT_PRIORITY); | |
568 size_t chunk_size = strlen(kUploadData); | |
569 AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY)); | |
570 AddWrite(ConstructDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData)); | |
571 AddWrite(ConstructDataPacket(3, kIncludeVersion, kFin, chunk_size, "")); | |
572 AddWrite(ConstructAckPacket(4, 3, 1)); | |
573 Initialize(); | |
574 | |
575 ChunkedUploadDataStream upload_data_stream(0); | |
576 upload_data_stream.AppendData(kUploadData, chunk_size, false); | |
577 | |
578 request_.method = "POST"; | |
579 request_.url = GURL("http://www.google.com/"); | |
580 request_.upload_data_stream = &upload_data_stream; | |
581 ASSERT_EQ(OK, request_.upload_data_stream->Init( | |
582 TestCompletionCallback().callback())); | |
583 | |
584 ASSERT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
585 net_log_, callback_.callback())); | |
586 ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, | |
587 callback_.callback())); | |
588 | |
589 upload_data_stream.AppendData(nullptr, 0, true); | |
590 | |
591 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
592 | |
593 // Send the response headers (but not the body). | |
594 SetResponse("200 OK", std::string()); | |
595 ProcessPacket(ConstructResponseHeadersPacket(2, !kFin)); | |
596 | |
597 // Since the headers have already arrived, this should return immediately. | |
598 ASSERT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback())); | |
599 ASSERT_TRUE(response_.headers.get()); | |
600 EXPECT_EQ(200, response_.headers->response_code()); | |
601 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
602 | |
603 // Send the response body. | |
604 const char kResponseBody[] = "Hello world!"; | |
605 ProcessPacket(ConstructDataPacket(3, false, kFin, response_data_.length(), | |
606 kResponseBody)); | |
607 | |
608 // Since the body has already arrived, this should return immediately. | |
609 ASSERT_EQ(static_cast<int>(strlen(kResponseBody)), | |
610 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(), | |
611 callback_.callback())); | |
612 | |
613 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
614 EXPECT_TRUE(AtEof()); | |
615 } | |
616 | |
617 TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithOneEmptyDataPacket) { | |
618 SetRequest("POST", "/", DEFAULT_PRIORITY); | |
619 AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY)); | |
620 AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, "")); | |
621 AddWrite(ConstructAckPacket(3, 3, 1)); | |
622 Initialize(); | |
623 | |
624 ChunkedUploadDataStream upload_data_stream(0); | |
625 | |
626 request_.method = "POST"; | |
627 request_.url = GURL("http://www.google.com/"); | |
628 request_.upload_data_stream = &upload_data_stream; | |
629 ASSERT_EQ(OK, request_.upload_data_stream->Init( | |
630 TestCompletionCallback().callback())); | |
631 | |
632 ASSERT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
633 net_log_, callback_.callback())); | |
634 ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, | |
635 callback_.callback())); | |
636 | |
637 upload_data_stream.AppendData(nullptr, 0, true); | |
638 | |
639 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
640 | |
641 // Send the response headers (but not the body). | |
642 SetResponse("200 OK", std::string()); | |
643 ProcessPacket(ConstructResponseHeadersPacket(2, !kFin)); | |
644 | |
645 // Since the headers have already arrived, this should return immediately. | |
646 ASSERT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback())); | |
647 ASSERT_TRUE(response_.headers.get()); | |
648 EXPECT_EQ(200, response_.headers->response_code()); | |
649 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); | |
650 | |
651 // Send the response body. | |
652 const char kResponseBody[] = "Hello world!"; | |
653 ProcessPacket(ConstructDataPacket(3, false, kFin, response_data_.length(), | |
654 kResponseBody)); | |
655 | |
656 // Since the body has already arrived, this should return immediately. | |
657 ASSERT_EQ(static_cast<int>(strlen(kResponseBody)), | |
658 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(), | |
659 callback_.callback())); | |
660 | |
661 EXPECT_TRUE(stream_->IsResponseBodyComplete()); | |
662 EXPECT_TRUE(AtEof()); | |
663 } | |
664 | |
665 TEST_P(QuicHttpStreamTest, DestroyedEarly) { | |
666 SetRequest("GET", "/", DEFAULT_PRIORITY); | |
667 AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY)); | |
668 AddWrite(ConstructAckAndRstStreamPacket(2)); | |
669 use_closing_stream_ = true; | |
670 Initialize(); | |
671 | |
672 request_.method = "GET"; | |
673 request_.url = GURL("http://www.google.com/"); | |
674 | |
675 EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, | |
676 net_log_, callback_.callback())); | |
677 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
678 callback_.callback())); | |
679 | |
680 // Ack the request. | |
681 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
682 EXPECT_EQ(ERR_IO_PENDING, | |
683 stream_->ReadResponseHeaders(callback_.callback())); | |
684 | |
685 // Send the response with a body. | |
686 SetResponse("404 OK", "hello world!"); | |
687 // In the course of processing this packet, the QuicHttpStream close itself. | |
688 ProcessPacket(ConstructResponseHeadersPacket(2, kFin)); | |
689 | |
690 EXPECT_TRUE(AtEof()); | |
691 } | |
692 | |
693 TEST_P(QuicHttpStreamTest, Priority) { | |
694 SetRequest("GET", "/", MEDIUM); | |
695 AddWrite(ConstructRequestHeadersPacket(1, kFin, MEDIUM)); | |
696 AddWrite(ConstructAckAndRstStreamPacket(2)); | |
697 use_closing_stream_ = true; | |
698 Initialize(); | |
699 | |
700 request_.method = "GET"; | |
701 request_.url = GURL("http://www.google.com/"); | |
702 | |
703 EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, | |
704 net_log_, callback_.callback())); | |
705 | |
706 // Check that priority is highest. | |
707 QuicReliableClientStream* reliable_stream = | |
708 QuicHttpStreamPeer::GetQuicReliableClientStream(stream_.get()); | |
709 DCHECK(reliable_stream); | |
710 DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, | |
711 reliable_stream->EffectivePriority()); | |
712 | |
713 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, | |
714 callback_.callback())); | |
715 | |
716 // Check that priority has now dropped back to MEDIUM. | |
717 DCHECK_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority( | |
718 reliable_stream->EffectivePriority())); | |
719 | |
720 // Ack the request. | |
721 ProcessPacket(ConstructAckPacket(1, 0, 0)); | |
722 EXPECT_EQ(ERR_IO_PENDING, | |
723 stream_->ReadResponseHeaders(callback_.callback())); | |
724 | |
725 // Send the response with a body. | |
726 SetResponse("404 OK", "hello world!"); | |
727 // In the course of processing this packet, the QuicHttpStream close itself. | |
728 ProcessPacket(ConstructResponseHeadersPacket(2, kFin)); | |
729 | |
730 EXPECT_TRUE(AtEof()); | |
731 } | |
732 | |
733 // Regression test for http://crbug.com/294870 | |
734 TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) { | |
735 SetRequest("GET", "/", MEDIUM); | |
736 use_closing_stream_ = true; | |
737 | |
738 AddWrite(ConstructRstStreamPacket(1)); | |
739 | |
740 Initialize(); | |
741 | |
742 request_.method = "GET"; | |
743 request_.url = GURL("http://www.google.com/"); | |
744 | |
745 EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, | |
746 net_log_, callback_.callback())); | |
747 | |
748 // Check that priority is highest. | |
749 QuicReliableClientStream* reliable_stream = | |
750 QuicHttpStreamPeer::GetQuicReliableClientStream(stream_.get()); | |
751 DCHECK(reliable_stream); | |
752 QuicReliableClientStream::Delegate* delegate = reliable_stream->GetDelegate(); | |
753 DCHECK(delegate); | |
754 DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, | |
755 reliable_stream->EffectivePriority()); | |
756 | |
757 // Set Delegate to nullptr and make sure EffectivePriority returns highest | |
758 // priority. | |
759 reliable_stream->SetDelegate(nullptr); | |
760 DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, | |
761 reliable_stream->EffectivePriority()); | |
762 reliable_stream->SetDelegate(delegate); | |
763 } | |
764 | |
765 } // namespace test | |
766 } // namespace net | |
OLD | NEW |