diff options
Diffstat (limited to 'net/url_request')
-rw-r--r-- | net/url_request/url_request_context.cc | 4 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 8 | ||||
-rw-r--r-- | net/url_request/url_request_context_storage.cc | 7 | ||||
-rw-r--r-- | net/url_request/url_request_context_storage.h | 3 | ||||
-rw-r--r-- | net/url_request/url_request_job_factory.cc | 93 | ||||
-rw-r--r-- | net/url_request/url_request_job_factory.h | 96 | ||||
-rw-r--r-- | net/url_request/url_request_job_factory_unittest.cc | 152 | ||||
-rw-r--r-- | net/url_request/url_request_job_manager.cc | 32 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.cc | 2 |
9 files changed, 394 insertions, 3 deletions
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc index 0057f2a..c9c232d 100644 --- a/net/url_request/url_request_context.cc +++ b/net/url_request/url_request_context.cc @@ -24,7 +24,8 @@ URLRequestContext::URLRequestContext() network_delegate_(NULL), transport_security_state_(NULL), http_transaction_factory_(NULL), - ftp_transaction_factory_(NULL) { + ftp_transaction_factory_(NULL), + job_factory_(NULL) { } void URLRequestContext::CopyFrom(URLRequestContext* other) { @@ -47,6 +48,7 @@ void URLRequestContext::CopyFrom(URLRequestContext* other) { set_referrer_charset(other->referrer_charset()); set_http_transaction_factory(other->http_transaction_factory()); set_ftp_transaction_factory(other->ftp_transaction_factory()); + set_job_factory(other->job_factory()); } void URLRequestContext::set_cookie_store(CookieStore* cookie_store) { diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index bc74459..8749573 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -32,6 +32,7 @@ class NetworkDelegate; class ProxyService; class SSLConfigService; class URLRequest; +class URLRequestJobFactory; // Subclass to provide application-specific context for URLRequest // instances. Note that URLRequestContext typically does not provide storage for @@ -172,6 +173,11 @@ class URLRequestContext bool is_main() const { return is_main_; } void set_is_main(bool is_main) { is_main_ = is_main; } + const URLRequestJobFactory* job_factory() const { return job_factory_; } + void set_job_factory(const URLRequestJobFactory* job_factory) { + job_factory_ = job_factory; + } + protected: friend class base::RefCountedThreadSafe<URLRequestContext>; @@ -206,9 +212,9 @@ class URLRequestContext // used in communication with a server but is used to construct a suggested // filename for file download. std::string referrer_charset_; - HttpTransactionFactory* http_transaction_factory_; FtpTransactionFactory* ftp_transaction_factory_; + const URLRequestJobFactory* job_factory_; // --------------------------------------------------------------------------- // Important: When adding any new members below, consider whether they need to diff --git a/net/url_request/url_request_context_storage.cc b/net/url_request/url_request_context_storage.cc index d54614a..7531fd7 100644 --- a/net/url_request/url_request_context_storage.cc +++ b/net/url_request/url_request_context_storage.cc @@ -16,6 +16,7 @@ #include "net/http/http_transaction_factory.h" #include "net/proxy/proxy_service.h" #include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_job_factory.h" namespace net { @@ -99,4 +100,10 @@ void URLRequestContextStorage::set_ftp_transaction_factory( ftp_transaction_factory_.reset(ftp_transaction_factory); } +void URLRequestContextStorage::set_job_factory( + URLRequestJobFactory* job_factory) { + context_->set_job_factory(job_factory); + job_factory_.reset(job_factory); +} + } // namespace net diff --git a/net/url_request/url_request_context_storage.h b/net/url_request/url_request_context_storage.h index ccb042e..4cdfc43 100644 --- a/net/url_request/url_request_context_storage.h +++ b/net/url_request/url_request_context_storage.h @@ -26,6 +26,7 @@ class ProxyService; class SSLConfigService; class TransportSecurityState; class URLRequestContext; +class URLRequestJobFactory; // URLRequestContextStorage is a helper class that provides storage for unowned // member variables of URLRequestContext. @@ -57,6 +58,7 @@ class URLRequestContextStorage { HttpTransactionFactory* http_transaction_factory); void set_ftp_transaction_factory( FtpTransactionFactory* ftp_transaction_factory); + void set_job_factory(URLRequestJobFactory* job_factory); private: // We use a raw pointer to prevent reference cycles, since @@ -80,6 +82,7 @@ class URLRequestContextStorage { scoped_ptr<HttpTransactionFactory> http_transaction_factory_; scoped_ptr<FtpTransactionFactory> ftp_transaction_factory_; + scoped_ptr<URLRequestJobFactory> job_factory_; DISALLOW_COPY_AND_ASSIGN(URLRequestContextStorage); }; diff --git a/net/url_request/url_request_job_factory.cc b/net/url_request/url_request_job_factory.cc new file mode 100644 index 0000000..78fcb38 --- /dev/null +++ b/net/url_request/url_request_job_factory.cc @@ -0,0 +1,93 @@ +// Copyright (c) 2011 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/url_request/url_request_job_factory.h" + +#include "base/stl_util-inl.h" +#include "googleurl/src/gurl.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_request_job_manager.h" + +namespace net { + +URLRequestJobFactory::ProtocolHandler::~ProtocolHandler() {} + +URLRequestJobFactory::Interceptor::~Interceptor() {} + +URLRequestJobFactory::URLRequestJobFactory() {} + +URLRequestJobFactory::~URLRequestJobFactory() { + STLDeleteValues(&protocol_handler_map_); + STLDeleteElements(&interceptors_); +} + +bool URLRequestJobFactory::SetProtocolHandler( + const std::string& scheme, + ProtocolHandler* protocol_handler) { + DCHECK(CalledOnValidThread()); + + if (!protocol_handler) { + ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme); + if (it == protocol_handler_map_.end()) + return false; + + delete it->second; + protocol_handler_map_.erase(it); + return true; + } + + if (ContainsKey(protocol_handler_map_, scheme)) + return false; + protocol_handler_map_[scheme] = protocol_handler; + return true; +} + +void URLRequestJobFactory::AddInterceptor(Interceptor* interceptor) { + DCHECK(CalledOnValidThread()); + CHECK(interceptor); + + interceptors_.push_back(interceptor); +} + +URLRequestJob* URLRequestJobFactory::MaybeCreateJobWithInterceptor( + URLRequest* request) const { + DCHECK(CalledOnValidThread()); + URLRequestJob* job = NULL; + + if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) { + InterceptorList::const_iterator i; + for (i = interceptors_.begin(); i != interceptors_.end(); ++i) { + job = (*i)->MaybeIntercept(request); + if (job) + return job; + } + } + return NULL; +} + +URLRequestJob* URLRequestJobFactory::MaybeCreateJobWithProtocolHandler( + const std::string& scheme, + URLRequest* request) const { + DCHECK(CalledOnValidThread()); + ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme); + if (it == protocol_handler_map_.end()) + return NULL; + return it->second->MaybeCreateJob(request); +} + +bool URLRequestJobFactory::IsHandledProtocol(const std::string& scheme) const { + DCHECK(CalledOnValidThread()); + return ContainsKey(protocol_handler_map_, scheme) || + URLRequestJobManager::GetInstance()->SupportsScheme(scheme); +} + +bool URLRequestJobFactory::IsHandledURL(const GURL& url) const { + if (!url.is_valid()) { + // We handle error cases. + return true; + } + return IsHandledProtocol(url.scheme()); +} + +} // namespace net diff --git a/net/url_request/url_request_job_factory.h b/net/url_request/url_request_job_factory.h new file mode 100644 index 0000000..594883a --- /dev/null +++ b/net/url_request/url_request_job_factory.h @@ -0,0 +1,96 @@ +// Copyright (c) 2011 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. + +#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_ +#define NET_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_ +#pragma once + +#include <map> +#include <string> +#include <vector> +#include "base/basictypes.h" +#include "base/threading/non_thread_safe.h" + +class GURL; + +namespace net { + +class URLRequest; +class URLRequestJob; + +class URLRequestJobFactory : public base::NonThreadSafe { + public: + class ProtocolHandler { + public: + virtual ~ProtocolHandler(); + + virtual URLRequestJob* MaybeCreateJob(URLRequest* request) const = 0; + }; + + class Interceptor { + public: + virtual ~Interceptor(); + + // Called for every request made. Should return a new job to handle the + // request if it should be intercepted, or NULL to allow the request to + // be handled in the normal manner. + virtual URLRequestJob* MaybeIntercept(URLRequest* request) const = 0; + + // Called after having received a redirect response, but prior to the + // the request delegate being informed of the redirect. Can return a new + // job to replace the existing job if it should be intercepted, or NULL + // to allow the normal handling to continue. If a new job is provided, + // the delegate never sees the original redirect response, instead the + // response produced by the intercept job will be returned. + virtual URLRequestJob* MaybeInterceptRedirect( + const GURL& location, + URLRequest* request) const = 0; + + // Called after having received a final response, but prior to the + // the request delegate being informed of the response. This is also + // called when there is no server response at all to allow interception + // on DNS or network errors. Can return a new job to replace the existing + // job if it should be intercepted, or NULL to allow the normal handling to + // continue. If a new job is provided, the delegate never sees the original + // response, instead the response produced by the intercept job will be + // returned. + virtual URLRequestJob* MaybeInterceptResponse( + URLRequest* request) const = 0; + }; + + URLRequestJobFactory(); + ~URLRequestJobFactory(); + + // Sets the ProtocolHandler for a scheme. Returns true on success, false on + // failure (a ProtocolHandler already exists for |scheme|). On success, + // URLRequestJobFactory takes ownership of |protocol_handler|. + bool SetProtocolHandler(const std::string& scheme, + ProtocolHandler* protocol_handler); + + // Takes ownership of |interceptor|. Adds it to the end of the Interceptor + // list. + void AddInterceptor(Interceptor* interceptor); + + URLRequestJob* MaybeCreateJobWithInterceptor(URLRequest* request) const; + + URLRequestJob* MaybeCreateJobWithProtocolHandler(const std::string& scheme, + URLRequest* request) const; + + bool IsHandledProtocol(const std::string& scheme) const; + + bool IsHandledURL(const GURL& url) const; + + private: + typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap; + typedef std::vector<Interceptor*> InterceptorList; + + ProtocolHandlerMap protocol_handler_map_; + InterceptorList interceptors_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestJobFactory); +}; + +} // namespace net + +#endif // NET_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_ diff --git a/net/url_request/url_request_job_factory_unittest.cc b/net/url_request/url_request_job_factory_unittest.cc new file mode 100644 index 0000000..46c952c --- /dev/null +++ b/net/url_request/url_request_job_factory_unittest.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2011 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/url_request/url_request_job_factory.h" + +#include "base/task.h" +#include "net/url_request/url_request_job.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +class MockURLRequestJob : public URLRequestJob { + public: + MockURLRequestJob(URLRequest* request, const URLRequestStatus& status) + : URLRequestJob(request), + status_(status), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {} + + virtual void Start() { + // Start reading asynchronously so that all error reporting and data + // callbacks happen as they would for network requests. + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod(&MockURLRequestJob::StartAsync)); + } + + private: + void StartAsync() { + SetStatus(status_); + NotifyHeadersComplete(); + } + + URLRequestStatus status_; + ScopedRunnableMethodFactory<MockURLRequestJob> method_factory_; +}; + +class DummyProtocolHandler : public URLRequestJobFactory::ProtocolHandler { + public: + virtual URLRequestJob* MaybeCreateJob(URLRequest* request) const { + return new MockURLRequestJob( + request, URLRequestStatus(URLRequestStatus::SUCCESS, OK)); + } +}; + +class DummyInterceptor : public URLRequestJobFactory::Interceptor { + public: + virtual URLRequestJob* MaybeIntercept(URLRequest* request) const { + return new MockURLRequestJob( + request, + URLRequestStatus(URLRequestStatus::FAILED, ERR_FAILED)); + } + + virtual URLRequestJob* MaybeInterceptRedirect( + const GURL& /* location */, + URLRequest* /* request */) const { + return NULL; + } + + virtual URLRequestJob* MaybeInterceptResponse( + URLRequest* /* request */) const { + return NULL; + } +}; + +TEST(URLRequestJobFactoryTest, NoProtocolHandler) { + TestDelegate delegate; + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + TestURLRequest request(GURL("foo://bar"), &delegate); + request.set_context(request_context); + request.Start(); + + MessageLoop::current()->Run(); + EXPECT_EQ(URLRequestStatus::FAILED, request.status().status()); + EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, request.status().os_error()); +} + +TEST(URLRequestJobFactoryTest, BasicProtocolHandler) { + TestDelegate delegate; + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + URLRequestJobFactory job_factory; + request_context->set_job_factory(&job_factory); + job_factory.SetProtocolHandler("foo", new DummyProtocolHandler); + TestURLRequest request(GURL("foo://bar"), &delegate); + request.set_context(request_context); + request.Start(); + + MessageLoop::current()->Run(); + EXPECT_EQ(URLRequestStatus::SUCCESS, request.status().status()); + EXPECT_EQ(OK, request.status().os_error()); +} + +TEST(URLRequestJobFactoryTest, DeleteProtocolHandler) { + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + URLRequestJobFactory job_factory; + request_context->set_job_factory(&job_factory); + job_factory.SetProtocolHandler("foo", new DummyProtocolHandler); + job_factory.SetProtocolHandler("foo", NULL); +} + +TEST(URLRequestJobFactoryTest, BasicInterceptor) { + TestDelegate delegate; + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + URLRequestJobFactory job_factory; + request_context->set_job_factory(&job_factory); + job_factory.AddInterceptor(new DummyInterceptor); + TestURLRequest request(GURL("http://bar"), &delegate); + request.set_context(request_context); + request.Start(); + + MessageLoop::current()->Run(); + EXPECT_EQ(URLRequestStatus::FAILED, request.status().status()); + EXPECT_EQ(ERR_FAILED, request.status().os_error()); +} + +TEST(URLRequestJobFactoryTest, InterceptorNeedsValidSchemeStill) { + TestDelegate delegate; + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + URLRequestJobFactory job_factory; + request_context->set_job_factory(&job_factory); + job_factory.AddInterceptor(new DummyInterceptor); + TestURLRequest request(GURL("foo://bar"), &delegate); + request.set_context(request_context); + request.Start(); + + MessageLoop::current()->Run(); + EXPECT_EQ(URLRequestStatus::FAILED, request.status().status()); + EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, request.status().os_error()); +} + +TEST(URLRequestJobFactoryTest, InterceptorOverridesProtocolHandler) { + TestDelegate delegate; + scoped_refptr<URLRequestContext> request_context(new TestURLRequestContext); + URLRequestJobFactory job_factory; + request_context->set_job_factory(&job_factory); + job_factory.SetProtocolHandler("foo", new DummyProtocolHandler); + job_factory.AddInterceptor(new DummyInterceptor); + TestURLRequest request(GURL("foo://bar"), &delegate); + request.set_context(request_context); + request.Start(); + + MessageLoop::current()->Run(); + EXPECT_EQ(URLRequestStatus::FAILED, request.status().status()); + EXPECT_EQ(ERR_FAILED, request.status().os_error()); +} + +} // namespace + +} // namespace net diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc index 06891b4..dc6af79 100644 --- a/net/url_request/url_request_job_manager.cc +++ b/net/url_request/url_request_job_manager.cc @@ -11,12 +11,15 @@ #include "base/string_util.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" +#include "net/base/network_delegate.h" #include "net/url_request/url_request_about_job.h" +#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_data_job.h" #include "net/url_request/url_request_error_job.h" #include "net/url_request/url_request_file_job.h" #include "net/url_request/url_request_ftp_job.h" #include "net/url_request/url_request_http_job.h" +#include "net/url_request/url_request_job_factory.h" namespace net { @@ -55,15 +58,33 @@ URLRequestJob* URLRequestJobManager::CreateJob( return new URLRequestErrorJob(request, ERR_INVALID_URL); // We do this here to avoid asking interceptors about unsupported schemes. + const URLRequestJobFactory* job_factory = NULL; + if (request->context()) + job_factory = request->context()->job_factory(); + const std::string& scheme = request->url().scheme(); // already lowercase - if (!SupportsScheme(scheme)) + if (job_factory) { + if (!job_factory->IsHandledProtocol(scheme)) { + return new URLRequestErrorJob(request, ERR_UNKNOWN_URL_SCHEME); + } + } else if (!SupportsScheme(scheme)) { return new URLRequestErrorJob(request, ERR_UNKNOWN_URL_SCHEME); + } // THREAD-SAFETY NOTICE: // We do not need to acquire the lock here since we are only reading our // data structures. They should only be modified on the current thread. // See if the request should be intercepted. + // + + if (job_factory) { + URLRequestJob* job = job_factory->MaybeCreateJobWithInterceptor(request); + if (job) + return job; + } + + // TODO(willchan): Remove this in favor of URLRequestJobFactory::Interceptor. if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) { InterceptorList::const_iterator i; for (i = interceptors_.begin(); i != interceptors_.end(); ++i) { @@ -73,6 +94,15 @@ URLRequestJob* URLRequestJobManager::CreateJob( } } + if (job_factory) { + URLRequestJob* job = + job_factory->MaybeCreateJobWithProtocolHandler(scheme, request); + if (job) + return job; + } + + // TODO(willchan): Remove this in favor of + // URLRequestJobFactory::ProtocolHandler. // See if the request should be handled by a registered protocol factory. // If the registered factory returns null, then we want to fall-back to the // built-in protocol factory. diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 680f12d..fff1d8b 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc @@ -10,6 +10,7 @@ #include "base/threading/thread.h" #include "net/base/host_port_pair.h" #include "net/http/http_network_session.h" +#include "net/url_request/url_request_job_factory.h" TestURLRequestContext::TestURLRequestContext() : ALLOW_THIS_IN_INITIALIZER_LIST(context_storage_(this)) { @@ -67,6 +68,7 @@ void TestURLRequestContext::Init() { context_storage_.set_cookie_store(new net::CookieMonster(NULL, NULL)); set_accept_language("en-us,fr"); set_accept_charset("iso-8859-1,*,utf-8"); + context_storage_.set_job_factory(new net::URLRequestJobFactory); } |