Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_http_stream_unittest.cc
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/spdy/spdy_http_stream.h"
6
7 #include <vector>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "crypto/ec_private_key.h"
14 #include "crypto/ec_signature_creator.h"
15 #include "crypto/signature_creator.h"
16 #include "net/base/capturing_net_log.h"
17 #include "net/base/chunked_upload_data_stream.h"
18 #include "net/base/load_timing_info.h"
19 #include "net/base/load_timing_info_test_util.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/cert/asn1_util.h"
22 #include "net/http/http_request_info.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/http/http_response_info.h"
25 #include "net/socket/next_proto.h"
26 #include "net/socket/socket_test_util.h"
27 #include "net/spdy/spdy_http_utils.h"
28 #include "net/spdy/spdy_session.h"
29 #include "net/spdy/spdy_test_util_common.h"
30 #include "net/ssl/default_channel_id_store.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 namespace net {
34
35 namespace {
36
37 // Tests the load timing of a stream that's connected and is not the first
38 // request sent on a connection.
39 void TestLoadTimingReused(const HttpStream& stream) {
40   LoadTimingInfo load_timing_info;
41   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
42
43   EXPECT_TRUE(load_timing_info.socket_reused);
44   EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
45
46   ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
47   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
48 }
49
50 // Tests the load timing of a stream that's connected and using a fresh
51 // connection.
52 void TestLoadTimingNotReused(const HttpStream& stream) {
53   LoadTimingInfo load_timing_info;
54   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
55
56   EXPECT_FALSE(load_timing_info.socket_reused);
57   EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
58
59   ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
60                               CONNECT_TIMING_HAS_DNS_TIMES);
61   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
62 }
63
64 }  // namespace
65
66 class SpdyHttpStreamTest : public testing::Test,
67                            public testing::WithParamInterface<NextProto> {
68  public:
69   SpdyHttpStreamTest()
70       : spdy_util_(GetParam()),
71         session_deps_(GetParam()) {
72     session_deps_.net_log = &net_log_;
73   }
74
75   DeterministicSocketData* deterministic_data() {
76     return deterministic_data_.get();
77   }
78
79   OrderedSocketData* data() { return data_.get(); }
80
81  protected:
82   void TearDown() override {
83     crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
84     base::MessageLoop::current()->RunUntilIdle();
85   }
86
87   // Initializes the session using DeterministicSocketData.  It's advisable
88   // to use this function rather than the OrderedSocketData, since the
89   // DeterministicSocketData behaves in a reasonable manner.
90   void InitSessionDeterministic(MockRead* reads, size_t reads_count,
91                                 MockWrite* writes, size_t writes_count,
92                                 const SpdySessionKey& key) {
93     deterministic_data_.reset(
94         new DeterministicSocketData(reads, reads_count, writes, writes_count));
95     session_deps_.deterministic_socket_factory->AddSocketDataProvider(
96         deterministic_data_.get());
97     http_session_ =
98         SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
99     session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
100   }
101
102   // Initializes the session using the finicky OrderedSocketData class.
103   void InitSession(MockRead* reads, size_t reads_count,
104                    MockWrite* writes, size_t writes_count,
105                    const SpdySessionKey& key) {
106     data_.reset(new OrderedSocketData(reads, reads_count,
107                                       writes, writes_count));
108     session_deps_.socket_factory->AddSocketDataProvider(data_.get());
109     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
110     session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
111   }
112
113   void TestSendCredentials(
114     ChannelIDService* channel_id_service,
115     const std::string& cert,
116     const std::string& proof);
117
118   SpdyTestUtil spdy_util_;
119   CapturingNetLog net_log_;
120   SpdySessionDependencies session_deps_;
121   scoped_ptr<OrderedSocketData> data_;
122   scoped_ptr<DeterministicSocketData> deterministic_data_;
123   scoped_refptr<HttpNetworkSession> http_session_;
124   base::WeakPtr<SpdySession> session_;
125
126  private:
127   MockECSignatureCreatorFactory ec_signature_creator_factory_;
128 };
129
130 INSTANTIATE_TEST_CASE_P(
131     NextProto,
132     SpdyHttpStreamTest,
133     testing::Values(kProtoDeprecatedSPDY2,
134                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
135
136 // SpdyHttpStream::GetUploadProgress() should still work even before the
137 // stream is initialized.
138 TEST_P(SpdyHttpStreamTest, GetUploadProgressBeforeInitialization) {
139   MockRead reads[] = {
140     MockRead(ASYNC, 0, 0)  // EOF
141   };
142
143   HostPortPair host_port_pair("www.google.com", 80);
144   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
145                      PRIVACY_MODE_DISABLED);
146   InitSession(reads, arraysize(reads), NULL, 0, key);
147
148   SpdyHttpStream stream(session_, false);
149   UploadProgress progress = stream.GetUploadProgress();
150   EXPECT_EQ(0u, progress.size());
151   EXPECT_EQ(0u, progress.position());
152
153   // Pump the event loop so |reads| is consumed before the function returns.
154   base::RunLoop().RunUntilIdle();
155 }
156
157 TEST_P(SpdyHttpStreamTest, SendRequest) {
158   scoped_ptr<SpdyFrame> req(
159       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
160   MockWrite writes[] = {
161     CreateMockWrite(*req.get(), 1),
162   };
163   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
164   MockRead reads[] = {
165     CreateMockRead(*resp, 2),
166     MockRead(SYNCHRONOUS, 0, 3)  // EOF
167   };
168
169   HostPortPair host_port_pair("www.google.com", 80);
170   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
171                      PRIVACY_MODE_DISABLED);
172   InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
173
174   HttpRequestInfo request;
175   request.method = "GET";
176   request.url = GURL("http://www.google.com/");
177   TestCompletionCallback callback;
178   HttpResponseInfo response;
179   HttpRequestHeaders headers;
180   BoundNetLog net_log;
181   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
182   // Make sure getting load timing information the stream early does not crash.
183   LoadTimingInfo load_timing_info;
184   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
185
186   ASSERT_EQ(
187       OK,
188       http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
189                                     net_log, CompletionCallback()));
190   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
191
192   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
193                                                      callback.callback()));
194   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
195   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
196
197   // This triggers the MockWrite and read 2
198   callback.WaitForResult();
199
200   // Can get timing information once the stream connects.
201   TestLoadTimingNotReused(*http_stream);
202
203   // This triggers read 3. The empty read causes the session to shut down.
204   data()->CompleteRead();
205
206   // Because we abandoned the stream, we don't expect to find a session in the
207   // pool anymore.
208   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
209   EXPECT_TRUE(data()->at_read_eof());
210   EXPECT_TRUE(data()->at_write_eof());
211
212   TestLoadTimingNotReused(*http_stream);
213   http_stream->Close(true);
214   // Test that there's no crash when trying to get the load timing after the
215   // stream has been closed.
216   TestLoadTimingNotReused(*http_stream);
217 }
218
219 TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
220   scoped_ptr<SpdyFrame> req1(
221       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
222   scoped_ptr<SpdyFrame> req2(
223       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
224   MockWrite writes[] = {
225     CreateMockWrite(*req1, 0),
226     CreateMockWrite(*req2, 1),
227   };
228   scoped_ptr<SpdyFrame> resp1(
229       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
230   scoped_ptr<SpdyFrame> body1(
231       spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
232   scoped_ptr<SpdyFrame> resp2(
233       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
234   scoped_ptr<SpdyFrame> body2(
235       spdy_util_.ConstructSpdyBodyFrame(3, "", 0, true));
236   MockRead reads[] = {
237     CreateMockRead(*resp1, 2),
238     CreateMockRead(*body1, 3),
239     CreateMockRead(*resp2, 4),
240     CreateMockRead(*body2, 5),
241     MockRead(ASYNC, 0, 6)  // EOF
242   };
243
244   HostPortPair host_port_pair("www.google.com", 80);
245   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
246                      PRIVACY_MODE_DISABLED);
247   InitSessionDeterministic(reads, arraysize(reads),
248                            writes, arraysize(writes),
249                            key);
250
251   HttpRequestInfo request1;
252   request1.method = "GET";
253   request1.url = GURL("http://www.google.com/");
254   TestCompletionCallback callback1;
255   HttpResponseInfo response1;
256   HttpRequestHeaders headers1;
257   scoped_ptr<SpdyHttpStream> http_stream1(new SpdyHttpStream(session_, true));
258
259   HttpRequestInfo request2;
260   request2.method = "GET";
261   request2.url = GURL("http://www.google.com/");
262   TestCompletionCallback callback2;
263   HttpResponseInfo response2;
264   HttpRequestHeaders headers2;
265   scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
266
267   // First write.
268   ASSERT_EQ(OK,
269             http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY,
270                                            BoundNetLog(),
271                                            CompletionCallback()));
272   EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1,
273                                                       callback1.callback()));
274   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
275
276   deterministic_data()->RunFor(1);
277   EXPECT_LE(0, callback1.WaitForResult());
278
279   TestLoadTimingNotReused(*http_stream1);
280   LoadTimingInfo load_timing_info1;
281   LoadTimingInfo load_timing_info2;
282   EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
283   EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
284
285   // Second write.
286   ASSERT_EQ(OK,
287             http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY,
288                                            BoundNetLog(),
289                                            CompletionCallback()));
290   EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2,
291                                                       callback2.callback()));
292   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
293
294   deterministic_data()->RunFor(1);
295   EXPECT_LE(0, callback2.WaitForResult());
296   TestLoadTimingReused(*http_stream2);
297   EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
298   EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
299
300   // All the reads.
301   deterministic_data()->RunFor(6);
302
303   // Read stream 1 to completion, before making sure we can still read load
304   // timing from both streams.
305   scoped_refptr<IOBuffer> buf1(new IOBuffer(1));
306   ASSERT_EQ(
307       0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback()));
308
309   // Stream 1 has been read to completion.
310   TestLoadTimingNotReused(*http_stream1);
311   // Stream 2 still has queued body data.
312   TestLoadTimingReused(*http_stream2);
313 }
314
315 TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
316   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
317
318   scoped_ptr<SpdyFrame> req(
319       spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
320   scoped_ptr<SpdyFrame> body(
321       framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN));
322   std::vector<MockWrite> writes;
323   int seq = 0;
324   writes.push_back(CreateMockWrite(*req, seq++));
325   writes.push_back(CreateMockWrite(*body, seq++));  // POST upload frame
326
327   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
328   std::vector<MockRead> reads;
329   reads.push_back(CreateMockRead(*resp, seq++));
330   reads.push_back(CreateMockRead(*body, seq++));
331   reads.push_back(MockRead(SYNCHRONOUS, 0, seq++));  // EOF
332
333   HostPortPair host_port_pair("www.google.com", 80);
334   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
335                      PRIVACY_MODE_DISABLED);
336   InitSession(vector_as_array(&reads), reads.size(),
337               vector_as_array(&writes), writes.size(),
338               key);
339   EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
340
341   ChunkedUploadDataStream upload_stream(0);
342   const int kFirstChunkSize = kUploadDataSize/2;
343   upload_stream.AppendData(kUploadData, kFirstChunkSize, false);
344   upload_stream.AppendData(kUploadData + kFirstChunkSize,
345                             kUploadDataSize - kFirstChunkSize, true);
346
347   HttpRequestInfo request;
348   request.method = "POST";
349   request.url = GURL("http://www.google.com/");
350   request.upload_data_stream = &upload_stream;
351
352   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
353
354   TestCompletionCallback callback;
355   HttpResponseInfo response;
356   HttpRequestHeaders headers;
357   BoundNetLog net_log;
358   SpdyHttpStream http_stream(session_, true);
359   ASSERT_EQ(
360       OK,
361       http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
362                                    net_log, CompletionCallback()));
363
364   EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
365       headers, &response, callback.callback()));
366   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
367
368   // This results in writing the post body and reading the response headers.
369   callback.WaitForResult();
370
371   // This triggers reading the body and the EOF, causing the session to shut
372   // down.
373   data()->CompleteRead();
374   base::MessageLoop::current()->RunUntilIdle();
375
376   // Because we abandoned the stream, we don't expect to find a session in the
377   // pool anymore.
378   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
379   EXPECT_TRUE(data()->at_read_eof());
380   EXPECT_TRUE(data()->at_write_eof());
381 }
382
383 // Test to ensure the SpdyStream state machine does not get confused when a
384 // chunk becomes available while a write is pending.
385 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
386   const char kUploadData1[] = "12345678";
387   const int kUploadData1Size = arraysize(kUploadData1)-1;
388   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
389   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
390   scoped_ptr<SpdyFrame> chunk2(
391       spdy_util_.ConstructSpdyBodyFrame(
392           1, kUploadData1, kUploadData1Size, false));
393   scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
394   MockWrite writes[] = {
395     CreateMockWrite(*req.get(), 0),
396     CreateMockWrite(*chunk1, 1),  // POST upload frames
397     CreateMockWrite(*chunk2, 2),
398     CreateMockWrite(*chunk3, 3),
399   };
400   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
401   MockRead reads[] = {
402     CreateMockRead(*resp, 4),
403     CreateMockRead(*chunk1, 5),
404     CreateMockRead(*chunk2, 6),
405     CreateMockRead(*chunk3, 7),
406     MockRead(ASYNC, 0, 8)  // EOF
407   };
408
409   HostPortPair host_port_pair("www.google.com", 80);
410   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
411                      PRIVACY_MODE_DISABLED);
412   InitSessionDeterministic(reads, arraysize(reads),
413                            writes, arraysize(writes),
414                            key);
415
416   ChunkedUploadDataStream upload_stream(0);
417
418   HttpRequestInfo request;
419   request.method = "POST";
420   request.url = GURL("http://www.google.com/");
421   request.upload_data_stream = &upload_stream;
422
423   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
424   upload_stream.AppendData(kUploadData, kUploadDataSize, false);
425
426   BoundNetLog net_log;
427   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
428   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
429                                               net_log, CompletionCallback()));
430
431   TestCompletionCallback callback;
432   HttpRequestHeaders headers;
433   HttpResponseInfo response;
434   // This will attempt to Write() the initial request and headers, which will
435   // complete asynchronously.
436   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
437                                                      callback.callback()));
438   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
439
440   // Complete the initial request write and the first chunk.
441   deterministic_data()->RunFor(2);
442   ASSERT_TRUE(callback.have_result());
443   EXPECT_EQ(OK, callback.WaitForResult());
444
445   // Now append the final two chunks which will enqueue two more writes.
446   upload_stream.AppendData(kUploadData1, kUploadData1Size, false);
447   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
448
449   // Finish writing all the chunks.
450   deterministic_data()->RunFor(2);
451
452   // Read response headers.
453   deterministic_data()->RunFor(1);
454   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
455
456   // Read and check |chunk1| response.
457   deterministic_data()->RunFor(1);
458   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
459   ASSERT_EQ(kUploadDataSize,
460             http_stream->ReadResponseBody(
461                 buf1.get(), kUploadDataSize, callback.callback()));
462   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
463
464   // Read and check |chunk2| response.
465   deterministic_data()->RunFor(1);
466   scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
467   ASSERT_EQ(kUploadData1Size,
468             http_stream->ReadResponseBody(
469                 buf2.get(), kUploadData1Size, callback.callback()));
470   EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
471
472   // Read and check |chunk3| response.
473   deterministic_data()->RunFor(1);
474   scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
475   ASSERT_EQ(kUploadDataSize,
476             http_stream->ReadResponseBody(
477                 buf3.get(), kUploadDataSize, callback.callback()));
478   EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
479
480   // Finish reading the |EOF|.
481   deterministic_data()->RunFor(1);
482   ASSERT_TRUE(response.headers.get());
483   ASSERT_EQ(200, response.headers->response_code());
484   EXPECT_TRUE(deterministic_data()->at_read_eof());
485   EXPECT_TRUE(deterministic_data()->at_write_eof());
486 }
487
488 // Test that the SpdyStream state machine can handle sending a final empty data
489 // frame when uploading a chunked data stream.
490 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
491   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
492   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
493   scoped_ptr<SpdyFrame> chunk2(
494       spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
495   MockWrite writes[] = {
496     CreateMockWrite(*req.get(), 0),
497     CreateMockWrite(*chunk1, 1),  // POST upload frames
498     CreateMockWrite(*chunk2, 2),
499   };
500   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
501   MockRead reads[] = {
502     CreateMockRead(*resp, 3),
503     CreateMockRead(*chunk1, 4),
504     CreateMockRead(*chunk2, 5),
505     MockRead(ASYNC, 0, 6)  // EOF
506   };
507
508   HostPortPair host_port_pair("www.google.com", 80);
509   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
510                      PRIVACY_MODE_DISABLED);
511   InitSessionDeterministic(reads, arraysize(reads),
512                            writes, arraysize(writes),
513                            key);
514
515   ChunkedUploadDataStream upload_stream(0);
516
517   HttpRequestInfo request;
518   request.method = "POST";
519   request.url = GURL("http://www.google.com/");
520   request.upload_data_stream = &upload_stream;
521
522   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
523   upload_stream.AppendData(kUploadData, kUploadDataSize, false);
524
525   BoundNetLog net_log;
526   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
527   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
528                                               net_log, CompletionCallback()));
529
530   TestCompletionCallback callback;
531   HttpRequestHeaders headers;
532   HttpResponseInfo response;
533   // This will attempt to Write() the initial request and headers, which will
534   // complete asynchronously.
535   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
536                                                      callback.callback()));
537   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
538
539   // Complete the initial request write and the first chunk.
540   deterministic_data()->RunFor(2);
541   ASSERT_TRUE(callback.have_result());
542   EXPECT_EQ(OK, callback.WaitForResult());
543
544   // Now end the stream with an empty data frame and the FIN set.
545   upload_stream.AppendData(NULL, 0, true);
546
547   // Finish writing the final frame.
548   deterministic_data()->RunFor(1);
549
550   // Read response headers.
551   deterministic_data()->RunFor(1);
552   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
553
554   // Read and check |chunk1| response.
555   deterministic_data()->RunFor(1);
556   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
557   ASSERT_EQ(kUploadDataSize,
558             http_stream->ReadResponseBody(
559                 buf1.get(), kUploadDataSize, callback.callback()));
560   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
561
562   // Read and check |chunk2| response.
563   deterministic_data()->RunFor(1);
564   ASSERT_EQ(0,
565             http_stream->ReadResponseBody(
566                 buf1.get(), kUploadDataSize, callback.callback()));
567
568   // Finish reading the |EOF|.
569   deterministic_data()->RunFor(1);
570   ASSERT_TRUE(response.headers.get());
571   ASSERT_EQ(200, response.headers->response_code());
572   EXPECT_TRUE(deterministic_data()->at_read_eof());
573   EXPECT_TRUE(deterministic_data()->at_write_eof());
574 }
575
576 // Test that the SpdyStream state machine handles a chunked upload with no
577 // payload. Unclear if this is a case worth supporting.
578 TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
579   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
580   scoped_ptr<SpdyFrame> chunk(
581       spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
582   MockWrite writes[] = {
583     CreateMockWrite(*req.get(), 0),
584     CreateMockWrite(*chunk, 1),
585   };
586   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
587   MockRead reads[] = {
588     CreateMockRead(*resp, 2),
589     CreateMockRead(*chunk, 3),
590     MockRead(ASYNC, 0, 4)  // EOF
591   };
592
593   HostPortPair host_port_pair("www.google.com", 80);
594   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
595                      PRIVACY_MODE_DISABLED);
596   InitSessionDeterministic(reads, arraysize(reads),
597                            writes, arraysize(writes),
598                            key);
599
600   ChunkedUploadDataStream upload_stream(0);
601
602   HttpRequestInfo request;
603   request.method = "POST";
604   request.url = GURL("http://www.google.com/");
605   request.upload_data_stream = &upload_stream;
606
607   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
608   upload_stream.AppendData("", 0, true);
609
610   BoundNetLog net_log;
611   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
612   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
613                                               net_log, CompletionCallback()));
614
615   TestCompletionCallback callback;
616   HttpRequestHeaders headers;
617   HttpResponseInfo response;
618   // This will attempt to Write() the initial request and headers, which will
619   // complete asynchronously.
620   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
621                                                      callback.callback()));
622   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
623
624   // Complete writing request, followed by a FIN.
625   deterministic_data()->RunFor(2);
626   ASSERT_TRUE(callback.have_result());
627   EXPECT_EQ(OK, callback.WaitForResult());
628
629   // Read response headers.
630   deterministic_data()->RunFor(1);
631   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
632
633   // Read and check |chunk| response.
634   deterministic_data()->RunFor(1);
635   scoped_refptr<IOBuffer> buf(new IOBuffer(1));
636   ASSERT_EQ(0,
637             http_stream->ReadResponseBody(
638                 buf.get(), 1, callback.callback()));
639
640   // Finish reading the |EOF|.
641   deterministic_data()->RunFor(1);
642   ASSERT_TRUE(response.headers.get());
643   ASSERT_EQ(200, response.headers->response_code());
644   EXPECT_TRUE(deterministic_data()->at_read_eof());
645   EXPECT_TRUE(deterministic_data()->at_write_eof());
646 }
647
648 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
649 TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
650   const char * const full_url = "http://www.google.com/foo?query=what#anchor";
651   const char * const base_url = "http://www.google.com/foo?query=what";
652   scoped_ptr<SpdyFrame> req(
653       spdy_util_.ConstructSpdyGet(base_url, false, 1, LOWEST));
654   MockWrite writes[] = {
655     CreateMockWrite(*req.get(), 1),
656   };
657   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
658   MockRead reads[] = {
659     CreateMockRead(*resp, 2),
660     MockRead(SYNCHRONOUS, 0, 3)  // EOF
661   };
662
663   HostPortPair host_port_pair("www.google.com", 80);
664   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
665                      PRIVACY_MODE_DISABLED);
666   InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
667
668   HttpRequestInfo request;
669   request.method = "GET";
670   request.url = GURL(full_url);
671   TestCompletionCallback callback;
672   HttpResponseInfo response;
673   HttpRequestHeaders headers;
674   BoundNetLog net_log;
675   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
676   ASSERT_EQ(OK,
677             http_stream->InitializeStream(
678                 &request, DEFAULT_PRIORITY, net_log, CompletionCallback()));
679
680   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
681                                                      callback.callback()));
682
683   EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec());
684
685   // This triggers the MockWrite and read 2
686   callback.WaitForResult();
687
688   // This triggers read 3. The empty read causes the session to shut down.
689   data()->CompleteRead();
690
691   // Because we abandoned the stream, we don't expect to find a session in the
692   // pool anymore.
693   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
694   EXPECT_TRUE(data()->at_read_eof());
695   EXPECT_TRUE(data()->at_write_eof());
696 }
697
698 // The tests below are only for SPDY/3 and above.
699
700 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
701 // made available is handled correctly.
702 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
703   if (GetParam() < kProtoSPDY3)
704     return;
705
706   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
707   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
708   MockWrite writes[] = {
709     CreateMockWrite(*req.get(), 0),
710     CreateMockWrite(*chunk1, 1),
711   };
712   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
713   scoped_ptr<SpdyFrame> window_update(
714       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
715   MockRead reads[] = {
716     CreateMockRead(*window_update, 2),
717     CreateMockRead(*resp, 3),
718     CreateMockRead(*chunk1, 4),
719     MockRead(ASYNC, 0, 5)  // EOF
720   };
721
722   HostPortPair host_port_pair("www.google.com", 80);
723   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
724                      PRIVACY_MODE_DISABLED);
725
726   InitSessionDeterministic(reads, arraysize(reads),
727                            writes, arraysize(writes),
728                            key);
729
730   ChunkedUploadDataStream upload_stream(0);
731
732   HttpRequestInfo request;
733   request.method = "POST";
734   request.url = GURL("http://www.google.com/");
735   request.upload_data_stream = &upload_stream;
736
737   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
738   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
739
740   BoundNetLog net_log;
741   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
742   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
743                                               net_log, CompletionCallback()));
744
745   HttpRequestHeaders headers;
746   HttpResponseInfo response;
747   // This will attempt to Write() the initial request and headers, which will
748   // complete asynchronously.
749   TestCompletionCallback callback;
750   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
751                                                      callback.callback()));
752   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
753
754   // Complete the initial request write and first chunk.
755   deterministic_data_->RunFor(2);
756   ASSERT_TRUE(callback.have_result());
757   EXPECT_EQ(OK, callback.WaitForResult());
758
759   // Verify that the window size has decreased.
760   ASSERT_TRUE(http_stream->stream() != NULL);
761   EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
762             http_stream->stream()->send_window_size());
763
764   // Read window update.
765   deterministic_data_->RunFor(1);
766
767   // Verify the window update.
768   ASSERT_TRUE(http_stream->stream() != NULL);
769   EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
770             http_stream->stream()->send_window_size());
771
772   // Read response headers.
773   deterministic_data_->RunFor(1);
774   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
775
776   // Read and check |chunk1| response.
777   deterministic_data_->RunFor(1);
778   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
779   ASSERT_EQ(kUploadDataSize,
780             http_stream->ReadResponseBody(
781                 buf1.get(), kUploadDataSize, callback.callback()));
782   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
783
784   // Finish reading the |EOF|.
785   deterministic_data_->RunFor(1);
786   ASSERT_TRUE(response.headers.get());
787   ASSERT_EQ(200, response.headers->response_code());
788   EXPECT_TRUE(deterministic_data_->at_read_eof());
789   EXPECT_TRUE(deterministic_data_->at_write_eof());
790 }
791
792 // TODO(willchan): Write a longer test for SpdyStream that exercises all
793 // methods.
794
795 }  // namespace net