| // Copyright (c) 2012 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_manager.h" |
| |
| #include <algorithm> |
| |
| #include "base/memory/singleton.h" |
| #include "base/strings/string_util.h" |
| #include "build/build_config.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/network_delegate.h" |
| #include "net/net_buildflags.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_error_job.h" |
| #include "net/url_request/url_request_http_job.h" |
| #include "net/url_request/url_request_job_factory.h" |
| |
| namespace net { |
| |
| // The built-in set of protocol factories |
| namespace { |
| |
| struct SchemeToFactory { |
| const char* scheme; |
| URLRequest::ProtocolFactory* factory; |
| }; |
| |
| } // namespace |
| |
| static const SchemeToFactory kBuiltinFactories[] = { |
| {"http", URLRequestHttpJob::Factory}, |
| {"https", URLRequestHttpJob::Factory}, |
| |
| #if BUILDFLAG(ENABLE_WEBSOCKETS) |
| {"ws", URLRequestHttpJob::Factory}, |
| {"wss", URLRequestHttpJob::Factory}, |
| #endif // BUILDFLAG(ENABLE_WEBSOCKETS) |
| }; |
| |
| // static |
| URLRequestJobManager* URLRequestJobManager::GetInstance() { |
| return base::Singleton<URLRequestJobManager>::get(); |
| } |
| |
| URLRequestJob* URLRequestJobManager::CreateJob( |
| URLRequest* request, NetworkDelegate* network_delegate) const { |
| DCHECK(IsAllowedThread()); |
| |
| // If we are given an invalid URL, then don't even try to inspect the scheme. |
| if (!request->url().is_valid()) |
| return new URLRequestErrorJob(request, network_delegate, ERR_INVALID_URL); |
| |
| // We do this here to avoid asking interceptors about unsupported schemes. |
| const URLRequestJobFactory* job_factory = |
| request->context()->job_factory(); |
| |
| const std::string& scheme = request->url().scheme(); // already lowercase |
| if (!job_factory->IsHandledProtocol(scheme)) { |
| return new URLRequestErrorJob( |
| request, network_delegate, 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. |
| // |
| URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler( |
| scheme, request, network_delegate); |
| if (job) |
| return job; |
| |
| // See if the request should be handled by a built-in protocol factory. |
| for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) { |
| if (scheme == kBuiltinFactories[i].scheme) { |
| URLRequestJob* new_job = |
| (kBuiltinFactories[i].factory)(request, network_delegate, scheme); |
| DCHECK(new_job); // The built-in factories are not expected to fail! |
| return new_job; |
| } |
| } |
| |
| // If we reached here, then it means that a registered protocol factory |
| // wasn't interested in handling the URL. That is fairly unexpected, and we |
| // don't have a specific error to report here :-( |
| LOG(WARNING) << "Failed to map: " << request->url().spec(); |
| return new URLRequestErrorJob(request, network_delegate, ERR_FAILED); |
| } |
| |
| URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect( |
| URLRequest* request, |
| NetworkDelegate* network_delegate, |
| const GURL& location) const { |
| DCHECK(IsAllowedThread()); |
| if (!request->url().is_valid() || |
| request->status().status() == URLRequestStatus::CANCELED) { |
| return NULL; |
| } |
| |
| const URLRequestJobFactory* job_factory = NULL; |
| job_factory = request->context()->job_factory(); |
| |
| const std::string& scheme = request->url().scheme(); // already lowercase |
| if (!job_factory->IsHandledProtocol(scheme)) |
| return NULL; |
| |
| URLRequestJob* job = |
| request->context()->job_factory()->MaybeInterceptRedirect( |
| request, network_delegate, location); |
| if (job) |
| return job; |
| |
| return NULL; |
| } |
| |
| URLRequestJob* URLRequestJobManager::MaybeInterceptResponse( |
| URLRequest* request, NetworkDelegate* network_delegate) const { |
| DCHECK(IsAllowedThread()); |
| if (!request->url().is_valid() || |
| request->status().status() == URLRequestStatus::CANCELED) { |
| return NULL; |
| } |
| |
| const URLRequestJobFactory* job_factory = NULL; |
| job_factory = request->context()->job_factory(); |
| |
| const std::string& scheme = request->url().scheme(); // already lowercase |
| if (!job_factory->IsHandledProtocol(scheme)) |
| return NULL; |
| |
| URLRequestJob* job = |
| request->context()->job_factory()->MaybeInterceptResponse( |
| request, network_delegate); |
| if (job) |
| return job; |
| |
| return NULL; |
| } |
| |
| // static |
| bool URLRequestJobManager::SupportsScheme(const std::string& scheme) { |
| for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) { |
| if (base::LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| URLRequestJobManager::URLRequestJobManager() = default; |
| |
| URLRequestJobManager::~URLRequestJobManager() = default; |
| |
| } // namespace net |