OLD | NEW |
| (Empty) |
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 "net/spdy/spdy_stream.h" | |
6 | |
7 #include <stdint.h> | |
8 | |
9 #include <algorithm> | |
10 #include <cstddef> | |
11 #include <limits> | |
12 #include <memory> | |
13 #include <utility> | |
14 #include <vector> | |
15 | |
16 #include "base/memory/ref_counted.h" | |
17 #include "base/run_loop.h" | |
18 #include "net/base/completion_callback.h" | |
19 #include "net/base/request_priority.h" | |
20 #include "net/log/net_log_event_type.h" | |
21 #include "net/log/test_net_log.h" | |
22 #include "net/log/test_net_log_entry.h" | |
23 #include "net/log/test_net_log_util.h" | |
24 #include "net/socket/socket_test_util.h" | |
25 #include "net/spdy/buffered_spdy_framer.h" | |
26 #include "net/spdy/platform/api/spdy_string_piece.h" | |
27 #include "net/spdy/spdy_http_utils.h" | |
28 #include "net/spdy/spdy_protocol.h" | |
29 #include "net/spdy/spdy_session.h" | |
30 #include "net/spdy/spdy_stream_test_util.h" | |
31 #include "net/spdy/spdy_test_util_common.h" | |
32 #include "net/test/cert_test_util.h" | |
33 #include "net/test/gtest_util.h" | |
34 #include "net/test/test_data_directory.h" | |
35 #include "testing/gmock/include/gmock/gmock.h" | |
36 #include "testing/gtest/include/gtest/gtest.h" | |
37 | |
38 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc | |
39 // | |
40 namespace net { | |
41 | |
42 namespace test { | |
43 | |
44 namespace { | |
45 | |
46 const char kPushUrl[] = "https://www.example.org/push"; | |
47 const char kPostBody[] = "\0hello!\xff"; | |
48 const size_t kPostBodyLength = arraysize(kPostBody); | |
49 const SpdyStringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength); | |
50 | |
51 static base::TimeTicks g_time_now; | |
52 | |
53 base::TimeTicks InstantaneousReads() { | |
54 return g_time_now; | |
55 } | |
56 | |
57 } // namespace | |
58 | |
59 class SpdyStreamTest : public ::testing::Test { | |
60 protected: | |
61 // A function that takes a SpdyStream and the number of bytes which | |
62 // will unstall the next frame completely. | |
63 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32_t)> | |
64 UnstallFunction; | |
65 | |
66 SpdyStreamTest() | |
67 : url_(kDefaultUrl), | |
68 session_(SpdySessionDependencies::SpdyCreateSession(&session_deps_)), | |
69 offset_(0), | |
70 ssl_(SYNCHRONOUS, OK) {} | |
71 | |
72 ~SpdyStreamTest() override {} | |
73 | |
74 base::WeakPtr<SpdySession> CreateDefaultSpdySession() { | |
75 SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(), | |
76 PRIVACY_MODE_DISABLED); | |
77 return CreateSecureSpdySession(session_.get(), key, NetLogWithSource()); | |
78 } | |
79 | |
80 void TearDown() override { base::RunLoop().RunUntilIdle(); } | |
81 | |
82 void RunResumeAfterUnstallRequestResponseTest( | |
83 const UnstallFunction& unstall_function); | |
84 | |
85 void RunResumeAfterUnstallBidirectionalTest( | |
86 const UnstallFunction& unstall_function); | |
87 | |
88 // Add{Read,Write}() populates lists that are eventually passed to a | |
89 // SocketData class. |frame| must live for the whole test. | |
90 | |
91 void AddRead(const SpdySerializedFrame& frame) { | |
92 reads_.push_back(CreateMockRead(frame, offset_++)); | |
93 } | |
94 | |
95 void AddWrite(const SpdySerializedFrame& frame) { | |
96 writes_.push_back(CreateMockWrite(frame, offset_++)); | |
97 } | |
98 | |
99 void AddReadEOF() { | |
100 reads_.push_back(MockRead(ASYNC, 0, offset_++)); | |
101 } | |
102 | |
103 void AddWritePause() { | |
104 writes_.push_back(MockWrite(ASYNC, ERR_IO_PENDING, offset_++)); | |
105 } | |
106 | |
107 void AddReadPause() { | |
108 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING, offset_++)); | |
109 } | |
110 | |
111 MockRead* GetReads() { return reads_.data(); } | |
112 | |
113 size_t GetNumReads() const { | |
114 return reads_.size(); | |
115 } | |
116 | |
117 MockWrite* GetWrites() { return writes_.data(); } | |
118 | |
119 int GetNumWrites() const { | |
120 return writes_.size(); | |
121 } | |
122 | |
123 void ActivatePushStream(SpdySession* session, SpdyStream* stream) { | |
124 std::unique_ptr<SpdyStream> activated = | |
125 session->ActivateCreatedStream(stream); | |
126 activated->set_stream_id(2); | |
127 session->InsertActivatedStream(std::move(activated)); | |
128 } | |
129 | |
130 void AddSSLSocketData() { | |
131 // Load a cert that is valid for | |
132 // www.example.org, mail.example.org, and mail.example.com. | |
133 ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
134 ASSERT_TRUE(ssl_.cert); | |
135 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_); | |
136 } | |
137 | |
138 const GURL url_; | |
139 SpdyTestUtil spdy_util_; | |
140 SpdySessionDependencies session_deps_; | |
141 std::unique_ptr<HttpNetworkSession> session_; | |
142 | |
143 private: | |
144 // Used by Add{Read,Write}() above. | |
145 std::vector<MockWrite> writes_; | |
146 std::vector<MockRead> reads_; | |
147 int offset_; | |
148 SSLSocketDataProvider ssl_; | |
149 }; | |
150 | |
151 TEST_F(SpdyStreamTest, SendDataAfterOpen) { | |
152 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
153 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
154 AddWrite(req); | |
155 | |
156 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
157 AddRead(resp); | |
158 | |
159 SpdySerializedFrame msg( | |
160 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
161 AddWrite(msg); | |
162 | |
163 SpdySerializedFrame echo( | |
164 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
165 AddRead(echo); | |
166 | |
167 AddReadEOF(); | |
168 | |
169 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
170 GetNumWrites()); | |
171 MockConnect connect_data(SYNCHRONOUS, OK); | |
172 data.set_connect_data(connect_data); | |
173 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
174 | |
175 AddSSLSocketData(); | |
176 | |
177 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
178 | |
179 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
180 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
181 ASSERT_TRUE(stream); | |
182 | |
183 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
184 stream->SetDelegate(&delegate); | |
185 | |
186 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
187 | |
188 SpdyHeaderBlock headers( | |
189 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
190 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
191 IsError(ERR_IO_PENDING)); | |
192 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
193 | |
194 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
195 | |
196 EXPECT_TRUE(delegate.send_headers_completed()); | |
197 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
198 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
199 delegate.TakeReceivedData()); | |
200 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
201 } | |
202 | |
203 // Delegate that receives trailers. | |
204 class StreamDelegateWithTrailers : public test::StreamDelegateWithBody { | |
205 public: | |
206 StreamDelegateWithTrailers(const base::WeakPtr<SpdyStream>& stream, | |
207 SpdyStringPiece data) | |
208 : StreamDelegateWithBody(stream, data) {} | |
209 | |
210 ~StreamDelegateWithTrailers() override {} | |
211 | |
212 void OnTrailers(const SpdyHeaderBlock& trailers) override { | |
213 trailers_ = trailers.Clone(); | |
214 } | |
215 | |
216 const SpdyHeaderBlock& trailers() const { return trailers_; } | |
217 | |
218 private: | |
219 SpdyHeaderBlock trailers_; | |
220 }; | |
221 | |
222 // Regression test for https://crbug.com/481033. | |
223 TEST_F(SpdyStreamTest, Trailers) { | |
224 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
225 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
226 AddWrite(req); | |
227 | |
228 SpdySerializedFrame msg( | |
229 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
230 AddWrite(msg); | |
231 | |
232 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
233 AddRead(resp); | |
234 | |
235 SpdySerializedFrame echo( | |
236 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
237 AddRead(echo); | |
238 | |
239 SpdyHeaderBlock late_headers; | |
240 late_headers["foo"] = "bar"; | |
241 SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
242 1, std::move(late_headers), false)); | |
243 AddRead(trailers); | |
244 | |
245 AddReadEOF(); | |
246 | |
247 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
248 GetNumWrites()); | |
249 MockConnect connect_data(SYNCHRONOUS, OK); | |
250 data.set_connect_data(connect_data); | |
251 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
252 | |
253 AddSSLSocketData(); | |
254 | |
255 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
256 | |
257 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
258 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
259 ASSERT_TRUE(stream); | |
260 | |
261 StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece); | |
262 stream->SetDelegate(&delegate); | |
263 | |
264 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
265 | |
266 SpdyHeaderBlock headers( | |
267 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
268 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
269 IsError(ERR_IO_PENDING)); | |
270 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
271 | |
272 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
273 | |
274 EXPECT_TRUE(delegate.send_headers_completed()); | |
275 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
276 const SpdyHeaderBlock& received_trailers = delegate.trailers(); | |
277 SpdyHeaderBlock::const_iterator it = received_trailers.find("foo"); | |
278 EXPECT_EQ("bar", it->second); | |
279 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
280 delegate.TakeReceivedData()); | |
281 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
282 } | |
283 | |
284 TEST_F(SpdyStreamTest, PushedStream) { | |
285 SpdySerializedFrame req( | |
286 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
287 AddWrite(req); | |
288 | |
289 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
290 AddRead(reply); | |
291 | |
292 SpdySerializedFrame push( | |
293 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushUrl)); | |
294 AddRead(push); | |
295 | |
296 SpdySerializedFrame priority( | |
297 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
298 AddWrite(priority); | |
299 | |
300 AddReadPause(); | |
301 | |
302 SpdyStringPiece pushed_msg("foo"); | |
303 SpdySerializedFrame pushed_body(spdy_util_.ConstructSpdyDataFrame( | |
304 2, pushed_msg.data(), pushed_msg.size(), true)); | |
305 AddRead(pushed_body); | |
306 | |
307 SpdyStringPiece msg("bar"); | |
308 SpdySerializedFrame body( | |
309 spdy_util_.ConstructSpdyDataFrame(1, msg.data(), msg.size(), true)); | |
310 AddRead(body); | |
311 | |
312 AddReadEOF(); | |
313 | |
314 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
315 GetNumWrites()); | |
316 MockConnect connect_data(SYNCHRONOUS, OK); | |
317 data.set_connect_data(connect_data); | |
318 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
319 | |
320 AddSSLSocketData(); | |
321 | |
322 g_time_now = base::TimeTicks::Now(); | |
323 session_deps_.time_func = InstantaneousReads; | |
324 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
325 | |
326 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
327 | |
328 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
329 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
330 ASSERT_TRUE(stream); | |
331 | |
332 StreamDelegateDoNothing delegate(stream); | |
333 stream->SetDelegate(&delegate); | |
334 | |
335 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
336 | |
337 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
338 EXPECT_THAT( | |
339 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
340 IsError(ERR_IO_PENDING)); | |
341 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
342 | |
343 data.RunUntilPaused(); | |
344 | |
345 SpdyStream* push_stream; | |
346 EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, | |
347 NetLogWithSource()), | |
348 IsOk()); | |
349 ASSERT_TRUE(push_stream); | |
350 EXPECT_EQ(kPushUrl, push_stream->GetUrlFromHeaders().spec()); | |
351 | |
352 LoadTimingInfo load_timing_info; | |
353 EXPECT_TRUE(push_stream->GetLoadTimingInfo(&load_timing_info)); | |
354 EXPECT_EQ(g_time_now, load_timing_info.push_start); | |
355 EXPECT_TRUE(load_timing_info.push_end.is_null()); | |
356 | |
357 StreamDelegateDoNothing push_delegate(push_stream->GetWeakPtr()); | |
358 push_stream->SetDelegate(&push_delegate); | |
359 | |
360 data.Resume(); | |
361 | |
362 EXPECT_TRUE(push_stream->GetLoadTimingInfo(&load_timing_info)); | |
363 EXPECT_EQ(g_time_now, load_timing_info.push_start); | |
364 EXPECT_FALSE(load_timing_info.push_end.is_null()); | |
365 | |
366 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
367 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
368 EXPECT_EQ(msg, delegate.TakeReceivedData()); | |
369 | |
370 EXPECT_THAT(push_delegate.WaitForClose(), IsOk()); | |
371 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
372 EXPECT_EQ(pushed_msg, push_delegate.TakeReceivedData()); | |
373 } | |
374 | |
375 TEST_F(SpdyStreamTest, StreamError) { | |
376 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
377 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
378 AddWrite(req); | |
379 | |
380 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
381 AddRead(resp); | |
382 | |
383 SpdySerializedFrame msg( | |
384 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
385 AddWrite(msg); | |
386 | |
387 SpdySerializedFrame echo( | |
388 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
389 AddRead(echo); | |
390 | |
391 AddReadEOF(); | |
392 | |
393 BoundTestNetLog log; | |
394 | |
395 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
396 GetNumWrites()); | |
397 MockConnect connect_data(SYNCHRONOUS, OK); | |
398 data.set_connect_data(connect_data); | |
399 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
400 | |
401 AddSSLSocketData(); | |
402 | |
403 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
404 | |
405 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
406 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, log.bound()); | |
407 ASSERT_TRUE(stream); | |
408 | |
409 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
410 stream->SetDelegate(&delegate); | |
411 | |
412 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
413 | |
414 SpdyHeaderBlock headers( | |
415 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
416 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
417 IsError(ERR_IO_PENDING)); | |
418 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
419 | |
420 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
421 | |
422 const SpdyStreamId stream_id = delegate.stream_id(); | |
423 | |
424 EXPECT_TRUE(delegate.send_headers_completed()); | |
425 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
426 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
427 delegate.TakeReceivedData()); | |
428 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
429 | |
430 // Check that the NetLog was filled reasonably. | |
431 TestNetLogEntry::List entries; | |
432 log.GetEntries(&entries); | |
433 EXPECT_LT(0u, entries.size()); | |
434 | |
435 // Check that we logged SPDY_STREAM_ERROR correctly. | |
436 int pos = ExpectLogContainsSomewhere( | |
437 entries, 0, NetLogEventType::HTTP2_STREAM_ERROR, NetLogEventPhase::NONE); | |
438 | |
439 int stream_id2; | |
440 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2)); | |
441 EXPECT_EQ(static_cast<int>(stream_id), stream_id2); | |
442 } | |
443 | |
444 // Make sure that large blocks of data are properly split up into frame-sized | |
445 // chunks for a request/response (i.e., an HTTP-like) stream. | |
446 TEST_F(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) { | |
447 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
448 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
449 AddWrite(req); | |
450 | |
451 SpdyString chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
452 SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame( | |
453 1, chunk_data.data(), chunk_data.length(), false)); | |
454 AddWrite(chunk); | |
455 AddWrite(chunk); | |
456 | |
457 SpdySerializedFrame last_chunk(spdy_util_.ConstructSpdyDataFrame( | |
458 1, chunk_data.data(), chunk_data.length(), true)); | |
459 AddWrite(last_chunk); | |
460 | |
461 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
462 AddRead(resp); | |
463 | |
464 AddReadEOF(); | |
465 | |
466 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
467 GetNumWrites()); | |
468 MockConnect connect_data(SYNCHRONOUS, OK); | |
469 data.set_connect_data(connect_data); | |
470 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
471 | |
472 AddSSLSocketData(); | |
473 | |
474 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
475 | |
476 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
477 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
478 ASSERT_TRUE(stream); | |
479 | |
480 SpdyString body_data(3 * kMaxSpdyFrameChunkSize, 'x'); | |
481 StreamDelegateWithBody delegate(stream, body_data); | |
482 stream->SetDelegate(&delegate); | |
483 | |
484 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
485 | |
486 SpdyHeaderBlock headers( | |
487 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
488 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
489 IsError(ERR_IO_PENDING)); | |
490 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
491 | |
492 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
493 | |
494 EXPECT_TRUE(delegate.send_headers_completed()); | |
495 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
496 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
497 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
498 } | |
499 | |
500 // Make sure that large blocks of data are properly split up into frame-sized | |
501 // chunks for a bidirectional (i.e., non-HTTP-like) stream. | |
502 TEST_F(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) { | |
503 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
504 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
505 AddWrite(req); | |
506 | |
507 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
508 AddRead(resp); | |
509 | |
510 SpdyString chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
511 SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame( | |
512 1, chunk_data.data(), chunk_data.length(), false)); | |
513 AddWrite(chunk); | |
514 AddWrite(chunk); | |
515 AddWrite(chunk); | |
516 | |
517 AddReadEOF(); | |
518 | |
519 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
520 GetNumWrites()); | |
521 MockConnect connect_data(SYNCHRONOUS, OK); | |
522 data.set_connect_data(connect_data); | |
523 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
524 | |
525 AddSSLSocketData(); | |
526 | |
527 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
528 | |
529 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
530 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
531 ASSERT_TRUE(stream); | |
532 | |
533 SpdyString body_data(3 * kMaxSpdyFrameChunkSize, 'x'); | |
534 StreamDelegateSendImmediate delegate(stream, body_data); | |
535 stream->SetDelegate(&delegate); | |
536 | |
537 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
538 | |
539 SpdyHeaderBlock headers( | |
540 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
541 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
542 IsError(ERR_IO_PENDING)); | |
543 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
544 | |
545 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
546 | |
547 EXPECT_TRUE(delegate.send_headers_completed()); | |
548 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
549 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
550 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
551 } | |
552 | |
553 // Receiving a header with uppercase ASCII should result in a protocol error. | |
554 TEST_F(SpdyStreamTest, UpperCaseHeaders) { | |
555 SpdySerializedFrame req( | |
556 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
557 AddWrite(req); | |
558 | |
559 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
560 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply( | |
561 kExtraHeaders, arraysize(kExtraHeaders) / 2, 1)); | |
562 AddRead(reply); | |
563 | |
564 SpdySerializedFrame rst( | |
565 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
566 AddWrite(rst); | |
567 | |
568 AddReadEOF(); | |
569 | |
570 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
571 GetNumWrites()); | |
572 MockConnect connect_data(SYNCHRONOUS, OK); | |
573 data.set_connect_data(connect_data); | |
574 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
575 | |
576 AddSSLSocketData(); | |
577 | |
578 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
579 | |
580 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
581 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
582 ASSERT_TRUE(stream); | |
583 | |
584 StreamDelegateDoNothing delegate(stream); | |
585 stream->SetDelegate(&delegate); | |
586 | |
587 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
588 | |
589 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
590 EXPECT_THAT( | |
591 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
592 IsError(ERR_IO_PENDING)); | |
593 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
594 | |
595 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
596 | |
597 // Finish async network reads and writes. | |
598 base::RunLoop().RunUntilIdle(); | |
599 | |
600 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
601 EXPECT_TRUE(data.AllReadDataConsumed()); | |
602 } | |
603 | |
604 // Receiving a header with uppercase ASCII should result in a protocol error | |
605 // even for a push stream. | |
606 TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) { | |
607 SpdySerializedFrame req( | |
608 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
609 AddWrite(req); | |
610 | |
611 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
612 AddRead(reply); | |
613 | |
614 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
615 SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( | |
616 kExtraHeaders, arraysize(kExtraHeaders) / 2, 2, 1, kPushUrl)); | |
617 AddRead(push); | |
618 | |
619 SpdySerializedFrame priority( | |
620 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
621 AddWrite(priority); | |
622 | |
623 SpdySerializedFrame rst( | |
624 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
625 AddWrite(rst); | |
626 | |
627 AddReadPause(); | |
628 | |
629 AddReadEOF(); | |
630 | |
631 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
632 GetNumWrites()); | |
633 MockConnect connect_data(SYNCHRONOUS, OK); | |
634 data.set_connect_data(connect_data); | |
635 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
636 | |
637 AddSSLSocketData(); | |
638 | |
639 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
640 | |
641 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
642 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
643 ASSERT_TRUE(stream); | |
644 | |
645 StreamDelegateDoNothing delegate(stream); | |
646 stream->SetDelegate(&delegate); | |
647 | |
648 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
649 | |
650 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
651 EXPECT_THAT( | |
652 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
653 IsError(ERR_IO_PENDING)); | |
654 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
655 | |
656 data.RunUntilPaused(); | |
657 | |
658 SpdyStream* push_stream; | |
659 EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, | |
660 NetLogWithSource()), | |
661 IsOk()); | |
662 EXPECT_FALSE(push_stream); | |
663 | |
664 data.Resume(); | |
665 | |
666 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
667 | |
668 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
669 EXPECT_TRUE(data.AllReadDataConsumed()); | |
670 } | |
671 | |
672 TEST_F(SpdyStreamTest, HeadersMustHaveStatus) { | |
673 SpdySerializedFrame req( | |
674 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
675 AddWrite(req); | |
676 | |
677 // Response headers without ":status" header field: protocol error. | |
678 SpdyHeaderBlock header_block_without_status; | |
679 header_block_without_status[spdy_util_.GetMethodKey()] = "GET"; | |
680 header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org"; | |
681 header_block_without_status[spdy_util_.GetSchemeKey()] = "https"; | |
682 header_block_without_status[spdy_util_.GetPathKey()] = "/"; | |
683 SpdySerializedFrame reply( | |
684 spdy_util_.ConstructSpdyReply(1, std::move(header_block_without_status))); | |
685 AddRead(reply); | |
686 | |
687 SpdySerializedFrame rst( | |
688 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
689 AddWrite(rst); | |
690 | |
691 AddReadEOF(); | |
692 | |
693 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
694 GetNumWrites()); | |
695 MockConnect connect_data(SYNCHRONOUS, OK); | |
696 data.set_connect_data(connect_data); | |
697 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
698 | |
699 AddSSLSocketData(); | |
700 | |
701 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
702 | |
703 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
704 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
705 ASSERT_TRUE(stream); | |
706 | |
707 StreamDelegateDoNothing delegate(stream); | |
708 stream->SetDelegate(&delegate); | |
709 | |
710 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
711 | |
712 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
713 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
714 NO_MORE_DATA_TO_SEND)); | |
715 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
716 | |
717 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
718 | |
719 // Finish async network reads and writes. | |
720 base::RunLoop().RunUntilIdle(); | |
721 | |
722 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
723 EXPECT_TRUE(data.AllReadDataConsumed()); | |
724 } | |
725 | |
726 TEST_F(SpdyStreamTest, HeadersMustHaveStatusOnPushedStream) { | |
727 SpdySerializedFrame req( | |
728 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
729 AddWrite(req); | |
730 | |
731 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
732 AddRead(reply); | |
733 | |
734 SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( | |
735 spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); | |
736 AddRead(push_promise); | |
737 | |
738 SpdySerializedFrame priority( | |
739 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
740 AddWrite(priority); | |
741 | |
742 // Response headers without ":status" header field: protocol error. | |
743 SpdyHeaderBlock header_block_without_status; | |
744 header_block_without_status[spdy_util_.GetMethodKey()] = "GET"; | |
745 header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org"; | |
746 header_block_without_status[spdy_util_.GetSchemeKey()] = "https"; | |
747 header_block_without_status[spdy_util_.GetPathKey()] = "/"; | |
748 SpdySerializedFrame pushed_reply( | |
749 spdy_util_.ConstructSpdyReply(2, std::move(header_block_without_status))); | |
750 AddRead(pushed_reply); | |
751 | |
752 SpdySerializedFrame rst( | |
753 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
754 AddWrite(rst); | |
755 | |
756 SpdySerializedFrame body( | |
757 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
758 AddRead(body); | |
759 | |
760 AddReadEOF(); | |
761 | |
762 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
763 GetNumWrites()); | |
764 MockConnect connect_data(SYNCHRONOUS, OK); | |
765 data.set_connect_data(connect_data); | |
766 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
767 | |
768 AddSSLSocketData(); | |
769 | |
770 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
771 | |
772 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
773 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
774 ASSERT_TRUE(stream); | |
775 | |
776 StreamDelegateDoNothing delegate(stream); | |
777 stream->SetDelegate(&delegate); | |
778 | |
779 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
780 | |
781 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
782 EXPECT_THAT( | |
783 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
784 IsError(ERR_IO_PENDING)); | |
785 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
786 | |
787 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
788 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
789 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
790 delegate.TakeReceivedData()); | |
791 | |
792 // Finish async network reads and writes. | |
793 base::RunLoop().RunUntilIdle(); | |
794 | |
795 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
796 EXPECT_TRUE(data.AllReadDataConsumed()); | |
797 } | |
798 | |
799 TEST_F(SpdyStreamTest, HeadersMustPreceedData) { | |
800 SpdySerializedFrame req( | |
801 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
802 AddWrite(req); | |
803 | |
804 // Response body not preceeded by headers: protocol error. | |
805 SpdySerializedFrame body( | |
806 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
807 AddRead(body); | |
808 | |
809 SpdySerializedFrame rst( | |
810 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
811 AddWrite(rst); | |
812 | |
813 AddReadEOF(); | |
814 | |
815 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
816 GetNumWrites()); | |
817 MockConnect connect_data(SYNCHRONOUS, OK); | |
818 data.set_connect_data(connect_data); | |
819 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
820 | |
821 AddSSLSocketData(); | |
822 | |
823 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
824 | |
825 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
826 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
827 ASSERT_TRUE(stream); | |
828 | |
829 StreamDelegateDoNothing delegate(stream); | |
830 stream->SetDelegate(&delegate); | |
831 | |
832 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
833 | |
834 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
835 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
836 NO_MORE_DATA_TO_SEND)); | |
837 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
838 | |
839 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
840 } | |
841 | |
842 TEST_F(SpdyStreamTest, HeadersMustPreceedDataOnPushedStream) { | |
843 SpdySerializedFrame req( | |
844 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
845 AddWrite(req); | |
846 | |
847 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
848 AddRead(reply); | |
849 | |
850 SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( | |
851 spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); | |
852 AddRead(push_promise); | |
853 | |
854 SpdySerializedFrame priority( | |
855 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
856 AddWrite(priority); | |
857 | |
858 SpdySerializedFrame pushed_body( | |
859 spdy_util_.ConstructSpdyDataFrame(2, kPostBody, kPostBodyLength, true)); | |
860 AddRead(pushed_body); | |
861 | |
862 SpdySerializedFrame rst( | |
863 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
864 AddWrite(rst); | |
865 | |
866 SpdySerializedFrame body( | |
867 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
868 AddRead(body); | |
869 | |
870 AddReadEOF(); | |
871 | |
872 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
873 GetNumWrites()); | |
874 MockConnect connect_data(SYNCHRONOUS, OK); | |
875 data.set_connect_data(connect_data); | |
876 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
877 | |
878 AddSSLSocketData(); | |
879 | |
880 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
881 | |
882 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
883 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
884 ASSERT_TRUE(stream); | |
885 | |
886 StreamDelegateDoNothing delegate(stream); | |
887 stream->SetDelegate(&delegate); | |
888 | |
889 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
890 | |
891 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
892 EXPECT_THAT( | |
893 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
894 IsError(ERR_IO_PENDING)); | |
895 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
896 | |
897 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
898 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
899 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
900 delegate.TakeReceivedData()); | |
901 | |
902 // Finish async network reads and writes. | |
903 base::RunLoop().RunUntilIdle(); | |
904 | |
905 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
906 EXPECT_TRUE(data.AllReadDataConsumed()); | |
907 } | |
908 | |
909 TEST_F(SpdyStreamTest, TrailersMustNotFollowTrailers) { | |
910 SpdySerializedFrame req( | |
911 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
912 AddWrite(req); | |
913 | |
914 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
915 AddRead(reply); | |
916 | |
917 SpdySerializedFrame body( | |
918 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
919 AddRead(body); | |
920 | |
921 SpdyHeaderBlock trailers_block; | |
922 trailers_block["foo"] = "bar"; | |
923 SpdySerializedFrame first_trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
924 1, std::move(trailers_block), false)); | |
925 AddRead(first_trailers); | |
926 | |
927 // Trailers following trailers: procotol error. | |
928 SpdySerializedFrame second_trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
929 1, std::move(trailers_block), true)); | |
930 AddRead(second_trailers); | |
931 | |
932 SpdySerializedFrame rst( | |
933 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
934 AddWrite(rst); | |
935 | |
936 AddReadEOF(); | |
937 | |
938 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
939 GetNumWrites()); | |
940 MockConnect connect_data(SYNCHRONOUS, OK); | |
941 data.set_connect_data(connect_data); | |
942 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
943 | |
944 AddSSLSocketData(); | |
945 | |
946 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
947 | |
948 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
949 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
950 ASSERT_TRUE(stream); | |
951 | |
952 StreamDelegateDoNothing delegate(stream); | |
953 stream->SetDelegate(&delegate); | |
954 | |
955 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
956 | |
957 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
958 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
959 NO_MORE_DATA_TO_SEND)); | |
960 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
961 | |
962 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
963 | |
964 // Finish async network reads and writes. | |
965 base::RunLoop().RunUntilIdle(); | |
966 | |
967 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
968 EXPECT_TRUE(data.AllReadDataConsumed()); | |
969 } | |
970 | |
971 TEST_F(SpdyStreamTest, DataMustNotFollowTrailers) { | |
972 SpdySerializedFrame req( | |
973 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
974 AddWrite(req); | |
975 | |
976 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
977 AddRead(reply); | |
978 | |
979 SpdySerializedFrame body( | |
980 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
981 AddRead(body); | |
982 | |
983 SpdyHeaderBlock trailers_block; | |
984 trailers_block["foo"] = "bar"; | |
985 SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
986 1, std::move(trailers_block), false)); | |
987 AddRead(trailers); | |
988 | |
989 // DATA frame following trailers: protocol error. | |
990 AddRead(body); | |
991 | |
992 SpdySerializedFrame rst( | |
993 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
994 AddWrite(rst); | |
995 | |
996 AddReadEOF(); | |
997 | |
998 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
999 GetNumWrites()); | |
1000 MockConnect connect_data(SYNCHRONOUS, OK); | |
1001 data.set_connect_data(connect_data); | |
1002 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1003 | |
1004 AddSSLSocketData(); | |
1005 | |
1006 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1007 | |
1008 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1009 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1010 ASSERT_TRUE(stream); | |
1011 | |
1012 StreamDelegateDoNothing delegate(stream); | |
1013 stream->SetDelegate(&delegate); | |
1014 | |
1015 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1016 | |
1017 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1018 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
1019 NO_MORE_DATA_TO_SEND)); | |
1020 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1021 | |
1022 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
1023 | |
1024 // Finish async network reads and writes. | |
1025 base::RunLoop().RunUntilIdle(); | |
1026 | |
1027 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1028 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1029 } | |
1030 | |
1031 TEST_F(SpdyStreamTest, InformationalHeaders) { | |
1032 SpdySerializedFrame req( | |
1033 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
1034 AddWrite(req); | |
1035 | |
1036 SpdyHeaderBlock informational_headers; | |
1037 informational_headers[":status"] = "100"; | |
1038 SpdySerializedFrame informational_response( | |
1039 spdy_util_.ConstructSpdyResponseHeaders( | |
1040 1, std::move(informational_headers), false)); | |
1041 AddRead(informational_response); | |
1042 | |
1043 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
1044 AddRead(reply); | |
1045 | |
1046 SpdySerializedFrame body( | |
1047 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
1048 AddRead(body); | |
1049 | |
1050 AddReadEOF(); | |
1051 | |
1052 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1053 GetNumWrites()); | |
1054 MockConnect connect_data(SYNCHRONOUS, OK); | |
1055 data.set_connect_data(connect_data); | |
1056 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1057 | |
1058 AddSSLSocketData(); | |
1059 | |
1060 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1061 | |
1062 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1063 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1064 ASSERT_TRUE(stream); | |
1065 | |
1066 StreamDelegateDoNothing delegate(stream); | |
1067 stream->SetDelegate(&delegate); | |
1068 | |
1069 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1070 | |
1071 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1072 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
1073 NO_MORE_DATA_TO_SEND)); | |
1074 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1075 | |
1076 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
1077 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
1078 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
1079 delegate.TakeReceivedData()); | |
1080 | |
1081 // Finish async network reads and writes. | |
1082 base::RunLoop().RunUntilIdle(); | |
1083 | |
1084 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1085 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1086 } | |
1087 | |
1088 TEST_F(SpdyStreamTest, StatusMustBeNumber) { | |
1089 SpdySerializedFrame req( | |
1090 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
1091 AddWrite(req); | |
1092 | |
1093 SpdyHeaderBlock incorrect_headers; | |
1094 incorrect_headers[":status"] = "nan"; | |
1095 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
1096 1, std::move(incorrect_headers), false)); | |
1097 AddRead(reply); | |
1098 | |
1099 SpdySerializedFrame rst( | |
1100 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
1101 AddWrite(rst); | |
1102 | |
1103 AddReadEOF(); | |
1104 | |
1105 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1106 GetNumWrites()); | |
1107 MockConnect connect_data(SYNCHRONOUS, OK); | |
1108 data.set_connect_data(connect_data); | |
1109 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1110 | |
1111 AddSSLSocketData(); | |
1112 | |
1113 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1114 | |
1115 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1116 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1117 ASSERT_TRUE(stream); | |
1118 | |
1119 StreamDelegateDoNothing delegate(stream); | |
1120 stream->SetDelegate(&delegate); | |
1121 | |
1122 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1123 | |
1124 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1125 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
1126 NO_MORE_DATA_TO_SEND)); | |
1127 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1128 | |
1129 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
1130 | |
1131 // Finish async network reads and writes. | |
1132 base::RunLoop().RunUntilIdle(); | |
1133 | |
1134 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1135 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1136 } | |
1137 | |
1138 TEST_F(SpdyStreamTest, StatusCannotHaveExtraText) { | |
1139 SpdySerializedFrame req( | |
1140 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
1141 AddWrite(req); | |
1142 | |
1143 SpdyHeaderBlock headers_with_status_text; | |
1144 headers_with_status_text[":status"] = | |
1145 "200 Some random extra text describing status"; | |
1146 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
1147 1, std::move(headers_with_status_text), false)); | |
1148 AddRead(reply); | |
1149 | |
1150 SpdySerializedFrame body( | |
1151 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
1152 AddRead(body); | |
1153 | |
1154 SpdySerializedFrame rst( | |
1155 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
1156 AddWrite(rst); | |
1157 | |
1158 AddReadEOF(); | |
1159 | |
1160 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1161 GetNumWrites()); | |
1162 MockConnect connect_data(SYNCHRONOUS, OK); | |
1163 data.set_connect_data(connect_data); | |
1164 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1165 | |
1166 AddSSLSocketData(); | |
1167 | |
1168 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1169 | |
1170 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1171 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1172 ASSERT_TRUE(stream); | |
1173 | |
1174 StreamDelegateDoNothing delegate(stream); | |
1175 stream->SetDelegate(&delegate); | |
1176 | |
1177 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1178 | |
1179 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1180 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
1181 NO_MORE_DATA_TO_SEND)); | |
1182 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1183 | |
1184 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
1185 | |
1186 // Finish async network reads and writes. | |
1187 base::RunLoop().RunUntilIdle(); | |
1188 | |
1189 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1190 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1191 } | |
1192 | |
1193 TEST_F(SpdyStreamTest, StatusMustBePresent) { | |
1194 SpdySerializedFrame req( | |
1195 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
1196 AddWrite(req); | |
1197 | |
1198 SpdyHeaderBlock headers_without_status; | |
1199 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
1200 1, std::move(headers_without_status), false)); | |
1201 AddRead(reply); | |
1202 | |
1203 SpdySerializedFrame body( | |
1204 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
1205 AddRead(body); | |
1206 | |
1207 SpdySerializedFrame rst( | |
1208 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
1209 AddWrite(rst); | |
1210 | |
1211 AddReadEOF(); | |
1212 | |
1213 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1214 GetNumWrites()); | |
1215 MockConnect connect_data(SYNCHRONOUS, OK); | |
1216 data.set_connect_data(connect_data); | |
1217 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1218 | |
1219 AddSSLSocketData(); | |
1220 | |
1221 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1222 | |
1223 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1224 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1225 ASSERT_TRUE(stream); | |
1226 | |
1227 StreamDelegateDoNothing delegate(stream); | |
1228 stream->SetDelegate(&delegate); | |
1229 | |
1230 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1231 | |
1232 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1233 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
1234 NO_MORE_DATA_TO_SEND)); | |
1235 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1236 | |
1237 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
1238 | |
1239 // Finish async network reads and writes. | |
1240 base::RunLoop().RunUntilIdle(); | |
1241 | |
1242 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1243 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1244 } | |
1245 | |
1246 // Call IncreaseSendWindowSize on a stream with a large enough delta to overflow | |
1247 // an int32_t. The SpdyStream should handle that case gracefully. | |
1248 TEST_F(SpdyStreamTest, IncreaseSendWindowSizeOverflow) { | |
1249 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
1250 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
1251 AddWrite(req); | |
1252 | |
1253 AddReadPause(); | |
1254 | |
1255 // Triggered by the overflowing call to IncreaseSendWindowSize | |
1256 // below. | |
1257 SpdySerializedFrame rst( | |
1258 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_FLOW_CONTROL_ERROR)); | |
1259 AddWrite(rst); | |
1260 | |
1261 AddReadEOF(); | |
1262 | |
1263 BoundTestNetLog log; | |
1264 | |
1265 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1266 GetNumWrites()); | |
1267 MockConnect connect_data(SYNCHRONOUS, OK); | |
1268 data.set_connect_data(connect_data); | |
1269 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1270 | |
1271 AddSSLSocketData(); | |
1272 | |
1273 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1274 | |
1275 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1276 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, log.bound()); | |
1277 ASSERT_TRUE(stream); | |
1278 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
1279 stream->SetDelegate(&delegate); | |
1280 | |
1281 SpdyHeaderBlock headers( | |
1282 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
1283 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
1284 IsError(ERR_IO_PENDING)); | |
1285 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1286 | |
1287 data.RunUntilPaused(); | |
1288 | |
1289 int32_t old_send_window_size = stream->send_window_size(); | |
1290 ASSERT_GT(old_send_window_size, 0); | |
1291 int32_t delta_window_size = | |
1292 std::numeric_limits<int32_t>::max() - old_send_window_size + 1; | |
1293 stream->IncreaseSendWindowSize(delta_window_size); | |
1294 EXPECT_FALSE(stream); | |
1295 | |
1296 data.Resume(); | |
1297 base::RunLoop().RunUntilIdle(); | |
1298 | |
1299 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
1300 } | |
1301 | |
1302 // Functions used with | |
1303 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test(). | |
1304 | |
1305 void StallStream(const base::WeakPtr<SpdyStream>& stream) { | |
1306 // Reduce the send window size to 0 to stall. | |
1307 while (stream->send_window_size() > 0) { | |
1308 stream->DecreaseSendWindowSize( | |
1309 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size())); | |
1310 } | |
1311 } | |
1312 | |
1313 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, | |
1314 int32_t delta_window_size) { | |
1315 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1316 stream->IncreaseSendWindowSize(delta_window_size); | |
1317 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1318 } | |
1319 | |
1320 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, | |
1321 int32_t delta_window_size) { | |
1322 // Make sure that negative adjustments are handled properly. | |
1323 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1324 stream->AdjustSendWindowSize(-delta_window_size); | |
1325 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1326 stream->AdjustSendWindowSize(+delta_window_size); | |
1327 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1328 stream->AdjustSendWindowSize(+delta_window_size); | |
1329 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1330 } | |
1331 | |
1332 // Given an unstall function, runs a test to make sure that a | |
1333 // request/response (i.e., an HTTP-like) stream resumes after a stall | |
1334 // and unstall. | |
1335 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest( | |
1336 const UnstallFunction& unstall_function) { | |
1337 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
1338 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
1339 AddWrite(req); | |
1340 | |
1341 SpdySerializedFrame body( | |
1342 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
1343 AddWrite(body); | |
1344 | |
1345 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
1346 AddRead(resp); | |
1347 | |
1348 AddReadEOF(); | |
1349 | |
1350 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1351 GetNumWrites()); | |
1352 MockConnect connect_data(SYNCHRONOUS, OK); | |
1353 data.set_connect_data(connect_data); | |
1354 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1355 | |
1356 AddSSLSocketData(); | |
1357 | |
1358 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1359 | |
1360 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1361 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1362 ASSERT_TRUE(stream); | |
1363 | |
1364 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece); | |
1365 stream->SetDelegate(&delegate); | |
1366 | |
1367 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1368 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1369 | |
1370 SpdyHeaderBlock headers( | |
1371 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
1372 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
1373 IsError(ERR_IO_PENDING)); | |
1374 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1375 | |
1376 StallStream(stream); | |
1377 | |
1378 base::RunLoop().RunUntilIdle(); | |
1379 | |
1380 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1381 | |
1382 unstall_function.Run(stream, kPostBodyLength); | |
1383 | |
1384 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1385 | |
1386 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
1387 | |
1388 EXPECT_TRUE(delegate.send_headers_completed()); | |
1389 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | |
1390 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
1391 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1392 } | |
1393 | |
1394 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) { | |
1395 RunResumeAfterUnstallRequestResponseTest( | |
1396 base::Bind(&IncreaseStreamSendWindowSize)); | |
1397 } | |
1398 | |
1399 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) { | |
1400 RunResumeAfterUnstallRequestResponseTest( | |
1401 base::Bind(&AdjustStreamSendWindowSize)); | |
1402 } | |
1403 | |
1404 // Given an unstall function, runs a test to make sure that a bidirectional | |
1405 // (i.e., non-HTTP-like) stream resumes after a stall and unstall. | |
1406 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest( | |
1407 const UnstallFunction& unstall_function) { | |
1408 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
1409 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
1410 AddWrite(req); | |
1411 | |
1412 AddReadPause(); | |
1413 | |
1414 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
1415 AddRead(resp); | |
1416 | |
1417 SpdySerializedFrame msg( | |
1418 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
1419 AddWrite(msg); | |
1420 | |
1421 SpdySerializedFrame echo( | |
1422 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
1423 AddRead(echo); | |
1424 | |
1425 AddReadEOF(); | |
1426 | |
1427 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1428 GetNumWrites()); | |
1429 MockConnect connect_data(SYNCHRONOUS, OK); | |
1430 data.set_connect_data(connect_data); | |
1431 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1432 | |
1433 AddSSLSocketData(); | |
1434 | |
1435 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1436 | |
1437 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1438 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1439 ASSERT_TRUE(stream); | |
1440 | |
1441 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
1442 stream->SetDelegate(&delegate); | |
1443 | |
1444 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1445 | |
1446 SpdyHeaderBlock headers( | |
1447 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
1448 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
1449 IsError(ERR_IO_PENDING)); | |
1450 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1451 | |
1452 data.RunUntilPaused(); | |
1453 | |
1454 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1455 | |
1456 StallStream(stream); | |
1457 | |
1458 data.Resume(); | |
1459 base::RunLoop().RunUntilIdle(); | |
1460 | |
1461 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
1462 | |
1463 unstall_function.Run(stream, kPostBodyLength); | |
1464 | |
1465 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
1466 | |
1467 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
1468 | |
1469 EXPECT_TRUE(delegate.send_headers_completed()); | |
1470 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | |
1471 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
1472 delegate.TakeReceivedData()); | |
1473 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1474 } | |
1475 | |
1476 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) { | |
1477 RunResumeAfterUnstallBidirectionalTest( | |
1478 base::Bind(&IncreaseStreamSendWindowSize)); | |
1479 } | |
1480 | |
1481 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) { | |
1482 RunResumeAfterUnstallBidirectionalTest( | |
1483 base::Bind(&AdjustStreamSendWindowSize)); | |
1484 } | |
1485 | |
1486 // Test calculation of amount of bytes received from network. | |
1487 TEST_F(SpdyStreamTest, ReceivedBytes) { | |
1488 SpdySerializedFrame req( | |
1489 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
1490 AddWrite(req); | |
1491 | |
1492 AddReadPause(); | |
1493 | |
1494 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
1495 AddRead(reply); | |
1496 | |
1497 AddReadPause(); | |
1498 | |
1499 SpdySerializedFrame msg( | |
1500 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
1501 AddRead(msg); | |
1502 | |
1503 AddReadPause(); | |
1504 | |
1505 AddReadEOF(); | |
1506 | |
1507 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
1508 GetNumWrites()); | |
1509 MockConnect connect_data(SYNCHRONOUS, OK); | |
1510 data.set_connect_data(connect_data); | |
1511 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1512 | |
1513 AddSSLSocketData(); | |
1514 | |
1515 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
1516 | |
1517 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
1518 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
1519 ASSERT_TRUE(stream); | |
1520 | |
1521 StreamDelegateDoNothing delegate(stream); | |
1522 stream->SetDelegate(&delegate); | |
1523 | |
1524 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
1525 | |
1526 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1527 EXPECT_THAT( | |
1528 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
1529 IsError(ERR_IO_PENDING)); | |
1530 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
1531 | |
1532 int64_t reply_frame_len = reply.size(); | |
1533 int64_t data_header_len = kDataFrameMinimumSize; | |
1534 int64_t data_frame_len = data_header_len + kPostBodyLength; | |
1535 int64_t response_len = reply_frame_len + data_frame_len; | |
1536 | |
1537 EXPECT_EQ(0, stream->raw_received_bytes()); | |
1538 | |
1539 // REQUEST | |
1540 data.RunUntilPaused(); | |
1541 EXPECT_EQ(0, stream->raw_received_bytes()); | |
1542 | |
1543 // REPLY | |
1544 data.Resume(); | |
1545 data.RunUntilPaused(); | |
1546 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes()); | |
1547 | |
1548 // DATA | |
1549 data.Resume(); | |
1550 data.RunUntilPaused(); | |
1551 EXPECT_EQ(response_len, stream->raw_received_bytes()); | |
1552 | |
1553 // FIN | |
1554 data.Resume(); | |
1555 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
1556 } | |
1557 | |
1558 } // namespace test | |
1559 | |
1560 } // namespace net | |
OLD | NEW |