diff options
Diffstat (limited to 'extensions/renderer/user_script_slave.cc')
-rw-r--r-- | extensions/renderer/user_script_slave.cc | 150 |
1 files changed, 104 insertions, 46 deletions
diff --git a/extensions/renderer/user_script_slave.cc b/extensions/renderer/user_script_slave.cc index eda1c0e..7e465c6 100644 --- a/extensions/renderer/user_script_slave.cc +++ b/extensions/renderer/user_script_slave.cc @@ -31,7 +31,6 @@ using blink::WebFrame; using blink::WebSecurityOrigin; using blink::WebSecurityPolicy; using blink::WebString; -using blink::WebView; using content::RenderThread; namespace extensions { @@ -102,9 +101,9 @@ const Extension* UserScriptSlave::GetExtension( return extensions_->GetByID(extension_id); } -bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { - script_injections_.clear(); - +bool UserScriptSlave::UpdateScripts( + base::SharedMemoryHandle shared_memory, + const std::set<std::string>& changed_extensions) { bool only_inject_incognito = ExtensionsRendererClient::Get()->IsIncognitoProcess(); @@ -131,6 +130,26 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { PickleIterator iter(pickle); CHECK(pickle.ReadUInt64(&iter, &num_scripts)); + // If we pass no explicit extension ids, we should refresh all extensions. + bool include_all_extensions = changed_extensions.empty(); + + // If we include all extensions, then we clear the script injections and + // start from scratch. If not, then clear only the scripts for extension ids + // that we are updating. This is important to maintain pending script + // injection state for each ScriptInjection. + if (include_all_extensions) { + script_injections_.clear(); + } else { + for (ScopedVector<ScriptInjection>::iterator iter = + script_injections_.begin(); + iter != script_injections_.end();) { + if (changed_extensions.count((*iter)->extension_id()) > 0) + iter = script_injections_.erase(iter); + else + ++iter; + } + } + script_injections_.reserve(num_scripts); for (uint64 i = 0; i < num_scripts; ++i) { scoped_ptr<UserScript> script(new UserScript()); @@ -157,9 +176,31 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { if (only_inject_incognito && !script->is_incognito_enabled()) continue; // This script shouldn't run in an incognito tab. - script_injections_.push_back(new ScriptInjection(script.Pass(), this)); + // If we include all extensions or the given extension changed, we add a + // new script injection. + if (include_all_extensions || + changed_extensions.count(script->extension_id()) > 0) { + script_injections_.push_back(new ScriptInjection(script.Pass(), this)); + } else { + // Otherwise, we need to update the existing script injection with the + // new user script (since the old content was invalidated). + // + // Note: Yes, this is O(n^2). But vectors are faster than maps for + // relatively few elements, and less than 1% of our users actually have + // enough content scripts for it to matter. If this changes, or if + // std::maps get a much faster implementation, we should look into + // making a map for script injections. + for (ScopedVector<ScriptInjection>::iterator iter = + script_injections_.begin(); + iter != script_injections_.end(); + ++iter) { + if ((*iter)->script()->id() == script->id()) { + (*iter)->SetScript(script.Pass()); + break; + } + } + } } - return true; } @@ -169,40 +210,46 @@ void UserScriptSlave::InjectScripts(WebFrame* frame, if (document_url.is_empty()) return; - content::RenderView* top_render_view = - content::RenderView::FromWebView(frame->top()->view()); - ScriptInjection::ScriptsRunInfo scripts_run_info; for (ScopedVector<ScriptInjection>::const_iterator iter = script_injections_.begin(); iter != script_injections_.end(); ++iter) { - ScriptInjection* injection = *iter; - if (!injection->WantsToRun(frame, location, document_url)) - continue; - - const Extension* extension = GetExtension(injection->extension_id()); - DCHECK(extension); - - if (PermissionsData::RequiresActionForScriptExecution( - extension, - ExtensionHelper::Get(top_render_view)->tab_id(), - document_url)) { - // TODO(rdevlin.cronin): Right now, this is just a notification, but soon - // we should block without user consent. - top_render_view->Send( - new ExtensionHostMsg_NotifyExtensionScriptExecution( - top_render_view->GetRoutingID(), - extension->id(), - top_render_view->GetPageId())); - } - - injection->Inject(frame, location, &scripts_run_info); + (*iter)->InjectIfAllowed(frame, location, document_url, &scripts_run_info); } LogScriptsRun(frame, location, scripts_run_info); } +void UserScriptSlave::OnContentScriptGrantedPermission( + content::RenderView* render_view, int request_id) { + ScriptInjection::ScriptsRunInfo run_info; + blink::WebFrame* frame = NULL; + // Notify the injections that a request to inject has been granted. + for (ScopedVector<ScriptInjection>::iterator iter = + script_injections_.begin(); + iter != script_injections_.end(); + ++iter) { + if ((*iter)->NotifyScriptPermitted(request_id, + render_view, + &run_info, + &frame)) { + DCHECK(frame); + LogScriptsRun(frame, UserScript::RUN_DEFERRED, run_info); + break; + } + } +} + +void UserScriptSlave::FrameDetached(blink::WebFrame* frame) { + for (ScopedVector<ScriptInjection>::iterator iter = + script_injections_.begin(); + iter != script_injections_.end(); + ++iter) { + (*iter)->FrameDetached(frame); + } +} + void UserScriptSlave::LogScriptsRun( blink::WebFrame* frame, UserScript::RunLocation location, @@ -218,22 +265,33 @@ void UserScriptSlave::LogScriptsRun( ScriptContext::GetDataSourceURLForFrame(frame))); } - if (location == UserScript::DOCUMENT_START) { - UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", - info.num_css); - UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", info.num_js); - if (info.num_css || info.num_js) - UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", info.timer.Elapsed()); - } else if (location == UserScript::DOCUMENT_END) { - UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); - if (info.num_js) - UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); - } else if (location == UserScript::DOCUMENT_IDLE) { - UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", info.num_js); - if (info.num_js) - UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); - } else { - NOTREACHED(); + switch (location) { + case UserScript::DOCUMENT_START: + UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", + info.num_css); + UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", + info.num_js); + if (info.num_css || info.num_js) + UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", + info.timer.Elapsed()); + break; + case UserScript::DOCUMENT_END: + UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); + if (info.num_js) + UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); + break; + case UserScript::DOCUMENT_IDLE: + UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", + info.num_js); + if (info.num_js) + UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); + break; + case UserScript::RUN_DEFERRED: + // TODO(rdevlin.cronin): Add histograms. + break; + case UserScript::UNDEFINED: + case UserScript::RUN_LOCATION_LAST: + NOTREACHED(); } } |