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