url_request_ftp_job_unittest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// 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
5#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"
10#include "net/ftp/ftp_auth_cache.h"
11#include "net/http/http_transaction_unittest.h"
12#include "net/proxy/mock_proxy_resolver.h"
13#include "net/proxy/proxy_config_service.h"
14#include "net/proxy/proxy_config_service_fixed.h"
15#include "net/socket/socket_test_util.h"
16#include "net/url_request/ftp_protocol_handler.h"
17#include "net/url_request/url_request.h"
18#include "net/url_request/url_request_context.h"
19#include "net/url_request/url_request_job_factory_impl.h"
20#include "net/url_request/url_request_status.h"
21#include "net/url_request/url_request_test_util.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "url/gurl.h"
24
25namespace net {
26
27class FtpTestURLRequestContext : public TestURLRequestContext {
28 public:
29  FtpTestURLRequestContext(ClientSocketFactory* socket_factory,
30                           ProxyService* proxy_service,
31                           NetworkDelegate* network_delegate,
32                           FtpTransactionFactory* ftp_transaction_factory)
33      : TestURLRequestContext(true),
34        ftp_protocol_handler_(new FtpProtocolHandler(ftp_transaction_factory)) {
35    set_client_socket_factory(socket_factory);
36    context_storage_.set_proxy_service(proxy_service);
37    set_network_delegate(network_delegate);
38    URLRequestJobFactoryImpl* job_factory = new URLRequestJobFactoryImpl;
39    job_factory->SetProtocolHandler("ftp", ftp_protocol_handler_);
40    context_storage_.set_job_factory(job_factory);
41    Init();
42  }
43
44  FtpAuthCache* GetFtpAuthCache() {
45    return ftp_protocol_handler_->ftp_auth_cache_.get();
46  }
47
48  void set_proxy_service(ProxyService* proxy_service) {
49    context_storage_.set_proxy_service(proxy_service);
50  }
51
52 private:
53  FtpProtocolHandler* ftp_protocol_handler_;
54};
55
56namespace {
57
58class SimpleProxyConfigService : public ProxyConfigService {
59 public:
60  SimpleProxyConfigService() {
61    // Any FTP requests that ever go through HTTP paths are proxied requests.
62    config_.proxy_rules().ParseFromString("ftp=localhost");
63  }
64
65  virtual void AddObserver(Observer* observer) OVERRIDE {
66    observer_ = observer;
67  }
68
69  virtual void RemoveObserver(Observer* observer) OVERRIDE {
70    if (observer_ == observer) {
71      observer_ = NULL;
72    }
73  }
74
75  virtual ConfigAvailability GetLatestProxyConfig(
76      ProxyConfig* config) OVERRIDE {
77    *config = config_;
78    return CONFIG_VALID;
79  }
80
81  void IncrementConfigId() {
82    config_.set_id(config_.id() + 1);
83    observer_->OnProxyConfigChanged(config_, ProxyConfigService::CONFIG_VALID);
84  }
85
86 private:
87  ProxyConfig config_;
88  Observer* observer_;
89};
90
91// Inherit from URLRequestFtpJob to expose the priority and some
92// other hidden functions.
93class TestURLRequestFtpJob : public URLRequestFtpJob {
94 public:
95  TestURLRequestFtpJob(URLRequest* request,
96                       FtpTransactionFactory* ftp_factory,
97                       FtpAuthCache* ftp_auth_cache)
98      : URLRequestFtpJob(request, NULL, ftp_factory, ftp_auth_cache) {}
99
100  using URLRequestFtpJob::SetPriority;
101  using URLRequestFtpJob::Start;
102  using URLRequestFtpJob::Kill;
103  using URLRequestFtpJob::priority;
104
105 protected:
106  virtual ~TestURLRequestFtpJob() {}
107};
108
109class MockFtpTransactionFactory : public FtpTransactionFactory {
110 public:
111  virtual FtpTransaction* CreateTransaction() OVERRIDE {
112    return NULL;
113  }
114
115  virtual void Suspend(bool suspend) OVERRIDE {}
116};
117
118// Fixture for priority-related tests. Priority matters when there is
119// an HTTP proxy.
120class URLRequestFtpJobPriorityTest : public testing::Test {
121 protected:
122  URLRequestFtpJobPriorityTest()
123      : proxy_service_(new SimpleProxyConfigService, NULL, NULL),
124        req_(GURL("ftp://ftp.example.com"), &delegate_, &context_, NULL) {
125    context_.set_proxy_service(&proxy_service_);
126    context_.set_http_transaction_factory(&network_layer_);
127  }
128
129  ProxyService proxy_service_;
130  MockNetworkLayer network_layer_;
131  MockFtpTransactionFactory ftp_factory_;
132  FtpAuthCache ftp_auth_cache_;
133  TestURLRequestContext context_;
134  TestDelegate delegate_;
135  TestURLRequest req_;
136};
137
138// Make sure that SetPriority actually sets the URLRequestFtpJob's
139// priority, both before and after start.
140TEST_F(URLRequestFtpJobPriorityTest, SetPriorityBasic) {
141  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
142      &req_, &ftp_factory_, &ftp_auth_cache_));
143  EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
144
145  job->SetPriority(LOWEST);
146  EXPECT_EQ(LOWEST, job->priority());
147
148  job->SetPriority(LOW);
149  EXPECT_EQ(LOW, job->priority());
150
151  job->Start();
152  EXPECT_EQ(LOW, job->priority());
153
154  job->SetPriority(MEDIUM);
155  EXPECT_EQ(MEDIUM, job->priority());
156}
157
158// Make sure that URLRequestFtpJob passes on its priority to its
159// transaction on start.
160TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriorityOnStart) {
161  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
162      &req_, &ftp_factory_, &ftp_auth_cache_));
163  job->SetPriority(LOW);
164
165  EXPECT_FALSE(network_layer_.last_transaction());
166
167  job->Start();
168
169  ASSERT_TRUE(network_layer_.last_transaction());
170  EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
171}
172
173// Make sure that URLRequestFtpJob passes on its priority updates to
174// its transaction.
175TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriority) {
176  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
177      &req_, &ftp_factory_, &ftp_auth_cache_));
178  job->SetPriority(LOW);
179  job->Start();
180  ASSERT_TRUE(network_layer_.last_transaction());
181  EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
182
183  job->SetPriority(HIGHEST);
184  EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority());
185}
186
187// Make sure that URLRequestFtpJob passes on its priority updates to
188// newly-created transactions after the first one.
189TEST_F(URLRequestFtpJobPriorityTest, SetSubsequentTransactionPriority) {
190  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
191      &req_, &ftp_factory_, &ftp_auth_cache_));
192  job->Start();
193
194  job->SetPriority(LOW);
195  ASSERT_TRUE(network_layer_.last_transaction());
196  EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
197
198  job->Kill();
199  network_layer_.ClearLastTransaction();
200
201  // Creates a second transaction.
202  job->Start();
203  ASSERT_TRUE(network_layer_.last_transaction());
204  EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
205}
206
207class URLRequestFtpJobTest : public testing::Test {
208 public:
209  URLRequestFtpJobTest()
210      : request_context_(&socket_factory_,
211                         new ProxyService(
212                             new SimpleProxyConfigService, NULL, NULL),
213                         &network_delegate_,
214                         &ftp_transaction_factory_) {
215  }
216
217  virtual ~URLRequestFtpJobTest() {
218    // Clean up any remaining tasks that mess up unrelated tests.
219    base::RunLoop run_loop;
220    run_loop.RunUntilIdle();
221  }
222
223  void AddSocket(MockRead* reads, size_t reads_size,
224                 MockWrite* writes, size_t writes_size) {
225    DeterministicSocketData* socket_data = new DeterministicSocketData(
226        reads, reads_size, writes, writes_size);
227    socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
228    socket_data->StopAfter(reads_size + writes_size - 1);
229    socket_factory_.AddSocketDataProvider(socket_data);
230
231    socket_data_.push_back(socket_data);
232  }
233
234  FtpTestURLRequestContext* request_context() { return &request_context_; }
235  TestNetworkDelegate* network_delegate() { return &network_delegate_; }
236  DeterministicSocketData* socket_data(size_t index) {
237    return socket_data_[index];
238  }
239
240 private:
241  ScopedVector<DeterministicSocketData> socket_data_;
242  DeterministicMockClientSocketFactory socket_factory_;
243  TestNetworkDelegate network_delegate_;
244  MockFtpTransactionFactory ftp_transaction_factory_;
245
246  FtpTestURLRequestContext request_context_;
247};
248
249TEST_F(URLRequestFtpJobTest, FtpProxyRequest) {
250  MockWrite writes[] = {
251    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
252              "Host: ftp.example.com\r\n"
253              "Proxy-Connection: keep-alive\r\n\r\n"),
254  };
255  MockRead reads[] = {
256    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
257    MockRead(ASYNC, 2, "Content-Length: 9\r\n\r\n"),
258    MockRead(ASYNC, 3, "test.html"),
259  };
260
261  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
262
263  TestDelegate request_delegate;
264  URLRequest url_request(GURL("ftp://ftp.example.com/"),
265                         &request_delegate,
266                         request_context(),
267                         network_delegate());
268  url_request.Start();
269  ASSERT_TRUE(url_request.is_pending());
270  socket_data(0)->RunFor(4);
271
272  EXPECT_TRUE(url_request.status().is_success());
273  EXPECT_EQ(1, network_delegate()->completed_requests());
274  EXPECT_EQ(0, network_delegate()->error_count());
275  EXPECT_FALSE(request_delegate.auth_required_called());
276  EXPECT_EQ("test.html", request_delegate.data_received());
277}
278
279// Regression test for http://crbug.com/237526 .
280TEST_F(URLRequestFtpJobTest, FtpProxyRequestOrphanJob) {
281  // Use a PAC URL so that URLRequestFtpJob's |pac_request_| field is non-NULL.
282  request_context()->set_proxy_service(
283      new ProxyService(
284          new ProxyConfigServiceFixed(
285              ProxyConfig::CreateFromCustomPacURL(GURL("http://foo"))),
286          new MockAsyncProxyResolver, NULL));
287
288  TestDelegate request_delegate;
289  URLRequest url_request(GURL("ftp://ftp.example.com/"),
290                         &request_delegate,
291                         request_context(),
292                         network_delegate());
293  url_request.Start();
294
295  // Now |url_request| will be deleted before its completion,
296  // resulting in it being orphaned. It should not crash.
297}
298
299TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthNoCredentials) {
300  MockWrite writes[] = {
301    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
302              "Host: ftp.example.com\r\n"
303              "Proxy-Connection: keep-alive\r\n\r\n"),
304  };
305  MockRead reads[] = {
306    // No credentials.
307    MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
308    MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
309             "realm=\"MyRealm1\"\r\n"),
310    MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
311    MockRead(ASYNC, 4, "test.html"),
312  };
313
314  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
315
316  TestDelegate request_delegate;
317  URLRequest url_request(GURL("ftp://ftp.example.com/"),
318                         &request_delegate,
319                         request_context(),
320                         network_delegate());
321  url_request.Start();
322  ASSERT_TRUE(url_request.is_pending());
323  socket_data(0)->RunFor(5);
324
325  EXPECT_TRUE(url_request.status().is_success());
326  EXPECT_EQ(1, network_delegate()->completed_requests());
327  EXPECT_EQ(0, network_delegate()->error_count());
328  EXPECT_TRUE(request_delegate.auth_required_called());
329  EXPECT_EQ("test.html", request_delegate.data_received());
330}
331
332TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthWithCredentials) {
333  MockWrite writes[] = {
334    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
335              "Host: ftp.example.com\r\n"
336              "Proxy-Connection: keep-alive\r\n\r\n"),
337    MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
338              "Host: ftp.example.com\r\n"
339              "Proxy-Connection: keep-alive\r\n"
340              "Proxy-Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
341  };
342  MockRead reads[] = {
343    // No credentials.
344    MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
345    MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
346             "realm=\"MyRealm1\"\r\n"),
347    MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
348    MockRead(ASYNC, 4, "test.html"),
349
350    // Second response.
351    MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"),
352    MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"),
353    MockRead(ASYNC, 8, "test2.html"),
354  };
355
356  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
357
358  TestDelegate request_delegate;
359  request_delegate.set_credentials(
360      AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
361  URLRequest url_request(GURL("ftp://ftp.example.com/"),
362                         &request_delegate,
363                         request_context(),
364                         network_delegate());
365  url_request.Start();
366  ASSERT_TRUE(url_request.is_pending());
367  socket_data(0)->RunFor(9);
368
369  EXPECT_TRUE(url_request.status().is_success());
370  EXPECT_EQ(1, network_delegate()->completed_requests());
371  EXPECT_EQ(0, network_delegate()->error_count());
372  EXPECT_TRUE(request_delegate.auth_required_called());
373  EXPECT_EQ("test2.html", request_delegate.data_received());
374}
375
376TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthNoCredentials) {
377  MockWrite writes[] = {
378    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
379              "Host: ftp.example.com\r\n"
380              "Proxy-Connection: keep-alive\r\n\r\n"),
381  };
382  MockRead reads[] = {
383    // No credentials.
384    MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"),
385    MockRead(ASYNC, 2, "WWW-Authenticate: Basic "
386             "realm=\"MyRealm1\"\r\n"),
387    MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
388    MockRead(ASYNC, 4, "test.html"),
389  };
390
391  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
392
393  TestDelegate request_delegate;
394  URLRequest url_request(GURL("ftp://ftp.example.com/"),
395                         &request_delegate,
396                         request_context(),
397                         network_delegate());
398  url_request.Start();
399  ASSERT_TRUE(url_request.is_pending());
400  socket_data(0)->RunFor(5);
401
402  EXPECT_TRUE(url_request.status().is_success());
403  EXPECT_EQ(1, network_delegate()->completed_requests());
404  EXPECT_EQ(0, network_delegate()->error_count());
405  EXPECT_TRUE(request_delegate.auth_required_called());
406  EXPECT_EQ("test.html", request_delegate.data_received());
407}
408
409TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthWithCredentials) {
410  MockWrite writes[] = {
411    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
412              "Host: ftp.example.com\r\n"
413              "Proxy-Connection: keep-alive\r\n\r\n"),
414    MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
415              "Host: ftp.example.com\r\n"
416              "Proxy-Connection: keep-alive\r\n"
417              "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
418  };
419  MockRead reads[] = {
420    // No credentials.
421    MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"),
422    MockRead(ASYNC, 2, "WWW-Authenticate: Basic "
423             "realm=\"MyRealm1\"\r\n"),
424    MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
425    MockRead(ASYNC, 4, "test.html"),
426
427    // Second response.
428    MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"),
429    MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"),
430    MockRead(ASYNC, 8, "test2.html"),
431  };
432
433  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
434
435  TestDelegate request_delegate;
436  request_delegate.set_credentials(
437      AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
438  URLRequest url_request(GURL("ftp://ftp.example.com/"),
439                         &request_delegate,
440                         request_context(),
441                         network_delegate());
442  url_request.Start();
443  ASSERT_TRUE(url_request.is_pending());
444  socket_data(0)->RunFor(9);
445
446  EXPECT_TRUE(url_request.status().is_success());
447  EXPECT_EQ(1, network_delegate()->completed_requests());
448  EXPECT_EQ(0, network_delegate()->error_count());
449  EXPECT_TRUE(request_delegate.auth_required_called());
450  EXPECT_EQ("test2.html", request_delegate.data_received());
451}
452
453TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAndServerAuth) {
454  MockWrite writes[] = {
455    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
456              "Host: ftp.example.com\r\n"
457              "Proxy-Connection: keep-alive\r\n\r\n"),
458    MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
459              "Host: ftp.example.com\r\n"
460              "Proxy-Connection: keep-alive\r\n"
461              "Proxy-Authorization: Basic "
462              "cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"),
463    MockWrite(ASYNC, 10, "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"
468              "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"),
469  };
470  MockRead reads[] = {
471    // No credentials.
472    MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
473    MockRead(ASYNC, 2, "Proxy-Authenticate: Basic "
474             "realm=\"MyRealm1\"\r\n"),
475    MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"),
476    MockRead(ASYNC, 4, "test.html"),
477
478    // Second response.
479    MockRead(ASYNC, 6, "HTTP/1.1 401 Unauthorized\r\n"),
480    MockRead(ASYNC, 7, "WWW-Authenticate: Basic "
481             "realm=\"MyRealm1\"\r\n"),
482    MockRead(ASYNC, 8, "Content-Length: 9\r\n\r\n"),
483    MockRead(ASYNC, 9, "test.html"),
484
485    // Third response.
486    MockRead(ASYNC, 11, "HTTP/1.1 200 OK\r\n"),
487    MockRead(ASYNC, 12, "Content-Length: 10\r\n\r\n"),
488    MockRead(ASYNC, 13, "test2.html"),
489  };
490
491  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
492
493  GURL url("ftp://ftp.example.com");
494
495  // Make sure cached FTP credentials are not used for proxy authentication.
496  request_context()->GetFtpAuthCache()->Add(
497      url.GetOrigin(),
498      AuthCredentials(ASCIIToUTF16("userdonotuse"),
499                      ASCIIToUTF16("passworddonotuse")));
500
501  TestDelegate request_delegate;
502  request_delegate.set_credentials(
503      AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")));
504  URLRequest url_request(url,
505                         &request_delegate,
506                         request_context(),
507                         network_delegate());
508  url_request.Start();
509  ASSERT_TRUE(url_request.is_pending());
510  socket_data(0)->RunFor(5);
511
512  request_delegate.set_credentials(
513      AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
514  socket_data(0)->RunFor(9);
515
516  EXPECT_TRUE(url_request.status().is_success());
517  EXPECT_EQ(1, network_delegate()->completed_requests());
518  EXPECT_EQ(0, network_delegate()->error_count());
519  EXPECT_TRUE(request_delegate.auth_required_called());
520  EXPECT_EQ("test2.html", request_delegate.data_received());
521}
522
523TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotSaveCookies) {
524  MockWrite writes[] = {
525    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
526              "Host: ftp.example.com\r\n"
527              "Proxy-Connection: keep-alive\r\n\r\n"),
528  };
529  MockRead reads[] = {
530    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
531    MockRead(ASYNC, 2, "Content-Length: 9\r\n"),
532    MockRead(ASYNC, 3, "Set-Cookie: name=value\r\n\r\n"),
533    MockRead(ASYNC, 4, "test.html"),
534  };
535
536  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
537
538  TestDelegate request_delegate;
539  URLRequest url_request(GURL("ftp://ftp.example.com/"),
540                         &request_delegate,
541                         request_context(),
542                         network_delegate());
543  url_request.Start();
544  ASSERT_TRUE(url_request.is_pending());
545
546  socket_data(0)->RunFor(5);
547
548  EXPECT_TRUE(url_request.status().is_success());
549  EXPECT_EQ(1, network_delegate()->completed_requests());
550  EXPECT_EQ(0, network_delegate()->error_count());
551
552  // Make sure we do not accept cookies.
553  EXPECT_EQ(0, network_delegate()->set_cookie_count());
554
555  EXPECT_FALSE(request_delegate.auth_required_called());
556  EXPECT_EQ("test.html", request_delegate.data_received());
557}
558
559TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotFollowRedirects) {
560  MockWrite writes[] = {
561    MockWrite(SYNCHRONOUS, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n"
562              "Host: ftp.example.com\r\n"
563              "Proxy-Connection: keep-alive\r\n\r\n"),
564  };
565  MockRead reads[] = {
566    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 302 Found\r\n"),
567    MockRead(ASYNC, 2, "Location: http://other.example.com/\r\n\r\n"),
568  };
569
570  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
571
572  TestDelegate request_delegate;
573  URLRequest url_request(GURL("ftp://ftp.example.com/"),
574                         &request_delegate,
575                         request_context(),
576                         network_delegate());
577  url_request.Start();
578  EXPECT_TRUE(url_request.is_pending());
579
580  base::MessageLoop::current()->RunUntilIdle();
581
582  EXPECT_TRUE(url_request.is_pending());
583  EXPECT_EQ(0, request_delegate.response_started_count());
584  EXPECT_EQ(0, network_delegate()->error_count());
585  ASSERT_TRUE(url_request.status().is_success());
586
587  socket_data(0)->RunFor(1);
588
589  EXPECT_EQ(1, network_delegate()->completed_requests());
590  EXPECT_EQ(1, network_delegate()->error_count());
591  EXPECT_FALSE(url_request.status().is_success());
592  EXPECT_EQ(ERR_UNSAFE_REDIRECT, url_request.status().error());
593}
594
595// We should re-use socket for requests using the same scheme, host, and port.
596TEST_F(URLRequestFtpJobTest, FtpProxyRequestReuseSocket) {
597  MockWrite writes[] = {
598    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n"
599              "Host: ftp.example.com\r\n"
600              "Proxy-Connection: keep-alive\r\n\r\n"),
601    MockWrite(ASYNC, 4, "GET ftp://ftp.example.com/second HTTP/1.1\r\n"
602              "Host: ftp.example.com\r\n"
603              "Proxy-Connection: keep-alive\r\n\r\n"),
604  };
605  MockRead reads[] = {
606    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
607    MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
608    MockRead(ASYNC, 3, "test1.html"),
609    MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"),
610    MockRead(ASYNC, 6, "Content-Length: 10\r\n\r\n"),
611    MockRead(ASYNC, 7, "test2.html"),
612  };
613
614  AddSocket(reads, arraysize(reads), writes, arraysize(writes));
615
616  TestDelegate request_delegate1;
617  URLRequest url_request1(GURL("ftp://ftp.example.com/first"),
618                          &request_delegate1,
619                          request_context(),
620                          network_delegate());
621  url_request1.Start();
622  ASSERT_TRUE(url_request1.is_pending());
623  socket_data(0)->RunFor(4);
624
625  EXPECT_TRUE(url_request1.status().is_success());
626  EXPECT_EQ(1, network_delegate()->completed_requests());
627  EXPECT_EQ(0, network_delegate()->error_count());
628  EXPECT_FALSE(request_delegate1.auth_required_called());
629  EXPECT_EQ("test1.html", request_delegate1.data_received());
630
631  TestDelegate request_delegate2;
632  URLRequest url_request2(GURL("ftp://ftp.example.com/second"),
633                          &request_delegate2,
634                          request_context(),
635                          network_delegate());
636  url_request2.Start();
637  ASSERT_TRUE(url_request2.is_pending());
638  socket_data(0)->RunFor(4);
639
640  EXPECT_TRUE(url_request2.status().is_success());
641  EXPECT_EQ(2, network_delegate()->completed_requests());
642  EXPECT_EQ(0, network_delegate()->error_count());
643  EXPECT_FALSE(request_delegate2.auth_required_called());
644  EXPECT_EQ("test2.html", request_delegate2.data_received());
645}
646
647// We should not re-use socket when there are two requests to the same host,
648// but one is FTP and the other is HTTP.
649TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotReuseSocket) {
650  MockWrite writes1[] = {
651    MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n"
652              "Host: ftp.example.com\r\n"
653              "Proxy-Connection: keep-alive\r\n\r\n"),
654  };
655  MockWrite writes2[] = {
656    MockWrite(ASYNC, 0, "GET /second HTTP/1.1\r\n"
657              "Host: ftp.example.com\r\n"
658              "Connection: keep-alive\r\n"
659              "User-Agent:\r\n"
660              "Accept-Encoding: gzip,deflate\r\n"
661              "Accept-Language: en-us,fr\r\n\r\n"),
662  };
663  MockRead reads1[] = {
664    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
665    MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
666    MockRead(ASYNC, 3, "test1.html"),
667  };
668  MockRead reads2[] = {
669    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
670    MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"),
671    MockRead(ASYNC, 3, "test2.html"),
672  };
673
674  AddSocket(reads1, arraysize(reads1), writes1, arraysize(writes1));
675  AddSocket(reads2, arraysize(reads2), writes2, arraysize(writes2));
676
677  TestDelegate request_delegate1;
678  URLRequest url_request1(GURL("ftp://ftp.example.com/first"),
679                          &request_delegate1,
680                          request_context(),
681                          network_delegate());
682  url_request1.Start();
683  ASSERT_TRUE(url_request1.is_pending());
684  socket_data(0)->RunFor(4);
685
686  EXPECT_TRUE(url_request1.status().is_success());
687  EXPECT_EQ(1, network_delegate()->completed_requests());
688  EXPECT_EQ(0, network_delegate()->error_count());
689  EXPECT_FALSE(request_delegate1.auth_required_called());
690  EXPECT_EQ("test1.html", request_delegate1.data_received());
691
692  TestDelegate request_delegate2;
693  URLRequest url_request2(GURL("http://ftp.example.com/second"),
694                          &request_delegate2,
695                          request_context(),
696                          network_delegate());
697  url_request2.Start();
698  ASSERT_TRUE(url_request2.is_pending());
699  socket_data(1)->RunFor(4);
700
701  EXPECT_TRUE(url_request2.status().is_success());
702  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
710}  // namespace net
711