url_request_ftp_job_unittest.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/base/host_port_pair.h"
11#include "net/base/request_priority.h"
12#include "net/ftp/ftp_auth_cache.h"
13#include "net/http/http_transaction_test_util.h"
14#include "net/proxy/mock_proxy_resolver.h"
15#include "net/proxy/proxy_config_service.h"
16#include "net/proxy/proxy_config_service_fixed.h"
17#include "net/socket/socket_test_util.h"
18#include "net/url_request/ftp_protocol_handler.h"
19#include "net/url_request/url_request.h"
20#include "net/url_request/url_request_context.h"
21#include "net/url_request/url_request_job_factory_impl.h"
22#include "net/url_request/url_request_status.h"
23#include "net/url_request/url_request_test_util.h"
24#include "testing/gtest/include/gtest/gtest.h"
25#include "url/gurl.h"
26
27using base::ASCIIToUTF16;
28
29namespace net {
30
31class 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
60namespace {
61
62class SimpleProxyConfigService : public ProxyConfigService {
63 public:
64  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_;
93};
94
95// Inherit from URLRequestFtpJob to expose the priority and some
96// other hidden functions.
97class TestURLRequestFtpJob : public URLRequestFtpJob {
98 public:
99  TestURLRequestFtpJob(URLRequest* request,
100                       FtpTransactionFactory* ftp_factory,
101                       FtpAuthCache* ftp_auth_cache)
102      : URLRequestFtpJob(request, NULL, ftp_factory, ftp_auth_cache) {}
103
104  using URLRequestFtpJob::SetPriority;
105  using URLRequestFtpJob::Start;
106  using URLRequestFtpJob::Kill;
107  using URLRequestFtpJob::priority;
108
109 protected:
110  virtual ~TestURLRequestFtpJob() {}
111};
112
113class MockFtpTransactionFactory : public FtpTransactionFactory {
114 public:
115  virtual FtpTransaction* CreateTransaction() OVERRIDE {
116    return NULL;
117  }
118
119  virtual void Suspend(bool suspend) OVERRIDE {}
120};
121
122// 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),
128        req_(GURL("ftp://ftp.example.com"),
129             DEFAULT_PRIORITY,
130             &delegate_,
131             &context_) {
132    context_.set_proxy_service(&proxy_service_);
133    context_.set_http_transaction_factory(&network_layer_);
134  }
135
136  ProxyService proxy_service_;
137  MockNetworkLayer network_layer_;
138  MockFtpTransactionFactory ftp_factory_;
139  FtpAuthCache ftp_auth_cache_;
140  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) {
148  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
149      &req_, &ftp_factory_, &ftp_auth_cache_));
150  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());
163}
164
165// Make sure that URLRequestFtpJob passes on its priority to its
166// transaction on start.
167TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriorityOnStart) {
168  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
169      &req_, &ftp_factory_, &ftp_auth_cache_));
170  job->SetPriority(LOW);
171
172  EXPECT_FALSE(network_layer_.last_transaction());
173
174  job->Start();
175
176  ASSERT_TRUE(network_layer_.last_transaction());
177  EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
178}
179
180// Make sure that URLRequestFtpJob passes on its priority updates to
181// its transaction.
182TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriority) {
183  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
184      &req_, &ftp_factory_, &ftp_auth_cache_));
185  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) {
197  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
198      &req_, &ftp_factory_, &ftp_auth_cache_));
199  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
214class URLRequestFtpJobTest : public testing::Test {
215 public:
216  URLRequestFtpJobTest()
217      : request_context_(&socket_factory_,
218                         new ProxyService(
219                             new SimpleProxyConfigService, NULL, NULL),
220                         &network_delegate_,
221                         &ftp_transaction_factory_) {
222  }
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
241  FtpTestURLRequestContext* request_context() { return &request_context_; }
242  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_;
251  MockFtpTransactionFactory ftp_transaction_factory_;
252
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;
271  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());
276  socket_data(0)->RunFor(4);
277
278  EXPECT_TRUE(url_request->status().is_success());
279  EXPECT_TRUE(url_request->proxy_server().Equals(
280      net::HostPortPair::FromString("localhost:80")));
281  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
287// 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;
297  scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
298      GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate,
299      NULL));
300  url_request->Start();
301
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) {
307  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;
324  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());
329  socket_data(0)->RunFor(5);
330
331  EXPECT_TRUE(url_request->status().is_success());
332  EXPECT_TRUE(url_request->proxy_server().Equals(
333      net::HostPortPair::FromString("localhost:80")));
334  EXPECT_EQ(1, network_delegate()->completed_requests());
335  EXPECT_EQ(0, network_delegate()->error_count());
336  EXPECT_TRUE(request_delegate.auth_required_called());
337  EXPECT_EQ("test.html", request_delegate.data_received());
338}
339
340TEST_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")));
369  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());
374  socket_data(0)->RunFor(9);
375
376  EXPECT_TRUE(url_request->status().is_success());
377  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;
401  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());
406  socket_data(0)->RunFor(5);
407
408  EXPECT_TRUE(url_request->status().is_success());
409  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")));
444  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());
449  socket_data(0)->RunFor(9);
450
451  EXPECT_TRUE(url_request->status().is_success());
452  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.
501  request_context()->GetFtpAuthCache()->Add(
502      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")));
509  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());
513  socket_data(0)->RunFor(5);
514
515  request_delegate.set_credentials(
516      AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
517  socket_data(0)->RunFor(9);
518
519  EXPECT_TRUE(url_request->status().is_success());
520  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
526TEST_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;
542  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());
547
548  socket_data(0)->RunFor(5);
549
550  EXPECT_TRUE(url_request->status().is_success());
551  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;
575  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());
580
581  base::MessageLoop::current()->RunUntilIdle();
582
583  EXPECT_TRUE(url_request->is_pending());
584  EXPECT_EQ(0, request_delegate.response_started_count());
585  EXPECT_EQ(0, network_delegate()->error_count());
586  ASSERT_TRUE(url_request->status().is_success());
587
588  socket_data(0)->RunFor(1);
589
590  EXPECT_EQ(1, network_delegate()->completed_requests());
591  EXPECT_EQ(1, network_delegate()->error_count());
592  EXPECT_FALSE(url_request->status().is_success());
593  EXPECT_EQ(ERR_UNSAFE_REDIRECT, url_request->status().error());
594}
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;
618
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());
624  socket_data(0)->RunFor(4);
625
626  EXPECT_TRUE(url_request1->status().is_success());
627  EXPECT_TRUE(url_request1->proxy_server().Equals(
628      net::HostPortPair::FromString("localhost:80")));
629  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;
635  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());
640  socket_data(0)->RunFor(4);
641
642  EXPECT_TRUE(url_request2->status().is_success());
643  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;
680  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());
685  socket_data(0)->RunFor(4);
686
687  EXPECT_TRUE(url_request1->status().is_success());
688  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;
694  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());
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