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