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