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 "net/spdy/spdy_http_stream.h"
6 #include "net/spdy/spdy_session.h"
7 #include "net/spdy/spdy_test_util.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace net {
11
12 class SpdyHttpStreamTest : public testing::Test {
13 public:
data()14 OrderedSocketData* data() { return data_; }
15 protected:
SpdyHttpStreamTest()16 SpdyHttpStreamTest() {}
17
EnableCompression(bool enabled)18 void EnableCompression(bool enabled) {
19 spdy::SpdyFramer::set_enable_compression_default(enabled);
20 }
21
TearDown()22 virtual void TearDown() {
23 MessageLoop::current()->RunAllPending();
24 }
InitSession(MockRead * reads,size_t reads_count,MockWrite * writes,size_t writes_count,HostPortPair & host_port_pair)25 int InitSession(MockRead* reads, size_t reads_count,
26 MockWrite* writes, size_t writes_count,
27 HostPortPair& host_port_pair) {
28 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
29 data_ = new OrderedSocketData(reads, reads_count, writes, writes_count);
30 session_deps_.socket_factory->AddSocketDataProvider(data_.get());
31 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
32 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
33 transport_params_ = new TransportSocketParams(host_port_pair,
34 MEDIUM, GURL(), false, false);
35 TestCompletionCallback callback;
36 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
37 EXPECT_EQ(ERR_IO_PENDING,
38 connection->Init(host_port_pair.ToString(),
39 transport_params_,
40 MEDIUM,
41 &callback,
42 http_session_->transport_socket_pool(),
43 BoundNetLog()));
44 EXPECT_EQ(OK, callback.WaitForResult());
45 return session_->InitializeWithSocket(connection.release(), false, OK);
46 }
47 SpdySessionDependencies session_deps_;
48 scoped_refptr<OrderedSocketData> data_;
49 scoped_refptr<HttpNetworkSession> http_session_;
50 scoped_refptr<SpdySession> session_;
51 scoped_refptr<TransportSocketParams> transport_params_;
52 };
53
TEST_F(SpdyHttpStreamTest,SendRequest)54 TEST_F(SpdyHttpStreamTest, SendRequest) {
55 EnableCompression(false);
56 SpdySession::SetSSLMode(false);
57
58 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
59 MockWrite writes[] = {
60 CreateMockWrite(*req.get(), 1),
61 };
62 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
63 MockRead reads[] = {
64 CreateMockRead(*resp, 2),
65 MockRead(false, 0, 3) // EOF
66 };
67
68 HostPortPair host_port_pair("www.google.com", 80);
69 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
70 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
71 host_port_pair));
72
73 HttpRequestInfo request;
74 request.method = "GET";
75 request.url = GURL("http://www.google.com/");
76 TestCompletionCallback callback;
77 HttpResponseInfo response;
78 HttpRequestHeaders headers;
79 BoundNetLog net_log;
80 scoped_ptr<SpdyHttpStream> http_stream(
81 new SpdyHttpStream(session_.get(), true));
82 ASSERT_EQ(
83 OK,
84 http_stream->InitializeStream(&request, net_log, NULL));
85
86 EXPECT_EQ(ERR_IO_PENDING,
87 http_stream->SendRequest(headers, NULL, &response, &callback));
88 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
89
90 // This triggers the MockWrite and read 2
91 callback.WaitForResult();
92
93 // This triggers read 3. The empty read causes the session to shut down.
94 data()->CompleteRead();
95
96 // Because we abandoned the stream, we don't expect to find a session in the
97 // pool anymore.
98 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
99 EXPECT_TRUE(data()->at_read_eof());
100 EXPECT_TRUE(data()->at_write_eof());
101 }
102
TEST_F(SpdyHttpStreamTest,SendChunkedPost)103 TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
104 EnableCompression(false);
105 SpdySession::SetSSLMode(false);
106 UploadDataStream::set_merge_chunks(false);
107
108 scoped_ptr<spdy::SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
109 scoped_ptr<spdy::SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
110 scoped_ptr<spdy::SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
111 MockWrite writes[] = {
112 CreateMockWrite(*req.get(), 1),
113 CreateMockWrite(*chunk1, 2), // POST upload frames
114 CreateMockWrite(*chunk2, 3),
115 };
116 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
117 MockRead reads[] = {
118 CreateMockRead(*resp, 4),
119 CreateMockRead(*chunk1, 5),
120 CreateMockRead(*chunk2, 5),
121 MockRead(false, 0, 6) // EOF
122 };
123
124 HostPortPair host_port_pair("www.google.com", 80);
125 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
126 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
127 host_port_pair));
128
129 HttpRequestInfo request;
130 request.method = "POST";
131 request.url = GURL("http://www.google.com/");
132 request.upload_data = new UploadData();
133 request.upload_data->set_is_chunked(true);
134 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
135 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, true);
136 TestCompletionCallback callback;
137 HttpResponseInfo response;
138 HttpRequestHeaders headers;
139 BoundNetLog net_log;
140 SpdyHttpStream http_stream(session_.get(), true);
141 ASSERT_EQ(
142 OK,
143 http_stream.InitializeStream(&request, net_log, NULL));
144
145 UploadDataStream* upload_stream =
146 UploadDataStream::Create(request.upload_data, NULL);
147 EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
148 headers, upload_stream, &response, &callback));
149 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
150
151 // This triggers the MockWrite and read 2
152 callback.WaitForResult();
153
154 // This triggers read 3. The empty read causes the session to shut down.
155 data()->CompleteRead();
156 MessageLoop::current()->RunAllPending();
157
158 // Because we abandoned the stream, we don't expect to find a session in the
159 // pool anymore.
160 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
161 EXPECT_TRUE(data()->at_read_eof());
162 EXPECT_TRUE(data()->at_write_eof());
163 }
164
165 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
TEST_F(SpdyHttpStreamTest,SpdyURLTest)166 TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
167 EnableCompression(false);
168 SpdySession::SetSSLMode(false);
169
170 const char * const full_url = "http://www.google.com/foo?query=what#anchor";
171 const char * const base_url = "http://www.google.com/foo?query=what";
172 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
173 MockWrite writes[] = {
174 CreateMockWrite(*req.get(), 1),
175 };
176 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
177 MockRead reads[] = {
178 CreateMockRead(*resp, 2),
179 MockRead(false, 0, 3) // EOF
180 };
181
182 HostPortPair host_port_pair("www.google.com", 80);
183 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
184 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
185 host_port_pair));
186
187 HttpRequestInfo request;
188 request.method = "GET";
189 request.url = GURL(full_url);
190 TestCompletionCallback callback;
191 HttpResponseInfo response;
192 HttpRequestHeaders headers;
193 BoundNetLog net_log;
194 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
195 ASSERT_EQ(
196 OK,
197 http_stream->InitializeStream(&request, net_log, NULL));
198
199 EXPECT_EQ(ERR_IO_PENDING,
200 http_stream->SendRequest(headers, NULL, &response, &callback));
201
202 spdy::SpdyHeaderBlock* spdy_header =
203 http_stream->stream()->spdy_headers().get();
204 EXPECT_TRUE(spdy_header != NULL);
205 if (spdy_header->find("url") != spdy_header->end())
206 EXPECT_EQ("/foo?query=what", spdy_header->find("url")->second);
207 else
208 FAIL() << "No url is set in spdy_header!";
209
210 // This triggers the MockWrite and read 2
211 callback.WaitForResult();
212
213 // This triggers read 3. The empty read causes the session to shut down.
214 data()->CompleteRead();
215
216 // Because we abandoned the stream, we don't expect to find a session in the
217 // pool anymore.
218 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
219 EXPECT_TRUE(data()->at_read_eof());
220 EXPECT_TRUE(data()->at_write_eof());
221 }
222
223 // TODO(willchan): Write a longer test for SpdyStream that exercises all
224 // methods.
225
226 } // namespace net
227