Upstream version 9.38.198.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/load_timing_info.h"
18 #include "net/base/load_timing_info_test_util.h"
19 #include "net/base/upload_data_stream.h"
20 #include "net/base/upload_element_reader.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   virtual 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   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
342   const int kFirstChunkSize = kUploadDataSize/2;
343   upload_stream.AppendChunk(kUploadData, kFirstChunkSize, false);
344   upload_stream.AppendChunk(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(CompletionCallback()));
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   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 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(CompletionCallback()));
424   upload_stream.AppendChunk(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.AppendChunk(kUploadData1, kUploadData1Size, false);
447   upload_stream.AppendChunk(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 case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
489 TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
490   const char * const full_url = "http://www.google.com/foo?query=what#anchor";
491   const char * const base_url = "http://www.google.com/foo?query=what";
492   scoped_ptr<SpdyFrame> req(
493       spdy_util_.ConstructSpdyGet(base_url, false, 1, LOWEST));
494   MockWrite writes[] = {
495     CreateMockWrite(*req.get(), 1),
496   };
497   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
498   MockRead reads[] = {
499     CreateMockRead(*resp, 2),
500     MockRead(SYNCHRONOUS, 0, 3)  // EOF
501   };
502
503   HostPortPair host_port_pair("www.google.com", 80);
504   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
505                      PRIVACY_MODE_DISABLED);
506   InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
507
508   HttpRequestInfo request;
509   request.method = "GET";
510   request.url = GURL(full_url);
511   TestCompletionCallback callback;
512   HttpResponseInfo response;
513   HttpRequestHeaders headers;
514   BoundNetLog net_log;
515   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
516   ASSERT_EQ(OK,
517             http_stream->InitializeStream(
518                 &request, DEFAULT_PRIORITY, net_log, CompletionCallback()));
519
520   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
521                                                      callback.callback()));
522
523   EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec());
524
525   // This triggers the MockWrite and read 2
526   callback.WaitForResult();
527
528   // This triggers read 3. The empty read causes the session to shut down.
529   data()->CompleteRead();
530
531   // Because we abandoned the stream, we don't expect to find a session in the
532   // pool anymore.
533   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
534   EXPECT_TRUE(data()->at_read_eof());
535   EXPECT_TRUE(data()->at_write_eof());
536 }
537
538 // The tests below are only for SPDY/3 and above.
539
540 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
541 // made available is handled correctly.
542 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
543   if (GetParam() < kProtoSPDY3)
544     return;
545
546   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
547   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
548   MockWrite writes[] = {
549     CreateMockWrite(*req.get(), 0),
550     CreateMockWrite(*chunk1, 1),
551   };
552   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
553   scoped_ptr<SpdyFrame> window_update(
554       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
555   MockRead reads[] = {
556     CreateMockRead(*window_update, 2),
557     CreateMockRead(*resp, 3),
558     CreateMockRead(*chunk1, 4),
559     MockRead(ASYNC, 0, 5)  // EOF
560   };
561
562   HostPortPair host_port_pair("www.google.com", 80);
563   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
564                      PRIVACY_MODE_DISABLED);
565
566   InitSessionDeterministic(reads, arraysize(reads),
567                            writes, arraysize(writes),
568                            key);
569
570   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
571
572   HttpRequestInfo request;
573   request.method = "POST";
574   request.url = GURL("http://www.google.com/");
575   request.upload_data_stream = &upload_stream;
576
577   ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
578   upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
579
580   BoundNetLog net_log;
581   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
582   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
583                                               net_log, CompletionCallback()));
584
585   HttpRequestHeaders headers;
586   HttpResponseInfo response;
587   // This will attempt to Write() the initial request and headers, which will
588   // complete asynchronously.
589   TestCompletionCallback callback;
590   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
591                                                      callback.callback()));
592   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
593
594   // Complete the initial request write and first chunk.
595   deterministic_data_->RunFor(2);
596   ASSERT_TRUE(callback.have_result());
597   EXPECT_EQ(OK, callback.WaitForResult());
598
599   // Verify that the window size has decreased.
600   ASSERT_TRUE(http_stream->stream() != NULL);
601   EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
602             http_stream->stream()->send_window_size());
603
604   // Read window update.
605   deterministic_data_->RunFor(1);
606
607   // Verify the window update.
608   ASSERT_TRUE(http_stream->stream() != NULL);
609   EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
610             http_stream->stream()->send_window_size());
611
612   // Read response headers.
613   deterministic_data_->RunFor(1);
614   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
615
616   // Read and check |chunk1| response.
617   deterministic_data_->RunFor(1);
618   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
619   ASSERT_EQ(kUploadDataSize,
620             http_stream->ReadResponseBody(
621                 buf1.get(), kUploadDataSize, callback.callback()));
622   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
623
624   // Finish reading the |EOF|.
625   deterministic_data_->RunFor(1);
626   ASSERT_TRUE(response.headers.get());
627   ASSERT_EQ(200, response.headers->response_code());
628   EXPECT_TRUE(deterministic_data_->at_read_eof());
629   EXPECT_TRUE(deterministic_data_->at_write_eof());
630 }
631
632 // TODO(willchan): Write a longer test for SpdyStream that exercises all
633 // methods.
634
635 }  // namespace net