• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cstddef>
6 #include <string>
7 #include <vector>
8 
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_piece.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/net_log_unittest.h"
15 #include "net/base/request_priority.h"
16 #include "net/socket/next_proto.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/spdy/buffered_spdy_framer.h"
19 #include "net/spdy/spdy_http_utils.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_stream.h"
23 #include "net/spdy/spdy_stream_test_util.h"
24 #include "net/spdy/spdy_test_util_common.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
28 //
29 namespace net {
30 
31 namespace test {
32 
33 namespace {
34 
35 const char kStreamUrl[] = "http://www.google.com/";
36 const char kPostBody[] = "\0hello!\xff";
37 const size_t kPostBodyLength = arraysize(kPostBody);
38 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
39 
40 class SpdyStreamTest : public ::testing::Test,
41                        public ::testing::WithParamInterface<NextProto> {
42  protected:
43   // A function that takes a SpdyStream and the number of bytes which
44   // will unstall the next frame completely.
45   typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
46       UnstallFunction;
47 
SpdyStreamTest()48   SpdyStreamTest()
49       : spdy_util_(GetParam()),
50         session_deps_(GetParam()),
51         offset_(0) {}
52 
CreateDefaultSpdySession()53   base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
54     SpdySessionKey key(HostPortPair("www.google.com", 80),
55                        ProxyServer::Direct(),
56                        kPrivacyModeDisabled);
57     return CreateInsecureSpdySession(session_, key, BoundNetLog());
58   }
59 
TearDown()60   virtual void TearDown() {
61     base::MessageLoop::current()->RunUntilIdle();
62   }
63 
64   void RunResumeAfterUnstallRequestResponseTest(
65       const UnstallFunction& unstall_function);
66 
67   void RunResumeAfterUnstallBidirectionalTest(
68       const UnstallFunction& unstall_function);
69 
70   // Add{Read,Write}() populates lists that are eventually passed to a
71   // SocketData class. |frame| must live for the whole test.
72 
AddRead(const SpdyFrame & frame)73   void AddRead(const SpdyFrame& frame) {
74     reads_.push_back(CreateMockRead(frame, offset_++));
75   }
76 
AddWrite(const SpdyFrame & frame)77   void AddWrite(const SpdyFrame& frame) {
78     writes_.push_back(CreateMockWrite(frame, offset_++));
79   }
80 
AddReadEOF()81   void AddReadEOF() {
82     reads_.push_back(MockRead(ASYNC, 0, offset_++));
83   }
84 
GetReads()85   MockRead* GetReads() {
86     return vector_as_array(&reads_);
87   }
88 
GetNumReads() const89   size_t GetNumReads() const {
90     return reads_.size();
91   }
92 
GetWrites()93   MockWrite* GetWrites() {
94     return vector_as_array(&writes_);
95   }
96 
GetNumWrites() const97   int GetNumWrites() const {
98     return writes_.size();
99   }
100 
101   SpdyTestUtil spdy_util_;
102   SpdySessionDependencies session_deps_;
103   scoped_refptr<HttpNetworkSession> session_;
104 
105  private:
106   // Used by Add{Read,Write}() above.
107   std::vector<MockWrite> writes_;
108   std::vector<MockRead> reads_;
109   int offset_;
110 };
111 
112 INSTANTIATE_TEST_CASE_P(
113     NextProto,
114     SpdyStreamTest,
115     testing::Values(kProtoDeprecatedSPDY2,
116                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
117                     kProtoHTTP2Draft04));
118 
TEST_P(SpdyStreamTest,SendDataAfterOpen)119 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
120   GURL url(kStreamUrl);
121 
122   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
123 
124   scoped_ptr<SpdyFrame> req(
125       spdy_util_.ConstructSpdyPost(
126           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
127   AddWrite(*req);
128 
129   scoped_ptr<SpdyFrame> resp(
130       spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
131   AddRead(*resp);
132 
133   scoped_ptr<SpdyFrame> msg(
134       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
135   AddWrite(*msg);
136 
137   scoped_ptr<SpdyFrame> echo(
138       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
139   AddRead(*echo);
140 
141   AddReadEOF();
142 
143   OrderedSocketData data(GetReads(), GetNumReads(),
144                          GetWrites(), GetNumWrites());
145   MockConnect connect_data(SYNCHRONOUS, OK);
146   data.set_connect_data(connect_data);
147 
148   session_deps_.socket_factory->AddSocketDataProvider(&data);
149 
150   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
151 
152   base::WeakPtr<SpdyStream> stream =
153       CreateStreamSynchronously(
154           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
155   ASSERT_TRUE(stream.get() != NULL);
156 
157   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
158   stream->SetDelegate(&delegate);
159 
160   EXPECT_FALSE(stream->HasUrlFromHeaders());
161 
162   scoped_ptr<SpdyHeaderBlock> headers(
163       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
164   EXPECT_EQ(ERR_IO_PENDING,
165             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
166   EXPECT_TRUE(stream->HasUrlFromHeaders());
167   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
168 
169   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
170 
171   EXPECT_TRUE(delegate.send_headers_completed());
172   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
173   EXPECT_EQ("HTTP/1.1",
174             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
175   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
176             delegate.TakeReceivedData());
177   EXPECT_TRUE(data.at_write_eof());
178 }
179 
TEST_P(SpdyStreamTest,PushedStream)180 TEST_P(SpdyStreamTest, PushedStream) {
181   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
182 
183   AddReadEOF();
184 
185   OrderedSocketData data(GetReads(), GetNumReads(),
186                          GetWrites(), GetNumWrites());
187   MockConnect connect_data(SYNCHRONOUS, OK);
188   data.set_connect_data(connect_data);
189 
190   session_deps_.socket_factory->AddSocketDataProvider(&data);
191 
192   base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
193 
194   // Conjure up a stream.
195   SpdyStream stream(SPDY_PUSH_STREAM,
196                     spdy_session,
197                     GURL(),
198                     DEFAULT_PRIORITY,
199                     kSpdyStreamInitialWindowSize,
200                     kSpdyStreamInitialWindowSize,
201                     BoundNetLog());
202   stream.set_stream_id(2);
203   EXPECT_FALSE(stream.HasUrlFromHeaders());
204 
205   // Set a couple of headers.
206   SpdyHeaderBlock response;
207   spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &response);
208   stream.OnInitialResponseHeadersReceived(
209       response, base::Time::Now(), base::TimeTicks::Now());
210 
211   // Send some basic headers.
212   SpdyHeaderBlock headers;
213   headers[spdy_util_.GetStatusKey()] = "200";
214   headers[spdy_util_.GetVersionKey()] = "OK";
215   stream.OnAdditionalResponseHeadersReceived(headers);
216 
217   EXPECT_TRUE(stream.HasUrlFromHeaders());
218   EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
219 
220   StreamDelegateDoNothing delegate(stream.GetWeakPtr());
221   stream.SetDelegate(&delegate);
222 
223   base::MessageLoop::current()->RunUntilIdle();
224 
225   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
226 
227   EXPECT_TRUE(spdy_session == NULL);
228 }
229 
TEST_P(SpdyStreamTest,StreamError)230 TEST_P(SpdyStreamTest, StreamError) {
231   GURL url(kStreamUrl);
232 
233   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
234 
235   scoped_ptr<SpdyFrame> req(
236       spdy_util_.ConstructSpdyPost(
237           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
238   AddWrite(*req);
239 
240   scoped_ptr<SpdyFrame> resp(
241       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
242   AddRead(*resp);
243 
244   scoped_ptr<SpdyFrame> msg(
245       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
246   AddWrite(*msg);
247 
248   scoped_ptr<SpdyFrame> echo(
249       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
250   AddRead(*echo);
251 
252   AddReadEOF();
253 
254   CapturingBoundNetLog log;
255 
256   OrderedSocketData data(GetReads(), GetNumReads(),
257                          GetWrites(), GetNumWrites());
258   MockConnect connect_data(SYNCHRONOUS, OK);
259   data.set_connect_data(connect_data);
260 
261   session_deps_.socket_factory->AddSocketDataProvider(&data);
262 
263   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
264 
265   base::WeakPtr<SpdyStream> stream =
266       CreateStreamSynchronously(
267           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
268   ASSERT_TRUE(stream.get() != NULL);
269 
270   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
271   stream->SetDelegate(&delegate);
272 
273   EXPECT_FALSE(stream->HasUrlFromHeaders());
274 
275   scoped_ptr<SpdyHeaderBlock> headers(
276       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
277   EXPECT_EQ(ERR_IO_PENDING,
278             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
279   EXPECT_TRUE(stream->HasUrlFromHeaders());
280   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
281 
282   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
283 
284   const SpdyStreamId stream_id = delegate.stream_id();
285 
286   EXPECT_TRUE(delegate.send_headers_completed());
287   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
288   EXPECT_EQ("HTTP/1.1",
289             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
290   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
291             delegate.TakeReceivedData());
292   EXPECT_TRUE(data.at_write_eof());
293 
294   // Check that the NetLog was filled reasonably.
295   net::CapturingNetLog::CapturedEntryList entries;
296   log.GetEntries(&entries);
297   EXPECT_LT(0u, entries.size());
298 
299   // Check that we logged SPDY_STREAM_ERROR correctly.
300   int pos = net::ExpectLogContainsSomewhere(
301       entries, 0,
302       net::NetLog::TYPE_SPDY_STREAM_ERROR,
303       net::NetLog::PHASE_NONE);
304 
305   int stream_id2;
306   ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
307   EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
308 }
309 
310 // Make sure that large blocks of data are properly split up into
311 // frame-sized chunks for a request/response (i.e., an HTTP-like)
312 // stream.
TEST_P(SpdyStreamTest,SendLargeDataAfterOpenRequestResponse)313 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
314   GURL url(kStreamUrl);
315 
316   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
317 
318   scoped_ptr<SpdyFrame> req(
319       spdy_util_.ConstructSpdyPost(
320           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
321   AddWrite(*req);
322 
323   std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
324   scoped_ptr<SpdyFrame> chunk(
325       spdy_util_.ConstructSpdyBodyFrame(
326           1, chunk_data.data(), chunk_data.length(), false));
327   AddWrite(*chunk);
328   AddWrite(*chunk);
329 
330   scoped_ptr<SpdyFrame> last_chunk(
331       spdy_util_.ConstructSpdyBodyFrame(
332           1, chunk_data.data(), chunk_data.length(), true));
333   AddWrite(*last_chunk);
334 
335   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
336   AddRead(*resp);
337 
338   AddReadEOF();
339 
340   OrderedSocketData data(GetReads(), GetNumReads(),
341                          GetWrites(), GetNumWrites());
342   MockConnect connect_data(SYNCHRONOUS, OK);
343   data.set_connect_data(connect_data);
344 
345   session_deps_.socket_factory->AddSocketDataProvider(&data);
346 
347   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
348 
349   base::WeakPtr<SpdyStream> stream =
350       CreateStreamSynchronously(
351           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
352   ASSERT_TRUE(stream.get() != NULL);
353 
354   std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
355   StreamDelegateWithBody delegate(stream, body_data);
356   stream->SetDelegate(&delegate);
357 
358   EXPECT_FALSE(stream->HasUrlFromHeaders());
359 
360   scoped_ptr<SpdyHeaderBlock> headers(
361       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
362   EXPECT_EQ(ERR_IO_PENDING,
363             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
364   EXPECT_TRUE(stream->HasUrlFromHeaders());
365   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
366 
367   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
368 
369   EXPECT_TRUE(delegate.send_headers_completed());
370   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
371   EXPECT_EQ("HTTP/1.1",
372             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
373   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
374   EXPECT_TRUE(data.at_write_eof());
375 }
376 
377 // Make sure that large blocks of data are properly split up into
378 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
379 // stream.
TEST_P(SpdyStreamTest,SendLargeDataAfterOpenBidirectional)380 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
381   GURL url(kStreamUrl);
382 
383   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
384 
385   scoped_ptr<SpdyFrame> req(
386       spdy_util_.ConstructSpdyPost(
387           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
388   AddWrite(*req);
389 
390   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
391   AddRead(*resp);
392 
393   std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
394   scoped_ptr<SpdyFrame> chunk(
395       spdy_util_.ConstructSpdyBodyFrame(
396           1, chunk_data.data(), chunk_data.length(), false));
397   AddWrite(*chunk);
398   AddWrite(*chunk);
399   AddWrite(*chunk);
400 
401   AddReadEOF();
402 
403   OrderedSocketData data(GetReads(), GetNumReads(),
404                          GetWrites(), GetNumWrites());
405   MockConnect connect_data(SYNCHRONOUS, OK);
406   data.set_connect_data(connect_data);
407 
408   session_deps_.socket_factory->AddSocketDataProvider(&data);
409 
410   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
411 
412   base::WeakPtr<SpdyStream> stream =
413       CreateStreamSynchronously(
414           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
415   ASSERT_TRUE(stream.get() != NULL);
416 
417   std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
418   StreamDelegateSendImmediate delegate(stream, body_data);
419   stream->SetDelegate(&delegate);
420 
421   EXPECT_FALSE(stream->HasUrlFromHeaders());
422 
423   scoped_ptr<SpdyHeaderBlock> headers(
424       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
425   EXPECT_EQ(ERR_IO_PENDING,
426             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
427   EXPECT_TRUE(stream->HasUrlFromHeaders());
428   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
429 
430   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
431 
432   EXPECT_TRUE(delegate.send_headers_completed());
433   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
434   EXPECT_EQ("HTTP/1.1",
435             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
436   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
437   EXPECT_TRUE(data.at_write_eof());
438 }
439 
440 // Receiving a header with uppercase ASCII should result in a protocol
441 // error.
TEST_P(SpdyStreamTest,UpperCaseHeaders)442 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
443   GURL url(kStreamUrl);
444 
445   session_ =
446       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
447 
448   scoped_ptr<SpdyFrame> syn(
449       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
450   AddWrite(*syn);
451 
452   const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
453   scoped_ptr<SpdyFrame>
454       reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
455   AddRead(*reply);
456 
457   scoped_ptr<SpdyFrame> rst(
458       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
459   AddWrite(*rst);
460 
461   AddReadEOF();
462 
463   DeterministicSocketData data(GetReads(), GetNumReads(),
464                                GetWrites(), GetNumWrites());
465   MockConnect connect_data(SYNCHRONOUS, OK);
466   data.set_connect_data(connect_data);
467 
468   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
469 
470   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
471 
472   base::WeakPtr<SpdyStream> stream =
473       CreateStreamSynchronously(
474           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
475   ASSERT_TRUE(stream.get() != NULL);
476 
477   StreamDelegateDoNothing delegate(stream);
478   stream->SetDelegate(&delegate);
479 
480   EXPECT_FALSE(stream->HasUrlFromHeaders());
481 
482   scoped_ptr<SpdyHeaderBlock> headers(
483       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
484   EXPECT_EQ(ERR_IO_PENDING,
485             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
486   EXPECT_TRUE(stream->HasUrlFromHeaders());
487   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
488 
489   data.RunFor(4);
490 
491   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
492 }
493 
494 // Receiving a header with uppercase ASCII should result in a protocol
495 // error even for a push stream.
TEST_P(SpdyStreamTest,UpperCaseHeadersOnPush)496 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
497   GURL url(kStreamUrl);
498 
499   session_ =
500       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
501 
502   scoped_ptr<SpdyFrame> syn(
503       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
504   AddWrite(*syn);
505 
506   scoped_ptr<SpdyFrame>
507       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
508   AddRead(*reply);
509 
510   const char* const extra_headers[] = {"X-UpperCase", "yes"};
511   scoped_ptr<SpdyFrame>
512       push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
513   AddRead(*push);
514 
515   scoped_ptr<SpdyFrame> rst(
516       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
517   AddWrite(*rst);
518 
519   AddReadEOF();
520 
521   DeterministicSocketData data(GetReads(), GetNumReads(),
522                                GetWrites(), GetNumWrites());
523   MockConnect connect_data(SYNCHRONOUS, OK);
524   data.set_connect_data(connect_data);
525 
526   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
527 
528   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
529 
530   base::WeakPtr<SpdyStream> stream =
531       CreateStreamSynchronously(
532           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
533   ASSERT_TRUE(stream.get() != NULL);
534 
535   StreamDelegateDoNothing delegate(stream);
536   stream->SetDelegate(&delegate);
537 
538   EXPECT_FALSE(stream->HasUrlFromHeaders());
539 
540   scoped_ptr<SpdyHeaderBlock> headers(
541       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
542   EXPECT_EQ(ERR_IO_PENDING,
543             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
544   EXPECT_TRUE(stream->HasUrlFromHeaders());
545   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
546 
547   data.RunFor(4);
548 
549   base::WeakPtr<SpdyStream> push_stream;
550   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
551   EXPECT_FALSE(push_stream);
552 
553   data.RunFor(1);
554 
555   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
556 }
557 
558 // Receiving a header with uppercase ASCII in a HEADERS frame should
559 // result in a protocol error.
TEST_P(SpdyStreamTest,UpperCaseHeadersInHeadersFrame)560 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
561   GURL url(kStreamUrl);
562 
563   session_ =
564       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
565 
566   scoped_ptr<SpdyFrame> syn(
567       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
568   AddWrite(*syn);
569 
570   scoped_ptr<SpdyFrame>
571       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
572   AddRead(*reply);
573 
574   scoped_ptr<SpdyFrame>
575       push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
576   AddRead(*push);
577 
578   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
579   (*late_headers)["X-UpperCase"] = "yes";
580   scoped_ptr<SpdyFrame> headers_frame(
581       spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
582                                            false,
583                                            2,
584                                            LOWEST,
585                                            HEADERS,
586                                            CONTROL_FLAG_NONE,
587                                            0));
588   AddRead(*headers_frame);
589 
590   scoped_ptr<SpdyFrame> rst(
591       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
592   AddWrite(*rst);
593 
594   AddReadEOF();
595 
596   DeterministicSocketData data(GetReads(), GetNumReads(),
597                                GetWrites(), GetNumWrites());
598   MockConnect connect_data(SYNCHRONOUS, OK);
599   data.set_connect_data(connect_data);
600 
601   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
602 
603   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
604 
605   base::WeakPtr<SpdyStream> stream =
606       CreateStreamSynchronously(
607           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
608   ASSERT_TRUE(stream.get() != NULL);
609 
610   StreamDelegateDoNothing delegate(stream);
611   stream->SetDelegate(&delegate);
612 
613   EXPECT_FALSE(stream->HasUrlFromHeaders());
614 
615   scoped_ptr<SpdyHeaderBlock> headers(
616       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
617   EXPECT_EQ(ERR_IO_PENDING,
618             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
619   EXPECT_TRUE(stream->HasUrlFromHeaders());
620   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
621 
622   data.RunFor(3);
623 
624   base::WeakPtr<SpdyStream> push_stream;
625   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
626   EXPECT_TRUE(push_stream);
627 
628   data.RunFor(1);
629 
630   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
631   EXPECT_FALSE(push_stream);
632 
633   data.RunFor(2);
634 
635   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
636 }
637 
638 // Receiving a duplicate header in a HEADERS frame should result in a
639 // protocol error.
TEST_P(SpdyStreamTest,DuplicateHeaders)640 TEST_P(SpdyStreamTest, DuplicateHeaders) {
641   GURL url(kStreamUrl);
642 
643   session_ =
644       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
645 
646   scoped_ptr<SpdyFrame> syn(
647       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
648   AddWrite(*syn);
649 
650   scoped_ptr<SpdyFrame>
651       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
652   AddRead(*reply);
653 
654   scoped_ptr<SpdyFrame>
655       push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
656   AddRead(*push);
657 
658   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
659   (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
660   scoped_ptr<SpdyFrame> headers_frame(
661       spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
662                                            false,
663                                            2,
664                                            LOWEST,
665                                            HEADERS,
666                                            CONTROL_FLAG_NONE,
667                                            0));
668   AddRead(*headers_frame);
669 
670   scoped_ptr<SpdyFrame> rst(
671       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
672   AddWrite(*rst);
673 
674   AddReadEOF();
675 
676   DeterministicSocketData data(GetReads(), GetNumReads(),
677                                GetWrites(), GetNumWrites());
678   MockConnect connect_data(SYNCHRONOUS, OK);
679   data.set_connect_data(connect_data);
680 
681   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
682 
683   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
684 
685   base::WeakPtr<SpdyStream> stream =
686       CreateStreamSynchronously(
687           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
688   ASSERT_TRUE(stream.get() != NULL);
689 
690   StreamDelegateDoNothing delegate(stream);
691   stream->SetDelegate(&delegate);
692 
693   EXPECT_FALSE(stream->HasUrlFromHeaders());
694 
695   scoped_ptr<SpdyHeaderBlock> headers(
696       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
697   EXPECT_EQ(ERR_IO_PENDING,
698             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
699   EXPECT_TRUE(stream->HasUrlFromHeaders());
700   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
701 
702   data.RunFor(3);
703 
704   base::WeakPtr<SpdyStream> push_stream;
705   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
706   EXPECT_TRUE(push_stream);
707 
708   data.RunFor(1);
709 
710   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
711   EXPECT_FALSE(push_stream);
712 
713   data.RunFor(2);
714 
715   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
716 }
717 
718 // The tests below are only for SPDY/3 and above.
719 
720 // Call IncreaseSendWindowSize on a stream with a large enough delta
721 // to overflow an int32. The SpdyStream should handle that case
722 // gracefully.
TEST_P(SpdyStreamTest,IncreaseSendWindowSizeOverflow)723 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
724   if (spdy_util_.protocol() < kProtoSPDY3)
725     return;
726 
727   session_ =
728       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
729 
730   scoped_ptr<SpdyFrame> req(
731       spdy_util_.ConstructSpdyPost(
732           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
733   AddWrite(*req);
734 
735   // Triggered by the overflowing call to IncreaseSendWindowSize
736   // below.
737   scoped_ptr<SpdyFrame> rst(
738       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
739   AddWrite(*rst);
740 
741   AddReadEOF();
742 
743   CapturingBoundNetLog log;
744 
745   DeterministicSocketData data(GetReads(), GetNumReads(),
746                                GetWrites(), GetNumWrites());
747   MockConnect connect_data(SYNCHRONOUS, OK);
748   data.set_connect_data(connect_data);
749 
750   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
751 
752   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
753   GURL url(kStreamUrl);
754 
755   base::WeakPtr<SpdyStream> stream =
756       CreateStreamSynchronously(
757           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
758   ASSERT_TRUE(stream.get() != NULL);
759   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
760   stream->SetDelegate(&delegate);
761 
762   scoped_ptr<SpdyHeaderBlock> headers(
763       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
764   EXPECT_EQ(ERR_IO_PENDING,
765             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
766   EXPECT_TRUE(stream->HasUrlFromHeaders());
767   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
768 
769   data.RunFor(1);
770 
771   int32 old_send_window_size = stream->send_window_size();
772   ASSERT_GT(old_send_window_size, 0);
773   int32 delta_window_size = kint32max - old_send_window_size + 1;
774   stream->IncreaseSendWindowSize(delta_window_size);
775   EXPECT_EQ(NULL, stream.get());
776 
777   data.RunFor(2);
778 
779   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
780 }
781 
782 // Functions used with
783 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
784 
StallStream(const base::WeakPtr<SpdyStream> & stream)785 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
786   // Reduce the send window size to 0 to stall.
787   while (stream->send_window_size() > 0) {
788     stream->DecreaseSendWindowSize(
789         std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
790   }
791 }
792 
IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream> & stream,int32 delta_window_size)793 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
794                                   int32 delta_window_size) {
795   EXPECT_TRUE(stream->send_stalled_by_flow_control());
796   stream->IncreaseSendWindowSize(delta_window_size);
797   EXPECT_FALSE(stream->send_stalled_by_flow_control());
798 }
799 
AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream> & stream,int32 delta_window_size)800 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
801                                 int32 delta_window_size) {
802   // Make sure that negative adjustments are handled properly.
803   EXPECT_TRUE(stream->send_stalled_by_flow_control());
804   stream->AdjustSendWindowSize(-delta_window_size);
805   EXPECT_TRUE(stream->send_stalled_by_flow_control());
806   stream->AdjustSendWindowSize(+delta_window_size);
807   EXPECT_TRUE(stream->send_stalled_by_flow_control());
808   stream->AdjustSendWindowSize(+delta_window_size);
809   EXPECT_FALSE(stream->send_stalled_by_flow_control());
810 }
811 
812 // Given an unstall function, runs a test to make sure that a
813 // request/response (i.e., an HTTP-like) stream resumes after a stall
814 // and unstall.
RunResumeAfterUnstallRequestResponseTest(const UnstallFunction & unstall_function)815 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
816     const UnstallFunction& unstall_function) {
817   GURL url(kStreamUrl);
818 
819   session_ =
820       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
821 
822   scoped_ptr<SpdyFrame> req(
823       spdy_util_.ConstructSpdyPost(
824           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
825   AddWrite(*req);
826 
827   scoped_ptr<SpdyFrame> body(
828       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
829   AddWrite(*body);
830 
831   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
832   AddRead(*resp);
833 
834   AddReadEOF();
835 
836   DeterministicSocketData data(GetReads(), GetNumReads(),
837                                GetWrites(), GetNumWrites());
838   MockConnect connect_data(SYNCHRONOUS, OK);
839   data.set_connect_data(connect_data);
840 
841   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
842 
843   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
844 
845   base::WeakPtr<SpdyStream> stream =
846       CreateStreamSynchronously(
847           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
848   ASSERT_TRUE(stream.get() != NULL);
849 
850   StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
851   stream->SetDelegate(&delegate);
852 
853   EXPECT_FALSE(stream->HasUrlFromHeaders());
854   EXPECT_FALSE(stream->send_stalled_by_flow_control());
855 
856   scoped_ptr<SpdyHeaderBlock> headers(
857       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
858   EXPECT_EQ(ERR_IO_PENDING,
859             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
860   EXPECT_TRUE(stream->HasUrlFromHeaders());
861   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
862 
863   StallStream(stream);
864 
865   data.RunFor(1);
866 
867   EXPECT_TRUE(stream->send_stalled_by_flow_control());
868 
869   unstall_function.Run(stream, kPostBodyLength);
870 
871   EXPECT_FALSE(stream->send_stalled_by_flow_control());
872 
873   data.RunFor(3);
874 
875   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
876 
877   EXPECT_TRUE(delegate.send_headers_completed());
878   EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
879   EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
880   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
881   EXPECT_TRUE(data.at_write_eof());
882 }
883 
TEST_P(SpdyStreamTest,ResumeAfterSendWindowSizeIncreaseRequestResponse)884 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
885   if (spdy_util_.protocol() < kProtoSPDY3)
886     return;
887 
888   RunResumeAfterUnstallRequestResponseTest(
889       base::Bind(&IncreaseStreamSendWindowSize));
890 }
891 
TEST_P(SpdyStreamTest,ResumeAfterSendWindowSizeAdjustRequestResponse)892 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
893   if (spdy_util_.protocol() < kProtoSPDY3)
894     return;
895 
896   RunResumeAfterUnstallRequestResponseTest(
897       base::Bind(&AdjustStreamSendWindowSize));
898 }
899 
900 // Given an unstall function, runs a test to make sure that a
901 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
902 // and unstall.
RunResumeAfterUnstallBidirectionalTest(const UnstallFunction & unstall_function)903 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
904     const UnstallFunction& unstall_function) {
905   GURL url(kStreamUrl);
906 
907   session_ =
908       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
909 
910   scoped_ptr<SpdyFrame> req(
911       spdy_util_.ConstructSpdyPost(
912           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
913   AddWrite(*req);
914 
915   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
916   AddRead(*resp);
917 
918   scoped_ptr<SpdyFrame> msg(
919       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
920   AddWrite(*msg);
921 
922   scoped_ptr<SpdyFrame> echo(
923       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
924   AddRead(*echo);
925 
926   AddReadEOF();
927 
928   DeterministicSocketData data(GetReads(), GetNumReads(),
929                                GetWrites(), GetNumWrites());
930   MockConnect connect_data(SYNCHRONOUS, OK);
931   data.set_connect_data(connect_data);
932 
933   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
934 
935   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
936 
937   base::WeakPtr<SpdyStream> stream =
938       CreateStreamSynchronously(
939           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
940   ASSERT_TRUE(stream.get() != NULL);
941 
942   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
943   stream->SetDelegate(&delegate);
944 
945   EXPECT_FALSE(stream->HasUrlFromHeaders());
946 
947   scoped_ptr<SpdyHeaderBlock> headers(
948       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
949   EXPECT_EQ(ERR_IO_PENDING,
950             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
951   EXPECT_TRUE(stream->HasUrlFromHeaders());
952   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
953 
954   data.RunFor(1);
955 
956   EXPECT_FALSE(stream->send_stalled_by_flow_control());
957 
958   StallStream(stream);
959 
960   data.RunFor(1);
961 
962   EXPECT_TRUE(stream->send_stalled_by_flow_control());
963 
964   unstall_function.Run(stream, kPostBodyLength);
965 
966   EXPECT_FALSE(stream->send_stalled_by_flow_control());
967 
968   data.RunFor(3);
969 
970   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
971 
972   EXPECT_TRUE(delegate.send_headers_completed());
973   EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
974   EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
975   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
976             delegate.TakeReceivedData());
977   EXPECT_TRUE(data.at_write_eof());
978 }
979 
TEST_P(SpdyStreamTest,ResumeAfterSendWindowSizeIncreaseBidirectional)980 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
981   if (spdy_util_.protocol() < kProtoSPDY3)
982     return;
983 
984   RunResumeAfterUnstallBidirectionalTest(
985       base::Bind(&IncreaseStreamSendWindowSize));
986 }
987 
TEST_P(SpdyStreamTest,ResumeAfterSendWindowSizeAdjustBidirectional)988 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
989   if (spdy_util_.protocol() < kProtoSPDY3)
990     return;
991 
992   RunResumeAfterUnstallBidirectionalTest(
993       base::Bind(&AdjustStreamSendWindowSize));
994 }
995 
996 // Test calculation of amount of bytes received from network.
TEST_P(SpdyStreamTest,ReceivedBytes)997 TEST_P(SpdyStreamTest, ReceivedBytes) {
998   GURL url(kStreamUrl);
999 
1000   session_ =
1001       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
1002 
1003   scoped_ptr<SpdyFrame> syn(
1004       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1005   AddWrite(*syn);
1006 
1007   scoped_ptr<SpdyFrame>
1008       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1009   AddRead(*reply);
1010 
1011   scoped_ptr<SpdyFrame> msg(
1012       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1013   AddRead(*msg);
1014 
1015   AddReadEOF();
1016 
1017   DeterministicSocketData data(GetReads(), GetNumReads(),
1018                                GetWrites(), GetNumWrites());
1019   MockConnect connect_data(SYNCHRONOUS, OK);
1020   data.set_connect_data(connect_data);
1021 
1022   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1023 
1024   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1025 
1026   base::WeakPtr<SpdyStream> stream =
1027       CreateStreamSynchronously(
1028           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1029   ASSERT_TRUE(stream.get() != NULL);
1030 
1031   StreamDelegateDoNothing delegate(stream);
1032   stream->SetDelegate(&delegate);
1033 
1034   EXPECT_FALSE(stream->HasUrlFromHeaders());
1035 
1036   scoped_ptr<SpdyHeaderBlock> headers(
1037       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1038   EXPECT_EQ(ERR_IO_PENDING,
1039             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1040   EXPECT_TRUE(stream->HasUrlFromHeaders());
1041   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1042 
1043   int64 reply_frame_len = reply->size();
1044   int64 data_header_len = spdy_util_.CreateFramer()->GetDataFrameMinimumSize();
1045   int64 data_frame_len = data_header_len + kPostBodyLength;
1046   int64 response_len = reply_frame_len + data_frame_len;
1047 
1048   EXPECT_EQ(0, stream->raw_received_bytes());
1049   data.RunFor(1); // SYN
1050   EXPECT_EQ(0, stream->raw_received_bytes());
1051   data.RunFor(1); // REPLY
1052   EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1053   data.RunFor(1); // DATA
1054   EXPECT_EQ(response_len, stream->raw_received_bytes());
1055   data.RunFor(1); // FIN
1056 
1057   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1058 }
1059 
1060 }  // namespace
1061 
1062 }  // namespace test
1063 
1064 }  // namespace net
1065