1 // Copyright (c) 2012 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 "base/memory/singleton.h"
10 #include "build/build_config.h"
11 #include "base/strings/string_util.h"
12 #include "net/base/load_flags.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/network_delegate.h"
15 #include "net/url_request/url_request_context.h"
16 #include "net/url_request/url_request_error_job.h"
17 #include "net/url_request/url_request_http_job.h"
18 #include "net/url_request/url_request_job_factory.h"
22 // The built-in set of protocol factories
25 struct SchemeToFactory
{
27 URLRequest::ProtocolFactory
* factory
;
32 static const SchemeToFactory kBuiltinFactories
[] = {
33 { "http", URLRequestHttpJob::Factory
},
34 { "https", URLRequestHttpJob::Factory
},
37 { "ws", URLRequestHttpJob::Factory
},
38 { "wss", URLRequestHttpJob::Factory
},
39 #endif // !defined(OS_IOS)
43 URLRequestJobManager
* URLRequestJobManager::GetInstance() {
44 return Singleton
<URLRequestJobManager
>::get();
47 URLRequestJob
* URLRequestJobManager::CreateJob(
48 URLRequest
* request
, NetworkDelegate
* network_delegate
) const {
49 DCHECK(IsAllowedThread());
51 // If we are given an invalid URL, then don't even try to inspect the scheme.
52 if (!request
->url().is_valid())
53 return new URLRequestErrorJob(request
, network_delegate
, ERR_INVALID_URL
);
55 // We do this here to avoid asking interceptors about unsupported schemes.
56 const URLRequestJobFactory
* job_factory
= NULL
;
57 job_factory
= request
->context()->job_factory();
59 const std::string
& scheme
= request
->url().scheme(); // already lowercase
60 if (!job_factory
->IsHandledProtocol(scheme
)) {
61 return new URLRequestErrorJob(
62 request
, network_delegate
, ERR_UNKNOWN_URL_SCHEME
);
65 // THREAD-SAFETY NOTICE:
66 // We do not need to acquire the lock here since we are only reading our
67 // data structures. They should only be modified on the current thread.
69 // See if the request should be intercepted.
72 // TODO(pauljensen): Remove this when AppCacheInterceptor is a
73 // ProtocolHandler, see crbug.com/161547.
74 if (!(request
->load_flags() & LOAD_DISABLE_INTERCEPT
)) {
75 InterceptorList::const_iterator i
;
76 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
77 URLRequestJob
* job
= (*i
)->MaybeIntercept(request
, network_delegate
);
83 URLRequestJob
* job
= job_factory
->MaybeCreateJobWithProtocolHandler(
84 scheme
, request
, network_delegate
);
88 // See if the request should be handled by a built-in protocol factory.
89 for (size_t i
= 0; i
< arraysize(kBuiltinFactories
); ++i
) {
90 if (scheme
== kBuiltinFactories
[i
].scheme
) {
91 URLRequestJob
* job
= (kBuiltinFactories
[i
].factory
)(
92 request
, network_delegate
, scheme
);
93 DCHECK(job
); // The built-in factories are not expected to fail!
98 // If we reached here, then it means that a registered protocol factory
99 // wasn't interested in handling the URL. That is fairly unexpected, and we
100 // don't have a specific error to report here :-(
101 LOG(WARNING
) << "Failed to map: " << request
->url().spec();
102 return new URLRequestErrorJob(request
, network_delegate
, ERR_FAILED
);
105 URLRequestJob
* URLRequestJobManager::MaybeInterceptRedirect(
107 NetworkDelegate
* network_delegate
,
108 const GURL
& location
) const {
109 DCHECK(IsAllowedThread());
110 if (!request
->url().is_valid() ||
111 request
->load_flags() & LOAD_DISABLE_INTERCEPT
||
112 request
->status().status() == URLRequestStatus::CANCELED
) {
116 const URLRequestJobFactory
* job_factory
= NULL
;
117 job_factory
= request
->context()->job_factory();
119 const std::string
& scheme
= request
->url().scheme(); // already lowercase
120 if (!job_factory
->IsHandledProtocol(scheme
))
123 InterceptorList::const_iterator i
;
124 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
125 URLRequestJob
* job
= (*i
)->MaybeInterceptRedirect(request
,
134 URLRequestJob
* URLRequestJobManager::MaybeInterceptResponse(
135 URLRequest
* request
, NetworkDelegate
* network_delegate
) const {
136 DCHECK(IsAllowedThread());
137 if (!request
->url().is_valid() ||
138 request
->load_flags() & LOAD_DISABLE_INTERCEPT
||
139 request
->status().status() == URLRequestStatus::CANCELED
) {
143 const URLRequestJobFactory
* job_factory
= NULL
;
144 job_factory
= request
->context()->job_factory();
146 const std::string
& scheme
= request
->url().scheme(); // already lowercase
147 if (!job_factory
->IsHandledProtocol(scheme
))
150 InterceptorList::const_iterator i
;
151 for (i
= interceptors_
.begin(); i
!= interceptors_
.end(); ++i
) {
152 URLRequestJob
* job
= (*i
)->MaybeInterceptResponse(request
,
161 bool URLRequestJobManager::SupportsScheme(const std::string
& scheme
) {
162 for (size_t i
= 0; i
< arraysize(kBuiltinFactories
); ++i
) {
163 if (LowerCaseEqualsASCII(scheme
, kBuiltinFactories
[i
].scheme
))
170 void URLRequestJobManager::RegisterRequestInterceptor(
171 URLRequest::Interceptor
* interceptor
) {
172 DCHECK(IsAllowedThread());
174 base::AutoLock
locked(lock_
);
176 DCHECK(std::find(interceptors_
.begin(), interceptors_
.end(), interceptor
) ==
177 interceptors_
.end());
178 interceptors_
.push_back(interceptor
);
181 void URLRequestJobManager::UnregisterRequestInterceptor(
182 URLRequest::Interceptor
* interceptor
) {
183 DCHECK(IsAllowedThread());
185 base::AutoLock
locked(lock_
);
187 InterceptorList::iterator i
=
188 std::find(interceptors_
.begin(), interceptors_
.end(), interceptor
);
189 DCHECK(i
!= interceptors_
.end());
190 interceptors_
.erase(i
);
193 URLRequestJobManager::URLRequestJobManager()
194 : allowed_thread_(0),
195 allowed_thread_initialized_(false) {
198 URLRequestJobManager::~URLRequestJobManager() {}