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 20namespace net { 21 22// The built-in set of protocol factories 23namespace { 24 25struct SchemeToFactory { 26 const char* scheme; 27 URLRequest::ProtocolFactory* factory; 28}; 29 30} // namespace 31 32static 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 43URLRequestJobManager* URLRequestJobManager::GetInstance() { 44 return Singleton<URLRequestJobManager>::get(); 45} 46 47URLRequestJob* 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 105URLRequestJob* 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 134URLRequestJob* 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 161bool 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 170void 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 181void 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 193URLRequestJobManager::URLRequestJobManager() 194 : allowed_thread_(0), 195 allowed_thread_initialized_(false) { 196} 197 198URLRequestJobManager::~URLRequestJobManager() {} 199 200} // namespace net 201