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