[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 1 | // Copyright 2012 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 "content/renderer/web_ui_extension.h" |
| 6 | |
dcheng | cedca561 | 2016-04-09 01:40:15 | [diff] [blame] | 7 | #include <memory> |
dcheng | 0232f57 | 2016-05-27 17:47:44 | [diff] [blame] | 8 | #include <utility> |
dcheng | cedca561 | 2016-04-09 01:40:15 | [diff] [blame] | 9 | |
Sebastien Marchand | f8cbfab | 2019-01-25 16:02:30 | [diff] [blame] | 10 | #include "base/bind.h" |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 11 | #include "base/values.h" |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 12 | #include "content/common/frame_messages.h" |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 13 | #include "content/public/common/bindings_policy.h" |
| 14 | #include "content/public/common/url_constants.h" |
donnd | bd8a661 | 2015-12-02 02:39:58 | [diff] [blame] | 15 | #include "content/public/renderer/chrome_object_extensions_utils.h" |
sammc | 7f6c6a0 | 2017-01-30 00:53:51 | [diff] [blame] | 16 | #include "content/public/renderer/render_frame.h" |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 17 | #include "content/public/renderer/render_thread.h" |
| 18 | #include "content/public/renderer/render_view.h" |
John Abd-El-Malek | 312a30bb | 2017-10-23 19:51:52 | [diff] [blame] | 19 | #include "content/public/renderer/v8_value_converter.h" |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 20 | #include "content/renderer/web_ui_extension_data.h" |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 21 | #include "gin/arguments.h" |
| 22 | #include "gin/function_template.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 23 | #include "third_party/blink/public/web/blink.h" |
| 24 | #include "third_party/blink/public/web/web_document.h" |
| 25 | #include "third_party/blink/public/web/web_local_frame.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 26 | #include "third_party/blink/public/web/web_view.h" |
[email protected] | 707e1c4 | 2013-07-09 21:18:58 | [diff] [blame] | 27 | #include "url/gurl.h" |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 28 | #include "v8/include/v8.h" |
| 29 | |
| 30 | namespace content { |
| 31 | |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 32 | namespace { |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 33 | |
lukasza | df18ba76 | 2017-06-09 22:24:30 | [diff] [blame] | 34 | bool ShouldRespondToRequest(blink::WebLocalFrame** frame_ptr, |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 35 | RenderFrame** render_frame_ptr) { |
lukasza | df18ba76 | 2017-06-09 22:24:30 | [diff] [blame] | 36 | blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForCurrentContext(); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 37 | if (!frame || !frame->View()) |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 38 | return false; |
| 39 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 40 | GURL frame_url = frame->GetDocument().Url(); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 41 | |
sammc | 7f6c6a0 | 2017-01-30 00:53:51 | [diff] [blame] | 42 | RenderFrame* render_frame = RenderFrame::FromWebFrame(frame); |
| 43 | if (!render_frame) |
| 44 | return false; |
| 45 | |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 46 | bool webui_enabled = |
sammc | 7f6c6a0 | 2017-01-30 00:53:51 | [diff] [blame] | 47 | (render_frame->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) && |
[email protected] | 2d9748b2 | 2014-02-11 00:17:29 | [diff] [blame] | 48 | (frame_url.SchemeIs(kChromeUIScheme) || |
[email protected] | cca6f39 | 2014-05-28 21:32:26 | [diff] [blame] | 49 | frame_url.SchemeIs(url::kDataScheme)); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 50 | |
| 51 | if (!webui_enabled) |
| 52 | return false; |
| 53 | |
| 54 | *frame_ptr = frame; |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 55 | *render_frame_ptr = render_frame; |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 56 | return true; |
| 57 | } |
| 58 | |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 59 | } // namespace |
| 60 | |
| 61 | // Exposes two methods: |
| 62 | // - chrome.send: Used to send messages to the browser. Requires the message |
| 63 | // name as the first argument and can have an optional second argument that |
| 64 | // should be an array. |
| 65 | // - chrome.getVariableValue: Returns value for the input variable name if such |
| 66 | // a value was set by the browser. Else will return an empty string. |
lukasza | df18ba76 | 2017-06-09 22:24:30 | [diff] [blame] | 67 | void WebUIExtension::Install(blink::WebLocalFrame* frame) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 68 | v8::Isolate* isolate = blink::MainThreadIsolate(); |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 69 | v8::HandleScope handle_scope(isolate); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 70 | v8::Local<v8::Context> context = frame->MainWorldScriptContext(); |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 71 | if (context.IsEmpty()) |
| 72 | return; |
| 73 | |
| 74 | v8::Context::Scope context_scope(context); |
| 75 | |
Dan Elphick | 258bbaf | 2019-02-01 17:37:35 | [diff] [blame] | 76 | v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate, context); |
Dan Elphick | 12bdce1 | 2019-04-04 20:18:54 | [diff] [blame] | 77 | chrome |
| 78 | ->Set(context, gin::StringToSymbol(isolate, "send"), |
danakj | ab347580 | 2019-05-22 19:05:17 | [diff] [blame] | 79 | gin::CreateFunctionTemplate( |
| 80 | isolate, base::BindRepeating(&WebUIExtension::Send)) |
Dan Elphick | 12bdce1 | 2019-04-04 20:18:54 | [diff] [blame] | 81 | ->GetFunction(context) |
| 82 | .ToLocalChecked()) |
| 83 | .Check(); |
| 84 | chrome |
| 85 | ->Set(context, gin::StringToSymbol(isolate, "getVariableValue"), |
| 86 | gin::CreateFunctionTemplate( |
danakj | ab347580 | 2019-05-22 19:05:17 | [diff] [blame] | 87 | isolate, base::BindRepeating(&WebUIExtension::GetVariableValue)) |
Dan Elphick | 12bdce1 | 2019-04-04 20:18:54 | [diff] [blame] | 88 | ->GetFunction(context) |
| 89 | .ToLocalChecked()) |
| 90 | .Check(); |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 91 | } |
| 92 | |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 93 | // static |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 94 | void WebUIExtension::Send(gin::Arguments* args) { |
lukasza | df18ba76 | 2017-06-09 22:24:30 | [diff] [blame] | 95 | blink::WebLocalFrame* frame; |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 96 | RenderFrame* render_frame; |
| 97 | if (!ShouldRespondToRequest(&frame, &render_frame)) |
[email protected] | 187a353 | 2013-06-13 20:25:01 | [diff] [blame] | 98 | return; |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 99 | |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 100 | std::string message; |
| 101 | if (!args->GetNext(&message)) { |
| 102 | args->ThrowError(); |
[email protected] | 187a353 | 2013-06-13 20:25:01 | [diff] [blame] | 103 | return; |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 104 | } |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 105 | |
| 106 | // If they've provided an optional message parameter, convert that into a |
| 107 | // Value to send to the browser process. |
dcheng | cedca561 | 2016-04-09 01:40:15 | [diff] [blame] | 108 | std::unique_ptr<base::ListValue> content; |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 109 | if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) { |
[email protected] | 85ecd7e | 2013-12-23 21:58:45 | [diff] [blame] | 110 | content.reset(new base::ListValue()); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 111 | } else { |
deepak.s | 750d68f | 2015-04-30 07:32:41 | [diff] [blame] | 112 | v8::Local<v8::Object> obj; |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 113 | if (!args->GetNext(&obj)) { |
| 114 | args->ThrowError(); |
[email protected] | 187a353 | 2013-06-13 20:25:01 | [diff] [blame] | 115 | return; |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 116 | } |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 117 | |
rdevlin.cronin | 694c605 | 2017-06-13 22:07:35 | [diff] [blame] | 118 | content = base::ListValue::From(V8ValueConverter::Create()->FromV8Value( |
| 119 | obj, frame->MainWorldScriptContext())); |
dcheng | 0232f57 | 2016-05-27 17:47:44 | [diff] [blame] | 120 | DCHECK(content); |
Rob Wu | 90585e65 | 2017-12-26 17:09:25 | [diff] [blame] | 121 | // The conversion of |obj| could have triggered arbitrary JavaScript code, |
| 122 | // so check that the frame is still valid to avoid dereferencing a stale |
| 123 | // pointer. |
| 124 | if (frame != blink::WebLocalFrame::FrameForCurrentContext()) { |
| 125 | NOTREACHED(); |
| 126 | return; |
| 127 | } |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | // Send the message up to the browser. |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 131 | render_frame->Send(new FrameHostMsg_WebUISend(render_frame->GetRoutingID(), |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 132 | message, *content)); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | // static |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 136 | std::string WebUIExtension::GetVariableValue(const std::string& name) { |
lukasza | df18ba76 | 2017-06-09 22:24:30 | [diff] [blame] | 137 | blink::WebLocalFrame* frame; |
Lukasz Anforowicz | 0292310 | 2017-10-09 18:11:37 | [diff] [blame] | 138 | RenderFrame* render_frame; |
| 139 | if (!ShouldRespondToRequest(&frame, &render_frame)) |
[email protected] | f5c9f088 | 2014-02-16 22:19:32 | [diff] [blame] | 140 | return std::string(); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 141 | |
Nasko Oskov | dce1a62 | 2019-11-06 23:58:33 | [diff] [blame] | 142 | return WebUIExtensionData::Get(render_frame)->GetValue(name); |
[email protected] | 940ed1d | 2012-11-27 21:03:21 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | } // namespace content |