Commit 7e1d7454 authored by mek's avatar mek Committed by Commit bot

Respect the clipboardRead and clipboardWrite permissions in content scripts.

Added an extra "effective extension" property to ScriptContext for this to still work correctly in about:blank iframes inside extension pages.

BUG=395376

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

Cr-Commit-Position: refs/heads/master@{#293818}
parent 1ce8e56e
......@@ -23,13 +23,11 @@
#include "content/public/browser/render_process_host.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/api/messaging/message.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/file_util.h"
#include "extensions/common/message_bundle.h"
using content::BrowserThread;
using extensions::APIPermission;
namespace {
......@@ -88,10 +86,6 @@ bool ChromeExtensionMessageFilter::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ChromeExtensionMessageFilter, message)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardRead,
OnCanTriggerClipboardRead)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardWrite,
OnCanTriggerClipboardWrite)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension,
OnOpenChannelToExtension)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab)
......@@ -133,21 +127,6 @@ void ChromeExtensionMessageFilter::OnDestruct() const {
}
}
void ChromeExtensionMessageFilter::OnCanTriggerClipboardRead(
const GURL& origin, bool* allowed) {
*allowed = extension_info_map_->SecurityOriginHasAPIPermission(
origin, render_process_id_, APIPermission::kClipboardRead);
}
void ChromeExtensionMessageFilter::OnCanTriggerClipboardWrite(
const GURL& origin, bool* allowed) {
// Since all extensions could historically write to the clipboard, preserve it
// for compatibility.
*allowed = (origin.SchemeIs(extensions::kExtensionScheme) ||
extension_info_map_->SecurityOriginHasAPIPermission(
origin, render_process_id_, APIPermission::kClipboardWrite));
}
void ChromeExtensionMessageFilter::OnOpenChannelToExtension(
int routing_id,
const ExtensionMsg_ExternalConnectionInfo& info,
......
......@@ -47,9 +47,6 @@ class ChromeExtensionMessageFilter : public content::BrowserMessageFilter,
virtual ~ChromeExtensionMessageFilter();
void OnCanTriggerClipboardRead(const GURL& origin, bool* allowed);
void OnCanTriggerClipboardWrite(const GURL& origin, bool* allowed);
// TODO(jamescook): Move these functions into the extensions module. Ideally
// this would be in extensions::ExtensionMessageFilter but that will require
// resolving the MessageService and ActivityLog dependencies on src/chrome.
......
......@@ -71,14 +71,6 @@ IPC_MESSAGE_ROUTED4(ExtensionMsg_InlineWebstoreInstallResponse,
// Messages sent from the renderer to the browser.
// Sent by the renderer to check if a URL has permission to trigger a clipboard
// read/write operation from the DOM.
IPC_SYNC_MESSAGE_CONTROL1_1(ChromeViewHostMsg_CanTriggerClipboardRead,
GURL /* origin */,
bool /* allowed */)
IPC_SYNC_MESSAGE_CONTROL1_1(ChromeViewHostMsg_CanTriggerClipboardWrite,
GURL /* origin */,
bool /* allowed */)
// Sent by the renderer to implement chrome.webstore.install().
IPC_MESSAGE_ROUTED5(ExtensionHostMsg_InlineWebstoreInstall,
......
......@@ -26,6 +26,8 @@
#include "chrome/common/extensions/chrome_extension_messages.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/renderer/dispatcher.h"
#endif
......@@ -410,10 +412,15 @@ bool ContentSettingsObserver::allowStorage(bool local) {
bool ContentSettingsObserver::allowReadFromClipboard(bool default_value) {
bool allowed = false;
#if defined(ENABLE_EXTENSIONS)
WebFrame* frame = render_frame()->GetWebFrame();
// TODO(dcheng): Should we consider a toURL() method on WebSecurityOrigin?
Send(new ChromeViewHostMsg_CanTriggerClipboardRead(
GURL(frame->document().securityOrigin().toString()), &allowed));
extensions::ScriptContext* calling_context =
extension_dispatcher_->script_context_set().GetCalling();
if (calling_context) {
const extensions::Extension* extension =
calling_context->effective_extension();
allowed = extension &&
extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kClipboardRead);
}
#endif
return allowed;
}
......@@ -421,9 +428,22 @@ bool ContentSettingsObserver::allowReadFromClipboard(bool default_value) {
bool ContentSettingsObserver::allowWriteToClipboard(bool default_value) {
bool allowed = false;
#if defined(ENABLE_EXTENSIONS)
WebFrame* frame = render_frame()->GetWebFrame();
Send(new ChromeViewHostMsg_CanTriggerClipboardWrite(
GURL(frame->document().securityOrigin().toString()), &allowed));
// All blessed extension pages could historically write to the clipboard, so
// preserve that for compatibility.
extensions::ScriptContext* calling_context =
extension_dispatcher_->script_context_set().GetCalling();
if (calling_context) {
if (calling_context->effective_context_type() ==
extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
allowed = true;
} else {
const extensions::Extension* extension =
calling_context->effective_extension();
allowed = extension &&
extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kClipboardWrite);
}
}
#endif
return allowed;
}
......
......@@ -111,7 +111,6 @@ class ContentSettingsObserver
// Otherwise returns NULL.
const extensions::Extension* GetExtension(
const blink::WebSecurityOrigin& origin) const;
#endif
// Helpers.
......
......@@ -63,9 +63,16 @@ ChromeExtensionsDispatcherDelegate::CreateScriptContext(
const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* frame,
const extensions::Extension* extension,
extensions::Feature::Context context_type) {
return scoped_ptr<extensions::ScriptContext>(new extensions::ChromeV8Context(
v8_context, frame, extension, context_type));
extensions::Feature::Context context_type,
const extensions::Extension* effective_extension,
extensions::Feature::Context effective_context_type) {
return scoped_ptr<extensions::ScriptContext>(
new extensions::ChromeV8Context(v8_context,
frame,
extension,
context_type,
effective_extension,
effective_context_type));
}
void ChromeExtensionsDispatcherDelegate::InitOriginPermissions(
......
......@@ -21,7 +21,9 @@ class ChromeExtensionsDispatcherDelegate
const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* frame,
const extensions::Extension* extension,
extensions::Feature::Context context_type) OVERRIDE;
extensions::Feature::Context context_type,
const extensions::Extension* effective_extension,
extensions::Feature::Context effective_context_type) OVERRIDE;
virtual void InitOriginPermissions(const extensions::Extension* extension,
bool is_extension_active) OVERRIDE;
virtual void RegisterNativeHandlers(
......
......@@ -9,8 +9,15 @@ namespace extensions {
ChromeV8Context::ChromeV8Context(const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* web_frame,
const Extension* extension,
Feature::Context context_type)
: ScriptContext(v8_context, web_frame, extension, context_type) {
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type)
: ScriptContext(v8_context,
web_frame,
extension,
context_type,
effective_extension,
effective_context_type) {
}
} // namespace extensions
......@@ -34,7 +34,9 @@ class ChromeV8Context : public ScriptContext {
ChromeV8Context(const v8::Handle<v8::Context>& context,
blink::WebFrame* frame,
const Extension* extension,
Feature::Context context_type);
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type);
private:
DISALLOW_COPY_AND_ASSIGN(ChromeV8Context);
......
// 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.
// TODO(kalman): Consolidate this test script with the other clipboard tests.
function appendTextarea() {
return document.body.appendChild(document.createElement('textarea'));
}
function run() {
var textIn = appendTextarea();
textIn.focus();
textIn.value = 'foobar';
textIn.selectionStart = 0;
textIn.selectionEnd = 'foobar'.length;
if (!document.execCommand('copy'))
return 'Failed to copy';
var textOut = appendTextarea();
textOut.focus();
if (!document.execCommand('paste'))
return 'Failed to paste';
if (textOut.value != 'foobar')
return 'Expected "foobar", got ' + textOut.value;
return '';
}
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
sendResponse(run());
});
......@@ -6,5 +6,11 @@
"background": {
"page": "test.html"
},
"permissions": ["clipboardRead"]
"permissions": ["clipboardRead", "clipboardWrite", "http://localhost/*"],
"content_scripts": [
{
"matches": ["http://*/*test_file_with_body.html"],
"js": ["content_script.js"]
}
]
}
......@@ -5,33 +5,35 @@
// Clipboard permission test for Chrome.
// browser_tests.exe --gtest_filter=ClipboardApiTest.Extension
chrome.test.runTests([
function domCopy() {
if (document.execCommand('copy'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("copy") failed');
},
function domPaste() {
if (document.execCommand('paste'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("paste") failed');
},
function copyInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'copy';
ifr.contentDocument.write('<script src="iframe.js"></script>');
},
function pasteInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'paste';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
]);
// TODO(kalman): Consolidate this test script with the other clipboard tests.
function testDomCopy() {
if (document.execCommand('copy'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("copy") failed');
}
function testDomPaste() {
if (document.execCommand('paste'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("paste") failed');
}
function testCopyInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'copy';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
function testPasteInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'paste';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
function testDone(result) {
if (result)
......@@ -39,3 +41,66 @@ function testDone(result) {
else
chrome.test.fail();
}
function testExecuteScriptCopyPaste(baseUrl) {
var tabUrl = baseUrl + '/test_file.html';
function runScript(tabId) {
chrome.tabs.executeScript(tabId, {file: 'content_script.js'},
chrome.test.callbackPass(function() {
chrome.tabs.sendMessage(tabId, "run",
chrome.test.callbackPass(function(result) {
chrome.tabs.remove(tabId);
chrome.test.assertEq('', result);
}));
}));
}
chrome.tabs.create({url: tabUrl}, chrome.test.callbackPass(function(newTab) {
var done = chrome.test.listenForever(chrome.tabs.onUpdated,
function(_, info, updatedTab) {
if (updatedTab.id == newTab.id && info.status == 'complete') {
runScript(newTab.id);
done();
}
});
}));
}
function testContentScriptCopyPaste(baseUrl) {
var tabUrl = baseUrl + '/test_file_with_body.html';
function runScript(tabId) {
chrome.tabs.sendMessage(tabId, "run",
chrome.test.callbackPass(function(result) {
chrome.tabs.remove(tabId);
chrome.test.assertEq('', result);
}));
}
chrome.tabs.create({url: tabUrl}, chrome.test.callbackPass(function(newTab) {
var done = chrome.test.listenForever(chrome.tabs.onUpdated,
function(_, info, updatedTab) {
if (updatedTab.id == newTab.id && info.status == 'complete') {
runScript(newTab.id);
done();
}
});
}));
}
function bindTest(test, param) {
var result = test.bind(null, param);
result.generatedName = test.name;
return result;
}
chrome.test.getConfig(function(config) {
var baseUrl = 'http://localhost:' + config.testServer.port + '/extensions';
chrome.test.runTests([
testDomCopy,
testDomPaste,
testCopyInIframe,
testPasteInIframe,
bindTest(testExecuteScriptCopyPaste, baseUrl),
bindTest(testContentScriptCopyPaste, baseUrl)
]);
})
// 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.
// TODO(kalman): Consolidate this test script with the other clipboard tests.
function appendTextarea() {
return document.body.appendChild(document.createElement('textarea'));
}
function run() {
var textIn = appendTextarea();
textIn.focus();
textIn.value = 'foobar';
textIn.selectionStart = 0;
textIn.selectionEnd = 'foobar'.length;
if (document.execCommand('copy'))
return 'Succeeded to copy';
var textOut = appendTextarea();
textOut.focus();
if (document.execCommand('paste'))
return 'Succeeded to paste';
if (textOut.value == 'foobar')
return 'Successfully copied/pasted despite execCommand failures';
return '';
}
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
sendResponse(run());
});
......@@ -5,5 +5,12 @@
"description": "end-to-end browser test for clipboard permissions",
"background": {
"page": "test.html"
}
},
"permissions": ["http://localhost/*"],
"content_scripts": [
{
"matches": ["http://*/*test_file_with_body.html"],
"js": ["content_script.js"]
}
]
}
......@@ -5,32 +5,37 @@
// Clipboard permission test for Chrome.
// browser_tests.exe --gtest_filter=ClipboardApiTest.ExtensionNoPermission
chrome.test.runTests([
function domCopy() {
if (document.execCommand('copy'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("copy") failed');
},
function domPaste() {
if (!document.execCommand('paste'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("paste") succeeded');
},
function copyInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'copy';
ifr.contentDocument.write('<script src="iframe.js"></script>');
},
function pasteInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'paste';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
]);
// TODO(kalman): Consolidate this test script with the other clipboard tests.
var pass = chrome.test.callbackPass;
function testDomCopy() {
if (document.execCommand('copy'))
chrome.test.succeed();
else
chrome.test.fail('execCommand("copy") failed');
}
function testDomPaste() {
if (document.execCommand('paste'))
chrome.test.fail('execCommand("paste") succeeded');
else
chrome.test.succeed();
}
function testCopyInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'copy';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
function testPasteInIframe() {
var ifr = document.createElement('iframe');
document.body.appendChild(ifr);
window.command = 'paste';
ifr.contentDocument.write('<script src="iframe.js"></script>');
}
function testDone(result) {
// 'copy' should always succeed regardless of the clipboardWrite permission,
......@@ -42,3 +47,66 @@ function testDone(result) {
else
chrome.test.fail();
}
function testExecuteScriptCopyPaste(baseUrl) {
var tabUrl = baseUrl + '/test_file.html';
function runScript(tabId) {
chrome.tabs.executeScript(tabId, {file: 'content_script.js'},
chrome.test.callbackPass(function() {
chrome.tabs.sendMessage(tabId, "run",
chrome.test.callbackPass(function(result) {
chrome.tabs.remove(tabId);
chrome.test.assertEq('', result);
}));
}));
}
chrome.tabs.create({url: tabUrl}, pass(function(newTab) {
var done = chrome.test.listenForever(chrome.tabs.onUpdated,
function(_, info, updatedTab) {
if (updatedTab.id == newTab.id && info.status == 'complete') {
runScript(newTab.id);
done();
}
});
}));
}
function testContentScriptCopyPaste(baseUrl) {
var tabUrl = baseUrl + '/test_file_with_body.html';
function runScript(tabId) {
chrome.tabs.sendMessage(tabId, "run",
chrome.test.callbackPass(function(result) {
chrome.tabs.remove(tabId);
chrome.test.assertEq('', result);
}));
}
chrome.tabs.create({url: tabUrl}, chrome.test.callbackPass(function(newTab) {
var done = chrome.test.listenForever(chrome.tabs.onUpdated,
function(_, info, updatedTab) {
if (updatedTab.id == newTab.id && info.status == 'complete') {
runScript(newTab.id);
done();
}
});
}));
}
function bindTest(test, param) {
var result = test.bind(null, param);
result.generatedName = test.name;
return result;
}
chrome.test.getConfig(function(config) {
var baseUrl = 'http://localhost:' + config.testServer.port + '/extensions';
chrome.test.runTests([
testDomCopy,
testDomPaste,
testCopyInIframe,
testPasteInIframe,
bindTest(testExecuteScriptCopyPaste, baseUrl),
bindTest(testContentScriptCopyPaste, baseUrl)
]);
});
......@@ -19,9 +19,15 @@ scoped_ptr<ScriptContext> DefaultDispatcherDelegate::CreateScriptContext(
const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* frame,
const Extension* extension,
Feature::Context context_type) {
return make_scoped_ptr(
new ScriptContext(v8_context, frame, extension, context_type));
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type) {
return make_scoped_ptr(new ScriptContext(v8_context,
frame,
extension,
context_type,
effective_extension,
effective_context_type));
}
} // namespace extensions
......@@ -19,7 +19,9 @@ class DefaultDispatcherDelegate : public DispatcherDelegate {
const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* frame,
const Extension* extension,
Feature::Context context_type) OVERRIDE;
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type) OVERRIDE;
};
} // namespace extensions
......
......@@ -220,32 +220,24 @@ bool Dispatcher::IsExtensionActive(const std::string& extension_id) const {
return is_active;
}
std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
const Extension* Dispatcher::GetExtensionFromFrameAndWorld(
const WebFrame* frame,
int world_id,
bool use_effective_url) {
std::string extension_id;
if (world_id != 0) {
// Isolated worlds (content script).
return ScriptInjection::GetExtensionIdForIsolatedWorld(world_id);
extension_id = ScriptInjection::GetExtensionIdForIsolatedWorld(world_id);
} else if (!frame->document().securityOrigin().isUnique()) {
// TODO(kalman): Delete the above check.
// Extension pages (chrome-extension:// URLs).
GURL frame_url = ScriptContext::GetDataSourceURLForFrame(frame);
frame_url = ScriptContext::GetEffectiveDocumentURL(
frame, frame_url, use_effective_url);
extension_id = extensions_.GetExtensionOrAppIDByURL(frame_url);
}
// TODO(kalman): Delete this check.
if (frame->document().securityOrigin().isUnique())
return std::string();
// Extension pages (chrome-extension:// URLs).
GURL frame_url = ScriptContext::GetDataSourceURLForFrame(frame);
return extensions_.GetExtensionOrAppIDByURL(frame_url);
}
void Dispatcher::DidCreateScriptContext(
WebFrame* frame,
const v8::Handle<v8::Context>& v8_context,
int extension_group,
int world_id) {
#if !defined(ENABLE_EXTENSIONS)
return;
#endif
std::string extension_id = GetExtensionID(frame, world_id);
const Extension* extension = extensions_.GetByID(extension_id);
if (!extension && !extension_id.empty()) {
// There are conditions where despite a context being associated with an
......@@ -257,19 +249,43 @@ void Dispatcher::DidCreateScriptContext(
RenderThread::Get()->RecordAction(
UserMetricsAction("ExtensionNotFound_ED"));
}
extension_id = "";
}
return extension;
}
void Dispatcher::DidCreateScriptContext(
WebFrame* frame,
const v8::Handle<v8::Context>& v8_context,
int extension_group,
int world_id) {
#if !defined(ENABLE_EXTENSIONS)
return;
#endif
const Extension* extension =
GetExtensionFromFrameAndWorld(frame, world_id, false);
const Extension* effective_extension =
GetExtensionFromFrameAndWorld(frame, world_id, true);
GURL frame_url = ScriptContext::GetDataSourceURLForFrame(frame);
Feature::Context context_type =
ClassifyJavaScriptContext(extension,
extension_group,
ScriptContext::GetDataSourceURLForFrame(frame),
frame_url,
frame->document().securityOrigin());
Feature::Context effective_context_type = ClassifyJavaScriptContext(
effective_extension,
extension_group,
ScriptContext::GetEffectiveDocumentURL(frame, frame_url, true),
frame->document().securityOrigin());
ScriptContext* context =
delegate_->CreateScriptContext(v8_context, frame, extension, context_type)
.release();
delegate_->CreateScriptContext(v8_context,
frame,
extension,
context_type,
effective_extension,
effective_context_type).release();
script_context_set_.Add(context);
// Initialize origin permissions for content scripts, which can't be
......
......@@ -90,11 +90,13 @@ class Dispatcher : public content::RenderProcessObserver,
bool IsExtensionActive(const std::string& extension_id) const;
// Finds the extension ID for the JavaScript context associated with the
// Finds the extension for the JavaScript context associated with the
// specified |frame| and isolated world. If |world_id| is zero, finds the
// extension ID associated with the main world's JavaScript context. If the
// JavaScript context isn't from an extension, returns empty string.
std::string GetExtensionID(const blink::WebFrame* frame, int world_id);
const Extension* GetExtensionFromFrameAndWorld(const blink::WebFrame* frame,
int world_id,
bool use_effective_url);
void DidCreateScriptContext(blink::WebFrame* frame,
const v8::Handle<v8::Context>& context,
......
......@@ -36,7 +36,9 @@ class DispatcherDelegate {
const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* frame,
const Extension* extension,
Feature::Context context_type) = 0;
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type) = 0;
// Initializes origin permissions for a newly created extension context.
virtual void InitOriginPermissions(const Extension* extension,
......
......@@ -131,6 +131,8 @@ ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(v8::Isolate* isolate)
context_.reset(new ScriptContext(context_holder_->context(),
NULL, // WebFrame
NULL, // Extension
Feature::BLESSED_EXTENSION_CONTEXT,
NULL, // Effective Extension
Feature::BLESSED_EXTENSION_CONTEXT));
context_->v8_context()->Enter();
assert_natives_ = new AssertNatives(context_.get());
......
......@@ -30,27 +30,62 @@ using content::V8ValueConverter;
namespace extensions {
namespace {
std::string GetContextTypeDescriptionString(Feature::Context context_type) {
switch (context_type) {
case Feature::UNSPECIFIED_CONTEXT:
return "UNSPECIFIED";
case Feature::BLESSED_EXTENSION_CONTEXT:
return "BLESSED_EXTENSION";
case Feature::UNBLESSED_EXTENSION_CONTEXT:
return "UNBLESSED_EXTENSION";
case Feature::CONTENT_SCRIPT_CONTEXT:
return "CONTENT_SCRIPT";
case Feature::WEB_PAGE_CONTEXT:
return "WEB_PAGE";
case Feature::BLESSED_WEB_PAGE_CONTEXT:
return "BLESSED_WEB_PAGE";
case Feature::WEBUI_CONTEXT:
return "WEBUI";
}
NOTREACHED();
return std::string();
}
} // namespace
ScriptContext::ScriptContext(const v8::Handle<v8::Context>& v8_context,
blink::WebFrame* web_frame,
const Extension* extension,
Feature::Context context_type)
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type)
: v8_context_(v8_context),
web_frame_(web_frame),
extension_(extension),
context_type_(context_type),
effective_extension_(effective_extension),
effective_context_type_(effective_context_type),
safe_builtins_(this),
isolate_(v8_context->GetIsolate()) {
VLOG(1) << "Created context:\n"
<< " extension id: " << GetExtensionID() << "\n"
<< " frame: " << web_frame_ << "\n"
<< " URL: " << GetURL() << "\n"
<< " context type: " << GetContextTypeDescription();
<< " context type: " << GetContextTypeDescription() << "\n"
<< " effective extension id: "
<< (effective_extension_.get() ? effective_extension_->id() : "")
<< " effective context type: "
<< GetEffectiveContextTypeDescription();
gin::PerContextData::From(v8_context)->set_runner(this);
}
ScriptContext::~ScriptContext() {
VLOG(1) << "Destroyed context for extension\n"
<< " extension id: " << GetExtensionID();
<< " extension id: " << GetExtensionID() << "\n"
<< " effective extension id: "
<< (effective_extension_.get() ? effective_extension_->id() : "");
Invalidate();
}
......@@ -133,24 +168,11 @@ void ScriptContext::DispatchOnUnloadEvent() {
}
std::string ScriptContext::GetContextTypeDescription() {
switch (context_type_) {
case Feature::UNSPECIFIED_CONTEXT:
return "UNSPECIFIED";
case Feature::BLESSED_EXTENSION_CONTEXT:
return "BLESSED_EXTENSION";
case Feature::UNBLESSED_EXTENSION_CONTEXT:
return "UNBLESSED_EXTENSION";
case Feature::CONTENT_SCRIPT_CONTEXT:
return "CONTENT_SCRIPT";
case Feature::WEB_PAGE_CONTEXT:
return "WEB_PAGE";
case Feature::BLESSED_WEB_PAGE_CONTEXT:
return "BLESSED_WEB_PAGE";
case Feature::WEBUI_CONTEXT:
return "WEBUI";
}
NOTREACHED();
return std::string();
return GetContextTypeDescriptionString(context_type_);
}
std::string ScriptContext::GetEffectiveContextTypeDescription() {
return GetContextTypeDescriptionString(effective_context_type_);
}
GURL ScriptContext::GetURL() const {
......
......@@ -35,7 +35,9 @@ class ScriptContext : public RequestSender::Source, public gin::Runner {
ScriptContext(const v8::Handle<v8::Context>& context,
blink::WebFrame* frame,
const Extension* extension,
Feature::Context context_type);
Feature::Context context_type,
const Extension* effective_extension,
Feature::Context effective_context_type);
virtual ~ScriptContext();
// Clears the WebFrame for this contexts and invalidates the associated
......@@ -52,10 +54,18 @@ class ScriptContext : public RequestSender::Source, public gin::Runner {
const Extension* extension() const { return extension_.get(); }
const Extension* effective_extension() const {
return effective_extension_.get();
}
blink::WebFrame* web_frame() const { return web_frame_; }
Feature::Context context_type() const { return context_type_; }
Feature::Context effective_context_type() const {
return effective_context_type_;
}
void set_module_system(scoped_ptr<ModuleSystem> module_system) {
module_system_ = module_system.Pass();
}
......@@ -97,6 +107,9 @@ class ScriptContext : public RequestSender::Source, public gin::Runner {
// Returns a string description of the type of context this is.
std::string GetContextTypeDescription();
// Returns a string description of the effective type of context this is.
std::string GetEffectiveContextTypeDescription();
v8::Isolate* isolate() const { return isolate_; }
// Get the URL of this context's web frame.
......@@ -152,6 +165,14 @@ class ScriptContext : public RequestSender::Source, public gin::Runner {
// The type of context.
Feature::Context context_type_;
// The effective extension associated with this context, or NULL if there is
// none. This is different from the above extension if this context is in an
// about:blank iframe for example.
scoped_refptr<const Extension> effective_extension_;
// The type of context.
Feature::Context effective_context_type_;
// Owns and structures the JS that is injected to set up extension bindings.
scoped_ptr<ModuleSystem> module_system_;
......
......@@ -32,6 +32,8 @@ TEST(ScriptContextSet, Lifecycle) {
new ScriptContext(context_holder.context(),
frame,
extension,
Feature::BLESSED_EXTENSION_CONTEXT,
extension,
Feature::BLESSED_EXTENSION_CONTEXT);
context_set.Add(context);
......
......@@ -52,6 +52,8 @@ scoped_ptr<NativeHandler> V8SchemaRegistry::AsNativeHandler() {
new ScriptContext(GetOrCreateContext(v8::Isolate::GetCurrent()),
NULL, // no frame
NULL, // no extension
Feature::UNSPECIFIED_CONTEXT,
NULL, // no effective extension
Feature::UNSPECIFIED_CONTEXT));
return scoped_ptr<NativeHandler>(
new SchemaRegistryNativeHandler(this, context.Pass()));
......
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