OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "base/memory/ref_counted.h" | |
6 #include "net/base/completion_callback.h" | |
7 #include "net/base/net_log_unittest.h" | |
8 #include "net/spdy/spdy_stream.h" | |
9 #include "net/spdy/spdy_http_utils.h" | |
10 #include "net/spdy/spdy_session.h" | |
11 #include "net/spdy/spdy_test_util.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc | |
15 // | |
16 namespace net { | |
17 | |
18 namespace { | |
19 | |
20 class TestSpdyStreamDelegate : public SpdyStream::Delegate { | |
21 public: | |
22 TestSpdyStreamDelegate(SpdyStream* stream, | |
23 IOBufferWithSize* buf, | |
24 const CompletionCallback& callback) | |
25 : stream_(stream), | |
26 buf_(buf), | |
27 callback_(callback), | |
28 send_headers_completed_(false), | |
29 response_(new spdy::SpdyHeaderBlock), | |
30 data_sent_(0), | |
31 closed_(false) {} | |
32 virtual ~TestSpdyStreamDelegate() {} | |
33 | |
34 virtual bool OnSendHeadersComplete(int status) { | |
35 send_headers_completed_ = true; | |
36 return true; | |
37 } | |
38 virtual int OnSendBody() { | |
39 ADD_FAILURE() << "OnSendBody should not be called"; | |
40 return ERR_UNEXPECTED; | |
41 } | |
42 virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) { | |
43 ADD_FAILURE() << "OnSendBodyComplete should not be called"; | |
44 return ERR_UNEXPECTED; | |
45 } | |
46 | |
47 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response, | |
48 base::Time response_time, | |
49 int status) { | |
50 EXPECT_TRUE(send_headers_completed_); | |
51 *response_ = response; | |
52 if (buf_) { | |
53 EXPECT_EQ(ERR_IO_PENDING, | |
54 stream_->WriteStreamData(buf_.get(), buf_->size(), | |
55 spdy::DATA_FLAG_NONE)); | |
56 } | |
57 return status; | |
58 } | |
59 virtual void OnDataReceived(const char* buffer, int bytes) { | |
60 received_data_ += std::string(buffer, bytes); | |
61 } | |
62 virtual void OnDataSent(int length) { | |
63 data_sent_ += length; | |
64 } | |
65 virtual void OnClose(int status) { | |
66 closed_ = true; | |
67 CompletionCallback callback = callback_; | |
68 callback_.Reset(); | |
69 callback.Run(OK); | |
70 } | |
71 virtual void set_chunk_callback(net::ChunkCallback *) {} | |
72 | |
73 bool send_headers_completed() const { return send_headers_completed_; } | |
74 const linked_ptr<spdy::SpdyHeaderBlock>& response() const { | |
75 return response_; | |
76 } | |
77 const std::string& received_data() const { return received_data_; } | |
78 int data_sent() const { return data_sent_; } | |
79 bool closed() const { return closed_; } | |
80 | |
81 private: | |
82 SpdyStream* stream_; | |
83 scoped_refptr<IOBufferWithSize> buf_; | |
84 CompletionCallback callback_; | |
85 bool send_headers_completed_; | |
86 linked_ptr<spdy::SpdyHeaderBlock> response_; | |
87 std::string received_data_; | |
88 int data_sent_; | |
89 bool closed_; | |
90 }; | |
91 | |
92 spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) { | |
93 spdy::SpdyFramer framer; | |
94 return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE); | |
95 } | |
96 | |
97 } // anonymous namespace | |
98 | |
99 class SpdyStreamTest : public testing::Test { | |
100 protected: | |
101 SpdyStreamTest() { | |
102 } | |
103 | |
104 scoped_refptr<SpdySession> CreateSpdySession() { | |
105 spdy::SpdyFramer::set_enable_compression_default(false); | |
106 HostPortPair host_port_pair("www.google.com", 80); | |
107 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
108 scoped_refptr<SpdySession> session( | |
109 session_->spdy_session_pool()->Get(pair, BoundNetLog())); | |
110 return session; | |
111 } | |
112 | |
113 virtual void TearDown() { | |
114 MessageLoop::current()->RunAllPending(); | |
115 } | |
116 | |
117 scoped_refptr<HttpNetworkSession> session_; | |
118 }; | |
119 | |
120 TEST_F(SpdyStreamTest, SendDataAfterOpen) { | |
121 SpdySessionDependencies session_deps; | |
122 | |
123 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
124 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
125 | |
126 const SpdyHeaderInfo kSynStartHeader = { | |
127 spdy::SYN_STREAM, | |
128 1, | |
129 0, | |
130 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
131 spdy::CONTROL_FLAG_NONE, | |
132 false, | |
133 spdy::INVALID, | |
134 NULL, | |
135 0, | |
136 spdy::DATA_FLAG_NONE | |
137 }; | |
138 static const char* const kGetHeaders[] = { | |
139 "method", | |
140 "GET", | |
141 "scheme", | |
142 "http", | |
143 "host", | |
144 "www.google.com", | |
145 "path", | |
146 "/", | |
147 "version", | |
148 "HTTP/1.1", | |
149 }; | |
150 scoped_ptr<spdy::SpdyFrame> req( | |
151 ConstructSpdyPacket( | |
152 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2)); | |
153 scoped_ptr<spdy::SpdyFrame> msg( | |
154 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
155 MockWrite writes[] = { | |
156 CreateMockWrite(*req), | |
157 CreateMockWrite(*msg), | |
158 }; | |
159 writes[0].sequence_number = 0; | |
160 writes[1].sequence_number = 2; | |
161 | |
162 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
163 scoped_ptr<spdy::SpdyFrame> echo( | |
164 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
165 MockRead reads[] = { | |
166 CreateMockRead(*resp), | |
167 CreateMockRead(*echo), | |
168 MockRead(ASYNC, 0, 0), // EOF | |
169 }; | |
170 reads[0].sequence_number = 1; | |
171 reads[1].sequence_number = 3; | |
172 reads[2].sequence_number = 4; | |
173 | |
174 scoped_ptr<OrderedSocketData> data( | |
175 new OrderedSocketData(reads, arraysize(reads), | |
176 writes, arraysize(writes))); | |
177 MockConnect connect_data(SYNCHRONOUS, OK); | |
178 data->set_connect_data(connect_data); | |
179 | |
180 session_deps.socket_factory->AddSocketDataProvider(data.get()); | |
181 SpdySession::SetSSLMode(false); | |
182 | |
183 scoped_refptr<SpdySession> session(CreateSpdySession()); | |
184 const char* kStreamUrl = "http://www.google.com/"; | |
185 GURL url(kStreamUrl); | |
186 | |
187 HostPortPair host_port_pair("www.google.com", 80); | |
188 scoped_refptr<TransportSocketParams> transport_params( | |
189 new TransportSocketParams(host_port_pair, LOWEST, false, false)); | |
190 | |
191 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
192 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params, | |
193 LOWEST, CompletionCallback(), | |
194 session_->GetTransportSocketPool(), | |
195 BoundNetLog())); | |
196 session->InitializeWithSocket(connection.release(), false, OK); | |
197 | |
198 scoped_refptr<SpdyStream> stream; | |
199 ASSERT_EQ( | |
200 OK, | |
201 session->CreateStream(url, LOWEST, &stream, BoundNetLog(), | |
202 CompletionCallback())); | |
203 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8)); | |
204 memcpy(buf->data(), "\0hello!\xff", 8); | |
205 TestCompletionCallback callback; | |
206 | |
207 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
208 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback())); | |
209 stream->SetDelegate(delegate.get()); | |
210 | |
211 EXPECT_FALSE(stream->HasUrl()); | |
212 | |
213 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); | |
214 (*headers)["method"] = "GET"; | |
215 (*headers)["scheme"] = url.scheme(); | |
216 (*headers)["host"] = url.host(); | |
217 (*headers)["path"] = url.path(); | |
218 (*headers)["version"] = "HTTP/1.1"; | |
219 stream->set_spdy_headers(headers); | |
220 EXPECT_TRUE(stream->HasUrl()); | |
221 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
222 | |
223 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true)); | |
224 | |
225 EXPECT_EQ(OK, callback.WaitForResult()); | |
226 | |
227 EXPECT_TRUE(delegate->send_headers_completed()); | |
228 EXPECT_EQ("200", (*delegate->response())["status"]); | |
229 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]); | |
230 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data()); | |
231 EXPECT_EQ(8, delegate->data_sent()); | |
232 EXPECT_TRUE(delegate->closed()); | |
233 } | |
234 | |
235 TEST_F(SpdyStreamTest, PushedStream) { | |
236 const char kStreamUrl[] = "http://www.google.com/"; | |
237 | |
238 SpdySessionDependencies session_deps; | |
239 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
240 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
241 scoped_refptr<SpdySession> spdy_session(CreateSpdySession()); | |
242 BoundNetLog net_log; | |
243 | |
244 // Conjure up a stream. | |
245 scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session, | |
246 2, | |
247 true, | |
248 net_log); | |
249 EXPECT_FALSE(stream->response_received()); | |
250 EXPECT_FALSE(stream->HasUrl()); | |
251 | |
252 // Set a couple of headers. | |
253 spdy::SpdyHeaderBlock response; | |
254 response["url"] = kStreamUrl; | |
255 stream->OnResponseReceived(response); | |
256 | |
257 // Send some basic headers. | |
258 spdy::SpdyHeaderBlock headers; | |
259 response["status"] = "200"; | |
260 response["version"] = "OK"; | |
261 stream->OnHeaders(headers); | |
262 | |
263 stream->set_response_received(); | |
264 EXPECT_TRUE(stream->response_received()); | |
265 EXPECT_TRUE(stream->HasUrl()); | |
266 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
267 } | |
268 | |
269 TEST_F(SpdyStreamTest, StreamError) { | |
270 SpdySessionDependencies session_deps; | |
271 | |
272 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
273 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
274 | |
275 const SpdyHeaderInfo kSynStartHeader = { | |
276 spdy::SYN_STREAM, | |
277 1, | |
278 0, | |
279 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
280 spdy::CONTROL_FLAG_NONE, | |
281 false, | |
282 spdy::INVALID, | |
283 NULL, | |
284 0, | |
285 spdy::DATA_FLAG_NONE | |
286 }; | |
287 static const char* const kGetHeaders[] = { | |
288 "method", | |
289 "GET", | |
290 "scheme", | |
291 "http", | |
292 "host", | |
293 "www.google.com", | |
294 "path", | |
295 "/", | |
296 "version", | |
297 "HTTP/1.1", | |
298 }; | |
299 scoped_ptr<spdy::SpdyFrame> req( | |
300 ConstructSpdyPacket( | |
301 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2)); | |
302 scoped_ptr<spdy::SpdyFrame> msg( | |
303 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
304 MockWrite writes[] = { | |
305 CreateMockWrite(*req), | |
306 CreateMockWrite(*msg), | |
307 }; | |
308 writes[0].sequence_number = 0; | |
309 writes[1].sequence_number = 2; | |
310 | |
311 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
312 scoped_ptr<spdy::SpdyFrame> echo( | |
313 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
314 MockRead reads[] = { | |
315 CreateMockRead(*resp), | |
316 CreateMockRead(*echo), | |
317 MockRead(ASYNC, 0, 0), // EOF | |
318 }; | |
319 reads[0].sequence_number = 1; | |
320 reads[1].sequence_number = 3; | |
321 reads[2].sequence_number = 4; | |
322 | |
323 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded); | |
324 | |
325 scoped_ptr<OrderedSocketData> data( | |
326 new OrderedSocketData(reads, arraysize(reads), | |
327 writes, arraysize(writes))); | |
328 MockConnect connect_data(SYNCHRONOUS, OK); | |
329 data->set_connect_data(connect_data); | |
330 | |
331 session_deps.socket_factory->AddSocketDataProvider(data.get()); | |
332 SpdySession::SetSSLMode(false); | |
333 | |
334 scoped_refptr<SpdySession> session(CreateSpdySession()); | |
335 const char* kStreamUrl = "http://www.google.com/"; | |
336 GURL url(kStreamUrl); | |
337 | |
338 HostPortPair host_port_pair("www.google.com", 80); | |
339 scoped_refptr<TransportSocketParams> transport_params( | |
340 new TransportSocketParams(host_port_pair, LOWEST, false, false)); | |
341 | |
342 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
343 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params, | |
344 LOWEST, CompletionCallback(), | |
345 session_->GetTransportSocketPool(), | |
346 log.bound())); | |
347 session->InitializeWithSocket(connection.release(), false, OK); | |
348 | |
349 scoped_refptr<SpdyStream> stream; | |
350 ASSERT_EQ( | |
351 OK, | |
352 session->CreateStream(url, LOWEST, &stream, log.bound(), | |
353 CompletionCallback())); | |
354 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8)); | |
355 memcpy(buf->data(), "\0hello!\xff", 8); | |
356 TestCompletionCallback callback; | |
357 | |
358 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
359 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback())); | |
360 stream->SetDelegate(delegate.get()); | |
361 | |
362 EXPECT_FALSE(stream->HasUrl()); | |
363 | |
364 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); | |
365 (*headers)["method"] = "GET"; | |
366 (*headers)["scheme"] = url.scheme(); | |
367 (*headers)["host"] = url.host(); | |
368 (*headers)["path"] = url.path(); | |
369 (*headers)["version"] = "HTTP/1.1"; | |
370 stream->set_spdy_headers(headers); | |
371 EXPECT_TRUE(stream->HasUrl()); | |
372 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
373 | |
374 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true)); | |
375 | |
376 const spdy::SpdyStreamId stream_id = stream->stream_id(); | |
377 | |
378 EXPECT_EQ(OK, callback.WaitForResult()); | |
379 | |
380 EXPECT_TRUE(delegate->send_headers_completed()); | |
381 EXPECT_EQ("200", (*delegate->response())["status"]); | |
382 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]); | |
383 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data()); | |
384 EXPECT_EQ(8, delegate->data_sent()); | |
385 EXPECT_TRUE(delegate->closed()); | |
386 | |
387 // Check that the NetLog was filled reasonably. | |
388 net::CapturingNetLog::EntryList entries; | |
389 log.GetEntries(&entries); | |
390 EXPECT_LT(0u, entries.size()); | |
391 | |
392 // Check that we logged SPDY_STREAM_ERROR correctly. | |
393 int pos = net::ExpectLogContainsSomewhere( | |
394 entries, 0, | |
395 net::NetLog::TYPE_SPDY_STREAM_ERROR, | |
396 net::NetLog::PHASE_NONE); | |
397 | |
398 CapturingNetLog::Entry entry = entries[pos]; | |
399 NetLogSpdyStreamErrorParameter* request_params = | |
400 static_cast<NetLogSpdyStreamErrorParameter*>( | |
401 entry.extra_parameters.get()); | |
402 EXPECT_EQ(stream_id, request_params->stream_id()); | |
403 } | |
404 | |
405 } // namespace net | |
OLD | NEW |