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. 4 5 #include "net/url_request/url_request_job_manager.h" 6 7 #include <algorithm> 8 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" 19 20 namespace net { 21 22 // The built-in set of protocol factories 23 namespace { 24 25 struct SchemeToFactory { 26 const char* scheme; 27 URLRequest::ProtocolFactory* factory; 28 }; 29 30 } // namespace 31 32 static const SchemeToFactory kBuiltinFactories[] = { 33 { "http", URLRequestHttpJob::Factory }, 34 { "https", URLRequestHttpJob::Factory }, 35 36 #if !defined(OS_IOS) 37 { "ws", URLRequestHttpJob::Factory }, 38 { "wss", URLRequestHttpJob::Factory }, 39 #endif // !defined(OS_IOS) 40 }; 41 42 // static 43 URLRequestJobManager* URLRequestJobManager::GetInstance() { 44 return Singleton<URLRequestJobManager>::get(); 45 } 46 47 URLRequestJob* URLRequestJobManager::CreateJob( 48 URLRequest* request, NetworkDelegate* network_delegate) const { 49 DCHECK(IsAllowedThread()); 50 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); 54 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(); 58 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); 63 } 64 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. 68 69 // See if the request should be intercepted. 70 // 71 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); 78 if (job) 79 return job; 80 } 81 } 82 83 URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler( 84 scheme, request, network_delegate); 85 if (job) 86 return job; 87 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! 94 return job; 95 } 96 } 97 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); 103 } 104 105 URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect( 106 URLRequest* request, 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) { 113 return NULL; 114 } 115 116 const URLRequestJobFactory* job_factory = NULL; 117 job_factory = request->context()->job_factory(); 118 119 const std::string& scheme = request->url().scheme(); // already lowercase 120 if (!job_factory->IsHandledProtocol(scheme)) 121 return NULL; 122 123 InterceptorList::const_iterator i; 124 for (i = interceptors_.begin(); i != interceptors_.end(); ++i) { 125 URLRequestJob* job = (*i)->MaybeInterceptRedirect(request, 126 network_delegate, 127 location); 128 if (job) 129 return job; 130 } 131 return NULL; 132 } 133 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) { 140 return NULL; 141 } 142 143 const URLRequestJobFactory* job_factory = NULL; 144 job_factory = request->context()->job_factory(); 145 146 const std::string& scheme = request->url().scheme(); // already lowercase 147 if (!job_factory->IsHandledProtocol(scheme)) 148 return NULL; 149 150 InterceptorList::const_iterator i; 151 for (i = interceptors_.begin(); i != interceptors_.end(); ++i) { 152 URLRequestJob* job = (*i)->MaybeInterceptResponse(request, 153 network_delegate); 154 if (job) 155 return job; 156 } 157 return NULL; 158 } 159 160 // static 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)) 164 return true; 165 } 166 167 return false; 168 } 169 170 void URLRequestJobManager::RegisterRequestInterceptor( 171 URLRequest::Interceptor* interceptor) { 172 DCHECK(IsAllowedThread()); 173 174 base::AutoLock locked(lock_); 175 176 DCHECK(std::find(interceptors_.begin(), interceptors_.end(), interceptor) == 177 interceptors_.end()); 178 interceptors_.push_back(interceptor); 179 } 180 181 void URLRequestJobManager::UnregisterRequestInterceptor( 182 URLRequest::Interceptor* interceptor) { 183 DCHECK(IsAllowedThread()); 184 185 base::AutoLock locked(lock_); 186 187 InterceptorList::iterator i = 188 std::find(interceptors_.begin(), interceptors_.end(), interceptor); 189 DCHECK(i != interceptors_.end()); 190 interceptors_.erase(i); 191 } 192 193 URLRequestJobManager::URLRequestJobManager() 194 : allowed_thread_(0), 195 allowed_thread_initialized_(false) { 196 } 197 198 URLRequestJobManager::~URLRequestJobManager() {} 199 200 } // namespace net 201