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/programmatic_script_injection.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/values.h" |
| 10 #include "content/public/renderer/render_view.h" |
| 11 #include "content/public/renderer/v8_value_converter.h" |
| 12 #include "extensions/common/error_utils.h" |
| 13 #include "extensions/common/extension.h" |
| 14 #include "extensions/common/extension_messages.h" |
| 15 #include "extensions/common/manifest_constants.h" |
| 16 #include "extensions/common/permissions/permissions_data.h" |
| 17 #include "extensions/renderer/dom_activity_logger.h" |
| 18 #include "extensions/renderer/extension_groups.h" |
| 19 #include "extensions/renderer/script_context.h" |
| 20 #include "third_party/WebKit/public/platform/WebString.h" |
| 21 #include "third_party/WebKit/public/web/WebDocument.h" |
| 22 #include "third_party/WebKit/public/web/WebFrame.h" |
| 23 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
| 24 #include "third_party/WebKit/public/web/WebScriptSource.h" |
| 25 #include "url/gurl.h" |
| 26 |
| 27 namespace extensions { |
| 28 |
| 29 namespace { |
| 30 |
| 31 // Append all the child frames of |parent_frame| to |frames_vector|. |
| 32 void AppendAllChildFrames(blink::WebFrame* parent_frame, |
| 33 std::vector<blink::WebFrame*>* frames_vector) { |
| 34 DCHECK(parent_frame); |
| 35 for (blink::WebFrame* child_frame = parent_frame->firstChild(); |
| 36 child_frame; |
| 37 child_frame = child_frame->nextSibling()) { |
| 38 frames_vector->push_back(child_frame); |
| 39 AppendAllChildFrames(child_frame, frames_vector); |
| 40 } |
| 41 } |
| 42 |
| 43 } // namespace |
| 44 |
| 45 ProgrammaticScriptInjection::ProgrammaticScriptInjection( |
| 46 blink::WebFrame* web_frame, |
| 47 const ExtensionMsg_ExecuteCode_Params& params, |
| 48 int tab_id) |
| 49 : ScriptInjection(web_frame, |
| 50 params.extension_id, |
| 51 static_cast<UserScript::RunLocation>(params.run_at), |
| 52 tab_id), |
| 53 params_(new ExtensionMsg_ExecuteCode_Params(params)) { |
| 54 } |
| 55 |
| 56 ProgrammaticScriptInjection::~ProgrammaticScriptInjection() { |
| 57 } |
| 58 |
| 59 content::RenderView* ProgrammaticScriptInjection::GetRenderView() { |
| 60 return content::RenderView::FromWebView(web_frame()->view()); |
| 61 } |
| 62 |
| 63 bool ProgrammaticScriptInjection::CanExecuteOnFrame( |
| 64 const Extension* extension, |
| 65 const blink::WebFrame* frame, |
| 66 const GURL& top_url) const { |
| 67 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( |
| 68 frame, frame->document().url(), params_->match_about_blank); |
| 69 if (params_->is_web_view) |
| 70 return effective_document_url == params_->webview_src; |
| 71 |
| 72 return extension->permissions_data()->CanAccessPage(extension, |
| 73 effective_document_url, |
| 74 top_url, |
| 75 tab_id(), |
| 76 -1, // no process ID. |
| 77 NULL); // ignore error. |
| 78 } |
| 79 |
| 80 void ProgrammaticScriptInjection::ExtensionNotFound() { |
| 81 content::RenderView* render_view = GetRenderView(); |
| 82 // Inform the browser process that we are not executing the script. |
| 83 render_view->Send( |
| 84 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), |
| 85 params_->request_id, |
| 86 std::string(), // no error |
| 87 -1, // no page id |
| 88 GURL(std::string()), |
| 89 base::ListValue())); |
| 90 } |
| 91 |
| 92 bool ProgrammaticScriptInjection::Allowed(const Extension* extension) { |
| 93 GURL url = web_frame()->document().url(); |
| 94 bool can_execute = CanExecuteOnFrame(extension, web_frame(), url); |
| 95 if (!can_execute) { |
| 96 // Send an error message indicating we could not execute script. |
| 97 content::RenderView* render_view = GetRenderView(); |
| 98 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
| 99 render_view->GetRoutingID(), |
| 100 params_->request_id, |
| 101 ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage, |
| 102 url.spec()), |
| 103 render_view->GetPageId(), |
| 104 ScriptContext::GetDataSourceURLForFrame(web_frame()), |
| 105 base::ListValue())); |
| 106 } |
| 107 |
| 108 return can_execute; |
| 109 } |
| 110 |
| 111 void ProgrammaticScriptInjection::Inject(ScriptsRunInfo* scripts_run_info, |
| 112 const Extension* extension) { |
| 113 std::vector<blink::WebFrame*> frame_vector; |
| 114 frame_vector.push_back(web_frame()); |
| 115 if (params_->all_frames) |
| 116 AppendAllChildFrames(web_frame(), &frame_vector); |
| 117 |
| 118 scoped_ptr<blink::WebScopedUserGesture> gesture; |
| 119 if (params_->user_gesture) |
| 120 gesture.reset(new blink::WebScopedUserGesture); |
| 121 |
| 122 GURL top_url = web_frame()->document().url(); |
| 123 base::ListValue execution_results; |
| 124 for (std::vector<blink::WebFrame*>::iterator frame_it = frame_vector.begin(); |
| 125 frame_it != frame_vector.end(); |
| 126 ++frame_it) { |
| 127 blink::WebFrame* child_frame = *frame_it; |
| 128 CHECK(child_frame) << top_url; |
| 129 |
| 130 // We recheck access here in the renderer for extra safety against races |
| 131 // with navigation, but different frames can have different URLs, and the |
| 132 // extension might only have access to a subset of them. |
| 133 // For child frames, we just skip ones the extension doesn't have access |
| 134 // to and carry on. |
| 135 if (!CanExecuteOnFrame(extension, child_frame, top_url)) { |
| 136 // If we couldn't access the top frame, we shouldn't be injecting at all. |
| 137 DCHECK(child_frame->parent()); |
| 138 continue; |
| 139 } |
| 140 |
| 141 if (params_->is_javascript) { |
| 142 blink::WebScriptSource source(blink::WebString::fromUTF8(params_->code), |
| 143 params_->file_url); |
| 144 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 145 |
| 146 scoped_ptr<content::V8ValueConverter> v8_converter( |
| 147 content::V8ValueConverter::create()); |
| 148 v8::Local<v8::Value> script_value; |
| 149 |
| 150 if (params_->in_main_world) { |
| 151 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId, |
| 152 extension->id()); |
| 153 script_value = child_frame->executeScriptAndReturnValue(source); |
| 154 } else { // in isolated world |
| 155 blink::WebVector<v8::Local<v8::Value> > results; |
| 156 std::vector<blink::WebScriptSource> sources; |
| 157 sources.push_back(source); |
| 158 int isolated_world_id = |
| 159 GetIsolatedWorldIdForExtension(extension, child_frame); |
| 160 DOMActivityLogger::AttachToWorld(isolated_world_id, extension->id()); |
| 161 child_frame->executeScriptInIsolatedWorld( |
| 162 isolated_world_id, |
| 163 &sources.front(), |
| 164 sources.size(), |
| 165 EXTENSION_GROUP_CONTENT_SCRIPTS, // A blatant lie! |
| 166 &results); |
| 167 // We only expect one value back since we only pushed one source |
| 168 if (results.size() == 1 && !results[0].IsEmpty()) |
| 169 script_value = results[0]; |
| 170 } |
| 171 |
| 172 if (params_->wants_result && !script_value.IsEmpty()) { |
| 173 // It's safe to always use the main world context when converting here. |
| 174 // V8ValueConverterImpl shouldn't actually care about the context scope, |
| 175 // and it switches to v8::Object's creation context when encountered. |
| 176 v8::Local<v8::Context> context = child_frame->mainWorldScriptContext(); |
| 177 base::Value* result = v8_converter->FromV8Value(script_value, context); |
| 178 // Always append an execution result (i.e. no result == null result) so |
| 179 // that |execution_results| lines up with the frames. |
| 180 execution_results.Append(result ? result |
| 181 : base::Value::CreateNullValue()); |
| 182 } |
| 183 } else { // css |
| 184 child_frame->document().insertStyleSheet( |
| 185 blink::WebString::fromUTF8(params_->code)); |
| 186 } |
| 187 } |
| 188 |
| 189 content::RenderView* render_view = GetRenderView(); |
| 190 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
| 191 render_view->GetRoutingID(), |
| 192 params_->request_id, |
| 193 std::string(), // no error. |
| 194 render_view->GetPageId(), |
| 195 ScriptContext::GetDataSourceURLForFrame(web_frame()), |
| 196 execution_results)); |
| 197 } |
| 198 |
| 199 } // namespace extensions |
OLD | NEW |