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