OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 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/url_request/url_request_http_job.h" | |
6 | |
7 #include <cstddef> | |
8 | |
9 #include "base/compiler_specific.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/run_loop.h" | |
13 #include "net/base/auth.h" | |
14 #include "net/base/request_priority.h" | |
15 #include "net/http/http_transaction_factory.h" | |
16 #include "net/http/http_transaction_test_util.h" | |
17 #include "net/socket/socket_test_util.h" | |
18 #include "net/url_request/url_request.h" | |
19 #include "net/url_request/url_request_status.h" | |
20 #include "net/url_request/url_request_test_util.h" | |
21 #include "net/websockets/websocket_handshake_stream_base.h" | |
22 #include "testing/gmock/include/gmock/gmock.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 #include "url/gurl.h" | |
25 | |
26 namespace net { | |
27 | |
28 namespace { | |
29 | |
30 using ::testing::Return; | |
31 | |
32 // Inherit from URLRequestHttpJob to expose the priority and some | |
33 // other hidden functions. | |
34 class TestURLRequestHttpJob : public URLRequestHttpJob { | |
35 public: | |
36 explicit TestURLRequestHttpJob(URLRequest* request) | |
37 : URLRequestHttpJob(request, request->context()->network_delegate(), | |
38 request->context()->http_user_agent_settings()) {} | |
39 | |
40 using URLRequestHttpJob::SetPriority; | |
41 using URLRequestHttpJob::Start; | |
42 using URLRequestHttpJob::Kill; | |
43 using URLRequestHttpJob::priority; | |
44 | |
45 protected: | |
46 ~TestURLRequestHttpJob() override {} | |
47 }; | |
48 | |
49 class URLRequestHttpJobTest : public ::testing::Test { | |
50 protected: | |
51 URLRequestHttpJobTest() | |
52 : req_(context_.CreateRequest(GURL("http://www.example.com"), | |
53 DEFAULT_PRIORITY, | |
54 &delegate_, | |
55 nullptr)) { | |
56 context_.set_http_transaction_factory(&network_layer_); | |
57 } | |
58 | |
59 bool TransactionAcceptsSdchEncoding() { | |
60 base::WeakPtr<MockNetworkTransaction> transaction( | |
61 network_layer_.last_transaction()); | |
62 EXPECT_TRUE(transaction); | |
63 if (!transaction) return false; | |
64 | |
65 const HttpRequestInfo* request_info = transaction->request(); | |
66 EXPECT_TRUE(request_info); | |
67 if (!request_info) return false; | |
68 | |
69 std::string encoding_headers; | |
70 bool get_success = request_info->extra_headers.GetHeader( | |
71 "Accept-Encoding", &encoding_headers); | |
72 EXPECT_TRUE(get_success); | |
73 if (!get_success) return false; | |
74 | |
75 // This check isn't wrapped with EXPECT* macros because different | |
76 // results from this function may be expected in different tests. | |
77 std::vector<std::string> tokens; | |
78 size_t num_tokens = Tokenize(encoding_headers, ", ", &tokens); | |
79 for (size_t i = 0; i < num_tokens; i++) { | |
80 if (!base::strncasecmp(tokens[i].data(), "sdch", tokens[i].length())) | |
81 return true; | |
82 } | |
83 return false; | |
84 } | |
85 | |
86 void EnableSdch() { | |
87 context_.SetSdchManager(scoped_ptr<SdchManager>(new SdchManager).Pass()); | |
88 } | |
89 | |
90 MockNetworkLayer network_layer_; | |
91 TestURLRequestContext context_; | |
92 TestDelegate delegate_; | |
93 scoped_ptr<URLRequest> req_; | |
94 }; | |
95 | |
96 // Make sure that SetPriority actually sets the URLRequestHttpJob's | |
97 // priority, both before and after start. | |
98 TEST_F(URLRequestHttpJobTest, SetPriorityBasic) { | |
99 scoped_refptr<TestURLRequestHttpJob> job( | |
100 new TestURLRequestHttpJob(req_.get())); | |
101 EXPECT_EQ(DEFAULT_PRIORITY, job->priority()); | |
102 | |
103 job->SetPriority(LOWEST); | |
104 EXPECT_EQ(LOWEST, job->priority()); | |
105 | |
106 job->SetPriority(LOW); | |
107 EXPECT_EQ(LOW, job->priority()); | |
108 | |
109 job->Start(); | |
110 EXPECT_EQ(LOW, job->priority()); | |
111 | |
112 job->SetPriority(MEDIUM); | |
113 EXPECT_EQ(MEDIUM, job->priority()); | |
114 } | |
115 | |
116 // Make sure that URLRequestHttpJob passes on its priority to its | |
117 // transaction on start. | |
118 TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) { | |
119 scoped_refptr<TestURLRequestHttpJob> job( | |
120 new TestURLRequestHttpJob(req_.get())); | |
121 job->SetPriority(LOW); | |
122 | |
123 EXPECT_FALSE(network_layer_.last_transaction()); | |
124 | |
125 job->Start(); | |
126 | |
127 ASSERT_TRUE(network_layer_.last_transaction()); | |
128 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); | |
129 } | |
130 | |
131 // Make sure that URLRequestHttpJob passes on its priority updates to | |
132 // its transaction. | |
133 TEST_F(URLRequestHttpJobTest, SetTransactionPriority) { | |
134 scoped_refptr<TestURLRequestHttpJob> job( | |
135 new TestURLRequestHttpJob(req_.get())); | |
136 job->SetPriority(LOW); | |
137 job->Start(); | |
138 ASSERT_TRUE(network_layer_.last_transaction()); | |
139 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); | |
140 | |
141 job->SetPriority(HIGHEST); | |
142 EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority()); | |
143 } | |
144 | |
145 // Make sure that URLRequestHttpJob passes on its priority updates to | |
146 // newly-created transactions after the first one. | |
147 TEST_F(URLRequestHttpJobTest, SetSubsequentTransactionPriority) { | |
148 scoped_refptr<TestURLRequestHttpJob> job( | |
149 new TestURLRequestHttpJob(req_.get())); | |
150 job->Start(); | |
151 | |
152 job->SetPriority(LOW); | |
153 ASSERT_TRUE(network_layer_.last_transaction()); | |
154 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); | |
155 | |
156 job->Kill(); | |
157 network_layer_.ClearLastTransaction(); | |
158 | |
159 // Creates a second transaction. | |
160 job->Start(); | |
161 ASSERT_TRUE(network_layer_.last_transaction()); | |
162 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); | |
163 } | |
164 | |
165 // Confirm we do advertise SDCH encoding in the case of a GET. | |
166 TEST_F(URLRequestHttpJobTest, SdchAdvertisementGet) { | |
167 EnableSdch(); | |
168 req_->set_method("GET"); // Redundant with default. | |
169 scoped_refptr<TestURLRequestHttpJob> job( | |
170 new TestURLRequestHttpJob(req_.get())); | |
171 job->Start(); | |
172 EXPECT_TRUE(TransactionAcceptsSdchEncoding()); | |
173 } | |
174 | |
175 // Confirm we don't advertise SDCH encoding in the case of a POST. | |
176 TEST_F(URLRequestHttpJobTest, SdchAdvertisementPost) { | |
177 EnableSdch(); | |
178 req_->set_method("POST"); | |
179 scoped_refptr<TestURLRequestHttpJob> job( | |
180 new TestURLRequestHttpJob(req_.get())); | |
181 job->Start(); | |
182 EXPECT_FALSE(TransactionAcceptsSdchEncoding()); | |
183 } | |
184 | |
185 // This base class just serves to set up some things before the TestURLRequest | |
186 // constructor is called. | |
187 class URLRequestHttpJobWebSocketTestBase : public ::testing::Test { | |
188 protected: | |
189 URLRequestHttpJobWebSocketTestBase() : socket_data_(nullptr, 0, nullptr, 0), | |
190 context_(true) { | |
191 // A Network Delegate is required for the WebSocketHandshakeStreamBase | |
192 // object to be passed on to the HttpNetworkTransaction. | |
193 context_.set_network_delegate(&network_delegate_); | |
194 | |
195 // Attempting to create real ClientSocketHandles is not going to work out so | |
196 // well. Set up a fake socket factory. | |
197 socket_factory_.AddSocketDataProvider(&socket_data_); | |
198 context_.set_client_socket_factory(&socket_factory_); | |
199 context_.Init(); | |
200 } | |
201 | |
202 StaticSocketDataProvider socket_data_; | |
203 TestNetworkDelegate network_delegate_; | |
204 MockClientSocketFactory socket_factory_; | |
205 TestURLRequestContext context_; | |
206 }; | |
207 | |
208 class URLRequestHttpJobWebSocketTest | |
209 : public URLRequestHttpJobWebSocketTestBase { | |
210 protected: | |
211 URLRequestHttpJobWebSocketTest() | |
212 : req_(context_.CreateRequest(GURL("ws://www.example.com"), | |
213 DEFAULT_PRIORITY, | |
214 &delegate_, | |
215 nullptr)) { | |
216 // The TestNetworkDelegate expects a call to NotifyBeforeURLRequest before | |
217 // anything else happens. | |
218 GURL url("ws://localhost/"); | |
219 TestCompletionCallback dummy; | |
220 network_delegate_.NotifyBeforeURLRequest( | |
221 req_.get(), dummy.callback(), &url); | |
222 } | |
223 | |
224 TestDelegate delegate_; | |
225 scoped_ptr<URLRequest> req_; | |
226 }; | |
227 | |
228 class MockCreateHelper : public WebSocketHandshakeStreamBase::CreateHelper { | |
229 public: | |
230 // GoogleMock does not appear to play nicely with move-only types like | |
231 // scoped_ptr, so this forwarding method acts as a workaround. | |
232 virtual WebSocketHandshakeStreamBase* CreateBasicStream( | |
233 scoped_ptr<ClientSocketHandle> connection, | |
234 bool using_proxy) override { | |
235 // Discard the arguments since we don't need them anyway. | |
236 return CreateBasicStreamMock(); | |
237 } | |
238 | |
239 MOCK_METHOD0(CreateBasicStreamMock, | |
240 WebSocketHandshakeStreamBase*()); | |
241 | |
242 MOCK_METHOD2(CreateSpdyStream, | |
243 WebSocketHandshakeStreamBase*(const base::WeakPtr<SpdySession>&, | |
244 bool)); | |
245 }; | |
246 | |
247 class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase { | |
248 public: | |
249 FakeWebSocketHandshakeStream() : initialize_stream_was_called_(false) {} | |
250 | |
251 bool initialize_stream_was_called() const { | |
252 return initialize_stream_was_called_; | |
253 } | |
254 | |
255 // Fake implementation of HttpStreamBase methods. | |
256 int InitializeStream(const HttpRequestInfo* request_info, | |
257 RequestPriority priority, | |
258 const BoundNetLog& net_log, | |
259 const CompletionCallback& callback) override { | |
260 initialize_stream_was_called_ = true; | |
261 return ERR_IO_PENDING; | |
262 } | |
263 | |
264 int SendRequest(const HttpRequestHeaders& request_headers, | |
265 HttpResponseInfo* response, | |
266 const CompletionCallback& callback) override { | |
267 return ERR_IO_PENDING; | |
268 } | |
269 | |
270 int ReadResponseHeaders(const CompletionCallback& callback) override { | |
271 return ERR_IO_PENDING; | |
272 } | |
273 | |
274 int ReadResponseBody(IOBuffer* buf, | |
275 int buf_len, | |
276 const CompletionCallback& callback) override { | |
277 return ERR_IO_PENDING; | |
278 } | |
279 | |
280 void Close(bool not_reusable) override {} | |
281 | |
282 bool IsResponseBodyComplete() const override { return false; } | |
283 | |
284 bool CanFindEndOfResponse() const override { return false; } | |
285 | |
286 bool IsConnectionReused() const override { return false; } | |
287 void SetConnectionReused() override {} | |
288 | |
289 bool IsConnectionReusable() const override { return false; } | |
290 | |
291 int64 GetTotalReceivedBytes() const override { return 0; } | |
292 | |
293 bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override { | |
294 return false; | |
295 } | |
296 | |
297 void GetSSLInfo(SSLInfo* ssl_info) override {} | |
298 | |
299 void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {} | |
300 | |
301 bool IsSpdyHttpStream() const override { return false; } | |
302 | |
303 void Drain(HttpNetworkSession* session) override {} | |
304 | |
305 void SetPriority(RequestPriority priority) override {} | |
306 | |
307 UploadProgress GetUploadProgress() const override { | |
308 return UploadProgress(); | |
309 } | |
310 | |
311 HttpStream* RenewStreamForAuth() override { return nullptr; } | |
312 | |
313 // Fake implementation of WebSocketHandshakeStreamBase method(s) | |
314 scoped_ptr<WebSocketStream> Upgrade() override { | |
315 return scoped_ptr<WebSocketStream>(); | |
316 } | |
317 | |
318 private: | |
319 bool initialize_stream_was_called_; | |
320 }; | |
321 | |
322 TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) { | |
323 scoped_refptr<TestURLRequestHttpJob> job( | |
324 new TestURLRequestHttpJob(req_.get())); | |
325 job->Start(); | |
326 base::RunLoop().RunUntilIdle(); | |
327 EXPECT_EQ(URLRequestStatus::FAILED, req_->status().status()); | |
328 EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, req_->status().error()); | |
329 } | |
330 | |
331 TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) { | |
332 scoped_refptr<TestURLRequestHttpJob> job( | |
333 new TestURLRequestHttpJob(req_.get())); | |
334 scoped_ptr<MockCreateHelper> create_helper( | |
335 new ::testing::StrictMock<MockCreateHelper>()); | |
336 FakeWebSocketHandshakeStream* fake_handshake_stream( | |
337 new FakeWebSocketHandshakeStream); | |
338 // Ownership of fake_handshake_stream is transferred when CreateBasicStream() | |
339 // is called. | |
340 EXPECT_CALL(*create_helper, CreateBasicStreamMock()) | |
341 .WillOnce(Return(fake_handshake_stream)); | |
342 req_->SetUserData(WebSocketHandshakeStreamBase::CreateHelper::DataKey(), | |
343 create_helper.release()); | |
344 req_->SetLoadFlags(LOAD_DISABLE_CACHE); | |
345 job->Start(); | |
346 base::RunLoop().RunUntilIdle(); | |
347 EXPECT_EQ(URLRequestStatus::IO_PENDING, req_->status().status()); | |
348 EXPECT_TRUE(fake_handshake_stream->initialize_stream_was_called()); | |
349 } | |
350 | |
351 } // namespace | |
352 | |
353 } // namespace net | |
OLD | NEW |