blob: d456a43a4cd14d31fafe26f30518beee281ec861 [file] [log] [blame]
[email protected]a1595312012-01-22 03:25:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]4f386422010-07-20 04:19:492// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]3b63f8f42011-03-28 01:54:155#include "base/memory/ref_counted.h"
[email protected]5a76b812011-12-21 20:52:006#include "net/base/completion_callback.h"
[email protected]d245c342012-02-23 20:49:157#include "net/base/net_log_unittest.h"
[email protected]f54c85792012-03-08 19:06:418#include "net/spdy/buffered_spdy_framer.h"
[email protected]4f386422010-07-20 04:19:499#include "net/spdy/spdy_stream.h"
[email protected]9e1bdd32011-02-03 21:48:3410#include "net/spdy/spdy_http_utils.h"
[email protected]4f386422010-07-20 04:19:4911#include "net/spdy/spdy_session.h"
[email protected]448d4ca52012-03-04 04:12:2312#include "net/spdy/spdy_test_util_spdy3.h"
[email protected]4f386422010-07-20 04:19:4913#include "testing/gtest/include/gtest/gtest.h"
14
[email protected]448d4ca52012-03-04 04:12:2315using namespace net::test_spdy3;
16
[email protected]4f386422010-07-20 04:19:4917// TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
[email protected]b9ec6882011-07-01 07:40:2618//
19namespace net {
[email protected]4f386422010-07-20 04:19:4920
21namespace {
22
[email protected]4f386422010-07-20 04:19:4923class TestSpdyStreamDelegate : public SpdyStream::Delegate {
24 public:
25 TestSpdyStreamDelegate(SpdyStream* stream,
26 IOBufferWithSize* buf,
[email protected]5a76b812011-12-21 20:52:0027 const CompletionCallback& callback)
[email protected]4f386422010-07-20 04:19:4928 : stream_(stream),
29 buf_(buf),
30 callback_(callback),
31 send_headers_completed_(false),
32 response_(new spdy::SpdyHeaderBlock),
33 data_sent_(0),
34 closed_(false) {}
35 virtual ~TestSpdyStreamDelegate() {}
36
37 virtual bool OnSendHeadersComplete(int status) {
38 send_headers_completed_ = true;
39 return true;
40 }
41 virtual int OnSendBody() {
42 ADD_FAILURE() << "OnSendBody should not be called";
43 return ERR_UNEXPECTED;
44 }
[email protected]0c9bf872011-03-04 17:53:2245 virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]4f386422010-07-20 04:19:4946 ADD_FAILURE() << "OnSendBodyComplete should not be called";
[email protected]0c9bf872011-03-04 17:53:2247 return ERR_UNEXPECTED;
[email protected]4f386422010-07-20 04:19:4948 }
[email protected]310240592010-08-05 21:04:1949
[email protected]4f386422010-07-20 04:19:4950 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
51 base::Time response_time,
52 int status) {
53 EXPECT_TRUE(send_headers_completed_);
54 *response_ = response;
55 if (buf_) {
56 EXPECT_EQ(ERR_IO_PENDING,
57 stream_->WriteStreamData(buf_.get(), buf_->size(),
58 spdy::DATA_FLAG_NONE));
59 }
60 return status;
61 }
62 virtual void OnDataReceived(const char* buffer, int bytes) {
63 received_data_ += std::string(buffer, bytes);
64 }
65 virtual void OnDataSent(int length) {
66 data_sent_ += length;
67 }
68 virtual void OnClose(int status) {
69 closed_ = true;
[email protected]5a76b812011-12-21 20:52:0070 CompletionCallback callback = callback_;
71 callback_.Reset();
72 callback.Run(OK);
[email protected]4f386422010-07-20 04:19:4973 }
[email protected]0c9bf872011-03-04 17:53:2274 virtual void set_chunk_callback(net::ChunkCallback *) {}
[email protected]4f386422010-07-20 04:19:4975
76 bool send_headers_completed() const { return send_headers_completed_; }
77 const linked_ptr<spdy::SpdyHeaderBlock>& response() const {
78 return response_;
79 }
80 const std::string& received_data() const { return received_data_; }
81 int data_sent() const { return data_sent_; }
82 bool closed() const { return closed_; }
83
84 private:
85 SpdyStream* stream_;
86 scoped_refptr<IOBufferWithSize> buf_;
[email protected]5a76b812011-12-21 20:52:0087 CompletionCallback callback_;
[email protected]4f386422010-07-20 04:19:4988 bool send_headers_completed_;
89 linked_ptr<spdy::SpdyHeaderBlock> response_;
90 std::string received_data_;
91 int data_sent_;
92 bool closed_;
93};
94
95spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) {
[email protected]f54c85792012-03-08 19:06:4196 spdy::BufferedSpdyFramer framer(3);
[email protected]4f386422010-07-20 04:19:4997 return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE);
98}
99
100} // anonymous namespace
101
[email protected]448d4ca52012-03-04 04:12:23102class SpdyStreamSpdy3Test : public testing::Test {
[email protected]4f386422010-07-20 04:19:49103 protected:
[email protected]448d4ca52012-03-04 04:12:23104 SpdyStreamSpdy3Test() {
[email protected]4f386422010-07-20 04:19:49105 }
106
107 scoped_refptr<SpdySession> CreateSpdySession() {
108 spdy::SpdyFramer::set_enable_compression_default(false);
109 HostPortPair host_port_pair("www.google.com", 80);
[email protected]31e68d72010-08-25 06:36:58110 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
[email protected]4f386422010-07-20 04:19:49111 scoped_refptr<SpdySession> session(
[email protected]102e27c2011-02-23 01:01:31112 session_->spdy_session_pool()->Get(pair, BoundNetLog()));
[email protected]4f386422010-07-20 04:19:49113 return session;
114 }
115
[email protected]39c48fc2012-03-12 18:42:12116 virtual void SetUp() {
117 SpdySession::set_default_protocol(SSLClientSocket::kProtoSPDY3);
118 }
119
[email protected]4f386422010-07-20 04:19:49120 virtual void TearDown() {
121 MessageLoop::current()->RunAllPending();
122 }
123
124 scoped_refptr<HttpNetworkSession> session_;
125};
126
[email protected]448d4ca52012-03-04 04:12:23127TEST_F(SpdyStreamSpdy3Test, SendDataAfterOpen) {
[email protected]30c942b2010-07-21 16:59:59128 SpdySessionDependencies session_deps;
[email protected]4f386422010-07-20 04:19:49129
[email protected]30c942b2010-07-21 16:59:59130 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
[email protected]4f386422010-07-20 04:19:49131 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
132
133 const SpdyHeaderInfo kSynStartHeader = {
134 spdy::SYN_STREAM,
135 1,
136 0,
[email protected]c9c6f5c2010-07-31 01:30:03137 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
[email protected]4f386422010-07-20 04:19:49138 spdy::CONTROL_FLAG_NONE,
139 false,
140 spdy::INVALID,
141 NULL,
142 0,
143 spdy::DATA_FLAG_NONE
144 };
145 static const char* const kGetHeaders[] = {
[email protected]0e861e92012-03-15 18:42:19146 ":method",
[email protected]4f386422010-07-20 04:19:49147 "GET",
[email protected]0e861e92012-03-15 18:42:19148 ":scheme",
[email protected]a7a265ef2010-12-08 18:05:57149 "http",
[email protected]0e861e92012-03-15 18:42:19150 ":host",
[email protected]a7a265ef2010-12-08 18:05:57151 "www.google.com",
[email protected]0e861e92012-03-15 18:42:19152 ":path",
[email protected]a7a265ef2010-12-08 18:05:57153 "/",
[email protected]0e861e92012-03-15 18:42:19154 ":version",
[email protected]4f386422010-07-20 04:19:49155 "HTTP/1.1",
156 };
157 scoped_ptr<spdy::SpdyFrame> req(
158 ConstructSpdyPacket(
159 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2));
160 scoped_ptr<spdy::SpdyFrame> msg(
161 ConstructSpdyBodyFrame("\0hello!\xff", 8));
162 MockWrite writes[] = {
163 CreateMockWrite(*req),
164 CreateMockWrite(*msg),
165 };
166 writes[0].sequence_number = 0;
167 writes[1].sequence_number = 2;
168
169 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
170 scoped_ptr<spdy::SpdyFrame> echo(
171 ConstructSpdyBodyFrame("\0hello!\xff", 8));
172 MockRead reads[] = {
173 CreateMockRead(*resp),
174 CreateMockRead(*echo),
[email protected]8ddf8322012-02-23 18:08:06175 MockRead(ASYNC, 0, 0), // EOF
[email protected]4f386422010-07-20 04:19:49176 };
177 reads[0].sequence_number = 1;
178 reads[1].sequence_number = 3;
179 reads[2].sequence_number = 4;
180
[email protected]a1595312012-01-22 03:25:04181 scoped_ptr<OrderedSocketData> data(
[email protected]4f386422010-07-20 04:19:49182 new OrderedSocketData(reads, arraysize(reads),
183 writes, arraysize(writes)));
[email protected]d973e99a2012-02-17 21:02:36184 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]1442b29a2010-07-20 11:14:54185 data->set_connect_data(connect_data);
[email protected]4f386422010-07-20 04:19:49186
[email protected]3b7828432010-08-18 18:33:27187 session_deps.socket_factory->AddSocketDataProvider(data.get());
[email protected]4f386422010-07-20 04:19:49188
189 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]a7a265ef2010-12-08 18:05:57190 const char* kStreamUrl = "http://www.google.com/";
191 GURL url(kStreamUrl);
[email protected]4f386422010-07-20 04:19:49192
193 HostPortPair host_port_pair("www.google.com", 80);
[email protected]ab739042011-04-07 15:22:28194 scoped_refptr<TransportSocketParams> transport_params(
[email protected]acdda412011-11-15 21:21:29195 new TransportSocketParams(host_port_pair, LOWEST, false, false));
[email protected]02b0c342010-09-25 21:09:38196
197 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
[email protected]6ecf2b92011-12-15 01:14:52198 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
199 LOWEST, CompletionCallback(),
[email protected]e5c026642012-03-17 00:14:02200 session_->GetTransportSocketPool(
201 HttpNetworkSession::NORMAL_SOCKET_POOL),
[email protected]6ecf2b92011-12-15 01:14:52202 BoundNetLog()));
[email protected]02b0c342010-09-25 21:09:38203 session->InitializeWithSocket(connection.release(), false, OK);
[email protected]4f386422010-07-20 04:19:49204
205 scoped_refptr<SpdyStream> stream;
206 ASSERT_EQ(
207 OK,
[email protected]49639fa2011-12-20 23:22:41208 session->CreateStream(url, LOWEST, &stream, BoundNetLog(),
209 CompletionCallback()));
[email protected]4f386422010-07-20 04:19:49210 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
211 memcpy(buf->data(), "\0hello!\xff", 8);
[email protected]5a76b812011-12-21 20:52:00212 TestCompletionCallback callback;
[email protected]4f386422010-07-20 04:19:49213
214 scoped_ptr<TestSpdyStreamDelegate> delegate(
[email protected]5a76b812011-12-21 20:52:00215 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
[email protected]4f386422010-07-20 04:19:49216 stream->SetDelegate(delegate.get());
217
[email protected]a7a265ef2010-12-08 18:05:57218 EXPECT_FALSE(stream->HasUrl());
219
[email protected]4f386422010-07-20 04:19:49220 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
[email protected]0e861e92012-03-15 18:42:19221 (*headers)[":method"] = "GET";
222 (*headers)[":scheme"] = url.scheme();
223 (*headers)[":host"] = url.host();
224 (*headers)[":path"] = url.path();
225 (*headers)[":version"] = "HTTP/1.1";
[email protected]4f386422010-07-20 04:19:49226 stream->set_spdy_headers(headers);
[email protected]a7a265ef2010-12-08 18:05:57227 EXPECT_TRUE(stream->HasUrl());
228 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]4f386422010-07-20 04:19:49229
[email protected]a5c493b92010-08-06 23:04:29230 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
[email protected]4f386422010-07-20 04:19:49231
232 EXPECT_EQ(OK, callback.WaitForResult());
233
234 EXPECT_TRUE(delegate->send_headers_completed());
235 EXPECT_EQ("200", (*delegate->response())["status"]);
236 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
237 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
238 EXPECT_EQ(8, delegate->data_sent());
239 EXPECT_TRUE(delegate->closed());
240}
241
[email protected]448d4ca52012-03-04 04:12:23242TEST_F(SpdyStreamSpdy3Test, PushedStream) {
[email protected]a7a265ef2010-12-08 18:05:57243 const char kStreamUrl[] = "http://www.google.com/";
244
245 SpdySessionDependencies session_deps;
246 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
247 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
248 scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
[email protected]0e861e92012-03-15 18:42:19249
250 MockRead reads[] = {
251 MockRead(ASYNC, 0, 0), // EOF
252 };
253
254 scoped_ptr<OrderedSocketData> data(
255 new OrderedSocketData(reads, arraysize(reads), NULL, 0));
256 MockConnect connect_data(SYNCHRONOUS, OK);
257 data->set_connect_data(connect_data);
258
259 session_deps.socket_factory->AddSocketDataProvider(data.get());
[email protected]0e861e92012-03-15 18:42:19260
261 HostPortPair host_port_pair("www.google.com", 80);
262 scoped_refptr<TransportSocketParams> transport_params(
263 new TransportSocketParams(host_port_pair, LOWEST, false, false));
264 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
265 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
266 LOWEST, CompletionCallback(),
[email protected]e5c026642012-03-17 00:14:02267 session_->GetTransportSocketPool(
268 HttpNetworkSession::NORMAL_SOCKET_POOL),
[email protected]0e861e92012-03-15 18:42:19269 BoundNetLog()));
270 spdy_session->InitializeWithSocket(connection.release(), false, OK);
[email protected]a7a265ef2010-12-08 18:05:57271 BoundNetLog net_log;
272
273 // Conjure up a stream.
274 scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session,
275 2,
276 true,
277 net_log);
278 EXPECT_FALSE(stream->response_received());
279 EXPECT_FALSE(stream->HasUrl());
280
281 // Set a couple of headers.
282 spdy::SpdyHeaderBlock response;
[email protected]0e861e92012-03-15 18:42:19283 GURL url(kStreamUrl);
284 response[":host"] = url.host();
285 response[":scheme"] = url.scheme();
286 response[":path"] = url.path();
[email protected]a7a265ef2010-12-08 18:05:57287 stream->OnResponseReceived(response);
288
289 // Send some basic headers.
290 spdy::SpdyHeaderBlock headers;
291 response["status"] = "200";
292 response["version"] = "OK";
293 stream->OnHeaders(headers);
294
295 stream->set_response_received();
296 EXPECT_TRUE(stream->response_received());
297 EXPECT_TRUE(stream->HasUrl());
298 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
299}
300
[email protected]448d4ca52012-03-04 04:12:23301TEST_F(SpdyStreamSpdy3Test, StreamError) {
[email protected]d245c342012-02-23 20:49:15302 SpdySessionDependencies session_deps;
303
304 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
305 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
306
307 const SpdyHeaderInfo kSynStartHeader = {
308 spdy::SYN_STREAM,
309 1,
310 0,
311 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
312 spdy::CONTROL_FLAG_NONE,
313 false,
314 spdy::INVALID,
315 NULL,
316 0,
317 spdy::DATA_FLAG_NONE
318 };
319 static const char* const kGetHeaders[] = {
[email protected]0e861e92012-03-15 18:42:19320 ":method",
[email protected]d245c342012-02-23 20:49:15321 "GET",
[email protected]0e861e92012-03-15 18:42:19322 ":scheme",
[email protected]d245c342012-02-23 20:49:15323 "http",
[email protected]0e861e92012-03-15 18:42:19324 ":host",
[email protected]d245c342012-02-23 20:49:15325 "www.google.com",
[email protected]0e861e92012-03-15 18:42:19326 ":path",
[email protected]d245c342012-02-23 20:49:15327 "/",
[email protected]0e861e92012-03-15 18:42:19328 ":version",
[email protected]d245c342012-02-23 20:49:15329 "HTTP/1.1",
330 };
331 scoped_ptr<spdy::SpdyFrame> req(
332 ConstructSpdyPacket(
333 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2));
334 scoped_ptr<spdy::SpdyFrame> msg(
335 ConstructSpdyBodyFrame("\0hello!\xff", 8));
336 MockWrite writes[] = {
337 CreateMockWrite(*req),
338 CreateMockWrite(*msg),
339 };
340 writes[0].sequence_number = 0;
341 writes[1].sequence_number = 2;
342
343 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
344 scoped_ptr<spdy::SpdyFrame> echo(
345 ConstructSpdyBodyFrame("\0hello!\xff", 8));
346 MockRead reads[] = {
347 CreateMockRead(*resp),
348 CreateMockRead(*echo),
349 MockRead(ASYNC, 0, 0), // EOF
350 };
351 reads[0].sequence_number = 1;
352 reads[1].sequence_number = 3;
353 reads[2].sequence_number = 4;
354
355 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded);
356
357 scoped_ptr<OrderedSocketData> data(
358 new OrderedSocketData(reads, arraysize(reads),
359 writes, arraysize(writes)));
360 MockConnect connect_data(SYNCHRONOUS, OK);
361 data->set_connect_data(connect_data);
362
363 session_deps.socket_factory->AddSocketDataProvider(data.get());
[email protected]d245c342012-02-23 20:49:15364
365 scoped_refptr<SpdySession> session(CreateSpdySession());
366 const char* kStreamUrl = "http://www.google.com/";
367 GURL url(kStreamUrl);
368
369 HostPortPair host_port_pair("www.google.com", 80);
370 scoped_refptr<TransportSocketParams> transport_params(
371 new TransportSocketParams(host_port_pair, LOWEST, false, false));
372
373 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
374 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
375 LOWEST, CompletionCallback(),
[email protected]e5c026642012-03-17 00:14:02376 session_->GetTransportSocketPool(
377 HttpNetworkSession::NORMAL_SOCKET_POOL),
[email protected]d245c342012-02-23 20:49:15378 log.bound()));
379 session->InitializeWithSocket(connection.release(), false, OK);
380
381 scoped_refptr<SpdyStream> stream;
382 ASSERT_EQ(
383 OK,
384 session->CreateStream(url, LOWEST, &stream, log.bound(),
385 CompletionCallback()));
386 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
387 memcpy(buf->data(), "\0hello!\xff", 8);
388 TestCompletionCallback callback;
389
390 scoped_ptr<TestSpdyStreamDelegate> delegate(
391 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
392 stream->SetDelegate(delegate.get());
393
394 EXPECT_FALSE(stream->HasUrl());
395
396 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
[email protected]0e861e92012-03-15 18:42:19397 (*headers)[":method"] = "GET";
398 (*headers)[":scheme"] = url.scheme();
399 (*headers)[":host"] = url.host();
400 (*headers)[":path"] = url.path();
401 (*headers)[":version"] = "HTTP/1.1";
[email protected]d245c342012-02-23 20:49:15402 stream->set_spdy_headers(headers);
403 EXPECT_TRUE(stream->HasUrl());
404 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
405
406 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
407
408 const spdy::SpdyStreamId stream_id = stream->stream_id();
409
410 EXPECT_EQ(OK, callback.WaitForResult());
411
412 EXPECT_TRUE(delegate->send_headers_completed());
413 EXPECT_EQ("200", (*delegate->response())["status"]);
414 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
415 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
416 EXPECT_EQ(8, delegate->data_sent());
417 EXPECT_TRUE(delegate->closed());
418
419 // Check that the NetLog was filled reasonably.
420 net::CapturingNetLog::EntryList entries;
421 log.GetEntries(&entries);
422 EXPECT_LT(0u, entries.size());
423
424 // Check that we logged SPDY_STREAM_ERROR correctly.
425 int pos = net::ExpectLogContainsSomewhere(
426 entries, 0,
427 net::NetLog::TYPE_SPDY_STREAM_ERROR,
428 net::NetLog::PHASE_NONE);
429
430 CapturingNetLog::Entry entry = entries[pos];
431 NetLogSpdyStreamErrorParameter* request_params =
432 static_cast<NetLogSpdyStreamErrorParameter*>(
433 entry.extra_parameters.get());
434 EXPECT_EQ(stream_id, request_params->stream_id());
435}
[email protected]a7a265ef2010-12-08 18:05:57436
[email protected]4f386422010-07-20 04:19:49437} // namespace net