Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "extensions/renderer/script_injection.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "content/public/common/url_constants.h" | |
| 12 #include "extensions/common/extension.h" | |
| 13 #include "extensions/common/extension_messages.h" | |
| 14 #include "extensions/common/permissions/permissions_data.h" | |
| 15 #include "extensions/renderer/dom_activity_logger.h" | |
| 16 #include "extensions/renderer/extension_groups.h" | |
| 17 #include "extensions/renderer/script_context.h" | |
| 18 #include "extensions/renderer/user_script_slave.h" | |
| 19 #include "grit/renderer_resources.h" | |
| 20 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 21 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 22 #include "third_party/WebKit/public/web/WebScriptSource.h" | |
| 23 #include "ui/base/resource/resource_bundle.h" | |
| 24 #include "url/gurl.h" | |
| 25 | |
| 26 namespace extensions { | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 // These two strings are injected before and after the Greasemonkey API and | |
| 31 // user script to wrap it in an anonymous scope. | |
| 32 const char kUserScriptHead[] = "(function (unsafeWindow) {\n"; | |
| 33 const char kUserScriptTail[] = "\n})(window);"; | |
| 34 | |
| 35 // Greasemonkey API source that is injected with the scripts. | |
| 36 struct GreasemonkeyApiJsString { | |
| 37 GreasemonkeyApiJsString(); | |
| 38 blink::WebScriptSource source; | |
| 39 }; | |
| 40 | |
| 41 // The below constructor, monstrous as it is, just makes a WebScriptSource from | |
| 42 // the GreasemonkeyApiJs resource. | |
| 43 GreasemonkeyApiJsString::GreasemonkeyApiJsString() | |
| 44 : source(blink::WebScriptSource(blink::WebString::fromUTF8( | |
| 45 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
| 46 IDR_GREASEMONKEY_API_JS).as_string()))) { | |
| 47 } | |
| 48 | |
| 49 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api = | |
| 50 LAZY_INSTANCE_INITIALIZER; | |
| 51 | |
| 52 } // namespace | |
| 53 | |
| 54 ScriptInjection::ScriptsRunInfo::ScriptsRunInfo() : num_css(0u), num_js(0u) { | |
| 55 } | |
| 56 | |
| 57 ScriptInjection::ScriptsRunInfo::~ScriptsRunInfo() { | |
| 58 } | |
| 59 | |
| 60 // static | |
| 61 GURL ScriptInjection::GetDocumentUrlForFrame(blink::WebFrame* frame) { | |
| 62 GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame); | |
| 63 if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) { | |
| 64 data_source_url = GURL(content::kViewSourceScheme + std::string(":") + | |
| 65 data_source_url.spec()); | |
| 66 } | |
| 67 | |
| 68 return data_source_url; | |
| 69 } | |
| 70 | |
| 71 ScriptInjection::ScriptInjection( | |
| 72 scoped_ptr<UserScript> script, | |
| 73 UserScriptSlave* user_script_slave) | |
| 74 : script_(script.Pass()), | |
| 75 extension_id_(script_->extension_id()), | |
| 76 user_script_slave_(user_script_slave), | |
| 77 is_standalone_or_emulate_greasemonkey_( | |
| 78 script_->is_standalone() || script_->emulate_greasemonkey()) { | |
| 79 } | |
| 80 | |
| 81 ScriptInjection::~ScriptInjection() { | |
| 82 } | |
| 83 | |
| 84 bool ScriptInjection::WantsToRun(blink::WebFrame* frame, | |
| 85 UserScript::RunLocation run_location, | |
| 86 const GURL& document_url) const { | |
| 87 if (frame->parent() && !script_->match_all_frames()) | |
| 88 return false; // Only match subframes if the script declared it wanted to. | |
| 89 | |
| 90 | |
|
not at google - send to devlin
2014/05/15 23:23:21
dd
Devlin
2014/05/16 22:32:20
Done.
| |
| 91 const Extension* extension = user_script_slave_->GetExtension(extension_id_); | |
| 92 // Since extension info is sent separately from user script info, they can | |
| 93 // be out of sync. We just ignore this situation. | |
| 94 if (!extension) | |
| 95 return false; | |
| 96 | |
| 97 // Content scripts are not tab-specific. | |
| 98 static const int kNoTabId = -1; | |
| 99 // We don't have a process id in this context. | |
| 100 static const int kNoProcessId = -1; | |
| 101 | |
| 102 if (!PermissionsData::CanExecuteScriptOnPage(extension, | |
| 103 document_url, | |
| 104 frame->top()->document().url(), | |
| 105 kNoTabId, | |
| 106 script_.get(), | |
| 107 kNoProcessId, | |
| 108 NULL /* ignore error */)) { | |
| 109 return false; | |
| 110 } | |
| 111 | |
| 112 return ShouldInjectCSS(run_location) || ShouldInjectJS(run_location); | |
| 113 } | |
| 114 | |
| 115 void ScriptInjection::Inject(blink::WebFrame* frame, | |
| 116 UserScript::RunLocation run_location, | |
| 117 ScriptsRunInfo* scripts_run_info) const { | |
| 118 DCHECK(frame); | |
| 119 DCHECK(scripts_run_info); | |
| 120 DCHECK(WantsToRun(frame, run_location, GetDocumentUrlForFrame(frame))); | |
| 121 DCHECK(user_script_slave_->GetExtension(extension_id_)); | |
| 122 | |
| 123 if (ShouldInjectCSS(run_location)) | |
| 124 InjectCSS(frame, scripts_run_info); | |
| 125 if (ShouldInjectJS(run_location)) | |
| 126 InjectJS(frame, scripts_run_info); | |
| 127 } | |
| 128 | |
| 129 bool ScriptInjection::ShouldInjectJS(UserScript::RunLocation run_location) | |
| 130 const { | |
| 131 return !script_->js_scripts().empty() && | |
| 132 script_->run_location() == run_location; | |
| 133 } | |
| 134 | |
| 135 bool ScriptInjection::ShouldInjectCSS(UserScript::RunLocation run_location) | |
| 136 const { | |
| 137 return !script_->css_scripts().empty() && | |
| 138 script_->run_location() == UserScript::DOCUMENT_START; | |
|
not at google - send to devlin
2014/05/15 23:23:21
I think you want |run_location| == DOCUMENT_START
Devlin
2014/05/16 22:32:20
Whoops, good catch - yes, meant |run_location|.
| |
| 139 } | |
| 140 | |
| 141 void ScriptInjection::InjectJS(blink::WebFrame* frame, | |
| 142 ScriptsRunInfo* scripts_run_info) const { | |
| 143 const UserScript::FileList& js_scripts = script_->js_scripts(); | |
| 144 std::vector<blink::WebScriptSource> sources; | |
| 145 scripts_run_info->num_js += js_scripts.size(); | |
| 146 for (UserScript::FileList::const_iterator iter = js_scripts.begin(); | |
| 147 iter != js_scripts.end(); | |
| 148 ++iter) { | |
| 149 std::string content = iter->GetContent().as_string(); | |
| 150 | |
| 151 // We add this dumb function wrapper for standalone user script to | |
| 152 // emulate what Greasemonkey does. | |
| 153 // TODO(aa): I think that maybe "is_standalone" scripts don't exist | |
| 154 // anymore. Investigate. | |
| 155 if (is_standalone_or_emulate_greasemonkey_) { | |
| 156 content.insert(0, kUserScriptHead); | |
| 157 content += kUserScriptTail; | |
| 158 } | |
| 159 sources.push_back(blink::WebScriptSource( | |
| 160 blink::WebString::fromUTF8(content), iter->url())); | |
| 161 } | |
| 162 | |
| 163 // Emulate Greasemonkey API for scripts that were converted to extensions | |
| 164 // and "standalone" user scripts. | |
| 165 if (is_standalone_or_emulate_greasemonkey_) | |
| 166 sources.insert(sources.begin(), g_greasemonkey_api.Get().source); | |
| 167 | |
| 168 int isolated_world_id = | |
| 169 user_script_slave_->GetIsolatedWorldIdForExtension( | |
| 170 user_script_slave_->GetExtension(extension_id_), frame); | |
| 171 base::ElapsedTimer exec_timer; | |
| 172 DOMActivityLogger::AttachToWorld(isolated_world_id, extension_id_); | |
| 173 frame->executeScriptInIsolatedWorld(isolated_world_id, | |
| 174 &sources.front(), | |
| 175 sources.size(), | |
| 176 EXTENSION_GROUP_CONTENT_SCRIPTS); | |
| 177 UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed()); | |
| 178 | |
| 179 for (std::vector<blink::WebScriptSource>::const_iterator iter = | |
| 180 sources.begin(); | |
| 181 iter != sources.end(); | |
| 182 ++iter) { | |
| 183 scripts_run_info->executing_scripts[extension_id_].insert( | |
| 184 GURL(iter->url).path()); | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 void ScriptInjection::InjectCSS(blink::WebFrame* frame, | |
| 189 ScriptsRunInfo* scripts_run_info) const { | |
| 190 const UserScript::FileList& css_scripts = script_->css_scripts(); | |
| 191 scripts_run_info->num_css += css_scripts.size(); | |
| 192 for (UserScript::FileList::const_iterator iter = css_scripts.begin(); | |
| 193 iter != css_scripts.end(); | |
| 194 ++iter) { | |
| 195 frame->document().insertStyleSheet( | |
| 196 blink::WebString::fromUTF8(iter->GetContent().as_string())); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 } // namespace extensions | |
| OLD | NEW |