2015-07-16 23:40:01 +02:00
|
|
|
// Copyright 2015 The Chromium Embedded Framework Authors.
|
|
|
|
// Portions copyright 2014 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.
|
2012-06-25 23:21:27 +02:00
|
|
|
|
|
|
|
#include "libcef/browser/resource_dispatcher_host_delegate.h"
|
2016-01-06 20:20:54 +01:00
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
2012-06-25 23:21:27 +02:00
|
|
|
#include "libcef/browser/browser_host_impl.h"
|
2013-04-18 19:58:23 +02:00
|
|
|
#include "libcef/browser/origin_whitelist_impl.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "libcef/browser/resource_context.h"
|
2013-09-12 19:44:54 +02:00
|
|
|
#include "libcef/browser/thread_util.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "libcef/common/extensions/extensions_util.h"
|
2013-09-12 19:44:54 +02:00
|
|
|
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "base/guid.h"
|
2016-01-06 20:20:54 +01:00
|
|
|
#include "build/build_config.h"
|
2016-07-20 20:03:38 +02:00
|
|
|
#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "content/public/browser/plugin_service.h"
|
|
|
|
#include "content/public/browser/plugin_service_filter.h"
|
2016-10-21 21:52:29 +02:00
|
|
|
#include "content/public/browser/render_frame_host.h"
|
2013-09-12 19:44:54 +02:00
|
|
|
#include "content/public/browser/resource_request_info.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "content/public/browser/stream_info.h"
|
2013-04-18 19:58:23 +02:00
|
|
|
#include "content/public/common/resource_response.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "content/public/common/webplugininfo.h"
|
|
|
|
#include "extensions/common/constants.h"
|
|
|
|
#include "extensions/common/extension.h"
|
|
|
|
#include "extensions/common/manifest_handlers/mime_types_handler.h"
|
2013-04-18 19:58:23 +02:00
|
|
|
#include "net/http/http_response_headers.h"
|
|
|
|
#include "net/url_request/url_request.h"
|
2012-06-25 23:21:27 +02:00
|
|
|
|
2013-09-12 19:44:54 +02:00
|
|
|
namespace {
|
|
|
|
|
2016-05-25 01:35:43 +02:00
|
|
|
void SendExecuteMimeTypeHandlerEvent(
|
|
|
|
std::unique_ptr<content::StreamInfo> stream,
|
|
|
|
int64_t expected_content_size,
|
|
|
|
const std::string& extension_id,
|
|
|
|
const std::string& view_id,
|
2016-10-21 21:52:29 +02:00
|
|
|
bool embedded,
|
|
|
|
int frame_tree_node_id,
|
|
|
|
int render_process_id,
|
|
|
|
int render_frame_id) {
|
2015-07-16 23:40:01 +02:00
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
2016-10-21 21:52:29 +02:00
|
|
|
content::WebContents* web_contents = nullptr;
|
|
|
|
if (frame_tree_node_id != -1) {
|
|
|
|
web_contents =
|
|
|
|
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
|
|
|
|
} else {
|
|
|
|
web_contents = content::WebContents::FromRenderFrameHost(
|
|
|
|
content::RenderFrameHost::FromID(render_process_id, render_frame_id));
|
|
|
|
}
|
2017-05-09 17:30:48 +02:00
|
|
|
if (!web_contents)
|
|
|
|
return;
|
2016-10-21 21:52:29 +02:00
|
|
|
|
2015-07-16 23:40:01 +02:00
|
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
2016-10-21 21:52:29 +02:00
|
|
|
CefBrowserHostImpl::GetBrowserForContents(web_contents);
|
2015-07-16 23:40:01 +02:00
|
|
|
if (!browser.get())
|
|
|
|
return;
|
|
|
|
|
|
|
|
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
|
|
|
|
|
2016-07-20 20:03:38 +02:00
|
|
|
extensions::StreamsPrivateAPI* streams_private =
|
|
|
|
extensions::StreamsPrivateAPI::Get(browser_context);
|
2015-07-16 23:40:01 +02:00
|
|
|
if (!streams_private)
|
|
|
|
return;
|
|
|
|
|
|
|
|
streams_private->ExecuteMimeTypeHandler(
|
2016-10-21 21:52:29 +02:00
|
|
|
extension_id, std::move(stream), view_id, expected_content_size, embedded,
|
|
|
|
frame_tree_node_id, render_process_id, render_frame_id);
|
2015-07-16 23:40:01 +02:00
|
|
|
}
|
|
|
|
|
2013-09-12 19:44:54 +02:00
|
|
|
} // namespace
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefResourceDispatcherHostDelegate::CefResourceDispatcherHostDelegate() {}
|
2012-06-25 23:21:27 +02:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefResourceDispatcherHostDelegate::~CefResourceDispatcherHostDelegate() {}
|
2012-06-25 23:21:27 +02:00
|
|
|
|
2014-04-30 19:14:40 +02:00
|
|
|
bool CefResourceDispatcherHostDelegate::HandleExternalProtocol(
|
|
|
|
const GURL& url,
|
2016-11-23 21:54:29 +01:00
|
|
|
content::ResourceRequestInfo* info) {
|
2017-05-17 11:29:28 +02:00
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT,
|
2016-11-23 21:54:29 +01:00
|
|
|
base::Bind(base::IgnoreResult(&CefResourceDispatcherHostDelegate::
|
2017-05-17 11:29:28 +02:00
|
|
|
HandleExternalProtocolOnUIThread),
|
|
|
|
base::Unretained(this), url,
|
|
|
|
info->GetWebContentsGetterForRequest()));
|
2012-11-05 21:18:20 +01:00
|
|
|
return false;
|
2012-06-25 23:21:27 +02:00
|
|
|
}
|
2013-04-18 19:58:23 +02:00
|
|
|
|
2015-07-16 23:40:01 +02:00
|
|
|
// Implementation based on
|
|
|
|
// ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream.
|
|
|
|
bool CefResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
|
|
|
|
net::URLRequest* request,
|
2015-08-14 16:41:08 +02:00
|
|
|
const base::FilePath& plugin_path,
|
2015-07-16 23:40:01 +02:00
|
|
|
const std::string& mime_type,
|
|
|
|
GURL* origin,
|
|
|
|
std::string* payload) {
|
|
|
|
if (!extensions::ExtensionsEnabled())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const content::ResourceRequestInfo* info =
|
|
|
|
content::ResourceRequestInfo::ForRequest(request);
|
|
|
|
CefResourceContext* context =
|
|
|
|
static_cast<CefResourceContext*>(info->GetContext());
|
|
|
|
bool profile_is_off_the_record = context->IsOffTheRecord();
|
|
|
|
const scoped_refptr<const extensions::InfoMap> extension_info_map(
|
|
|
|
context->GetExtensionInfoMap());
|
|
|
|
|
|
|
|
std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist();
|
|
|
|
// Go through the white-listed extensions and try to use them to intercept
|
|
|
|
// the URL request.
|
|
|
|
for (const std::string& extension_id : whitelist) {
|
|
|
|
const extensions::Extension* extension =
|
|
|
|
extension_info_map->extensions().GetByID(extension_id);
|
|
|
|
// The white-listed extension may not be installed, so we have to NULL check
|
|
|
|
// |extension|.
|
2017-05-17 11:29:28 +02:00
|
|
|
if (!extension || (profile_is_off_the_record &&
|
|
|
|
!extension_info_map->IsIncognitoEnabled(extension_id))) {
|
2015-07-16 23:40:01 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
|
2015-08-14 16:41:08 +02:00
|
|
|
if (!handler)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If a plugin path is provided then a stream is being intercepted for the
|
|
|
|
// mimeHandlerPrivate API. Otherwise a stream is being intercepted for the
|
|
|
|
// streamsPrivate API.
|
|
|
|
if (!plugin_path.empty()) {
|
|
|
|
if (handler->HasPlugin() && plugin_path == handler->GetPluginPath()) {
|
|
|
|
StreamTargetInfo target_info;
|
|
|
|
*origin =
|
|
|
|
extensions::Extension::GetBaseURLFromExtensionId(extension_id);
|
|
|
|
target_info.extension_id = extension_id;
|
2015-07-16 23:40:01 +02:00
|
|
|
target_info.view_id = base::GenerateGUID();
|
|
|
|
*payload = target_info.view_id;
|
2015-08-14 16:41:08 +02:00
|
|
|
stream_target_info_[request] = target_info;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!handler->HasPlugin() && handler->CanHandleMIMEType(mime_type)) {
|
|
|
|
StreamTargetInfo target_info;
|
|
|
|
*origin =
|
|
|
|
extensions::Extension::GetBaseURLFromExtensionId(extension_id);
|
|
|
|
target_info.extension_id = extension_id;
|
|
|
|
stream_target_info_[request] = target_info;
|
|
|
|
return true;
|
2015-07-16 23:40:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implementation based on
|
|
|
|
// ChromeResourceDispatcherHostDelegate::OnStreamCreated.
|
|
|
|
void CefResourceDispatcherHostDelegate::OnStreamCreated(
|
|
|
|
net::URLRequest* request,
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<content::StreamInfo> stream) {
|
2015-07-16 23:40:01 +02:00
|
|
|
DCHECK(extensions::ExtensionsEnabled());
|
|
|
|
const content::ResourceRequestInfo* info =
|
|
|
|
content::ResourceRequestInfo::ForRequest(request);
|
|
|
|
std::map<net::URLRequest*, StreamTargetInfo>::iterator ix =
|
|
|
|
stream_target_info_.find(request);
|
|
|
|
CHECK(ix != stream_target_info_.end());
|
|
|
|
bool embedded = info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME;
|
2017-05-17 11:29:28 +02:00
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT,
|
2015-07-16 23:40:01 +02:00
|
|
|
base::Bind(&SendExecuteMimeTypeHandlerEvent, base::Passed(&stream),
|
2016-10-21 21:52:29 +02:00
|
|
|
request->GetExpectedContentSize(), ix->second.extension_id,
|
|
|
|
ix->second.view_id, embedded, info->GetFrameTreeNodeId(),
|
|
|
|
info->GetChildID(), info->GetRenderFrameID()));
|
2015-07-16 23:40:01 +02:00
|
|
|
stream_target_info_.erase(request);
|
|
|
|
}
|
|
|
|
|
2013-04-18 19:58:23 +02:00
|
|
|
void CefResourceDispatcherHostDelegate::OnRequestRedirected(
|
|
|
|
const GURL& redirect_url,
|
|
|
|
net::URLRequest* request,
|
|
|
|
content::ResourceContext* resource_context,
|
|
|
|
content::ResourceResponse* response) {
|
|
|
|
const GURL& active_url = request->url();
|
|
|
|
if (active_url.is_valid() && redirect_url.is_valid() &&
|
|
|
|
active_url.GetOrigin() != redirect_url.GetOrigin() &&
|
|
|
|
HasCrossOriginWhitelistEntry(active_url, redirect_url)) {
|
2014-09-27 01:48:19 +02:00
|
|
|
if (!response->head.headers.get())
|
2013-04-18 19:58:23 +02:00
|
|
|
response->head.headers = new net::HttpResponseHeaders(std::string());
|
|
|
|
|
|
|
|
// Add CORS headers to support XMLHttpRequest redirects.
|
2017-05-17 11:29:28 +02:00
|
|
|
response->head.headers->AddHeader(
|
|
|
|
"Access-Control-Allow-Origin: " + active_url.scheme() + "://" +
|
|
|
|
active_url.host());
|
2013-04-18 19:58:23 +02:00
|
|
|
response->head.headers->AddHeader("Access-Control-Allow-Credentials: true");
|
|
|
|
}
|
|
|
|
}
|
2016-07-06 21:34:09 +02:00
|
|
|
|
|
|
|
std::unique_ptr<net::ClientCertStore>
|
2017-05-17 11:29:28 +02:00
|
|
|
CefResourceDispatcherHostDelegate::CreateClientCertStore(
|
|
|
|
content::ResourceContext* resource_context) {
|
|
|
|
return static_cast<CefResourceContext*>(resource_context)
|
|
|
|
->CreateClientCertStore();
|
2016-07-06 21:34:09 +02:00
|
|
|
}
|
2016-11-23 21:54:29 +01:00
|
|
|
|
|
|
|
void CefResourceDispatcherHostDelegate::HandleExternalProtocolOnUIThread(
|
|
|
|
const GURL& url,
|
|
|
|
const content::ResourceRequestInfo::WebContentsGetter&
|
|
|
|
web_contents_getter) {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
content::WebContents* web_contents = web_contents_getter.Run();
|
|
|
|
if (web_contents) {
|
|
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
|
|
|
CefBrowserHostImpl::GetBrowserForContents(web_contents);
|
|
|
|
if (browser.get())
|
|
|
|
browser->HandleExternalProtocol(url);
|
|
|
|
}
|
|
|
|
}
|