• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2008 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/proxy/proxy_script_fetcher.h"
6 
7 #include "base/file_path.h"
8 #include "base/compiler_specific.h"
9 #include "base/path_service.h"
10 #include "net/base/net_util.h"
11 #include "net/base/ssl_config_service_defaults.h"
12 #include "net/base/test_completion_callback.h"
13 #include "net/disk_cache/disk_cache.h"
14 #include "net/http/http_cache.h"
15 #include "net/url_request/url_request_unittest.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18 
19 // TODO(eroman):
20 //   - Test canceling an outstanding request.
21 //   - Test deleting ProxyScriptFetcher while a request is in progress.
22 
23 const wchar_t kDocRoot[] = L"net/data/proxy_script_fetcher_unittest";
24 
25 struct FetchResult {
26   int code;
27   std::string bytes;
28 };
29 
30 // A non-mock URL request which can access http:// and file:// urls.
31 class RequestContext : public URLRequestContext {
32  public:
RequestContext()33   RequestContext() {
34     net::ProxyConfig no_proxy;
35     host_resolver_ = net::CreateSystemHostResolver(NULL);
36     proxy_service_ = net::ProxyService::CreateFixed(no_proxy);
37     ssl_config_service_ = new net::SSLConfigServiceDefaults;
38 
39     http_transaction_factory_ =
40         new net::HttpCache(net::HttpNetworkLayer::CreateFactory(
41             NULL, host_resolver_, proxy_service_, ssl_config_service_),
42             disk_cache::CreateInMemoryCacheBackend(0));
43   }
44 
45  private:
~RequestContext()46   ~RequestContext() {
47     delete http_transaction_factory_;
48   }
49 };
50 
51 // Required to be in net namespace by FRIEND_TEST.
52 namespace net {
53 
54 // Get a file:// url relative to net/data/proxy/proxy_script_fetcher_unittest.
GetTestFileUrl(const std::string & relpath)55 GURL GetTestFileUrl(const std::string& relpath) {
56   FilePath path;
57   PathService::Get(base::DIR_SOURCE_ROOT, &path);
58   path = path.AppendASCII("net");
59   path = path.AppendASCII("data");
60   path = path.AppendASCII("proxy_script_fetcher_unittest");
61   GURL base_url = FilePathToFileURL(path);
62   return GURL(base_url.spec() + "/" + relpath);
63 }
64 
65 typedef PlatformTest ProxyScriptFetcherTest;
66 
TEST_F(ProxyScriptFetcherTest,FileUrl)67 TEST_F(ProxyScriptFetcherTest, FileUrl) {
68   scoped_refptr<URLRequestContext> context = new RequestContext;
69   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
70       ProxyScriptFetcher::Create(context));
71 
72   { // Fetch a non-existent file.
73     std::string bytes;
74     TestCompletionCallback callback;
75     int result = pac_fetcher->Fetch(GetTestFileUrl("does-not-exist"),
76                                     &bytes, &callback);
77     EXPECT_EQ(ERR_IO_PENDING, result);
78     EXPECT_EQ(ERR_FILE_NOT_FOUND, callback.WaitForResult());
79     EXPECT_TRUE(bytes.empty());
80   }
81   { // Fetch a file that exists.
82     std::string bytes;
83     TestCompletionCallback callback;
84     int result = pac_fetcher->Fetch(GetTestFileUrl("pac.txt"),
85                                     &bytes, &callback);
86     EXPECT_EQ(ERR_IO_PENDING, result);
87     EXPECT_EQ(OK, callback.WaitForResult());
88     EXPECT_EQ("-pac.txt-\n", bytes);
89   }
90 }
91 
92 // Note that all mime types are allowed for PAC file, to be consistent
93 // with other browsers.
TEST_F(ProxyScriptFetcherTest,HttpMimeType)94 TEST_F(ProxyScriptFetcherTest, HttpMimeType) {
95   scoped_refptr<HTTPTestServer> server =
96       HTTPTestServer::CreateServer(kDocRoot, NULL);
97   ASSERT_TRUE(NULL != server.get());
98   scoped_refptr<URLRequestContext> context = new RequestContext;
99   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
100       ProxyScriptFetcher::Create(context));
101 
102   { // Fetch a PAC with mime type "text/plain"
103     GURL url = server->TestServerPage("files/pac.txt");
104     std::string bytes;
105     TestCompletionCallback callback;
106     int result = pac_fetcher->Fetch(url, &bytes, &callback);
107     EXPECT_EQ(ERR_IO_PENDING, result);
108     EXPECT_EQ(OK, callback.WaitForResult());
109     EXPECT_EQ("-pac.txt-\n", bytes);
110   }
111   { // Fetch a PAC with mime type "text/html"
112     GURL url = server->TestServerPage("files/pac.html");
113     std::string bytes;
114     TestCompletionCallback callback;
115     int result = pac_fetcher->Fetch(url, &bytes, &callback);
116     EXPECT_EQ(ERR_IO_PENDING, result);
117     EXPECT_EQ(OK, callback.WaitForResult());
118     EXPECT_EQ("-pac.html-\n", bytes);
119   }
120   { // Fetch a PAC with mime type "application/x-ns-proxy-autoconfig"
121     GURL url = server->TestServerPage("files/pac.nsproxy");
122     std::string bytes;
123     TestCompletionCallback callback;
124     int result = pac_fetcher->Fetch(url, &bytes, &callback);
125     EXPECT_EQ(ERR_IO_PENDING, result);
126     EXPECT_EQ(OK, callback.WaitForResult());
127     EXPECT_EQ("-pac.nsproxy-\n", bytes);
128   }
129 }
130 
TEST_F(ProxyScriptFetcherTest,HttpStatusCode)131 TEST_F(ProxyScriptFetcherTest, HttpStatusCode) {
132   scoped_refptr<HTTPTestServer> server =
133       HTTPTestServer::CreateServer(kDocRoot, NULL);
134   ASSERT_TRUE(NULL != server.get());
135   scoped_refptr<URLRequestContext> context = new RequestContext;
136   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
137       ProxyScriptFetcher::Create(context));
138 
139   { // Fetch a PAC which gives a 500 -- FAIL
140     GURL url = server->TestServerPage("files/500.pac");
141     std::string bytes;
142     TestCompletionCallback callback;
143     int result = pac_fetcher->Fetch(url, &bytes, &callback);
144     EXPECT_EQ(ERR_IO_PENDING, result);
145     EXPECT_EQ(ERR_PAC_STATUS_NOT_OK, callback.WaitForResult());
146     EXPECT_TRUE(bytes.empty());
147   }
148   { // Fetch a PAC which gives a 404 -- FAIL
149     GURL url = server->TestServerPage("files/404.pac");
150     std::string bytes;
151     TestCompletionCallback callback;
152     int result = pac_fetcher->Fetch(url, &bytes, &callback);
153     EXPECT_EQ(ERR_IO_PENDING, result);
154     EXPECT_EQ(ERR_PAC_STATUS_NOT_OK, callback.WaitForResult());
155     EXPECT_TRUE(bytes.empty());
156   }
157 }
158 
TEST_F(ProxyScriptFetcherTest,ContentDisposition)159 TEST_F(ProxyScriptFetcherTest, ContentDisposition) {
160   scoped_refptr<HTTPTestServer> server =
161       HTTPTestServer::CreateServer(kDocRoot, NULL);
162   ASSERT_TRUE(NULL != server.get());
163   scoped_refptr<URLRequestContext> context = new RequestContext;
164   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
165       ProxyScriptFetcher::Create(context));
166 
167   // Fetch PAC scripts via HTTP with a Content-Disposition header -- should
168   // have no effect.
169   GURL url = server->TestServerPage("files/downloadable.pac");
170   std::string bytes;
171   TestCompletionCallback callback;
172   int result = pac_fetcher->Fetch(url, &bytes, &callback);
173   EXPECT_EQ(ERR_IO_PENDING, result);
174   EXPECT_EQ(OK, callback.WaitForResult());
175   EXPECT_EQ("-downloadable.pac-\n", bytes);
176 }
177 
TEST_F(ProxyScriptFetcherTest,NoCache)178 TEST_F(ProxyScriptFetcherTest, NoCache) {
179   scoped_refptr<HTTPTestServer> server =
180       HTTPTestServer::CreateServer(kDocRoot, NULL);
181   ASSERT_TRUE(NULL != server.get());
182   scoped_refptr<URLRequestContext> context = new RequestContext;
183   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
184       ProxyScriptFetcher::Create(context));
185 
186   // Fetch a PAC script whose HTTP headers make it cacheable for 1 hour.
187   GURL url = server->TestServerPage("files/cacheable_1hr.pac");
188   {
189     std::string bytes;
190     TestCompletionCallback callback;
191     int result = pac_fetcher->Fetch(url, &bytes, &callback);
192     EXPECT_EQ(ERR_IO_PENDING, result);
193     EXPECT_EQ(OK, callback.WaitForResult());
194     EXPECT_EQ("-cacheable_1hr.pac-\n", bytes);
195   }
196 
197   // Now kill the HTTP server.
198   EXPECT_TRUE(server->Stop());  // Verify it shutdown synchronously.
199   server = NULL;
200 
201   // Try to fetch the file again -- if should fail, since the server is not
202   // running anymore. (If it were instead being loaded from cache, we would
203   // get a success.
204   {
205     std::string bytes;
206     TestCompletionCallback callback;
207     int result = pac_fetcher->Fetch(url, &bytes, &callback);
208     EXPECT_EQ(ERR_IO_PENDING, result);
209     EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult());
210   }
211 }
212 
TEST_F(ProxyScriptFetcherTest,TooLarge)213 TEST_F(ProxyScriptFetcherTest, TooLarge) {
214   scoped_refptr<HTTPTestServer> server =
215       HTTPTestServer::CreateServer(kDocRoot, NULL);
216   ASSERT_TRUE(NULL != server.get());
217   scoped_refptr<URLRequestContext> context = new RequestContext;
218   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
219       ProxyScriptFetcher::Create(context));
220 
221   // Set the maximum response size to 50 bytes.
222   int prev_size = ProxyScriptFetcher::SetSizeConstraintForUnittest(50);
223 
224   // These two URLs are the same file, but are http:// vs file://
225   GURL urls[] = {
226     server->TestServerPage("files/large-pac.nsproxy"),
227     GetTestFileUrl("large-pac.nsproxy")
228   };
229 
230   // Try fetching URLs that are 101 bytes large. We should abort the request
231   // after 50 bytes have been read, and fail with a too large error.
232   for (size_t i = 0; i < arraysize(urls); ++i) {
233     const GURL& url = urls[i];
234     std::string bytes;
235     TestCompletionCallback callback;
236     int result = pac_fetcher->Fetch(url, &bytes, &callback);
237     EXPECT_EQ(ERR_IO_PENDING, result);
238     EXPECT_EQ(ERR_FILE_TOO_BIG, callback.WaitForResult());
239     EXPECT_TRUE(bytes.empty());
240   }
241 
242   // Restore the original size bound.
243   ProxyScriptFetcher::SetSizeConstraintForUnittest(prev_size);
244 
245   { // Make sure we can still fetch regular URLs.
246     GURL url = server->TestServerPage("files/pac.nsproxy");
247     std::string bytes;
248     TestCompletionCallback callback;
249     int result = pac_fetcher->Fetch(url, &bytes, &callback);
250     EXPECT_EQ(ERR_IO_PENDING, result);
251     EXPECT_EQ(OK, callback.WaitForResult());
252     EXPECT_EQ("-pac.nsproxy-\n", bytes);
253   }
254 }
255 
TEST_F(ProxyScriptFetcherTest,Hang)256 TEST_F(ProxyScriptFetcherTest, Hang) {
257   scoped_refptr<HTTPTestServer> server =
258       HTTPTestServer::CreateServer(kDocRoot, NULL);
259   ASSERT_TRUE(NULL != server.get());
260   scoped_refptr<URLRequestContext> context = new RequestContext;
261   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
262       ProxyScriptFetcher::Create(context));
263 
264   // Set the timeout period to 0.5 seconds.
265   int prev_timeout =
266       ProxyScriptFetcher::SetTimeoutConstraintForUnittest(500);
267 
268   // Try fetching a URL which takes 1.2 seconds. We should abort the request
269   // after 500 ms, and fail with a timeout error.
270   { GURL url = server->TestServerPage("slow/proxy.pac?1.2");
271     std::string bytes;
272     TestCompletionCallback callback;
273     int result = pac_fetcher->Fetch(url, &bytes, &callback);
274     EXPECT_EQ(ERR_IO_PENDING, result);
275     EXPECT_EQ(ERR_TIMED_OUT, callback.WaitForResult());
276     EXPECT_TRUE(bytes.empty());
277   }
278 
279   // Restore the original timeout period.
280   ProxyScriptFetcher::SetTimeoutConstraintForUnittest(prev_timeout);
281 
282   { // Make sure we can still fetch regular URLs.
283     GURL url = server->TestServerPage("files/pac.nsproxy");
284     std::string bytes;
285     TestCompletionCallback callback;
286     int result = pac_fetcher->Fetch(url, &bytes, &callback);
287     EXPECT_EQ(ERR_IO_PENDING, result);
288     EXPECT_EQ(OK, callback.WaitForResult());
289     EXPECT_EQ("-pac.nsproxy-\n", bytes);
290   }
291 }
292 
293 // The ProxyScriptFetcher should decode any content-codings
294 // (like gzip, bzip, etc.), and apply any charset conversions to yield
295 // UTF8.
TEST_F(ProxyScriptFetcherTest,Encodings)296 TEST_F(ProxyScriptFetcherTest, Encodings) {
297   scoped_refptr<HTTPTestServer> server =
298       HTTPTestServer::CreateServer(kDocRoot, NULL);
299   ASSERT_TRUE(NULL != server.get());
300   scoped_refptr<URLRequestContext> context = new RequestContext;
301   scoped_ptr<ProxyScriptFetcher> pac_fetcher(
302       ProxyScriptFetcher::Create(context));
303 
304   // Test a response that is gzip-encoded -- should get inflated.
305   {
306     GURL url = server->TestServerPage("files/gzipped_pac");
307     std::string bytes;
308     TestCompletionCallback callback;
309     int result = pac_fetcher->Fetch(url, &bytes, &callback);
310     EXPECT_EQ(ERR_IO_PENDING, result);
311     EXPECT_EQ(OK, callback.WaitForResult());
312     EXPECT_EQ("This data was gzipped.\n", bytes);
313   }
314 
315   // Test a response that was served as UTF-16 (BE). It should
316   // be converted to UTF8.
317   {
318     GURL url = server->TestServerPage("files/utf16be_pac");
319     std::string bytes;
320     TestCompletionCallback callback;
321     int result = pac_fetcher->Fetch(url, &bytes, &callback);
322     EXPECT_EQ(ERR_IO_PENDING, result);
323     EXPECT_EQ(OK, callback.WaitForResult());
324     EXPECT_EQ("This was encoded as UTF-16BE.\n", bytes);
325   }
326 }
327 
328 }  // namespace net
329