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