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 <stdint.h>
8 
9 #include <string>
10 
11 #include "base/bind.h"
12 #include "base/run_loop.h"
13 #include "base/stl_util.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "crypto/ec_private_key.h"
16 #include "crypto/ec_signature_creator.h"
17 #include "crypto/signature_creator.h"
18 #include "net/base/chunked_upload_data_stream.h"
19 #include "net/base/load_timing_info.h"
20 #include "net/base/load_timing_info_test_util.h"
21 #include "net/base/test_completion_callback.h"
22 #include "net/cert/asn1_util.h"
23 #include "net/http/http_request_info.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_response_info.h"
26 #include "net/log/net_log_with_source.h"
27 #include "net/log/test_net_log.h"
28 #include "net/socket/socket_tag.h"
29 #include "net/socket/socket_test_util.h"
30 #include "net/spdy/spdy_http_utils.h"
31 #include "net/spdy/spdy_test_util_common.h"
32 #include "net/test/cert_test_util.h"
33 #include "net/test/gtest_util.h"
34 #include "net/test/test_data_directory.h"
35 #include "net/test/test_with_task_environment.h"
36 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 
40 namespace net {
41 
42 namespace test {
43 
44 namespace {
45 
46 // Tests the load timing of a stream that's connected and is not the first
47 // request sent on a connection.
TestLoadTimingReused(const HttpStream & stream)48 void TestLoadTimingReused(const HttpStream& stream) {
49   LoadTimingInfo load_timing_info;
50   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
51 
52   EXPECT_TRUE(load_timing_info.socket_reused);
53   EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
54 
55   ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
56   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
57 }
58 
59 // Tests the load timing of a stream that's connected and using a fresh
60 // connection.
TestLoadTimingNotReused(const HttpStream & stream)61 void TestLoadTimingNotReused(const HttpStream& stream) {
62   LoadTimingInfo load_timing_info;
63   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
64 
65   EXPECT_FALSE(load_timing_info.socket_reused);
66   EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
67 
68   ExpectConnectTimingHasTimes(
69       load_timing_info.connect_timing,
70       CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES);
71   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
72 }
73 
74 class ReadErrorUploadDataStream : public UploadDataStream {
75  public:
76   enum class FailureMode { SYNC, ASYNC };
77 
ReadErrorUploadDataStream(FailureMode mode)78   explicit ReadErrorUploadDataStream(FailureMode mode)
79       : UploadDataStream(true, 0), async_(mode) {}
80 
81  private:
CompleteRead()82   void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
83 
84   // UploadDataStream implementation:
InitInternal(const NetLogWithSource & net_log)85   int InitInternal(const NetLogWithSource& net_log) override { return OK; }
86 
ReadInternal(IOBuffer * buf,int buf_len)87   int ReadInternal(IOBuffer* buf, int buf_len) override {
88     if (async_ == FailureMode::ASYNC) {
89       base::ThreadTaskRunnerHandle::Get()->PostTask(
90           FROM_HERE, base::BindOnce(&ReadErrorUploadDataStream::CompleteRead,
91                                     weak_factory_.GetWeakPtr()));
92       return ERR_IO_PENDING;
93     }
94     return ERR_FAILED;
95   }
96 
ResetInternal()97   void ResetInternal() override {}
98 
99   const FailureMode async_;
100 
101   base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_{this};
102 
103   DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
104 };
105 
106 class CancelStreamCallback : public TestCompletionCallbackBase {
107  public:
CancelStreamCallback(SpdyHttpStream * stream)108   explicit CancelStreamCallback(SpdyHttpStream* stream) : stream_(stream) {}
109 
callback()110   CompletionOnceCallback callback() {
111     return base::BindOnce(&CancelStreamCallback::CancelStream,
112                           base::Unretained(this));
113   }
114 
115  private:
CancelStream(int result)116   void CancelStream(int result) {
117     stream_->Cancel();
118     SetResult(result);
119   }
120 
121   SpdyHttpStream* stream_;
122 };
123 
124 }  // namespace
125 
126 class SpdyHttpStreamTest : public TestWithTaskEnvironment {
127  public:
SpdyHttpStreamTest()128   SpdyHttpStreamTest()
129       : url_(kDefaultUrl),
130         host_port_pair_(HostPortPair::FromURL(url_)),
131         key_(host_port_pair_,
132              ProxyServer::Direct(),
133              PRIVACY_MODE_DISABLED,
134              SpdySessionKey::IsProxySession::kFalse,
135              SocketTag(),
136              NetworkIsolationKey(),
137              false /* disable_secure_dns */),
138         ssl_(SYNCHRONOUS, OK) {
139     session_deps_.net_log = &net_log_;
140   }
141 
142   ~SpdyHttpStreamTest() override = default;
143 
144  protected:
TearDown()145   void TearDown() override {
146     crypto::ECSignatureCreator::SetFactoryForTesting(nullptr);
147     base::RunLoop().RunUntilIdle();
148     EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
149     EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
150   }
151 
152   // Initializes the session using SequencedSocketData.
InitSession(base::span<const MockRead> reads,base::span<const MockWrite> writes)153   void InitSession(base::span<const MockRead> reads,
154                    base::span<const MockWrite> writes) {
155     sequenced_data_ = std::make_unique<SequencedSocketData>(reads, writes);
156     session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
157 
158     ssl_.ssl_info.cert =
159         ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
160     ASSERT_TRUE(ssl_.ssl_info.cert);
161     session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
162 
163     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
164     session_ = CreateSpdySession(http_session_.get(), key_, NetLogWithSource());
165   }
166 
167   SpdyTestUtil spdy_util_;
168   RecordingTestNetLog net_log_;
169   SpdySessionDependencies session_deps_;
170   const GURL url_;
171   const HostPortPair host_port_pair_;
172   const SpdySessionKey key_;
173   std::unique_ptr<SequencedSocketData> sequenced_data_;
174   std::unique_ptr<HttpNetworkSession> http_session_;
175   base::WeakPtr<SpdySession> session_;
176 
177  private:
178   MockECSignatureCreatorFactory ec_signature_creator_factory_;
179   SSLSocketDataProvider ssl_;
180 };
181 
TEST_F(SpdyHttpStreamTest,SendRequest)182 TEST_F(SpdyHttpStreamTest, SendRequest) {
183   spdy::SpdySerializedFrame req(
184       spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
185   MockWrite writes[] = {
186       CreateMockWrite(req, 0),
187   };
188   spdy::SpdySerializedFrame resp(
189       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
190   MockRead reads[] = {
191       CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2)  // EOF
192   };
193 
194   InitSession(reads, writes);
195 
196   HttpRequestInfo request;
197   request.method = "GET";
198   request.url = url_;
199   request.traffic_annotation =
200       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
201   TestCompletionCallback callback;
202   HttpResponseInfo response;
203   HttpRequestHeaders headers;
204   NetLogWithSource net_log;
205   auto http_stream = std::make_unique<SpdyHttpStream>(
206       session_, kNoPushedStreamFound, net_log.source());
207   // Make sure getting load timing information the stream early does not crash.
208   LoadTimingInfo load_timing_info;
209   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
210 
211   ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY,
212                                             net_log, CompletionOnceCallback()),
213               IsOk());
214   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
215 
216   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
217               IsError(ERR_IO_PENDING));
218   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
219   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
220 
221   callback.WaitForResult();
222 
223   // Can get timing information once the stream connects.
224   TestLoadTimingNotReused(*http_stream);
225 
226   // Because we abandoned the stream, we don't expect to find a session in the
227   // pool anymore.
228   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
229 
230   TestLoadTimingNotReused(*http_stream);
231   http_stream->Close(true);
232   // Test that there's no crash when trying to get the load timing after the
233   // stream has been closed.
234   TestLoadTimingNotReused(*http_stream);
235 
236   EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
237   EXPECT_EQ(static_cast<int64_t>(resp.size()),
238             http_stream->GetTotalReceivedBytes());
239 }
240 
TEST_F(SpdyHttpStreamTest,RequestInfoDestroyedBeforeRead)241 TEST_F(SpdyHttpStreamTest, RequestInfoDestroyedBeforeRead) {
242   spdy::SpdySerializedFrame req(
243       spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
244   MockWrite writes[] = {CreateMockWrite(req, 0)};
245   spdy::SpdySerializedFrame resp(
246       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
247   spdy::SpdySerializedFrame body(
248       spdy_util_.ConstructSpdyDataFrame(1, "", true));
249   MockRead reads[] = {
250       CreateMockRead(resp, 1), CreateMockRead(body, 2),
251       MockRead(ASYNC, 0, 3)  // EOF
252   };
253 
254   InitSession(reads, writes);
255 
256   std::unique_ptr<HttpRequestInfo> request =
257       std::make_unique<HttpRequestInfo>();
258   request->method = "GET";
259   request->url = url_;
260   request->traffic_annotation =
261       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
262   TestCompletionCallback callback;
263   HttpResponseInfo response;
264   HttpRequestHeaders headers;
265   NetLogWithSource net_log;
266   auto http_stream = std::make_unique<SpdyHttpStream>(
267       session_, kNoPushedStreamFound, net_log.source());
268 
269   ASSERT_THAT(
270       http_stream->InitializeStream(request.get(), true, DEFAULT_PRIORITY,
271                                     net_log, CompletionOnceCallback()),
272       IsOk());
273   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
274               IsError(ERR_IO_PENDING));
275   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
276 
277   EXPECT_LE(0, callback.WaitForResult());
278 
279   TestLoadTimingNotReused(*http_stream);
280   LoadTimingInfo load_timing_info;
281   EXPECT_TRUE(http_stream->GetLoadTimingInfo(&load_timing_info));
282 
283   // Perform all async reads.
284   base::RunLoop().RunUntilIdle();
285 
286   // Destroy the request info before Read starts.
287   request.reset();
288 
289   // Read stream to completion.
290   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(1);
291   ASSERT_EQ(0,
292             http_stream->ReadResponseBody(buf.get(), 1, callback.callback()));
293 
294   // Stream 1 has been read to completion.
295   TestLoadTimingNotReused(*http_stream);
296 
297   EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
298   EXPECT_EQ(static_cast<int64_t>(resp.size() + body.size()),
299             http_stream->GetTotalReceivedBytes());
300 }
301 
TEST_F(SpdyHttpStreamTest,LoadTimingTwoRequests)302 TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) {
303   spdy::SpdySerializedFrame req1(
304       spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
305   spdy::SpdySerializedFrame req2(
306       spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
307   MockWrite writes[] = {
308       CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
309   };
310   spdy::SpdySerializedFrame resp1(
311       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
312   spdy::SpdySerializedFrame body1(
313       spdy_util_.ConstructSpdyDataFrame(1, "", true));
314   spdy::SpdySerializedFrame resp2(
315       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
316   spdy::SpdySerializedFrame body2(
317       spdy_util_.ConstructSpdyDataFrame(3, "", true));
318   MockRead reads[] = {
319       CreateMockRead(resp1, 2), CreateMockRead(body1, 3),
320       CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
321       MockRead(ASYNC, 0, 6)  // EOF
322   };
323 
324   InitSession(reads, writes);
325 
326   HttpRequestInfo request1;
327   request1.method = "GET";
328   request1.url = url_;
329   request1.traffic_annotation =
330       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
331   TestCompletionCallback callback1;
332   HttpResponseInfo response1;
333   HttpRequestHeaders headers1;
334   NetLogWithSource net_log;
335   auto http_stream1 = std::make_unique<SpdyHttpStream>(
336       session_, kNoPushedStreamFound, net_log.source());
337 
338   HttpRequestInfo request2;
339   request2.method = "GET";
340   request2.url = url_;
341   request2.traffic_annotation =
342       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
343   TestCompletionCallback callback2;
344   HttpResponseInfo response2;
345   HttpRequestHeaders headers2;
346   auto http_stream2 = std::make_unique<SpdyHttpStream>(
347       session_, kNoPushedStreamFound, net_log.source());
348 
349   // First write.
350   ASSERT_THAT(http_stream1->InitializeStream(&request1, true, DEFAULT_PRIORITY,
351                                              net_log, CompletionOnceCallback()),
352               IsOk());
353   EXPECT_THAT(
354       http_stream1->SendRequest(headers1, &response1, callback1.callback()),
355       IsError(ERR_IO_PENDING));
356   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
357 
358   EXPECT_LE(0, callback1.WaitForResult());
359 
360   TestLoadTimingNotReused(*http_stream1);
361   LoadTimingInfo load_timing_info1;
362   LoadTimingInfo load_timing_info2;
363   EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
364   EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
365 
366   // Second write.
367   ASSERT_THAT(http_stream2->InitializeStream(&request2, true, DEFAULT_PRIORITY,
368                                              net_log, CompletionOnceCallback()),
369               IsOk());
370   EXPECT_THAT(
371       http_stream2->SendRequest(headers2, &response2, callback2.callback()),
372       IsError(ERR_IO_PENDING));
373   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
374 
375   EXPECT_LE(0, callback2.WaitForResult());
376 
377   // Perform all async reads.
378   base::RunLoop().RunUntilIdle();
379 
380   TestLoadTimingReused(*http_stream2);
381   EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
382   EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
383 
384   // Read stream 1 to completion, before making sure we can still read load
385   // timing from both streams.
386   scoped_refptr<IOBuffer> buf1 = base::MakeRefCounted<IOBuffer>(1);
387   ASSERT_EQ(
388       0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback()));
389 
390   // Stream 1 has been read to completion.
391   TestLoadTimingNotReused(*http_stream1);
392 
393   EXPECT_EQ(static_cast<int64_t>(req1.size()),
394             http_stream1->GetTotalSentBytes());
395   EXPECT_EQ(static_cast<int64_t>(resp1.size() + body1.size()),
396             http_stream1->GetTotalReceivedBytes());
397 
398   // Stream 2 still has queued body data.
399   TestLoadTimingReused(*http_stream2);
400 
401   EXPECT_EQ(static_cast<int64_t>(req2.size()),
402             http_stream2->GetTotalSentBytes());
403   EXPECT_EQ(static_cast<int64_t>(resp2.size() + body2.size()),
404             http_stream2->GetTotalReceivedBytes());
405 }
406 
TEST_F(SpdyHttpStreamTest,SendChunkedPost)407 TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
408   spdy::SpdySerializedFrame req(
409       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
410   spdy::SpdySerializedFrame body(
411       spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
412                                         /*fin=*/true));
413   MockWrite writes[] = {
414       CreateMockWrite(req, 0),  // request
415       CreateMockWrite(body, 1)  // POST upload frame
416   };
417 
418   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
419   MockRead reads[] = {
420       CreateMockRead(resp, 2), CreateMockRead(body, 3, SYNCHRONOUS),
421       MockRead(SYNCHRONOUS, 0, 4)  // EOF
422   };
423 
424   InitSession(reads, writes);
425 
426   ChunkedUploadDataStream upload_stream(0);
427   const int kFirstChunkSize = kUploadDataSize/2;
428   upload_stream.AppendData(kUploadData, kFirstChunkSize, false);
429   upload_stream.AppendData(kUploadData + kFirstChunkSize,
430                             kUploadDataSize - kFirstChunkSize, true);
431 
432   HttpRequestInfo request;
433   request.method = "POST";
434   request.url = url_;
435   request.traffic_annotation =
436       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
437   request.upload_data_stream = &upload_stream;
438 
439   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
440                                  NetLogWithSource()),
441               IsOk());
442 
443   TestCompletionCallback callback;
444   HttpResponseInfo response;
445   HttpRequestHeaders headers;
446   NetLogWithSource net_log;
447   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
448   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
449                                            net_log, CompletionOnceCallback()),
450               IsOk());
451 
452   EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
453               IsError(ERR_IO_PENDING));
454   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
455 
456   EXPECT_THAT(callback.WaitForResult(), IsOk());
457 
458   EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
459             http_stream.GetTotalSentBytes());
460   EXPECT_EQ(static_cast<int64_t>(resp.size() + body.size()),
461             http_stream.GetTotalReceivedBytes());
462 
463   // Because the server closed the connection, we there shouldn't be a session
464   // in the pool anymore.
465   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
466 }
467 
468 // This unittest tests the request callback is properly called and handled.
TEST_F(SpdyHttpStreamTest,SendChunkedPostLastEmpty)469 TEST_F(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
470   spdy::SpdySerializedFrame req(
471       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
472   spdy::SpdySerializedFrame chunk(
473       spdy_util_.ConstructSpdyDataFrame(1, "", true));
474   MockWrite writes[] = {
475       CreateMockWrite(req, 0),  // request
476       CreateMockWrite(chunk, 1),
477   };
478 
479   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
480   MockRead reads[] = {
481       CreateMockRead(resp, 2), CreateMockRead(chunk, 3, SYNCHRONOUS),
482       MockRead(SYNCHRONOUS, 0, 4)  // EOF
483   };
484 
485   InitSession(reads, writes);
486 
487   ChunkedUploadDataStream upload_stream(0);
488   upload_stream.AppendData(nullptr, 0, true);
489 
490   HttpRequestInfo request;
491   request.method = "POST";
492   request.url = url_;
493   request.traffic_annotation =
494       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
495   request.upload_data_stream = &upload_stream;
496 
497   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
498                                  NetLogWithSource()),
499               IsOk());
500 
501   TestCompletionCallback callback;
502   HttpResponseInfo response;
503   HttpRequestHeaders headers;
504   NetLogWithSource net_log;
505   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
506   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
507                                            net_log, CompletionOnceCallback()),
508               IsOk());
509   EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
510               IsError(ERR_IO_PENDING));
511   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
512 
513   EXPECT_THAT(callback.WaitForResult(), IsOk());
514 
515   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
516             http_stream.GetTotalSentBytes());
517   EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
518             http_stream.GetTotalReceivedBytes());
519 
520   // Because the server closed the connection, there shouldn't be a session
521   // in the pool anymore.
522   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
523 }
524 
TEST_F(SpdyHttpStreamTest,ConnectionClosedDuringChunkedPost)525 TEST_F(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
526   spdy::SpdySerializedFrame req(
527       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
528   spdy::SpdySerializedFrame body(
529       spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
530                                         /*fin=*/false));
531   MockWrite writes[] = {
532       CreateMockWrite(req, 0),  // Request
533       CreateMockWrite(body, 1)  // First POST upload frame
534   };
535 
536   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
537   MockRead reads[] = {
538       MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2)  // Server hangs up early.
539   };
540 
541   InitSession(reads, writes);
542 
543   ChunkedUploadDataStream upload_stream(0);
544   // Append first chunk.
545   upload_stream.AppendData(kUploadData, kUploadDataSize, false);
546 
547   HttpRequestInfo request;
548   request.method = "POST";
549   request.url = url_;
550   request.traffic_annotation =
551       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
552   request.upload_data_stream = &upload_stream;
553 
554   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
555                                  NetLogWithSource()),
556               IsOk());
557 
558   TestCompletionCallback callback;
559   HttpResponseInfo response;
560   HttpRequestHeaders headers;
561   NetLogWithSource net_log;
562   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
563   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
564                                            net_log, CompletionOnceCallback()),
565               IsOk());
566 
567   EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
568               IsError(ERR_IO_PENDING));
569   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
570 
571   EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
572 
573   EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
574             http_stream.GetTotalSentBytes());
575   EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
576 
577   // Because the server closed the connection, we there shouldn't be a session
578   // in the pool anymore.
579   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
580 
581   // Appending a second chunk now should not result in a crash.
582   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
583   // Appending data is currently done synchronously, but seems best to be
584   // paranoid.
585   base::RunLoop().RunUntilIdle();
586 
587   // The total sent and received bytes should be unchanged.
588   EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
589             http_stream.GetTotalSentBytes());
590   EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
591 }
592 
593 // Test to ensure the SpdyStream state machine does not get confused when a
594 // chunk becomes available while a write is pending.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPost)595 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPost) {
596   const char kUploadData1[] = "12345678";
597   const int kUploadData1Size = base::size(kUploadData1) - 1;
598   spdy::SpdySerializedFrame req(
599       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
600   spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
601   spdy::SpdySerializedFrame chunk2(
602       spdy_util_.ConstructSpdyDataFrame(1, kUploadData1, false));
603   spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
604   MockWrite writes[] = {
605       CreateMockWrite(req, 0),
606       CreateMockWrite(chunk1, 1),  // POST upload frames
607       CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
608   };
609   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
610   MockRead reads[] = {
611       CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
612       CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
613       MockRead(ASYNC, 0, 8)  // EOF
614   };
615 
616   InitSession(reads, writes);
617 
618   ChunkedUploadDataStream upload_stream(0);
619 
620   HttpRequestInfo request;
621   request.method = "POST";
622   request.url = url_;
623   request.traffic_annotation =
624       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
625   request.upload_data_stream = &upload_stream;
626 
627   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
628                                  NetLogWithSource()),
629               IsOk());
630   upload_stream.AppendData(kUploadData, kUploadDataSize, false);
631 
632   NetLogWithSource net_log;
633   auto http_stream = std::make_unique<SpdyHttpStream>(
634       session_, kNoPushedStreamFound, net_log.source());
635   ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
636                                             net_log, CompletionOnceCallback()),
637               IsOk());
638 
639   TestCompletionCallback callback;
640   HttpRequestHeaders headers;
641   HttpResponseInfo response;
642   // This will attempt to Write() the initial request and headers, which will
643   // complete asynchronously.
644   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
645               IsError(ERR_IO_PENDING));
646   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
647 
648   // Complete the initial request write and the first chunk.
649   base::RunLoop().RunUntilIdle();
650   ASSERT_FALSE(callback.have_result());
651 
652   // Now append the final two chunks which will enqueue two more writes.
653   upload_stream.AppendData(kUploadData1, kUploadData1Size, false);
654   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
655 
656   // Finish writing all the chunks and do all reads.
657   base::RunLoop().RunUntilIdle();
658   ASSERT_TRUE(callback.have_result());
659   EXPECT_THAT(callback.WaitForResult(), IsOk());
660 
661   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size() +
662                                  chunk3.size()),
663             http_stream->GetTotalSentBytes());
664   EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size() +
665                                  chunk3.size()),
666             http_stream->GetTotalReceivedBytes());
667 
668   // Check response headers.
669   ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
670 
671   // Check |chunk1| response.
672   scoped_refptr<IOBuffer> buf1 =
673       base::MakeRefCounted<IOBuffer>(kUploadDataSize);
674   ASSERT_EQ(kUploadDataSize,
675             http_stream->ReadResponseBody(
676                 buf1.get(), kUploadDataSize, callback.callback()));
677   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
678 
679   // Check |chunk2| response.
680   scoped_refptr<IOBuffer> buf2 =
681       base::MakeRefCounted<IOBuffer>(kUploadData1Size);
682   ASSERT_EQ(kUploadData1Size,
683             http_stream->ReadResponseBody(
684                 buf2.get(), kUploadData1Size, callback.callback()));
685   EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
686 
687   // Check |chunk3| response.
688   scoped_refptr<IOBuffer> buf3 =
689       base::MakeRefCounted<IOBuffer>(kUploadDataSize);
690   ASSERT_EQ(kUploadDataSize,
691             http_stream->ReadResponseBody(
692                 buf3.get(), kUploadDataSize, callback.callback()));
693   EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
694 
695   ASSERT_TRUE(response.headers.get());
696   ASSERT_EQ(200, response.headers->response_code());
697 }
698 
699 // Test that the SpdyStream state machine can handle sending a final empty data
700 // frame when uploading a chunked data stream.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPostWithEmptyFinalDataFrame)701 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
702   spdy::SpdySerializedFrame req(
703       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
704   spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
705   spdy::SpdySerializedFrame chunk2(
706       spdy_util_.ConstructSpdyDataFrame(1, "", true));
707   MockWrite writes[] = {
708       CreateMockWrite(req, 0),
709       CreateMockWrite(chunk1, 1),  // POST upload frames
710       CreateMockWrite(chunk2, 2),
711   };
712   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
713   MockRead reads[] = {
714       CreateMockRead(resp, 3), CreateMockRead(chunk1, 4),
715       CreateMockRead(chunk2, 5), MockRead(ASYNC, 0, 6)  // EOF
716   };
717 
718   InitSession(reads, writes);
719 
720   ChunkedUploadDataStream upload_stream(0);
721 
722   HttpRequestInfo request;
723   request.method = "POST";
724   request.url = url_;
725   request.traffic_annotation =
726       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
727   request.upload_data_stream = &upload_stream;
728 
729   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
730                                  NetLogWithSource()),
731               IsOk());
732   upload_stream.AppendData(kUploadData, kUploadDataSize, false);
733 
734   NetLogWithSource net_log;
735   auto http_stream = std::make_unique<SpdyHttpStream>(
736       session_, kNoPushedStreamFound, net_log.source());
737   ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
738                                             net_log, CompletionOnceCallback()),
739               IsOk());
740 
741   TestCompletionCallback callback;
742   HttpRequestHeaders headers;
743   HttpResponseInfo response;
744   // This will attempt to Write() the initial request and headers, which will
745   // complete asynchronously.
746   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
747               IsError(ERR_IO_PENDING));
748   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
749 
750   // Complete the initial request write and the first chunk.
751   base::RunLoop().RunUntilIdle();
752   ASSERT_FALSE(callback.have_result());
753 
754   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
755             http_stream->GetTotalSentBytes());
756   EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
757 
758   // Now end the stream with an empty data frame and the FIN set.
759   upload_stream.AppendData(nullptr, 0, true);
760 
761   // Finish writing the final frame, and perform all reads.
762   base::RunLoop().RunUntilIdle();
763   ASSERT_TRUE(callback.have_result());
764   EXPECT_THAT(callback.WaitForResult(), IsOk());
765 
766   // Check response headers.
767   ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
768 
769   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size()),
770             http_stream->GetTotalSentBytes());
771   EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size()),
772             http_stream->GetTotalReceivedBytes());
773 
774   // Check |chunk1| response.
775   scoped_refptr<IOBuffer> buf1 =
776       base::MakeRefCounted<IOBuffer>(kUploadDataSize);
777   ASSERT_EQ(kUploadDataSize,
778             http_stream->ReadResponseBody(
779                 buf1.get(), kUploadDataSize, callback.callback()));
780   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
781 
782   // Check |chunk2| response.
783   ASSERT_EQ(0,
784             http_stream->ReadResponseBody(
785                 buf1.get(), kUploadDataSize, callback.callback()));
786 
787   ASSERT_TRUE(response.headers.get());
788   ASSERT_EQ(200, response.headers->response_code());
789 }
790 
791 // Test that the SpdyStream state machine handles a chunked upload with no
792 // payload. Unclear if this is a case worth supporting.
TEST_F(SpdyHttpStreamTest,ChunkedPostWithEmptyPayload)793 TEST_F(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
794   spdy::SpdySerializedFrame req(
795       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
796   spdy::SpdySerializedFrame chunk(
797       spdy_util_.ConstructSpdyDataFrame(1, "", true));
798   MockWrite writes[] = {
799       CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
800   };
801   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
802   MockRead reads[] = {
803       CreateMockRead(resp, 2), CreateMockRead(chunk, 3),
804       MockRead(ASYNC, 0, 4)  // EOF
805   };
806 
807   InitSession(reads, writes);
808 
809   ChunkedUploadDataStream upload_stream(0);
810 
811   HttpRequestInfo request;
812   request.method = "POST";
813   request.url = url_;
814   request.traffic_annotation =
815       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
816   request.upload_data_stream = &upload_stream;
817 
818   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
819                                  NetLogWithSource()),
820               IsOk());
821   upload_stream.AppendData("", 0, true);
822 
823   NetLogWithSource net_log;
824   auto http_stream = std::make_unique<SpdyHttpStream>(
825       session_, kNoPushedStreamFound, net_log.source());
826   ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
827                                             net_log, CompletionOnceCallback()),
828               IsOk());
829 
830   TestCompletionCallback callback;
831   HttpRequestHeaders headers;
832   HttpResponseInfo response;
833   // This will attempt to Write() the initial request and headers, which will
834   // complete asynchronously.
835   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
836               IsError(ERR_IO_PENDING));
837   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
838 
839   // Complete writing request, followed by a FIN.
840   base::RunLoop().RunUntilIdle();
841   ASSERT_TRUE(callback.have_result());
842   EXPECT_THAT(callback.WaitForResult(), IsOk());
843 
844   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
845             http_stream->GetTotalSentBytes());
846   EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
847             http_stream->GetTotalReceivedBytes());
848 
849   // Check response headers.
850   ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
851 
852   // Check |chunk| response.
853   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(1);
854   ASSERT_EQ(0,
855             http_stream->ReadResponseBody(
856                 buf.get(), 1, callback.callback()));
857 
858   ASSERT_TRUE(response.headers.get());
859   ASSERT_EQ(200, response.headers->response_code());
860 }
861 
862 // Test case for https://crbug.com/50058.
TEST_F(SpdyHttpStreamTest,SpdyURLTest)863 TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
864   const char* const full_url = "https://www.example.org/foo?query=what#anchor";
865   const char* const base_url = "https://www.example.org/foo?query=what";
866   spdy::SpdySerializedFrame req(
867       spdy_util_.ConstructSpdyGet(base_url, 1, LOWEST));
868   MockWrite writes[] = {
869       CreateMockWrite(req, 0),
870   };
871   spdy::SpdySerializedFrame resp(
872       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
873   MockRead reads[] = {
874       CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2)  // EOF
875   };
876 
877   InitSession(reads, writes);
878 
879   HttpRequestInfo request;
880   request.method = "GET";
881   request.url = GURL(full_url);
882   request.traffic_annotation =
883       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
884   TestCompletionCallback callback;
885   HttpResponseInfo response;
886   HttpRequestHeaders headers;
887   NetLogWithSource net_log;
888   auto http_stream = std::make_unique<SpdyHttpStream>(
889       session_, kNoPushedStreamFound, net_log.source());
890   ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY,
891                                             net_log, CompletionOnceCallback()),
892               IsOk());
893 
894   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
895               IsError(ERR_IO_PENDING));
896 
897   EXPECT_EQ(base_url, http_stream->stream()->url().spec());
898 
899   callback.WaitForResult();
900 
901   EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
902   EXPECT_EQ(static_cast<int64_t>(resp.size()),
903             http_stream->GetTotalReceivedBytes());
904 
905   // Because we abandoned the stream, we don't expect to find a session in the
906   // pool anymore.
907   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
908 }
909 
910 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
911 // made available is handled correctly.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPostWithWindowUpdate)912 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
913   spdy::SpdySerializedFrame req(
914       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
915   spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, true));
916   MockWrite writes[] = {
917       CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
918   };
919   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
920   spdy::SpdySerializedFrame window_update(
921       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
922   MockRead reads[] = {
923       CreateMockRead(window_update, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
924       CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
925       MockRead(ASYNC, 0, 6)  // EOF
926   };
927 
928   InitSession(reads, writes);
929 
930   ChunkedUploadDataStream upload_stream(0);
931 
932   HttpRequestInfo request;
933   request.method = "POST";
934   request.url = url_;
935   request.traffic_annotation =
936       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
937   request.upload_data_stream = &upload_stream;
938 
939   ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
940                                  NetLogWithSource()),
941               IsOk());
942 
943   NetLogWithSource net_log;
944   auto http_stream = std::make_unique<SpdyHttpStream>(
945       session_, kNoPushedStreamFound, net_log.source());
946   ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
947                                             net_log, CompletionOnceCallback()),
948               IsOk());
949 
950   HttpRequestHeaders headers;
951   HttpResponseInfo response;
952   // This will attempt to Write() the initial request and headers, which will
953   // complete asynchronously.
954   TestCompletionCallback callback;
955   EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
956               IsError(ERR_IO_PENDING));
957   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
958 
959   // Complete the initial request write and first chunk.
960   base::RunLoop().RunUntilIdle();
961   ASSERT_FALSE(callback.have_result());
962 
963   EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
964   EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
965 
966   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
967 
968   // Verify that the window size has decreased.
969   ASSERT_TRUE(http_stream->stream() != nullptr);
970   EXPECT_NE(static_cast<int>(kDefaultInitialWindowSize),
971             http_stream->stream()->send_window_size());
972 
973   // Read window update.
974   base::RunLoop().RunUntilIdle();
975 
976   ASSERT_TRUE(callback.have_result());
977   EXPECT_THAT(callback.WaitForResult(), IsOk());
978 
979   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
980             http_stream->GetTotalSentBytes());
981   // The window update is not counted in the total received bytes.
982   EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
983 
984   // Verify the window update.
985   ASSERT_TRUE(http_stream->stream() != nullptr);
986   EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize),
987             http_stream->stream()->send_window_size());
988 
989   // Read rest of data.
990   sequenced_data_->Resume();
991   base::RunLoop().RunUntilIdle();
992 
993   EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
994             http_stream->GetTotalSentBytes());
995   EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size()),
996             http_stream->GetTotalReceivedBytes());
997 
998   // Check response headers.
999   ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
1000 
1001   // Check |chunk1| response.
1002   scoped_refptr<IOBuffer> buf1 =
1003       base::MakeRefCounted<IOBuffer>(kUploadDataSize);
1004   ASSERT_EQ(kUploadDataSize,
1005             http_stream->ReadResponseBody(
1006                 buf1.get(), kUploadDataSize, callback.callback()));
1007   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
1008 
1009   ASSERT_TRUE(response.headers.get());
1010   ASSERT_EQ(200, response.headers->response_code());
1011 }
1012 
TEST_F(SpdyHttpStreamTest,DataReadErrorSynchronous)1013 TEST_F(SpdyHttpStreamTest, DataReadErrorSynchronous) {
1014   spdy::SpdySerializedFrame req(
1015       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1016 
1017   // Server receives spdy::ERROR_CODE_INTERNAL_ERROR on client's internal
1018   // failure. The failure is a reading error in this case caused by
1019   // UploadDataStream::Read().
1020   spdy::SpdySerializedFrame rst_frame(
1021       spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_INTERNAL_ERROR));
1022 
1023   MockWrite writes[] = {
1024       CreateMockWrite(req, 0, SYNCHRONOUS),       // Request
1025       CreateMockWrite(rst_frame, 1, SYNCHRONOUS)  // Reset frame
1026   };
1027 
1028   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1029 
1030   MockRead reads[] = {
1031       CreateMockRead(resp, 2), MockRead(SYNCHRONOUS, 0, 3),
1032   };
1033 
1034   InitSession(reads, writes);
1035 
1036   ReadErrorUploadDataStream upload_data_stream(
1037       ReadErrorUploadDataStream::FailureMode::SYNC);
1038   ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
1039                                       NetLogWithSource()),
1040               IsOk());
1041 
1042   HttpRequestInfo request;
1043   request.method = "POST";
1044   request.url = url_;
1045   request.traffic_annotation =
1046       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1047   request.upload_data_stream = &upload_data_stream;
1048 
1049   TestCompletionCallback callback;
1050   HttpResponseInfo response;
1051   HttpRequestHeaders headers;
1052   NetLogWithSource net_log;
1053   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1054   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1055                                            net_log, CompletionOnceCallback()),
1056               IsOk());
1057 
1058   int result = http_stream.SendRequest(headers, &response, callback.callback());
1059   EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
1060 
1061   // Run posted SpdyHttpStream::ResetStreamInternal() task.
1062   base::RunLoop().RunUntilIdle();
1063 
1064   // Because the server has not closed the connection yet, there shouldn't be
1065   // a stream but a session in the pool
1066   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1067 }
1068 
TEST_F(SpdyHttpStreamTest,DataReadErrorAsynchronous)1069 TEST_F(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
1070   spdy::SpdySerializedFrame req(
1071       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1072 
1073   // Server receives spdy::ERROR_CODE_INTERNAL_ERROR on client's internal
1074   // failure. The failure is a reading error in this case caused by
1075   // UploadDataStream::Read().
1076   spdy::SpdySerializedFrame rst_frame(
1077       spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_INTERNAL_ERROR));
1078 
1079   MockWrite writes[] = {
1080       CreateMockWrite(req, 0),       // Request
1081       CreateMockWrite(rst_frame, 1)  // Reset frame
1082   };
1083 
1084   spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1085 
1086   MockRead reads[] = {
1087       MockRead(ASYNC, 0, 2),
1088   };
1089 
1090   InitSession(reads, writes);
1091 
1092   ReadErrorUploadDataStream upload_data_stream(
1093       ReadErrorUploadDataStream::FailureMode::ASYNC);
1094   ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
1095                                       NetLogWithSource()),
1096               IsOk());
1097 
1098   HttpRequestInfo request;
1099   request.method = "POST";
1100   request.url = url_;
1101   request.traffic_annotation =
1102       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1103   request.upload_data_stream = &upload_data_stream;
1104 
1105   TestCompletionCallback callback;
1106   HttpResponseInfo response;
1107   HttpRequestHeaders headers;
1108   NetLogWithSource net_log;
1109   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1110   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1111                                            net_log, CompletionOnceCallback()),
1112               IsOk());
1113 
1114   int result = http_stream.SendRequest(headers, &response, callback.callback());
1115   EXPECT_THAT(result, IsError(ERR_IO_PENDING));
1116   EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
1117 
1118   // Run posted SpdyHttpStream::ResetStreamInternal() task.
1119   base::RunLoop().RunUntilIdle();
1120 
1121   // Because the server has closed the connection, there shouldn't be a session
1122   // in the pool anymore.
1123   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1124 }
1125 
1126 // Regression test for https://crbug.com/622447.
TEST_F(SpdyHttpStreamTest,RequestCallbackCancelsStream)1127 TEST_F(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
1128   spdy::SpdySerializedFrame req(
1129       spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1130   spdy::SpdySerializedFrame chunk(
1131       spdy_util_.ConstructSpdyDataFrame(1, "", true));
1132   spdy::SpdySerializedFrame rst(
1133       spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
1134   MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
1135                         CreateMockWrite(rst, 2)};
1136   MockRead reads[] = {MockRead(ASYNC, 0, 3)};
1137   InitSession(reads, writes);
1138 
1139   HttpRequestInfo request;
1140   request.method = "POST";
1141   request.url = url_;
1142   request.traffic_annotation =
1143       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1144   ChunkedUploadDataStream upload_stream(0);
1145   request.upload_data_stream = &upload_stream;
1146 
1147   TestCompletionCallback upload_callback;
1148   ASSERT_THAT(
1149       upload_stream.Init(upload_callback.callback(), NetLogWithSource()),
1150       IsOk());
1151   upload_stream.AppendData("", 0, true);
1152 
1153   NetLogWithSource net_log;
1154   SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1155   ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1156                                            net_log, CompletionOnceCallback()),
1157               IsOk());
1158 
1159   CancelStreamCallback callback(&http_stream);
1160   HttpRequestHeaders headers;
1161   HttpResponseInfo response;
1162   // This will attempt to Write() the initial request and headers, which will
1163   // complete asynchronously.
1164   EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
1165               IsError(ERR_IO_PENDING));
1166   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1167 
1168   // The callback cancels |http_stream|.
1169   EXPECT_THAT(callback.WaitForResult(), IsOk());
1170 
1171   // Finish async network reads/writes.
1172   base::RunLoop().RunUntilIdle();
1173 
1174   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1175 }
1176 
1177 // TODO(willchan): Write a longer test for SpdyStream that exercises all
1178 // methods.
1179 
1180 }  // namespace test
1181 
1182 }  // namespace net
1183