283 lines
8.5 KiB
C++
283 lines
8.5 KiB
C++
// Copyright (c) 2015 The Chromium Embedded Framework Authors.
|
|
// Portions copyright (c) 2006-2009 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 "libcef/browser/url_request_manager.h"
|
|
|
|
#include "include/cef_browser.h"
|
|
#include "include/cef_scheme.h"
|
|
#include "libcef/browser/browser_context.h"
|
|
#include "libcef/browser/browser_host_impl.h"
|
|
#include "libcef/browser/resource_request_job.h"
|
|
#include "libcef/browser/scheme_handler.h"
|
|
#include "libcef/browser/thread_util.h"
|
|
#include "libcef/common/request_impl.h"
|
|
#include "libcef/common/scheme_registration.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "net/url_request/url_request.h"
|
|
#include "net/url_request/url_request_context.h"
|
|
#include "net/url_request/url_request_filter.h"
|
|
#include "net/url_request/url_request_http_job.h"
|
|
#include "net/url_request/url_request_job.h"
|
|
#include "net/url_request/url_request_job_factory_impl.h"
|
|
#include "url/third_party/mozilla/url_parse.h"
|
|
#include "url/url_util.h"
|
|
|
|
using net::URLRequestStatus;
|
|
|
|
namespace {
|
|
|
|
bool IsStandardScheme(const std::string& scheme) {
|
|
url::Component scheme_comp(0, scheme.length());
|
|
return url::IsStandard(scheme.c_str(), scheme_comp);
|
|
}
|
|
|
|
// Copied from net/url_request/url_request_job_manager.cc.
|
|
struct SchemeToFactory {
|
|
const char* scheme;
|
|
net::URLRequest::ProtocolFactory* factory;
|
|
};
|
|
static const SchemeToFactory kBuiltinFactories[] = {
|
|
{ "http", net::URLRequestHttpJob::Factory },
|
|
{ "https", net::URLRequestHttpJob::Factory },
|
|
};
|
|
|
|
bool IsBuiltinScheme(const std::string& scheme) {
|
|
for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i)
|
|
if (base::LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
net::URLRequestJob* GetBuiltinSchemeRequestJob(
|
|
net::URLRequest* request,
|
|
net::NetworkDelegate* network_delegate,
|
|
const std::string& scheme) {
|
|
// 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) {
|
|
net::URLRequestJob* job =
|
|
(kBuiltinFactories[i].factory)(request, network_delegate, scheme);
|
|
DCHECK(job); // The built-in factories are not expected to fail!
|
|
return job;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
std::string ToLower(const std::string& str) {
|
|
std::string str_lower = str;
|
|
std::transform(str_lower.begin(), str_lower.end(), str_lower.begin(),
|
|
towlower);
|
|
return str;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Class used for creating URLRequestJob instances. The lifespan of this object
|
|
// is managed by URLRequestJobFactory.
|
|
class CefProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
|
|
public:
|
|
CefProtocolHandler(CefURLRequestManager* request_manager,
|
|
const std::string& scheme)
|
|
: request_manager_(request_manager),
|
|
scheme_(scheme) {}
|
|
|
|
// From net::URLRequestJobFactory::ProtocolHandler
|
|
net::URLRequestJob* MaybeCreateJob(
|
|
net::URLRequest* request,
|
|
net::NetworkDelegate* network_delegate) const override {
|
|
CEF_REQUIRE_IOT();
|
|
return request_manager_->GetRequestJob(request, network_delegate, scheme_);
|
|
}
|
|
|
|
private:
|
|
CefURLRequestManager* request_manager_;
|
|
std::string scheme_;
|
|
};
|
|
|
|
|
|
CefURLRequestManager::CefURLRequestManager(
|
|
net::URLRequestJobFactoryImpl* job_factory)
|
|
: job_factory_(job_factory) {
|
|
CEF_REQUIRE_IOT();
|
|
DCHECK(job_factory_);
|
|
}
|
|
|
|
CefURLRequestManager::~CefURLRequestManager() {
|
|
CEF_REQUIRE_IOT();
|
|
}
|
|
|
|
bool CefURLRequestManager::AddFactory(
|
|
const std::string& scheme,
|
|
const std::string& domain,
|
|
CefRefPtr<CefSchemeHandlerFactory> factory) {
|
|
if (!factory.get()) {
|
|
RemoveFactory(scheme, domain);
|
|
return true;
|
|
}
|
|
|
|
CEF_REQUIRE_IOT();
|
|
|
|
std::string scheme_lower = ToLower(scheme);
|
|
std::string domain_lower = ToLower(domain);
|
|
|
|
// Hostname is only supported for standard schemes.
|
|
if (!IsStandardScheme(scheme_lower))
|
|
domain_lower.clear();
|
|
|
|
SetProtocolHandlerIfNecessary(scheme_lower, true);
|
|
|
|
handler_map_[make_pair(scheme_lower, domain_lower)] = factory;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CefURLRequestManager::RemoveFactory(const std::string& scheme,
|
|
const std::string& domain) {
|
|
CEF_REQUIRE_IOT();
|
|
|
|
std::string scheme_lower = ToLower(scheme);
|
|
std::string domain_lower = ToLower(domain);
|
|
|
|
// Hostname is only supported for standard schemes.
|
|
if (!IsStandardScheme(scheme_lower))
|
|
domain_lower.clear();
|
|
|
|
HandlerMap::iterator iter =
|
|
handler_map_.find(make_pair(scheme_lower, domain_lower));
|
|
if (iter != handler_map_.end()) {
|
|
handler_map_.erase(iter);
|
|
|
|
SetProtocolHandlerIfNecessary(scheme_lower, false);
|
|
}
|
|
}
|
|
|
|
// Clear all the existing URL handlers and unregister the ProtocolFactory.
|
|
void CefURLRequestManager::ClearFactories() {
|
|
CEF_REQUIRE_IOT();
|
|
|
|
// Create a unique set of scheme names.
|
|
std::set<std::string> schemes;
|
|
for (HandlerMap::const_iterator i = handler_map_.begin();
|
|
i != handler_map_.end(); ++i) {
|
|
schemes.insert(i->first.first);
|
|
}
|
|
|
|
for (std::set<std::string>::const_iterator scheme = schemes.begin();
|
|
scheme != schemes.end(); ++scheme) {
|
|
const std::string& scheme_name = *scheme;
|
|
if (!scheme::IsInternalProtectedScheme(scheme_name)) {
|
|
bool set_protocol = job_factory_->SetProtocolHandler(scheme_name, NULL);
|
|
DCHECK(set_protocol);
|
|
}
|
|
}
|
|
|
|
handler_map_.clear();
|
|
|
|
// Re-register internal scheme handlers that can be overridden.
|
|
scheme::RegisterInternalHandlers(this);
|
|
}
|
|
|
|
// Helper for chaining ProtocolHandler implementations.
|
|
net::URLRequestJob* CefURLRequestManager::GetRequestJob(
|
|
net::URLRequest* request,
|
|
net::NetworkDelegate* network_delegate) {
|
|
CEF_REQUIRE_IOT();
|
|
return GetRequestJob(request, network_delegate, request->url().scheme());
|
|
}
|
|
|
|
void CefURLRequestManager::SetProtocolHandlerIfNecessary(
|
|
const std::string& scheme,
|
|
bool add) {
|
|
// Don't modify a protocol handler for internal protected schemes or if the
|
|
// protocol handler is still needed by other registered factories.
|
|
if (scheme::IsInternalProtectedScheme(scheme) || HasFactory(scheme))
|
|
return;
|
|
|
|
bool set_protocol = job_factory_->SetProtocolHandler(
|
|
scheme,
|
|
make_scoped_ptr(add ? new CefProtocolHandler(this, scheme) : NULL));
|
|
DCHECK(set_protocol);
|
|
}
|
|
|
|
bool CefURLRequestManager::HasFactory(const std::string& scheme) {
|
|
if (handler_map_.empty())
|
|
return false;
|
|
|
|
for (HandlerMap::const_iterator i = handler_map_.begin();
|
|
i != handler_map_.end(); ++i) {
|
|
if (scheme == i->first.first)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CefRefPtr<CefSchemeHandlerFactory> CefURLRequestManager::GetHandlerFactory(
|
|
net::URLRequest* request,
|
|
const std::string& scheme) {
|
|
CefRefPtr<CefSchemeHandlerFactory> factory;
|
|
|
|
if (request->url().is_valid() && IsStandardScheme(scheme)) {
|
|
// Check for a match with a domain first.
|
|
const std::string& domain = request->url().host();
|
|
|
|
HandlerMap::iterator i = handler_map_.find(make_pair(scheme, domain));
|
|
if (i != handler_map_.end())
|
|
factory = i->second;
|
|
}
|
|
|
|
if (!factory.get()) {
|
|
// Check for a match with no specified domain.
|
|
HandlerMap::iterator i =
|
|
handler_map_.find(make_pair(scheme, std::string()));
|
|
if (i != handler_map_.end())
|
|
factory = i->second;
|
|
}
|
|
|
|
return factory;
|
|
}
|
|
|
|
net::URLRequestJob* CefURLRequestManager::GetRequestJob(
|
|
net::URLRequest* request,
|
|
net::NetworkDelegate* network_delegate,
|
|
const std::string& scheme) {
|
|
net::URLRequestJob* job = NULL;
|
|
CefRefPtr<CefSchemeHandlerFactory> factory =
|
|
GetHandlerFactory(request, scheme);
|
|
if (factory.get()) {
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
|
CefBrowserHostImpl::GetBrowserForRequest(request);
|
|
CefRefPtr<CefFrame> frame;
|
|
if (browser.get())
|
|
frame = browser->GetFrameForRequest(request);
|
|
|
|
// Populate the request data.
|
|
CefRefPtr<CefRequestImpl> requestPtr(new CefRequestImpl());
|
|
requestPtr->Set(request);
|
|
|
|
// Call the handler factory to create the handler for the request.
|
|
CefRefPtr<CefResourceHandler> handler =
|
|
factory->Create(browser.get(), frame, scheme, requestPtr.get());
|
|
if (handler.get())
|
|
job = new CefResourceRequestJob(request, network_delegate, handler);
|
|
}
|
|
|
|
if (!job && IsBuiltinScheme(scheme)) {
|
|
// Give the built-in scheme handler a chance to handle the request.
|
|
job = GetBuiltinSchemeRequestJob(request, network_delegate, scheme);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if (job)
|
|
DLOG(INFO) << "CefURLRequestManager hit for " << request->url().spec();
|
|
#endif
|
|
|
|
return job;
|
|
}
|