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