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