blob: e672413228880bc2b1d43ef6ce03a129e065ddb7 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 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
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00005#include "net/url_request/url_request_ftp_job.h"
6
7#include "base/memory/ref_counted.h"
8#include "base/memory/scoped_vector.h"
9#include "base/run_loop.h"
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010010#include "net/base/host_port_pair.h"
Torne (Richard Coles)0f1bc082013-11-06 12:27:47 +000011#include "net/base/request_priority.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010012#include "net/ftp/ftp_auth_cache.h"
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010013#include "net/http/http_transaction_test_util.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010014#include "net/proxy/mock_proxy_resolver.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000015#include "net/proxy/proxy_config_service.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010016#include "net/proxy/proxy_config_service_fixed.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000017#include "net/socket/socket_test_util.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010018#include "net/url_request/ftp_protocol_handler.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "net/url_request/url_request.h"
20#include "net/url_request/url_request_context.h"
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010021#include "net/url_request/url_request_job_factory_impl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000022#include "net/url_request/url_request_status.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000023#include "net/url_request/url_request_test_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000024#include "testing/gtest/include/gtest/gtest.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010025#include "url/gurl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000027using base::ASCIIToUTF16;
28
Torne (Richard Coles)58218062012-11-14 11:43:16 +000029namespace net {
30
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010031class FtpTestURLRequestContext : public TestURLRequestContext {
32 public:
33 FtpTestURLRequestContext(ClientSocketFactory* socket_factory,
34 ProxyService* proxy_service,
35 NetworkDelegate* network_delegate,
36 FtpTransactionFactory* ftp_transaction_factory)
37 : TestURLRequestContext(true),
38 ftp_protocol_handler_(new FtpProtocolHandler(ftp_transaction_factory)) {
39 set_client_socket_factory(socket_factory);
40 context_storage_.set_proxy_service(proxy_service);
41 set_network_delegate(network_delegate);
42 URLRequestJobFactoryImpl* job_factory = new URLRequestJobFactoryImpl;
43 job_factory->SetProtocolHandler("ftp", ftp_protocol_handler_);
44 context_storage_.set_job_factory(job_factory);
45 Init();
46 }
47
48 FtpAuthCache* GetFtpAuthCache() {
49 return ftp_protocol_handler_->ftp_auth_cache_.get();
50 }
51
52 void set_proxy_service(ProxyService* proxy_service) {
53 context_storage_.set_proxy_service(proxy_service);
54 }
55
56 private:
57 FtpProtocolHandler* ftp_protocol_handler_;
58};
59
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000060namespace {
61
62class SimpleProxyConfigService : public ProxyConfigService {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000063 public:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000064 SimpleProxyConfigService() {
65 // Any FTP requests that ever go through HTTP paths are proxied requests.
66 config_.proxy_rules().ParseFromString("ftp=localhost");
67 }
68
69 virtual void AddObserver(Observer* observer) OVERRIDE {
70 observer_ = observer;
71 }
72
73 virtual void RemoveObserver(Observer* observer) OVERRIDE {
74 if (observer_ == observer) {
75 observer_ = NULL;
76 }
77 }
78
79 virtual ConfigAvailability GetLatestProxyConfig(
80 ProxyConfig* config) OVERRIDE {
81 *config = config_;
82 return CONFIG_VALID;
83 }
84
85 void IncrementConfigId() {
86 config_.set_id(config_.id() + 1);
87 observer_->OnProxyConfigChanged(config_, ProxyConfigService::CONFIG_VALID);
88 }
89
90 private:
91 ProxyConfig config_;
92 Observer* observer_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000093};
94
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000095// Inherit from URLRequestFtpJob to expose the priority and some
96// other hidden functions.
97class TestURLRequestFtpJob : public URLRequestFtpJob {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000098 public:
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010099 TestURLRequestFtpJob(URLRequest* request,
100 FtpTransactionFactory* ftp_factory,
101 FtpAuthCache* ftp_auth_cache)
102 : URLRequestFtpJob(request, NULL, ftp_factory, ftp_auth_cache) {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000103
104 using URLRequestFtpJob::SetPriority;
105 using URLRequestFtpJob::Start;
106 using URLRequestFtpJob::Kill;
107 using URLRequestFtpJob::priority;
108
109 protected:
110 virtual ~TestURLRequestFtpJob() {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000111};
112
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100113class MockFtpTransactionFactory : public FtpTransactionFactory {
114 public:
115 virtual FtpTransaction* CreateTransaction() OVERRIDE {
116 return NULL;
117 }
118
119 virtual void Suspend(bool suspend) OVERRIDE {}
120};
121
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000122// Fixture for priority-related tests. Priority matters when there is
123// an HTTP proxy.
124class URLRequestFtpJobPriorityTest : public testing::Test {
125 protected:
126 URLRequestFtpJobPriorityTest()
127 : proxy_service_(new SimpleProxyConfigService, NULL, NULL),
Torne (Richard Coles)0f1bc082013-11-06 12:27:47 +0000128 req_(GURL("ftp://ftp.example.com"),
129 DEFAULT_PRIORITY,
130 &delegate_,
131 &context_) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000132 context_.set_proxy_service(&proxy_service_);
133 context_.set_http_transaction_factory(&network_layer_);
134 }
135
136 ProxyService proxy_service_;
137 MockNetworkLayer network_layer_;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100138 MockFtpTransactionFactory ftp_factory_;
139 FtpAuthCache ftp_auth_cache_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000140 TestURLRequestContext context_;
141 TestDelegate delegate_;
142 TestURLRequest req_;
143};
144
145// Make sure that SetPriority actually sets the URLRequestFtpJob's
146// priority, both before and after start.
147TEST_F(URLRequestFtpJobPriorityTest, SetPriorityBasic) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100148 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
149 &req_, &ftp_factory_, &ftp_auth_cache_));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000150 EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
151
152 job->SetPriority(LOWEST);
153 EXPECT_EQ(LOWEST, job->priority());
154
155 job->SetPriority(LOW);
156 EXPECT_EQ(LOW, job->priority());
157
158 job->Start();
159 EXPECT_EQ(LOW, job->priority());
160
161 job->SetPriority(MEDIUM);
162 EXPECT_EQ(MEDIUM, job->priority());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000163}
164
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000165// Make sure that URLRequestFtpJob passes on its priority to its
166// transaction on start.
167TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriorityOnStart) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100168 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
169 &req_, &ftp_factory_, &ftp_auth_cache_));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000170 job->SetPriority(LOW);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000171
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000172 EXPECT_FALSE(network_layer_.last_transaction());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000173
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000174 job->Start();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000175
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000176 ASSERT_TRUE(network_layer_.last_transaction());
177 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000178}
179
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000180// Make sure that URLRequestFtpJob passes on its priority updates to
181// its transaction.
182TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriority) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100183 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
184 &req_, &ftp_factory_, &ftp_auth_cache_));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000185 job->SetPriority(LOW);
186 job->Start();
187 ASSERT_TRUE(network_layer_.last_transaction());
188 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
189
190 job->SetPriority(HIGHEST);
191 EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority());
192}
193
194// Make sure that URLRequestFtpJob passes on its priority updates to
195// newly-created transactions after the first one.
196TEST_F(URLRequestFtpJobPriorityTest, SetSubsequentTransactionPriority) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100197 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
198 &req_, &ftp_factory_, &ftp_auth_cache_));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000199 job->Start();
200
201 job->SetPriority(LOW);
202 ASSERT_TRUE(network_layer_.last_transaction());
203 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
204
205 job->Kill();
206 network_layer_.ClearLastTransaction();
207
208 // Creates a second transaction.
209 job->Start();
210 ASSERT_TRUE(network_layer_.last_transaction());
211 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
212}
213
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000214class URLRequestFtpJobTest : public testing::Test {
215 public:
216 URLRequestFtpJobTest()
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100217 : request_context_(&socket_factory_,
218 new ProxyService(
219 new SimpleProxyConfigService, NULL, NULL),
220 &network_delegate_,
221 &ftp_transaction_factory_) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000222 }
223
224 virtual ~URLRequestFtpJobTest() {
225 // Clean up any remaining tasks that mess up unrelated tests.
226 base::RunLoop run_loop;
227 run_loop.RunUntilIdle();
228 }
229
230 void AddSocket(MockRead* reads, size_t reads_size,
231 MockWrite* writes, size_t writes_size) {
232 DeterministicSocketData* socket_data = new DeterministicSocketData(
233 reads, reads_size, writes, writes_size);
234 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
235 socket_data->StopAfter(reads_size + writes_size - 1);
236 socket_factory_.AddSocketDataProvider(socket_data);
237
238 socket_data_.push_back(socket_data);
239 }
240
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100241 FtpTestURLRequestContext* request_context() { return &request_context_; }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000242 TestNetworkDelegate* network_delegate() { return &network_delegate_; }
243 DeterministicSocketData* socket_data(size_t index) {
244 return socket_data_[index];
245 }
246
247 private:
248 ScopedVector<DeterministicSocketData> socket_data_;
249 DeterministicMockClientSocketFactory socket_factory_;
250 TestNetworkDelegate network_delegate_;
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100251 MockFtpTransactionFactory ftp_transaction_factory_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000252
253 FtpTestURLRequestContext request_context_;
254};
255
256TEST_F(URLRequestFtpJobTest, FtpProxyRequest) {
257 MockWrite writes[] = {
258 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
259 "Host: ftp.example.com\r\n"
260 "Proxy-Connection: keep-alive\r\n\r\n"),
261 };
262 MockRead reads[] = {
263 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
264 MockRead(ASYNC, 2, "Content-Length: 9\r\n\r\n"),
265 MockRead(ASYNC, 3, "test.html"),
266 };
267
268 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
269
270 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100271 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
272 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY,
273 &request_delegate, NULL));
274 url_request->Start();
275 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000276 socket_data(0)->RunFor(4);
277
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100278 EXPECT_TRUE(url_request->status().is_success());
279 EXPECT_TRUE(url_request->proxy_server().Equals(
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100280 net::HostPortPair::FromString("localhost:80")));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000281 EXPECT_EQ(1, network_delegate()->completed_requests());
282 EXPECT_EQ(0, network_delegate()->error_count());
283 EXPECT_FALSE(request_delegate.auth_required_called());
284 EXPECT_EQ("test.html", request_delegate.data_received());
285}
286
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100287// Regression test for http://crbug.com/237526 .
288TEST_F(URLRequestFtpJobTest, FtpProxyRequestOrphanJob) {
289 // Use a PAC URL so that URLRequestFtpJob's |pac_request_| field is non-NULL.
290 request_context()->set_proxy_service(
291 new ProxyService(
292 new ProxyConfigServiceFixed(
293 ProxyConfig::CreateFromCustomPacURL(GURL("http://foo"))),
294 new MockAsyncProxyResolver, NULL));
295
296 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100297 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
298 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
299 NULL));
300 url_request->Start();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100301
302 // Now |url_request| will be deleted before its completion,
303 // resulting in it being orphaned. It should not crash.
304}
305
306TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthNoCredentials) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000307 MockWrite writes[] = {
308 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
309 "Host: ftp.example.com\r\n"
310 "Proxy-Connection: keep-alive\r\n\r\n"),
311 };
312 MockRead reads[] = {
313 // No credentials.
314 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
315 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
316 "realm=\"MyRealm1\"\r\n"),
317 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
318 MockRead(ASYNC, 4, "test.html"),
319 };
320
321 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
322
323 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100324 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
325 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
326 NULL));
327 url_request->Start();
328 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000329 socket_data(0)->RunFor(5);
330
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100331 EXPECT_TRUE(url_request->status().is_success());
332 EXPECT_TRUE(url_request->proxy_server().Equals(
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100333 net::HostPortPair::FromString("localhost:80")));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000334 EXPECT_EQ(1, network_delegate()->completed_requests());
335 EXPECT_EQ(0, network_delegate()->error_count());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100336 EXPECT_TRUE(request_delegate.auth_required_called());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000337 EXPECT_EQ("test.html", request_delegate.data_received());
338}
339
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100340TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthWithCredentials) {
341 MockWrite writes[] = {
342 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
343 "Host: ftp.example.com\r\n"
344 "Proxy-Connection: keep-alive\r\n\r\n"),
345 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
346 "Host: ftp.example.com\r\n"
347 "Proxy-Connection: keep-alive\r\n"
348 "Proxy-Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
349 };
350 MockRead reads[] = {
351 // No credentials.
352 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
353 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
354 "realm=\"MyRealm1\"\r\n"),
355 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
356 MockRead(ASYNC, 4, "test.html"),
357
358 // Second response.
359 MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"),
360 MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"),
361 MockRead(ASYNC, 8, "test2.html"),
362 };
363
364 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
365
366 TestDelegate request_delegate;
367 request_delegate.set_credentials(
368 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100369 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
370 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
371 NULL));
372 url_request->Start();
373 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100374 socket_data(0)->RunFor(9);
375
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100376 EXPECT_TRUE(url_request->status().is_success());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100377 EXPECT_EQ(1, network_delegate()->completed_requests());
378 EXPECT_EQ(0, network_delegate()->error_count());
379 EXPECT_TRUE(request_delegate.auth_required_called());
380 EXPECT_EQ("test2.html", request_delegate.data_received());
381}
382
383TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthNoCredentials) {
384 MockWrite writes[] = {
385 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
386 "Host: ftp.example.com\r\n"
387 "Proxy-Connection: keep-alive\r\n\r\n"),
388 };
389 MockRead reads[] = {
390 // No credentials.
391 MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"),
392 MockRead(ASYNC, 2, "WWW-Authenticate: Basic "
393 "realm=\"MyRealm1\"\r\n"),
394 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
395 MockRead(ASYNC, 4, "test.html"),
396 };
397
398 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
399
400 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100401 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
402 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
403 NULL));
404 url_request->Start();
405 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100406 socket_data(0)->RunFor(5);
407
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100408 EXPECT_TRUE(url_request->status().is_success());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100409 EXPECT_EQ(1, network_delegate()->completed_requests());
410 EXPECT_EQ(0, network_delegate()->error_count());
411 EXPECT_TRUE(request_delegate.auth_required_called());
412 EXPECT_EQ("test.html", request_delegate.data_received());
413}
414
415TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthWithCredentials) {
416 MockWrite writes[] = {
417 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
418 "Host: ftp.example.com\r\n"
419 "Proxy-Connection: keep-alive\r\n\r\n"),
420 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
421 "Host: ftp.example.com\r\n"
422 "Proxy-Connection: keep-alive\r\n"
423 "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
424 };
425 MockRead reads[] = {
426 // No credentials.
427 MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"),
428 MockRead(ASYNC, 2, "WWW-Authenticate: Basic "
429 "realm=\"MyRealm1\"\r\n"),
430 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
431 MockRead(ASYNC, 4, "test.html"),
432
433 // Second response.
434 MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"),
435 MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"),
436 MockRead(ASYNC, 8, "test2.html"),
437 };
438
439 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
440
441 TestDelegate request_delegate;
442 request_delegate.set_credentials(
443 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100444 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
445 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
446 NULL));
447 url_request->Start();
448 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100449 socket_data(0)->RunFor(9);
450
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100451 EXPECT_TRUE(url_request->status().is_success());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100452 EXPECT_EQ(1, network_delegate()->completed_requests());
453 EXPECT_EQ(0, network_delegate()->error_count());
454 EXPECT_TRUE(request_delegate.auth_required_called());
455 EXPECT_EQ("test2.html", request_delegate.data_received());
456}
457
458TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAndServerAuth) {
459 MockWrite writes[] = {
460 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
461 "Host: ftp.example.com\r\n"
462 "Proxy-Connection: keep-alive\r\n\r\n"),
463 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
464 "Host: ftp.example.com\r\n"
465 "Proxy-Connection: keep-alive\r\n"
466 "Proxy-Authorization: Basic "
467 "cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"),
468 MockWrite(ASYNC, 10, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
469 "Host: ftp.example.com\r\n"
470 "Proxy-Connection: keep-alive\r\n"
471 "Proxy-Authorization: Basic "
472 "cHJveHl1c2VyOnByb3h5cGFzcw==\r\n"
473 "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
474 };
475 MockRead reads[] = {
476 // No credentials.
477 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
478 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
479 "realm=\"MyRealm1\"\r\n"),
480 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
481 MockRead(ASYNC, 4, "test.html"),
482
483 // Second response.
484 MockRead(ASYNC, 6, "HTTP/1.1 401 Unauthorized\r\n"),
485 MockRead(ASYNC, 7, "WWW-Authenticate: Basic "
486 "realm=\"MyRealm1\"\r\n"),
487 MockRead(ASYNC, 8, "Content-Length: 9\r\n\r\n"),
488 MockRead(ASYNC, 9, "test.html"),
489
490 // Third response.
491 MockRead(ASYNC, 11, "HTTP/1.1 200 OK\r\n"),
492 MockRead(ASYNC, 12, "Content-Length: 10\r\n\r\n"),
493 MockRead(ASYNC, 13, "test2.html"),
494 };
495
496 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
497
498 GURL url("ftp://ftp.example.com");
499
500 // Make sure cached FTP credentials are not used for proxy authentication.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100501 request_context()->GetFtpAuthCache()->Add(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100502 url.GetOrigin(),
503 AuthCredentials(ASCIIToUTF16("userdonotuse"),
504 ASCIIToUTF16("passworddonotuse")));
505
506 TestDelegate request_delegate;
507 request_delegate.set_credentials(
508 AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")));
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100509 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
510 url, DEFAULT_PRIORITY, &request_delegate, NULL));
511 url_request->Start();
512 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100513 socket_data(0)->RunFor(5);
514
515 request_delegate.set_credentials(
516 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
517 socket_data(0)->RunFor(9);
518
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100519 EXPECT_TRUE(url_request->status().is_success());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100520 EXPECT_EQ(1, network_delegate()->completed_requests());
521 EXPECT_EQ(0, network_delegate()->error_count());
522 EXPECT_TRUE(request_delegate.auth_required_called());
523 EXPECT_EQ("test2.html", request_delegate.data_received());
524}
525
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000526TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotSaveCookies) {
527 MockWrite writes[] = {
528 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
529 "Host: ftp.example.com\r\n"
530 "Proxy-Connection: keep-alive\r\n\r\n"),
531 };
532 MockRead reads[] = {
533 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
534 MockRead(ASYNC, 2, "Content-Length: 9\r\n"),
535 MockRead(ASYNC, 3, "Set-Cookie: name=value\r\n\r\n"),
536 MockRead(ASYNC, 4, "test.html"),
537 };
538
539 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
540
541 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100542 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
543 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
544 NULL));
545 url_request->Start();
546 ASSERT_TRUE(url_request->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000547
548 socket_data(0)->RunFor(5);
549
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100550 EXPECT_TRUE(url_request->status().is_success());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000551 EXPECT_EQ(1, network_delegate()->completed_requests());
552 EXPECT_EQ(0, network_delegate()->error_count());
553
554 // Make sure we do not accept cookies.
555 EXPECT_EQ(0, network_delegate()->set_cookie_count());
556
557 EXPECT_FALSE(request_delegate.auth_required_called());
558 EXPECT_EQ("test.html", request_delegate.data_received());
559}
560
561TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotFollowRedirects) {
562 MockWrite writes[] = {
563 MockWrite(SYNCHRONOUS, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
564 "Host: ftp.example.com\r\n"
565 "Proxy-Connection: keep-alive\r\n\r\n"),
566 };
567 MockRead reads[] = {
568 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 302 Found\r\n"),
569 MockRead(ASYNC, 2, "Location: http://other.example.com/\r\n\r\n"),
570 };
571
572 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
573
574 TestDelegate request_delegate;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100575 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
576 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
577 NULL));
578 url_request->Start();
579 EXPECT_TRUE(url_request->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000580
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100581 base::MessageLoop::current()->RunUntilIdle();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000582
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100583 EXPECT_TRUE(url_request->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000584 EXPECT_EQ(0, request_delegate.response_started_count());
585 EXPECT_EQ(0, network_delegate()->error_count());
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100586 ASSERT_TRUE(url_request->status().is_success());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000587
588 socket_data(0)->RunFor(1);
589
590 EXPECT_EQ(1, network_delegate()->completed_requests());
591 EXPECT_EQ(1, network_delegate()->error_count());
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100592 EXPECT_FALSE(url_request->status().is_success());
593 EXPECT_EQ(ERR_UNSAFE_REDIRECT, url_request->status().error());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000594}
595
596// We should re-use socket for requests using the same scheme, host, and port.
597TEST_F(URLRequestFtpJobTest, FtpProxyRequestReuseSocket) {
598 MockWrite writes[] = {
599 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n"
600 "Host: ftp.example.com\r\n"
601 "Proxy-Connection: keep-alive\r\n\r\n"),
602 MockWrite(ASYNC, 4, "GET ftp://ftp.example.com/second HTTP/1.1\r\n"
603 "Host: ftp.example.com\r\n"
604 "Proxy-Connection: keep-alive\r\n\r\n"),
605 };
606 MockRead reads[] = {
607 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
608 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
609 MockRead(ASYNC, 3, "test1.html"),
610 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"),
611 MockRead(ASYNC, 6, "Content-Length: 10\r\n\r\n"),
612 MockRead(ASYNC, 7, "test2.html"),
613 };
614
615 AddSocket(reads, arraysize(reads), writes, arraysize(writes));
616
617 TestDelegate request_delegate1;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100618
619 scoped_ptr<URLRequest> url_request1(request_context()->CreateRequest(
620 GURL("ftp://ftp.example.com/first"), DEFAULT_PRIORITY, &request_delegate1,
621 NULL));
622 url_request1->Start();
623 ASSERT_TRUE(url_request1->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000624 socket_data(0)->RunFor(4);
625
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100626 EXPECT_TRUE(url_request1->status().is_success());
627 EXPECT_TRUE(url_request1->proxy_server().Equals(
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100628 net::HostPortPair::FromString("localhost:80")));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000629 EXPECT_EQ(1, network_delegate()->completed_requests());
630 EXPECT_EQ(0, network_delegate()->error_count());
631 EXPECT_FALSE(request_delegate1.auth_required_called());
632 EXPECT_EQ("test1.html", request_delegate1.data_received());
633
634 TestDelegate request_delegate2;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100635 scoped_ptr<URLRequest> url_request2(request_context()->CreateRequest(
636 GURL("ftp://ftp.example.com/second"), DEFAULT_PRIORITY,
637 &request_delegate2, NULL));
638 url_request2->Start();
639 ASSERT_TRUE(url_request2->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000640 socket_data(0)->RunFor(4);
641
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100642 EXPECT_TRUE(url_request2->status().is_success());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000643 EXPECT_EQ(2, network_delegate()->completed_requests());
644 EXPECT_EQ(0, network_delegate()->error_count());
645 EXPECT_FALSE(request_delegate2.auth_required_called());
646 EXPECT_EQ("test2.html", request_delegate2.data_received());
647}
648
649// We should not re-use socket when there are two requests to the same host,
650// but one is FTP and the other is HTTP.
651TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotReuseSocket) {
652 MockWrite writes1[] = {
653 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n"
654 "Host: ftp.example.com\r\n"
655 "Proxy-Connection: keep-alive\r\n\r\n"),
656 };
657 MockWrite writes2[] = {
658 MockWrite(ASYNC, 0, "GET /second HTTP/1.1\r\n"
659 "Host: ftp.example.com\r\n"
660 "Connection: keep-alive\r\n"
661 "User-Agent:\r\n"
662 "Accept-Encoding: gzip,deflate\r\n"
663 "Accept-Language: en-us,fr\r\n\r\n"),
664 };
665 MockRead reads1[] = {
666 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
667 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
668 MockRead(ASYNC, 3, "test1.html"),
669 };
670 MockRead reads2[] = {
671 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
672 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
673 MockRead(ASYNC, 3, "test2.html"),
674 };
675
676 AddSocket(reads1, arraysize(reads1), writes1, arraysize(writes1));
677 AddSocket(reads2, arraysize(reads2), writes2, arraysize(writes2));
678
679 TestDelegate request_delegate1;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100680 scoped_ptr<URLRequest> url_request1(request_context()->CreateRequest(
681 GURL("ftp://ftp.example.com/first"), DEFAULT_PRIORITY,
682 &request_delegate1, NULL));
683 url_request1->Start();
684 ASSERT_TRUE(url_request1->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000685 socket_data(0)->RunFor(4);
686
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100687 EXPECT_TRUE(url_request1->status().is_success());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000688 EXPECT_EQ(1, network_delegate()->completed_requests());
689 EXPECT_EQ(0, network_delegate()->error_count());
690 EXPECT_FALSE(request_delegate1.auth_required_called());
691 EXPECT_EQ("test1.html", request_delegate1.data_received());
692
693 TestDelegate request_delegate2;
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100694 scoped_ptr<URLRequest> url_request2(request_context()->CreateRequest(
695 GURL("http://ftp.example.com/second"), DEFAULT_PRIORITY,
696 &request_delegate2, NULL));
697 url_request2->Start();
698 ASSERT_TRUE(url_request2->is_pending());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000699 socket_data(1)->RunFor(4);
700
Torne (Richard Coles)03b57e02014-08-28 12:05:23 +0100701 EXPECT_TRUE(url_request2->status().is_success());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000702 EXPECT_EQ(2, network_delegate()->completed_requests());
703 EXPECT_EQ(0, network_delegate()->error_count());
704 EXPECT_FALSE(request_delegate2.auth_required_called());
705 EXPECT_EQ("test2.html", request_delegate2.data_received());
706}
707
708} // namespace
709
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000710} // namespace net