blob: e66878989273c30370827a0cd2b3b4e0775b3cdb [file] [log] [blame]
[email protected]4f386422010-07-20 04:19:491// Copyright (c) 2010 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#include "base/ref_counted.h"
7#include "base/time.h"
8#include "net/base/mock_host_resolver.h"
9#include "net/base/net_errors.h"
10#include "net/base/net_log.h"
11#include "net/base/ssl_config_service.h"
12#include "net/base/ssl_config_service_defaults.h"
13#include "net/base/test_completion_callback.h"
14#include "net/http/http_auth_handler_factory.h"
15#include "net/http/http_network_session.h"
16#include "net/http/http_request_info.h"
17#include "net/http/http_response_info.h"
18#include "net/proxy/proxy_service.h"
19#include "net/socket/socket_test_util.h"
20#include "net/spdy/spdy_framer.h"
21#include "net/spdy/spdy_session.h"
22#include "net/spdy/spdy_session_pool.h"
23#include "net/spdy/spdy_test_util.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26namespace net {
27
28// TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
29class SpdySessionPoolPeer {
30 public:
31 explicit SpdySessionPoolPeer(const scoped_refptr<SpdySessionPool>& pool)
32 : pool_(pool) {}
33
34 void RemoveSpdySession(const scoped_refptr<SpdySession>& session) {
35 pool_->Remove(session);
36 }
37
38 private:
39 const scoped_refptr<SpdySessionPool> pool_;
40
41 DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
42};
43
44namespace {
45
46// Create a proxy service which fails on all requests (falls back to direct).
47ProxyService* CreateNullProxyService() {
48 return ProxyService::CreateNull();
49}
50
51// Helper to manage the lifetimes of the dependencies for a
52// SpdyNetworkTransaction.
53class SessionDependencies {
54 public:
55 // Default set of dependencies -- "null" proxy service.
56 SessionDependencies()
57 : host_resolver(new MockHostResolver),
58 proxy_service(CreateNullProxyService()),
59 ssl_config_service(new SSLConfigServiceDefaults),
60 http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
61 spdy_session_pool(new SpdySessionPool()) {}
62
63 // Custom proxy service dependency.
64 explicit SessionDependencies(ProxyService* proxy_service)
65 : host_resolver(new MockHostResolver),
66 proxy_service(proxy_service),
67 ssl_config_service(new SSLConfigServiceDefaults),
68 http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
69 spdy_session_pool(new SpdySessionPool()) {}
70
71 scoped_refptr<MockHostResolverBase> host_resolver;
72 scoped_refptr<ProxyService> proxy_service;
73 scoped_refptr<SSLConfigService> ssl_config_service;
74 MockClientSocketFactory socket_factory;
75 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
76 scoped_refptr<SpdySessionPool> spdy_session_pool;
77};
78
79HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
80 return new HttpNetworkSession(session_deps->host_resolver,
81 session_deps->proxy_service,
82 &session_deps->socket_factory,
83 session_deps->ssl_config_service,
84 session_deps->spdy_session_pool,
85 session_deps->http_auth_handler_factory.get(),
86 NULL,
87 NULL);
88}
89
90class TestSpdyStreamDelegate : public SpdyStream::Delegate {
91 public:
92 TestSpdyStreamDelegate(SpdyStream* stream,
93 IOBufferWithSize* buf,
94 CompletionCallback* callback)
95 : stream_(stream),
96 buf_(buf),
97 callback_(callback),
98 send_headers_completed_(false),
99 response_(new spdy::SpdyHeaderBlock),
100 data_sent_(0),
101 closed_(false) {}
102 virtual ~TestSpdyStreamDelegate() {}
103
104 virtual bool OnSendHeadersComplete(int status) {
105 send_headers_completed_ = true;
106 return true;
107 }
108 virtual int OnSendBody() {
109 ADD_FAILURE() << "OnSendBody should not be called";
110 return ERR_UNEXPECTED;
111 }
112 virtual bool OnSendBodyComplete(int status) {
113 ADD_FAILURE() << "OnSendBodyComplete should not be called";
114 return true;
115 }
116 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
117 base::Time response_time,
118 int status) {
119 EXPECT_TRUE(send_headers_completed_);
120 *response_ = response;
121 if (buf_) {
122 EXPECT_EQ(ERR_IO_PENDING,
123 stream_->WriteStreamData(buf_.get(), buf_->size(),
124 spdy::DATA_FLAG_NONE));
125 }
126 return status;
127 }
128 virtual void OnDataReceived(const char* buffer, int bytes) {
129 received_data_ += std::string(buffer, bytes);
130 }
131 virtual void OnDataSent(int length) {
132 data_sent_ += length;
133 }
134 virtual void OnClose(int status) {
135 closed_ = true;
136 CompletionCallback* callback = callback_;
137 callback_ = NULL;
138 callback->Run(OK);
139 }
140
141 bool send_headers_completed() const { return send_headers_completed_; }
142 const linked_ptr<spdy::SpdyHeaderBlock>& response() const {
143 return response_;
144 }
145 const std::string& received_data() const { return received_data_; }
146 int data_sent() const { return data_sent_; }
147 bool closed() const { return closed_; }
148
149 private:
150 SpdyStream* stream_;
151 scoped_refptr<IOBufferWithSize> buf_;
152 CompletionCallback* callback_;
153 bool send_headers_completed_;
154 linked_ptr<spdy::SpdyHeaderBlock> response_;
155 std::string received_data_;
156 int data_sent_;
157 bool closed_;
158};
159
160spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) {
161 spdy::SpdyFramer framer;
162 return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE);
163}
164
165} // anonymous namespace
166
167class SpdyStreamTest : public testing::Test {
168 protected:
169 SpdyStreamTest() {
170 }
171
172 scoped_refptr<SpdySession> CreateSpdySession() {
173 spdy::SpdyFramer::set_enable_compression_default(false);
174 HostPortPair host_port_pair("www.google.com", 80);
175 scoped_refptr<SpdySession> session(
176 session_->spdy_session_pool()->Get(
177 host_port_pair, session_, BoundNetLog()));
178 return session;
179 }
180
181 virtual void TearDown() {
182 MessageLoop::current()->RunAllPending();
183 }
184
185 scoped_refptr<HttpNetworkSession> session_;
186};
187
188TEST_F(SpdyStreamTest, SendDataAfterOpen) {
189 SessionDependencies session_deps;
190
191 session_ = CreateSession(&session_deps);
192 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
193
194 const SpdyHeaderInfo kSynStartHeader = {
195 spdy::SYN_STREAM,
196 1,
197 0,
198 SPDY_PRIORITY_LOWEST,
199 spdy::CONTROL_FLAG_NONE,
200 false,
201 spdy::INVALID,
202 NULL,
203 0,
204 spdy::DATA_FLAG_NONE
205 };
206 static const char* const kGetHeaders[] = {
207 "method",
208 "GET",
209 "url",
210 "http://www.google.com/",
211 "version",
212 "HTTP/1.1",
213 };
214 scoped_ptr<spdy::SpdyFrame> req(
215 ConstructSpdyPacket(
216 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2));
217 scoped_ptr<spdy::SpdyFrame> msg(
218 ConstructSpdyBodyFrame("\0hello!\xff", 8));
219 MockWrite writes[] = {
220 CreateMockWrite(*req),
221 CreateMockWrite(*msg),
222 };
223 writes[0].sequence_number = 0;
224 writes[1].sequence_number = 2;
225
226 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
227 scoped_ptr<spdy::SpdyFrame> echo(
228 ConstructSpdyBodyFrame("\0hello!\xff", 8));
229 MockRead reads[] = {
230 CreateMockRead(*resp),
231 CreateMockRead(*echo),
232 MockRead(true, 0, 0), // EOF
233 };
234 reads[0].sequence_number = 1;
235 reads[1].sequence_number = 3;
236 reads[2].sequence_number = 4;
237
238 scoped_refptr<OrderedSocketData> data(
239 new OrderedSocketData(reads, arraysize(reads),
240 writes, arraysize(writes)));
[email protected]1442b29a2010-07-20 11:14:54241 MockConnect connect_data(false, OK);
242 data->set_connect_data(connect_data);
[email protected]4f386422010-07-20 04:19:49243
244 session_deps.socket_factory.AddSocketDataProvider(data.get());
245 SpdySession::SetSSLMode(false);
246
247 scoped_refptr<SpdySession> session(CreateSpdySession());
248 GURL url("http://www.google.com/");
249
250 HostPortPair host_port_pair("www.google.com", 80);
251 scoped_refptr<TCPSocketParams> tcp_params =
252 new TCPSocketParams(host_port_pair, LOWEST, GURL(), false);
253 EXPECT_EQ(OK, session->Connect("spdy.www.google.com", tcp_params,
254 LOWEST));
255
256 scoped_refptr<SpdyStream> stream;
257 ASSERT_EQ(
258 OK,
[email protected]971746e2010-07-21 03:02:23259 session->CreateStream(url, LOWEST, &stream, BoundNetLog(), NULL));
[email protected]4f386422010-07-20 04:19:49260 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
261 memcpy(buf->data(), "\0hello!\xff", 8);
262 TestCompletionCallback callback;
263
264 scoped_ptr<TestSpdyStreamDelegate> delegate(
265 new TestSpdyStreamDelegate(stream.get(), buf.get(), &callback));
266 stream->SetDelegate(delegate.get());
267
268 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
269 (*headers)["method"] = "GET";
270 (*headers)["url"] = "http://www.google.com/";
271 (*headers)["version"] = "HTTP/1.1";
272 stream->set_spdy_headers(headers);
273
274 EXPECT_EQ(ERR_IO_PENDING, stream->DoSendRequest(true));
275
276 EXPECT_EQ(OK, callback.WaitForResult());
277
278 EXPECT_TRUE(delegate->send_headers_completed());
279 EXPECT_EQ("200", (*delegate->response())["status"]);
280 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
281 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
282 EXPECT_EQ(8, delegate->data_sent());
283 EXPECT_TRUE(delegate->closed());
284}
285
286} // namespace net