diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-10 09:03:15 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-10 09:03:15 +0000 |
commit | 677c9057fafb4c263f001ded0e173075a945a4c2 (patch) | |
tree | ca4b253831c082fe4a7ccaba2ba3cae6f264615a /net/proxy/proxy_script_fetcher_unittest.cc | |
parent | 1b9cad81c98ec37ce2f6b4c3ef47571efc61bd3d (diff) | |
download | chromium_src-677c9057fafb4c263f001ded0e173075a945a4c2.zip chromium_src-677c9057fafb4c263f001ded0e173075a945a4c2.tar.gz chromium_src-677c9057fafb4c263f001ded0e173075a945a4c2.tar.bz2 |
Add a ProxyScriptFetcher class for doing asynch downloads of PAC scripts.This object will be owned by ProxyService. It will be used to manage the fetching of PAC scripts (on the IO thread, using the primary URLRequestContext).BUG=74,2764 (partial)
Review URL: http://codereview.chromium.org/13251
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6699 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/proxy/proxy_script_fetcher_unittest.cc')
-rw-r--r-- | net/proxy/proxy_script_fetcher_unittest.cc | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/net/proxy/proxy_script_fetcher_unittest.cc b/net/proxy/proxy_script_fetcher_unittest.cc new file mode 100644 index 0000000..73476ed --- /dev/null +++ b/net/proxy/proxy_script_fetcher_unittest.cc @@ -0,0 +1,294 @@ +// Copyright (c) 2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/proxy/proxy_script_fetcher.h" + +#include "base/file_path.h" +#include "base/compiler_specific.h" +#include "base/path_service.h" +#include "net/base/net_util.h" +#include "net/url_request/url_request_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" + +// TODO(eroman): +// - Test canceling an outstanding request. +// - Test deleting ProxyScriptFetcher while a request is in progress. + +const wchar_t kDocRoot[] = L"net/data/proxy_script_fetcher_unittest"; + +struct FetchResult { + int code; + std::string bytes; +}; + +// A non-mock URL request which can access http:// and file:// urls. +class RequestContext : public URLRequestContext { + public: + RequestContext() { + net::ProxyInfo no_proxy; + proxy_service_ = net::ProxyService::Create(&no_proxy); + http_transaction_factory_ = net::HttpNetworkLayer::CreateFactory( + proxy_service_); + } + ~RequestContext() { + delete http_transaction_factory_; + delete proxy_service_; + } +}; + +// Helper for doing synch fetches. This object lives in SynchFetcher's +// |io_thread_| and communicates with SynchFetcher though (|result|, |event|). +class SynchFetcherThreadHelper { + public: + SynchFetcherThreadHelper(base::WaitableEvent* event, FetchResult* result) + : event_(event), + fetch_result_(result), + url_request_context_(NULL), + fetcher_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + callback_(this, &SynchFetcherThreadHelper::OnFetchCompletion)) { + url_request_context_ = new RequestContext; + fetcher_.reset(net::ProxyScriptFetcher::Create(url_request_context_.get())); + } + + // Starts fetching the script at |url|. Upon completion |event_| will be + // signalled, and the bytes read will have been written to |fetch_result_|. + void Start(const GURL& url) { + fetcher_->Fetch(url, &fetch_result_->bytes, &callback_); + } + + void OnFetchCompletion(int result) { + fetch_result_->code = result; + event_->Signal(); + } + + private: + base::WaitableEvent* event_; + FetchResult* fetch_result_; + + scoped_refptr<URLRequestContext> url_request_context_; + + scoped_ptr<net::ProxyScriptFetcher> fetcher_; + net::CompletionCallbackImpl<SynchFetcherThreadHelper> callback_; +}; + +// Helper that wraps ProxyScriptFetcher::Fetch() with a synchronous interface. +// It executes Fetch() on a helper thread (IO_Thread). +class SynchFetcher { + public: + SynchFetcher() + : event_(false, false), + io_thread_("IO_Thread"), + thread_helper_(NULL) { + // Start an IO thread. + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + + // Initialize the state in |io_thread_|. + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SynchFetcher::Init)); + Wait(); + } + + ~SynchFetcher() { + // Tear down the state in |io_thread_|. + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SynchFetcher::Cleanup)); + Wait(); + } + + // Synchronously fetch the url. + FetchResult Fetch(const GURL& url) { + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SynchFetcher::AsynchFetch, url)); + Wait(); + return fetch_result_; + } + + private: + // [Runs on |io_thread_|] Allocates the URLRequestContext and the + // ProxyScriptFetcher, which live inside |thread_helper_|. + void Init() { + thread_helper_ = new SynchFetcherThreadHelper(&event_, &fetch_result_); + event_.Signal(); + } + + // [Runs on |io_thread_|] Signals |event_| on completion. + void AsynchFetch(const GURL& url) { + thread_helper_->Start(url); + } + + // [Runs on |io_thread_|] Signals |event_| on cleanup completion. + void Cleanup() { + delete thread_helper_; + thread_helper_ = NULL; + MessageLoop::current()->RunAllPending(); + event_.Signal(); + } + + void Wait() { + event_.Wait(); + event_.Reset(); + } + + base::WaitableEvent event_; + base::Thread io_thread_; + FetchResult fetch_result_; + // Holds all the state that lives on the IO thread, for easy cleanup. + SynchFetcherThreadHelper* thread_helper_; +}; + +// Template specialization so SynchFetcher does not have to be refcounted. +template<> +void RunnableMethodTraits<SynchFetcher>::RetainCallee(SynchFetcher* remover) {} +template<> +void RunnableMethodTraits<SynchFetcher>::ReleaseCallee(SynchFetcher* remover) {} + +// Required to be in net namespace by FRIEND_TEST. +namespace net { + +// Get a file:// url relative to net/data/proxy/proxy_script_fetcher_unittest. +GURL GetTestFileUrl(const std::string& relpath) { + FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + path = path.Append(FILE_PATH_LITERAL("net")); + path = path.Append(FILE_PATH_LITERAL("data")); + path = path.Append(FILE_PATH_LITERAL("proxy_script_fetcher_unittest")); + GURL base_url = net::FilePathToFileURL(path); + return GURL(base_url.spec() + "/" + relpath); +} + +TEST(ProxyScriptFetcherTest, FileUrl) { + SynchFetcher pac_fetcher; + + { // Fetch a non-existent file. + FetchResult result = pac_fetcher.Fetch(GetTestFileUrl("does-not-exist")); + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, result.code); + EXPECT_TRUE(result.bytes.empty()); + } + { // Fetch a file that exists. + FetchResult result = pac_fetcher.Fetch(GetTestFileUrl("pac.txt")); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.txt-\n", result.bytes); + } +} + +// Note that all mime types are allowed for PAC file, to be consistent +// with other browsers. +TEST(ProxyScriptFetcherTest, HttpMimeType) { + TestServer server(kDocRoot); + SynchFetcher pac_fetcher; + + { // Fetch a PAC with mime type "text/plain" + GURL url = server.TestServerPage("files/pac.txt"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.txt-\n", result.bytes); + } + { // Fetch a PAC with mime type "text/html" + GURL url = server.TestServerPage("files/pac.html"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.html-\n", result.bytes); + } + { // Fetch a PAC with mime type "application/x-ns-proxy-autoconfig" + GURL url = server.TestServerPage("files/pac.nsproxy"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.nsproxy-\n", result.bytes); + } +} + +TEST(ProxyScriptFetcherTest, HttpStatusCode) { + TestServer server(kDocRoot); + SynchFetcher pac_fetcher; + + { // Fetch a PAC which gives a 500 -- FAIL + GURL url = server.TestServerPage("files/500.pac"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::ERR_PAC_STATUS_NOT_OK, result.code); + EXPECT_TRUE(result.bytes.empty()); + } + { // Fetch a PAC which gives a 404 -- FAIL + GURL url = server.TestServerPage("files/404.pac"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::ERR_PAC_STATUS_NOT_OK, result.code); + EXPECT_TRUE(result.bytes.empty()); + } +} + +TEST(ProxyScriptFetcherTest, ContentDisposition) { + TestServer server(kDocRoot); + SynchFetcher pac_fetcher; + + // Fetch PAC scripts via HTTP with a Content-Disposition header -- should + // have no effect. + GURL url = server.TestServerPage("files/downloadable.pac"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-downloadable.pac-\n", result.bytes); +} + +TEST(ProxyScriptFetcherTest, TooLarge) { + TestServer server(kDocRoot); + SynchFetcher pac_fetcher; + + // Set the maximum response size to 50 bytes. + int prev_size = net::ProxyScriptFetcher::SetSizeConstraintForUnittest(50); + + // These two URLs are the same file, but are http:// vs file:// + GURL urls[] = { + server.TestServerPage("files/large-pac.nsproxy"), + GetTestFileUrl("large-pac.nsproxy") + }; + + // Try fetching URLs that are 101 bytes large. We should abort the request + // after 50 bytes have been read, and fail with a too large error. + for (size_t i = 0; i < arraysize(urls); ++i) { + const GURL& url = urls[i]; + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::ERR_FILE_TOO_BIG, result.code); + EXPECT_TRUE(result.bytes.empty()); + } + + // Restore the original size bound. + net::ProxyScriptFetcher::SetSizeConstraintForUnittest(prev_size); + + { // Make sure we can still fetch regular URLs. + GURL url = server.TestServerPage("files/pac.nsproxy"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.nsproxy-\n", result.bytes); + } +} + +TEST(ProxyScriptFetcherTest, Hang) { + TestServer server(kDocRoot); + SynchFetcher pac_fetcher; + + // Set the timeout period to 0.5 seconds. + int prev_timeout = + net::ProxyScriptFetcher::SetTimeoutConstraintForUnittest(500); + + // Try fetching a URL which takes 1.2 seconds. We should abort the request + // after 500 ms, and fail with a timeout error. + { GURL url = server.TestServerPage("slow/proxy.pac?1.2"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::ERR_TIMED_OUT, result.code); + EXPECT_TRUE(result.bytes.empty()); + } + + // Restore the original timeout period. + net::ProxyScriptFetcher::SetTimeoutConstraintForUnittest(prev_timeout); + + { // Make sure we can still fetch regular URLs. + GURL url = server.TestServerPage("files/pac.nsproxy"); + FetchResult result = pac_fetcher.Fetch(url); + EXPECT_EQ(net::OK, result.code); + EXPECT_EQ("-pac.nsproxy-\n", result.bytes); + } +} + +} // namespace net |