1 // Copyright (c) 2010 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.
5 #include "net/url_request/url_request_job_manager.h"
9 #include "build/build_config.h"
10 #include "base/singleton.h"
11 #include "base/string_util.h"
12 #include "net/base/load_flags.h"
13 #include "net/base/net_errors.h"
14 #include "net/url_request/url_request_about_job.h"
15 #include "net/url_request/url_request_data_job.h"
16 #include "net/url_request/url_request_error_job.h"
17 #include "net/url_request/url_request_file_job.h"
18 #include "net/url_request/url_request_ftp_job.h"
19 #include "net/url_request/url_request_http_job.h"
21 // The built-in set of protocol factories
24 struct SchemeToFactory
{
26 net::URLRequest::ProtocolFactory
* factory
;
33 static const SchemeToFactory kBuiltinFactories
[] = {
34 { "http", URLRequestHttpJob::Factory
},
35 { "https", URLRequestHttpJob::Factory
},
36 { "file", URLRequestFileJob::Factory
},
37 { "ftp", URLRequestFtpJob::Factory
},
38 { "about", URLRequestAboutJob::Factory
},
39 { "data", URLRequestDataJob::Factory
},
43 URLRequestJobManager
* URLRequestJobManager::GetInstance() {
44 return Singleton
<URLRequestJobManager
>::get();
47 net::URLRequestJob
* URLRequestJobManager::CreateJob(
48 net::URLRequest
* request
) const {
50 DCHECK(IsAllowedThread());
53 // If we are given an invalid URL, then don't even try to inspect the scheme.
54 if (!request
->url().is_valid())
55 return new net::URLRequestErrorJob(request
, net::ERR_INVALID_URL
);
57 // We do this here to avoid asking interceptors about unsupported schemes.
58 const std::string
& scheme
= request
->url().scheme(); // already lowercase
59 if (!SupportsScheme(scheme
))
60 return new net::URLRequestErrorJob(request
, net::ERR_UNKNOWN_URL_SCHEME
);
62 // THREAD-SAFETY NOTICE:
63 // We do not need to acquire the lock here since we are only reading our
64 // data structures. They should only be modified on the current thread.
66 // See if the request should be intercepted.
67 if (!(request
->load_flags() & net::LOAD_DISABLE_INTERCEPT
)) {
68 InterceptorList::const_iterator i
;
69 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
70 net::URLRequestJob
* job
= (*i
)->MaybeIntercept(request
);
76 // See if the request should be handled by a registered protocol factory.
77 // If the registered factory returns null, then we want to fall-back to the
78 // built-in protocol factory.
79 FactoryMap::const_iterator i
= factories_
.find(scheme
);
80 if (i
!= factories_
.end()) {
81 net::URLRequestJob
* job
= i
->second(request
, scheme
);
86 // See if the request should be handled by a built-in protocol factory.
87 for (size_t i
= 0; i
< arraysize(kBuiltinFactories
); ++i
) {
88 if (scheme
== kBuiltinFactories
[i
].scheme
) {
89 net::URLRequestJob
* job
= (kBuiltinFactories
[i
].factory
)(request
, scheme
);
90 DCHECK(job
); // The built-in factories are not expected to fail!
95 // If we reached here, then it means that a registered protocol factory
96 // wasn't interested in handling the URL. That is fairly unexpected, and we
97 // don't know have a specific error to report here :-(
98 LOG(WARNING
) << "Failed to map: " << request
->url().spec();
99 return new net::URLRequestErrorJob(request
, net::ERR_FAILED
);
102 net::URLRequestJob
* URLRequestJobManager::MaybeInterceptRedirect(
103 net::URLRequest
* request
,
104 const GURL
& location
) const {
106 DCHECK(IsAllowedThread());
108 if ((request
->load_flags() & net::LOAD_DISABLE_INTERCEPT
) ||
109 (request
->status().status() == URLRequestStatus::CANCELED
) ||
110 !request
->url().is_valid() ||
111 !SupportsScheme(request
->url().scheme()))
114 InterceptorList::const_iterator i
;
115 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
116 net::URLRequestJob
* job
= (*i
)->MaybeInterceptRedirect(request
, location
);
123 net::URLRequestJob
* URLRequestJobManager::MaybeInterceptResponse(
124 net::URLRequest
* request
) const {
126 DCHECK(IsAllowedThread());
128 if ((request
->load_flags() & net::LOAD_DISABLE_INTERCEPT
) ||
129 (request
->status().status() == URLRequestStatus::CANCELED
) ||
130 !request
->url().is_valid() ||
131 !SupportsScheme(request
->url().scheme()))
134 InterceptorList::const_iterator i
;
135 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
136 net::URLRequestJob
* job
= (*i
)->MaybeInterceptResponse(request
);
143 bool URLRequestJobManager::SupportsScheme(const std::string
& scheme
) const {
144 // The set of registered factories may change on another thread.
146 base::AutoLock
locked(lock_
);
147 if (factories_
.find(scheme
) != factories_
.end())
151 for (size_t i
= 0; i
< arraysize(kBuiltinFactories
); ++i
)
152 if (LowerCaseEqualsASCII(scheme
, kBuiltinFactories
[i
].scheme
))
158 net::URLRequest::ProtocolFactory
* URLRequestJobManager::RegisterProtocolFactory(
159 const std::string
& scheme
,
160 net::URLRequest::ProtocolFactory
* factory
) {
162 DCHECK(IsAllowedThread());
165 base::AutoLock
locked(lock_
);
167 net::URLRequest::ProtocolFactory
* old_factory
;
168 FactoryMap::iterator i
= factories_
.find(scheme
);
169 if (i
!= factories_
.end()) {
170 old_factory
= i
->second
;
175 factories_
[scheme
] = factory
;
176 } else if (i
!= factories_
.end()) { // uninstall any old one
182 void URLRequestJobManager::RegisterRequestInterceptor(
183 net::URLRequest::Interceptor
* interceptor
) {
185 DCHECK(IsAllowedThread());
188 base::AutoLock
locked(lock_
);
190 DCHECK(std::find(interceptors_
.begin(), interceptors_
.end(), interceptor
) ==
191 interceptors_
.end());
192 interceptors_
.push_back(interceptor
);
195 void URLRequestJobManager::UnregisterRequestInterceptor(
196 net::URLRequest::Interceptor
* interceptor
) {
198 DCHECK(IsAllowedThread());
201 base::AutoLock
locked(lock_
);
203 InterceptorList::iterator i
=
204 std::find(interceptors_
.begin(), interceptors_
.end(), interceptor
);
205 DCHECK(i
!= interceptors_
.end());
206 interceptors_
.erase(i
);
209 URLRequestJobManager::URLRequestJobManager() : enable_file_access_(false) {
212 allowed_thread_initialized_
= false;
216 URLRequestJobManager::~URLRequestJobManager() {}