spdy_stream_unittest.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1// 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 "net/spdy/spdy_session.h"
8#include "net/spdy/spdy_test_util.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace net {
12
13// TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
14class SpdySessionPoolPeer {
15 public:
16  explicit SpdySessionPoolPeer(SpdySessionPool* pool)
17      : pool_(pool) {}
18
19  void RemoveSpdySession(const scoped_refptr<SpdySession>& session) {
20    pool_->Remove(session);
21  }
22
23 private:
24  SpdySessionPool* const pool_;
25
26  DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
27};
28
29namespace {
30
31class TestSpdyStreamDelegate : public SpdyStream::Delegate {
32 public:
33  TestSpdyStreamDelegate(SpdyStream* stream,
34                         IOBufferWithSize* buf,
35                         CompletionCallback* callback)
36      : stream_(stream),
37        buf_(buf),
38        callback_(callback),
39        send_headers_completed_(false),
40        response_(new spdy::SpdyHeaderBlock),
41        data_sent_(0),
42        closed_(false) {}
43  virtual ~TestSpdyStreamDelegate() {}
44
45  virtual bool OnSendHeadersComplete(int status) {
46    send_headers_completed_ = true;
47    return true;
48  }
49  virtual int OnSendBody() {
50    ADD_FAILURE() << "OnSendBody should not be called";
51    return ERR_UNEXPECTED;
52  }
53  virtual bool OnSendBodyComplete(int status) {
54    ADD_FAILURE() << "OnSendBodyComplete should not be called";
55    return true;
56  }
57
58  virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
59                                 base::Time response_time,
60                                 int status) {
61    EXPECT_TRUE(send_headers_completed_);
62    *response_ = response;
63    if (buf_) {
64      EXPECT_EQ(ERR_IO_PENDING,
65                stream_->WriteStreamData(buf_.get(), buf_->size(),
66                                         spdy::DATA_FLAG_NONE));
67    }
68    return status;
69  }
70  virtual void OnDataReceived(const char* buffer, int bytes) {
71    received_data_ += std::string(buffer, bytes);
72  }
73  virtual void OnDataSent(int length) {
74    data_sent_ += length;
75  }
76  virtual void OnClose(int status) {
77    closed_ = true;
78    CompletionCallback* callback = callback_;
79    callback_ = NULL;
80    callback->Run(OK);
81  }
82
83  bool send_headers_completed() const { return send_headers_completed_; }
84  const linked_ptr<spdy::SpdyHeaderBlock>& response() const {
85    return response_;
86  }
87  const std::string& received_data() const { return received_data_; }
88  int data_sent() const { return data_sent_; }
89  bool closed() const {  return closed_; }
90
91 private:
92  SpdyStream* stream_;
93  scoped_refptr<IOBufferWithSize> buf_;
94  CompletionCallback* callback_;
95  bool send_headers_completed_;
96  linked_ptr<spdy::SpdyHeaderBlock> response_;
97  std::string received_data_;
98  int data_sent_;
99  bool closed_;
100};
101
102spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) {
103  spdy::SpdyFramer framer;
104  return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE);
105}
106
107}  // anonymous namespace
108
109class SpdyStreamTest : public testing::Test {
110 protected:
111  SpdyStreamTest() {
112  }
113
114  scoped_refptr<SpdySession> CreateSpdySession() {
115    spdy::SpdyFramer::set_enable_compression_default(false);
116    HostPortPair host_port_pair("www.google.com", 80);
117    HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
118    scoped_refptr<SpdySession> session(
119        session_->spdy_session_pool()->Get(pair,
120                                           session_->mutable_spdy_settings(),
121                                           BoundNetLog()));
122    return session;
123  }
124
125  virtual void TearDown() {
126    MessageLoop::current()->RunAllPending();
127  }
128
129  scoped_refptr<HttpNetworkSession> session_;
130};
131
132TEST_F(SpdyStreamTest, SendDataAfterOpen) {
133  SpdySessionDependencies session_deps;
134
135  session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
136  SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
137
138  const SpdyHeaderInfo kSynStartHeader = {
139    spdy::SYN_STREAM,
140    1,
141    0,
142    net::ConvertRequestPriorityToSpdyPriority(LOWEST),
143    spdy::CONTROL_FLAG_NONE,
144    false,
145    spdy::INVALID,
146    NULL,
147    0,
148    spdy::DATA_FLAG_NONE
149  };
150  static const char* const kGetHeaders[] = {
151    "method",
152    "GET",
153    "scheme",
154    "http",
155    "host",
156    "www.google.com",
157    "path",
158    "/",
159    "version",
160    "HTTP/1.1",
161  };
162  scoped_ptr<spdy::SpdyFrame> req(
163      ConstructSpdyPacket(
164          kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2));
165  scoped_ptr<spdy::SpdyFrame> msg(
166      ConstructSpdyBodyFrame("\0hello!\xff", 8));
167  MockWrite writes[] = {
168    CreateMockWrite(*req),
169    CreateMockWrite(*msg),
170  };
171  writes[0].sequence_number = 0;
172  writes[1].sequence_number = 2;
173
174  scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
175  scoped_ptr<spdy::SpdyFrame> echo(
176      ConstructSpdyBodyFrame("\0hello!\xff", 8));
177  MockRead reads[] = {
178    CreateMockRead(*resp),
179    CreateMockRead(*echo),
180    MockRead(true, 0, 0), // EOF
181  };
182  reads[0].sequence_number = 1;
183  reads[1].sequence_number = 3;
184  reads[2].sequence_number = 4;
185
186  scoped_refptr<OrderedSocketData> data(
187      new OrderedSocketData(reads, arraysize(reads),
188                            writes, arraysize(writes)));
189  MockConnect connect_data(false, OK);
190  data->set_connect_data(connect_data);
191
192  session_deps.socket_factory->AddSocketDataProvider(data.get());
193  SpdySession::SetSSLMode(false);
194
195  scoped_refptr<SpdySession> session(CreateSpdySession());
196  const char* kStreamUrl = "http://www.google.com/";
197  GURL url(kStreamUrl);
198
199  HostPortPair host_port_pair("www.google.com", 80);
200  scoped_refptr<TCPSocketParams> tcp_params(
201      new TCPSocketParams(host_port_pair, LOWEST, GURL(), false));
202
203  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
204  EXPECT_EQ(OK,
205            connection->Init(host_port_pair.ToString(), tcp_params, LOWEST,
206                             NULL, session_->tcp_socket_pool(), BoundNetLog()));
207  session->InitializeWithSocket(connection.release(), false, OK);
208
209  scoped_refptr<SpdyStream> stream;
210  ASSERT_EQ(
211      OK,
212      session->CreateStream(url, LOWEST, &stream, BoundNetLog(), NULL));
213  scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
214  memcpy(buf->data(), "\0hello!\xff", 8);
215  TestCompletionCallback callback;
216
217  scoped_ptr<TestSpdyStreamDelegate> delegate(
218      new TestSpdyStreamDelegate(stream.get(), buf.get(), &callback));
219  stream->SetDelegate(delegate.get());
220
221  EXPECT_FALSE(stream->HasUrl());
222
223  linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
224  (*headers)["method"] = "GET";
225  (*headers)["scheme"] = url.scheme();
226  (*headers)["host"] = url.host();
227  (*headers)["path"] = url.path();
228  (*headers)["version"] = "HTTP/1.1";
229  stream->set_spdy_headers(headers);
230  EXPECT_TRUE(stream->HasUrl());
231  EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
232
233  EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
234
235  EXPECT_EQ(OK, callback.WaitForResult());
236
237  EXPECT_TRUE(delegate->send_headers_completed());
238  EXPECT_EQ("200", (*delegate->response())["status"]);
239  EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
240  EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
241  EXPECT_EQ(8, delegate->data_sent());
242  EXPECT_TRUE(delegate->closed());
243}
244
245TEST_F(SpdyStreamTest, PushedStream) {
246  const char kStreamUrl[] = "http://www.google.com/";
247
248  SpdySessionDependencies session_deps;
249  session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
250  SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
251  scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
252  BoundNetLog net_log;
253
254  // Conjure up a stream.
255  scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session,
256                                                    2,
257                                                    true,
258                                                    net_log);
259  EXPECT_FALSE(stream->response_received());
260  EXPECT_FALSE(stream->HasUrl());
261
262  // Set a couple of headers.
263  spdy::SpdyHeaderBlock response;
264  response["url"] = kStreamUrl;
265  stream->OnResponseReceived(response);
266
267  // Send some basic headers.
268  spdy::SpdyHeaderBlock headers;
269  response["status"] = "200";
270  response["version"] = "OK";
271  stream->OnHeaders(headers);
272
273  stream->set_response_received();
274  EXPECT_TRUE(stream->response_received());
275  EXPECT_TRUE(stream->HasUrl());
276  EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
277}
278
279
280}  // namespace net
281