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