• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/spdy/spdy_stream.h"
7 #include "net/spdy/spdy_http_utils.h"
8 #include "net/spdy/spdy_session.h"
9 #include "net/spdy/spdy_test_util.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace net {
13 
14 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
15 class SpdySessionPoolPeer {
16  public:
SpdySessionPoolPeer(SpdySessionPool * pool)17   explicit SpdySessionPoolPeer(SpdySessionPool* pool)
18       : pool_(pool) {}
19 
RemoveSpdySession(const scoped_refptr<SpdySession> & session)20   void RemoveSpdySession(const scoped_refptr<SpdySession>& session) {
21     pool_->Remove(session);
22   }
23 
24  private:
25   SpdySessionPool* const pool_;
26 
27   DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
28 };
29 
30 namespace {
31 
32 class TestSpdyStreamDelegate : public SpdyStream::Delegate {
33  public:
TestSpdyStreamDelegate(SpdyStream * stream,IOBufferWithSize * buf,CompletionCallback * callback)34   TestSpdyStreamDelegate(SpdyStream* stream,
35                          IOBufferWithSize* buf,
36                          CompletionCallback* callback)
37       : stream_(stream),
38         buf_(buf),
39         callback_(callback),
40         send_headers_completed_(false),
41         response_(new spdy::SpdyHeaderBlock),
42         data_sent_(0),
43         closed_(false) {}
~TestSpdyStreamDelegate()44   virtual ~TestSpdyStreamDelegate() {}
45 
OnSendHeadersComplete(int status)46   virtual bool OnSendHeadersComplete(int status) {
47     send_headers_completed_ = true;
48     return true;
49   }
OnSendBody()50   virtual int OnSendBody() {
51     ADD_FAILURE() << "OnSendBody should not be called";
52     return ERR_UNEXPECTED;
53   }
OnSendBodyComplete(int,bool *)54   virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
55     ADD_FAILURE() << "OnSendBodyComplete should not be called";
56     return ERR_UNEXPECTED;
57   }
58 
OnResponseReceived(const spdy::SpdyHeaderBlock & response,base::Time response_time,int status)59   virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
60                                  base::Time response_time,
61                                  int status) {
62     EXPECT_TRUE(send_headers_completed_);
63     *response_ = response;
64     if (buf_) {
65       EXPECT_EQ(ERR_IO_PENDING,
66                 stream_->WriteStreamData(buf_.get(), buf_->size(),
67                                          spdy::DATA_FLAG_NONE));
68     }
69     return status;
70   }
OnDataReceived(const char * buffer,int bytes)71   virtual void OnDataReceived(const char* buffer, int bytes) {
72     received_data_ += std::string(buffer, bytes);
73   }
OnDataSent(int length)74   virtual void OnDataSent(int length) {
75     data_sent_ += length;
76   }
OnClose(int status)77   virtual void OnClose(int status) {
78     closed_ = true;
79     CompletionCallback* callback = callback_;
80     callback_ = NULL;
81     callback->Run(OK);
82   }
set_chunk_callback(net::ChunkCallback *)83   virtual void set_chunk_callback(net::ChunkCallback *) {}
84 
send_headers_completed() const85   bool send_headers_completed() const { return send_headers_completed_; }
response() const86   const linked_ptr<spdy::SpdyHeaderBlock>& response() const {
87     return response_;
88   }
received_data() const89   const std::string& received_data() const { return received_data_; }
data_sent() const90   int data_sent() const { return data_sent_; }
closed() const91   bool closed() const {  return closed_; }
92 
93  private:
94   SpdyStream* stream_;
95   scoped_refptr<IOBufferWithSize> buf_;
96   CompletionCallback* callback_;
97   bool send_headers_completed_;
98   linked_ptr<spdy::SpdyHeaderBlock> response_;
99   std::string received_data_;
100   int data_sent_;
101   bool closed_;
102 };
103 
ConstructSpdyBodyFrame(const char * data,int length)104 spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) {
105   spdy::SpdyFramer framer;
106   return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE);
107 }
108 
109 }  // anonymous namespace
110 
111 class SpdyStreamTest : public testing::Test {
112  protected:
SpdyStreamTest()113   SpdyStreamTest() {
114   }
115 
CreateSpdySession()116   scoped_refptr<SpdySession> CreateSpdySession() {
117     spdy::SpdyFramer::set_enable_compression_default(false);
118     HostPortPair host_port_pair("www.google.com", 80);
119     HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
120     scoped_refptr<SpdySession> session(
121         session_->spdy_session_pool()->Get(pair, BoundNetLog()));
122     return session;
123   }
124 
TearDown()125   virtual void TearDown() {
126     MessageLoop::current()->RunAllPending();
127   }
128 
129   scoped_refptr<HttpNetworkSession> session_;
130 };
131 
TEST_F(SpdyStreamTest,SendDataAfterOpen)132 TEST_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<TransportSocketParams> transport_params(
201       new TransportSocketParams(host_port_pair, LOWEST, GURL(), false, false));
202 
203   scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
204   EXPECT_EQ(OK,
205             connection->Init(host_port_pair.ToString(),
206                              transport_params,
207                              LOWEST,
208                              NULL,
209                              session_->transport_socket_pool(),
210                              BoundNetLog()));
211   session->InitializeWithSocket(connection.release(), false, OK);
212 
213   scoped_refptr<SpdyStream> stream;
214   ASSERT_EQ(
215       OK,
216       session->CreateStream(url, LOWEST, &stream, BoundNetLog(), NULL));
217   scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
218   memcpy(buf->data(), "\0hello!\xff", 8);
219   TestCompletionCallback callback;
220 
221   scoped_ptr<TestSpdyStreamDelegate> delegate(
222       new TestSpdyStreamDelegate(stream.get(), buf.get(), &callback));
223   stream->SetDelegate(delegate.get());
224 
225   EXPECT_FALSE(stream->HasUrl());
226 
227   linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
228   (*headers)["method"] = "GET";
229   (*headers)["scheme"] = url.scheme();
230   (*headers)["host"] = url.host();
231   (*headers)["path"] = url.path();
232   (*headers)["version"] = "HTTP/1.1";
233   stream->set_spdy_headers(headers);
234   EXPECT_TRUE(stream->HasUrl());
235   EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
236 
237   EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
238 
239   EXPECT_EQ(OK, callback.WaitForResult());
240 
241   EXPECT_TRUE(delegate->send_headers_completed());
242   EXPECT_EQ("200", (*delegate->response())["status"]);
243   EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
244   EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
245   EXPECT_EQ(8, delegate->data_sent());
246   EXPECT_TRUE(delegate->closed());
247 }
248 
TEST_F(SpdyStreamTest,PushedStream)249 TEST_F(SpdyStreamTest, PushedStream) {
250   const char kStreamUrl[] = "http://www.google.com/";
251 
252   SpdySessionDependencies session_deps;
253   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
254   SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
255   scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
256   BoundNetLog net_log;
257 
258   // Conjure up a stream.
259   scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session,
260                                                     2,
261                                                     true,
262                                                     net_log);
263   EXPECT_FALSE(stream->response_received());
264   EXPECT_FALSE(stream->HasUrl());
265 
266   // Set a couple of headers.
267   spdy::SpdyHeaderBlock response;
268   response["url"] = kStreamUrl;
269   stream->OnResponseReceived(response);
270 
271   // Send some basic headers.
272   spdy::SpdyHeaderBlock headers;
273   response["status"] = "200";
274   response["version"] = "OK";
275   stream->OnHeaders(headers);
276 
277   stream->set_response_received();
278   EXPECT_TRUE(stream->response_received());
279   EXPECT_TRUE(stream->HasUrl());
280   EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
281 }
282 
283 
284 }  // namespace net
285