Commit 7e10653a authored by sammc's avatar sammc Committed by Commit bot

Serve mojo WebUI resources from the same origin as the WebUI itself.

Currently, mojo resources are served from chrome://mojo and each mojo
WebUI controller replaces the WebUIDataSource for that origin with one
containing the resource it needs on construction. If a WebUI page's
controller (or an equivalent one) was not the last one to be
constructed, any requests for mojo bindings for its mojo interfaces
will fail. This change fixes this problem by serving the mojo resources
from the same origin as the WebUI itself.

BUG=557540

Review URL: https://codereview.chromium.org/1457623004

Cr-Commit-Position: refs/heads/master@{#361275}
parent 5b2aedd6
...@@ -70,13 +70,13 @@ SiteEngagementUI::SiteEngagementUI(content::WebUI* web_ui) ...@@ -70,13 +70,13 @@ SiteEngagementUI::SiteEngagementUI(content::WebUI* web_ui)
source->AddResourcePath("engagement_table.js", source->AddResourcePath("engagement_table.js",
IDR_SITE_ENGAGEMENT_ENGAGEMENT_TABLE_JS); IDR_SITE_ENGAGEMENT_ENGAGEMENT_TABLE_JS);
source->AddResourcePath("site_engagement.js", IDR_SITE_ENGAGEMENT_JS); source->AddResourcePath("site_engagement.js", IDR_SITE_ENGAGEMENT_JS);
source->AddResourcePath(
"chrome/browser/ui/webui/engagement/site_engagement.mojom",
IDR_SITE_ENGAGEMENT_MOJO_JS);
source->AddMojoResources();
source->SetDefaultResource(IDR_SITE_ENGAGEMENT_HTML); source->SetDefaultResource(IDR_SITE_ENGAGEMENT_HTML);
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release()); content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
AddMojoResourcePath(
"chrome/browser/ui/webui/engagement/site_engagement.mojom",
IDR_SITE_ENGAGEMENT_MOJO_JS);
} }
SiteEngagementUI::~SiteEngagementUI() {} SiteEngagementUI::~SiteEngagementUI() {}
......
...@@ -22,12 +22,3 @@ void MojoWebUIControllerBase::RenderViewCreated( ...@@ -22,12 +22,3 @@ void MojoWebUIControllerBase::RenderViewCreated(
content::RenderViewHost* render_view_host) { content::RenderViewHost* render_view_host) {
render_view_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI); render_view_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI);
} }
void MojoWebUIControllerBase::AddMojoResourcePath(const std::string& path,
int resource_id) {
if (!mojo_data_source_) {
mojo_data_source_ = content::WebUIDataSource::AddMojoDataSource(
Profile::FromWebUI(web_ui()));
}
mojo_data_source_->AddResourcePath(path, resource_id);
}
...@@ -30,10 +30,6 @@ class MojoWebUIControllerBase : public content::WebUIController { ...@@ -30,10 +30,6 @@ class MojoWebUIControllerBase : public content::WebUIController {
// WebUIController overrides: // WebUIController overrides:
void RenderViewCreated(content::RenderViewHost* render_view_host) override; void RenderViewCreated(content::RenderViewHost* render_view_host) override;
protected:
// Invoke to register mapping between binding file and resource id (IDR_...).
void AddMojoResourcePath(const std::string& path, int resource_id);
private: private:
// Bindings files are registered here. // Bindings files are registered here.
content::WebUIDataSource* mojo_data_source_; content::WebUIDataSource* mojo_data_source_;
......
...@@ -14,16 +14,16 @@ ...@@ -14,16 +14,16 @@
OmniboxUI::OmniboxUI(content::WebUI* web_ui) : MojoWebUIController(web_ui) { OmniboxUI::OmniboxUI(content::WebUI* web_ui) : MojoWebUIController(web_ui) {
// Set up the chrome://omnibox/ source. // Set up the chrome://omnibox/ source.
content::WebUIDataSource* html_source = content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUIOmniboxHost); content::WebUIDataSource::Create(chrome::kChromeUIOmniboxHost);
html_source->AddResourcePath("omnibox.css", IDR_OMNIBOX_CSS); source->AddResourcePath("omnibox.css", IDR_OMNIBOX_CSS);
html_source->AddResourcePath("omnibox.js", IDR_OMNIBOX_JS); source->AddResourcePath("omnibox.js", IDR_OMNIBOX_JS);
html_source->SetDefaultResource(IDR_OMNIBOX_HTML); source->AddResourcePath("chrome/browser/ui/webui/omnibox/omnibox.mojom",
IDR_OMNIBOX_MOJO_JS);
source->AddMojoResources();
source->SetDefaultResource(IDR_OMNIBOX_HTML);
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source); content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
AddMojoResourcePath("chrome/browser/ui/webui/omnibox/omnibox.mojom",
IDR_OMNIBOX_MOJO_JS);
} }
OmniboxUI::~OmniboxUI() {} OmniboxUI::~OmniboxUI() {}
......
...@@ -23,31 +23,6 @@ WebUIDataSource* WebUIDataSource::Create(const std::string& source_name) { ...@@ -23,31 +23,6 @@ WebUIDataSource* WebUIDataSource::Create(const std::string& source_name) {
return new WebUIDataSourceImpl(source_name); return new WebUIDataSourceImpl(source_name);
} }
// static
WebUIDataSource* WebUIDataSource::AddMojoDataSource(
BrowserContext* browser_context) {
WebUIDataSource* mojo_source = Create("mojo");
static const struct {
const char* path;
int id;
} resources[] = {
{ mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS },
{ mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS },
{ mojo::kCodecModuleName, IDR_MOJO_CODEC_JS },
{ mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS },
{ mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS },
{ mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS },
{ mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS },
{ mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS },
};
for (size_t i = 0; i < arraysize(resources); ++i)
mojo_source->AddResourcePath(resources[i].path, resources[i].id);
URLDataManager::AddWebUIDataSource(browser_context, mojo_source);
return mojo_source;
}
// static // static
void WebUIDataSource::Add(BrowserContext* browser_context, void WebUIDataSource::Add(BrowserContext* browser_context,
WebUIDataSource* source) { WebUIDataSource* source) {
...@@ -161,6 +136,24 @@ void WebUIDataSourceImpl::SetRequestFilter( ...@@ -161,6 +136,24 @@ void WebUIDataSourceImpl::SetRequestFilter(
filter_callback_ = callback; filter_callback_ = callback;
} }
void WebUIDataSourceImpl::AddMojoResources() {
static const struct {
const char* path;
int id;
} resources[] = {
{mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS},
{mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS},
{mojo::kCodecModuleName, IDR_MOJO_CODEC_JS},
{mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS},
{mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS},
{mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS},
{mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS},
{mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS},
};
for (size_t i = 0; i < arraysize(resources); ++i)
AddResourcePath(resources[i].path, resources[i].id);
}
void WebUIDataSourceImpl::DisableReplaceExistingSource() { void WebUIDataSourceImpl::DisableReplaceExistingSource() {
replace_existing_source_ = false; replace_existing_source_ = false;
} }
......
...@@ -38,6 +38,7 @@ class CONTENT_EXPORT WebUIDataSourceImpl ...@@ -38,6 +38,7 @@ class CONTENT_EXPORT WebUIDataSourceImpl
void SetDefaultResource(int resource_id) override; void SetDefaultResource(int resource_id) override;
void SetRequestFilter( void SetRequestFilter(
const WebUIDataSource::HandleRequestCallback& callback) override; const WebUIDataSource::HandleRequestCallback& callback) override;
void AddMojoResources() override;
void DisableReplaceExistingSource() override; void DisableReplaceExistingSource() override;
void DisableContentSecurityPolicy() override; void DisableContentSecurityPolicy() override;
void OverrideContentSecurityPolicyObjectSrc(const std::string& data) override; void OverrideContentSecurityPolicyObjectSrc(const std::string& data) override;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h" #include "content/browser/webui/web_ui_controller_factory_registry.h"
...@@ -52,10 +53,22 @@ bool GetResource(const std::string& id, ...@@ -52,10 +53,22 @@ bool GetResource(const std::string& id,
id == mojo::kValidatorModuleName) id == mojo::kValidatorModuleName)
return false; return false;
if (id.find(".mojom") != std::string::npos) {
std::string contents;
CHECK(base::ReadFileToString(mojo::test::GetFilePathForJSResource(id),
&contents, std::string::npos))
<< id;
base::RefCountedString* ref_contents = new base::RefCountedString;
ref_contents->data() = contents;
callback.Run(ref_contents);
return true;
}
base::FilePath path;
DCHECK(base::PathService::Get(content::DIR_TEST_DATA, &path));
path = path.AppendASCII(id.substr(0, id.find("?")));
std::string contents; std::string contents;
CHECK(base::ReadFileToString(mojo::test::GetFilePathForJSResource(id), CHECK(base::ReadFileToString(path, &contents, std::string::npos)) << id;
&contents,
std::string::npos)) << id;
base::RefCountedString* ref_contents = new base::RefCountedString; base::RefCountedString* ref_contents = new base::RefCountedString;
ref_contents->data() = contents; ref_contents->data() = contents;
callback.Run(ref_contents); callback.Run(ref_contents);
...@@ -90,13 +103,14 @@ class BrowserTargetImpl : public BrowserTarget { ...@@ -90,13 +103,14 @@ class BrowserTargetImpl : public BrowserTarget {
// WebUIController that sets up mojo bindings. // WebUIController that sets up mojo bindings.
class TestWebUIController : public WebUIController { class TestWebUIController : public WebUIController {
public: public:
TestWebUIController(WebUI* web_ui, base::RunLoop* run_loop) TestWebUIController(WebUI* web_ui, base::RunLoop* run_loop)
: WebUIController(web_ui), : WebUIController(web_ui), run_loop_(run_loop) {
run_loop_(run_loop) {
content::WebUIDataSource* data_source = content::WebUIDataSource* data_source =
WebUIDataSource::AddMojoDataSource( WebUIDataSource::Create("mojo-web-ui");
web_ui->GetWebContents()->GetBrowserContext()); data_source->AddMojoResources();
data_source->SetRequestFilter(base::Bind(&GetResource)); data_source->SetRequestFilter(base::Bind(&GetResource));
content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
data_source);
} }
protected: protected:
...@@ -205,7 +219,7 @@ IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) { ...@@ -205,7 +219,7 @@ IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
base::RunLoop run_loop; base::RunLoop run_loop;
factory()->set_run_loop(&run_loop); factory()->set_run_loop(&run_loop);
GURL test_url(embedded_test_server()->GetURL("/web_ui_mojo.html?ping")); GURL test_url("chrome://mojo-web-ui/web_ui_mojo.html?ping");
NavigateToURL(shell(), test_url); NavigateToURL(shell(), test_url);
// RunLoop is quit when message received from page. // RunLoop is quit when message received from page.
run_loop.Run(); run_loop.Run();
...@@ -234,7 +248,7 @@ IN_PROC_BROWSER_TEST_F(WebUIMojoTest, ConnectToApplication) { ...@@ -234,7 +248,7 @@ IN_PROC_BROWSER_TEST_F(WebUIMojoTest, ConnectToApplication) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
NavigateToURL(shell(), NavigateToURL(shell(),
embedded_test_server()->GetURL("/web_ui_mojo_shell_test.html")); GURL("chrome://mojo-web-ui/web_ui_mojo_shell_test.html"));
DOMMessageQueue message_queue; DOMMessageQueue message_queue;
std::string message; std::string message;
......
...@@ -25,12 +25,6 @@ class WebUIDataSource { ...@@ -25,12 +25,6 @@ class WebUIDataSource {
CONTENT_EXPORT static WebUIDataSource* Create(const std::string& source_name); CONTENT_EXPORT static WebUIDataSource* Create(const std::string& source_name);
// Adds the necessary resources for mojo bindings returning the
// WebUIDataSource that handles the resources. Callers do not own the return
// value.
CONTENT_EXPORT static WebUIDataSource* AddMojoDataSource(
BrowserContext* browser_context);
// Adds a WebUI data source to |browser_context|. // Adds a WebUI data source to |browser_context|.
CONTENT_EXPORT static void Add(BrowserContext* browser_context, CONTENT_EXPORT static void Add(BrowserContext* browser_context,
WebUIDataSource* source); WebUIDataSource* source);
...@@ -77,6 +71,9 @@ class WebUIDataSource { ...@@ -77,6 +71,9 @@ class WebUIDataSource {
// Allows a caller to add a filter for URL requests. // Allows a caller to add a filter for URL requests.
virtual void SetRequestFilter(const HandleRequestCallback& callback) = 0; virtual void SetRequestFilter(const HandleRequestCallback& callback) = 0;
// Adds the necessary resources for mojo bindings.
virtual void AddMojoResources() = 0;
// The following map to methods on URLDataSource. See the documentation there. // The following map to methods on URLDataSource. See the documentation there.
// NOTE: it's not acceptable to call DisableContentSecurityPolicy for new // NOTE: it's not acceptable to call DisableContentSecurityPolicy for new
// pages, see URLDataSource::ShouldAddContentSecurityPolicy and talk to // pages, see URLDataSource::ShouldAddContentSecurityPolicy and talk to
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
using v8::Context; using v8::Context;
using v8::HandleScope; using v8::HandleScope;
...@@ -29,10 +30,6 @@ namespace content { ...@@ -29,10 +30,6 @@ namespace content {
namespace { namespace {
// All modules have this prefixed to them when downloading.
// TODO(sky): move this into some common place.
const char kModulePrefix[] = "chrome://mojo/";
void RunMain(base::WeakPtr<gin::Runner> runner, void RunMain(base::WeakPtr<gin::Runner> runner,
v8::Local<v8::Value> module) { v8::Local<v8::Value> module) {
v8::Isolate* isolate = runner->GetContextHolder()->isolate(); v8::Isolate* isolate = runner->GetContextHolder()->isolate();
...@@ -48,7 +45,8 @@ void RunMain(base::WeakPtr<gin::Runner> runner, ...@@ -48,7 +45,8 @@ void RunMain(base::WeakPtr<gin::Runner> runner,
WebUIMojoContextState::WebUIMojoContextState(blink::WebFrame* frame, WebUIMojoContextState::WebUIMojoContextState(blink::WebFrame* frame,
v8::Local<v8::Context> context) v8::Local<v8::Context> context)
: frame_(frame), : frame_(frame),
module_added_(false) { module_added_(false),
module_prefix_(frame_->securityOrigin().toString().utf8() + "/") {
gin::PerContextData* context_data = gin::PerContextData::From(context); gin::PerContextData* context_data = gin::PerContextData::From(context);
gin::ContextHolder* context_holder = context_data->context_holder(); gin::ContextHolder* context_holder = context_data->context_holder();
runner_.reset(new WebUIRunner(frame_, context_holder)); runner_.reset(new WebUIRunner(frame_, context_holder));
...@@ -89,7 +87,7 @@ void WebUIMojoContextState::FetchModules(const std::vector<std::string>& ids) { ...@@ -89,7 +87,7 @@ void WebUIMojoContextState::FetchModules(const std::vector<std::string>& ids) {
} }
void WebUIMojoContextState::FetchModule(const std::string& id) { void WebUIMojoContextState::FetchModule(const std::string& id) {
const GURL url(kModulePrefix + id); const GURL url(module_prefix_ + id);
// TODO(sky): better error checks here? // TODO(sky): better error checks here?
DCHECK(url.is_valid() && !url.is_empty()); DCHECK(url.is_valid() && !url.is_empty());
DCHECK(fetched_modules_.find(id) == fetched_modules_.end()); DCHECK(fetched_modules_.find(id) == fetched_modules_.end());
...@@ -109,10 +107,10 @@ void WebUIMojoContextState::OnFetchModuleComplete( ...@@ -109,10 +107,10 @@ void WebUIMojoContextState::OnFetchModuleComplete(
ResourceFetcher* fetcher, ResourceFetcher* fetcher,
const blink::WebURLResponse& response, const blink::WebURLResponse& response,
const std::string& data) { const std::string& data) {
DCHECK_EQ(kModulePrefix, DCHECK_EQ(module_prefix_,
response.url().string().utf8().substr(0, arraysize(kModulePrefix) - 1)); response.url().string().utf8().substr(0, module_prefix_.size()));
const std::string module = const std::string module =
response.url().string().utf8().substr(arraysize(kModulePrefix) - 1); response.url().string().utf8().substr(module_prefix_.size());
// We can't delete fetch right now as the arguments to this function come from // We can't delete fetch right now as the arguments to this function come from
// it and are used below. Instead use a scope_ptr to cleanup. // it and are used below. Instead use a scope_ptr to cleanup.
scoped_ptr<ResourceFetcher> deleter(fetcher); scoped_ptr<ResourceFetcher> deleter(fetcher);
......
...@@ -77,6 +77,9 @@ class WebUIMojoContextState : public gin::ModuleRegistryObserver { ...@@ -77,6 +77,9 @@ class WebUIMojoContextState : public gin::ModuleRegistryObserver {
// Set of modules we've fetched script from. // Set of modules we've fetched script from.
std::set<std::string> fetched_modules_; std::set<std::string> fetched_modules_;
// The prefix to use for all module requests.
const std::string module_prefix_;
DISALLOW_COPY_AND_ASSIGN(WebUIMojoContextState); DISALLOW_COPY_AND_ASSIGN(WebUIMojoContextState);
}; };
......
...@@ -35,9 +35,8 @@ define('main', [ ...@@ -35,9 +35,8 @@ define('main', [
function (services) { function (services) {
var test = connectToService(services, testMojom.TestMojoService); var test = connectToService(services, testMojom.TestMojoService);
test.getRequestorURL().then(function(response) { test.getRequestorURL().then(function(response) {
// The requestor URL seen by the app should be localhost because the domAutomationController.send(
// connection comes from this script hosted on the test server. response.url == 'chrome://mojo-web-ui/');
domAutomationController.send(response.url == 'http://127.0.0.1/');
}); });
}, },
function (exposedServices) {}); function (exposedServices) {});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment