Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome/browser/extensions/api/automation_internal/automation_internal_api.cc

Issue 655273005: Implement AutomationNode.querySelector(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Fix heap-use-after-free issue by not keeping a scoped_ptr to automation_api_helper in extension_hel… Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h" 5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/strings/string16.h"
9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/accessibility/ax_tree_id_registry.h" 12 #include "chrome/browser/accessibility/ax_tree_id_registry.h"
11 #include "chrome/browser/extensions/api/automation_internal/automation_action_ad apter.h" 13 #include "chrome/browser/extensions/api/automation_internal/automation_action_ad apter.h"
12 #include "chrome/browser/extensions/api/automation_internal/automation_util.h" 14 #include "chrome/browser/extensions/api/automation_internal/automation_util.h"
13 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 15 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
14 #include "chrome/browser/extensions/extension_tab_util.h" 16 #include "chrome/browser/extensions/extension_tab_util.h"
15 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/extensions/api/automation_internal.h" 20 #include "chrome/common/extensions/api/automation_internal.h"
19 #include "chrome/common/extensions/manifest_handlers/automation.h" 21 #include "chrome/common/extensions/manifest_handlers/automation.h"
20 #include "content/public/browser/ax_event_notification_details.h" 22 #include "content/public/browser/ax_event_notification_details.h"
21 #include "content/public/browser/browser_accessibility_state.h" 23 #include "content/public/browser/browser_accessibility_state.h"
22 #include "content/public/browser/render_frame_host.h" 24 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_process_host.h" 25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/render_widget_host.h" 27 #include "content/public/browser/render_widget_host.h"
25 #include "content/public/browser/render_widget_host_view.h" 28 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents.h"
30 #include "extensions/common/extension_messages.h"
27 #include "extensions/common/permissions/permissions_data.h" 31 #include "extensions/common/permissions/permissions_data.h"
28 32
29 #if defined(OS_CHROMEOS) 33 #if defined(OS_CHROMEOS)
30 #include "chrome/browser/ui/ash/accessibility/automation_manager_ash.h" 34 #include "chrome/browser/ui/ash/accessibility/automation_manager_ash.h"
31 #endif 35 #endif
32 36
33 namespace extensions { 37 namespace extensions {
34 class AutomationWebContentsObserver; 38 class AutomationWebContentsObserver;
35 } // namespace extensions 39 } // namespace extensions
36 40
37 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver); 41 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver);
38 42
43 namespace extensions {
44
39 namespace { 45 namespace {
40 const int kDesktopTreeID = 0; 46 const int kDesktopTreeID = 0;
41 const char kCannotRequestAutomationOnPage[] = 47 const char kCannotRequestAutomationOnPage[] =
42 "Cannot request automation tree on url \"*\". " 48 "Cannot request automation tree on url \"*\". "
43 "Extension manifest must request permission to access this host."; 49 "Extension manifest must request permission to access this host.";
44 } // namespace 50 const char kRendererDestroyed[] = "The tab was closed.";
51 const char kNoMainFrame[] = "No main frame.";
52 const char kNoDocument[] = "No document.";
53 const char kNodeDestroyed[] =
54 "querySelector sent on node which is no longer in the tree.";
45 55
46 namespace extensions { 56 // Handles sending and receiving IPCs for a single querySelector request. On
57 // creation, sends the request IPC, and is destroyed either when the response is
58 // received or the renderer is destroyed.
59 class QuerySelectorHandler : public content::WebContentsObserver {
60 public:
61 QuerySelectorHandler(
62 content::WebContents* web_contents,
63 int request_id,
64 int acc_obj_id,
65 const base::string16& query,
66 const extensions::AutomationInternalQuerySelectorFunction::Callback&
67 callback)
68 : content::WebContentsObserver(web_contents),
69 request_id_(request_id),
70 callback_(callback) {
71 content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
72
73 rvh->Send(new ExtensionMsg_AutomationQuerySelector(
74 rvh->GetRoutingID(), request_id, acc_obj_id, query));
75 }
76
77 ~QuerySelectorHandler() override {}
78
79 bool OnMessageReceived(const IPC::Message& message) override {
80 if (message.type() != ExtensionHostMsg_AutomationQuerySelector_Result::ID)
81 return false;
82
83 // There may be several requests in flight; check this response matches.
84 int message_request_id = 0;
85 PickleIterator iter(message);
86 if (!message.ReadInt(&iter, &message_request_id))
87 return false;
88
89 if (message_request_id != request_id_)
90 return false;
91
92 IPC_BEGIN_MESSAGE_MAP(QuerySelectorHandler, message)
93 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AutomationQuerySelector_Result,
94 OnQueryResponse)
95 IPC_END_MESSAGE_MAP()
96 return true;
97 }
98
99 void WebContentsDestroyed() override {
100 callback_.Run(kRendererDestroyed, 0);
101 delete this;
102 }
103
104 private:
105 void OnQueryResponse(int request_id,
106 ExtensionHostMsg_AutomationQuerySelector_Error error,
107 int result_acc_obj_id) {
108 std::string error_string;
109 switch (error.value) {
110 case ExtensionHostMsg_AutomationQuerySelector_Error::kNone:
111 error_string = "";
112 break;
113 case ExtensionHostMsg_AutomationQuerySelector_Error::kNoMainFrame:
114 error_string = kNoMainFrame;
115 break;
116 case ExtensionHostMsg_AutomationQuerySelector_Error::kNoDocument:
117 error_string = kNoDocument;
118 break;
119 case ExtensionHostMsg_AutomationQuerySelector_Error::kNodeDestroyed:
120 error_string = kNodeDestroyed;
121 break;
122 }
123 callback_.Run(error_string, result_acc_obj_id);
124 delete this;
125 }
126
127 int request_id_;
128 const extensions::AutomationInternalQuerySelectorFunction::Callback callback_;
129 };
47 130
48 bool CanRequestAutomation(const Extension* extension, 131 bool CanRequestAutomation(const Extension* extension,
49 const AutomationInfo* automation_info, 132 const AutomationInfo* automation_info,
50 const content::WebContents* contents) { 133 const content::WebContents* contents) {
51 if (automation_info->desktop) 134 if (automation_info->desktop)
52 return true; 135 return true;
53 136
54 const GURL& url = contents->GetURL(); 137 const GURL& url = contents->GetURL();
55 // TODO(aboxhall): check for webstore URL 138 // TODO(aboxhall): check for webstore URL
56 if (automation_info->matches.MatchesURL(url)) 139 if (automation_info->matches.MatchesURL(url))
57 return true; 140 return true;
58 141
59 int tab_id = ExtensionTabUtil::GetTabId(contents); 142 int tab_id = ExtensionTabUtil::GetTabId(contents);
60 content::RenderProcessHost* process = contents->GetRenderProcessHost(); 143 content::RenderProcessHost* process = contents->GetRenderProcessHost();
61 int process_id = process ? process->GetID() : -1; 144 int process_id = process ? process->GetID() : -1;
62 std::string unused_error; 145 std::string unused_error;
63 return extension->permissions_data()->CanAccessPage( 146 return extension->permissions_data()->CanAccessPage(
64 extension, url, url, tab_id, process_id, &unused_error); 147 extension, url, url, tab_id, process_id, &unused_error);
65 } 148 }
66 149
150 // Helper class that implements an action adapter for a |RenderFrameHost|.
151 class RenderFrameHostActionAdapter : public AutomationActionAdapter {
152 public:
153 explicit RenderFrameHostActionAdapter(content::RenderFrameHost* rfh)
154 : rfh_(rfh) {}
155
156 virtual ~RenderFrameHostActionAdapter() {}
157
158 // AutomationActionAdapter implementation.
159 void DoDefault(int32 id) override { rfh_->AccessibilityDoDefaultAction(id); }
160
161 void Focus(int32 id) override { rfh_->AccessibilitySetFocus(id); }
162
163 void MakeVisible(int32 id) override {
164 rfh_->AccessibilityScrollToMakeVisible(id, gfx::Rect());
165 }
166
167 void SetSelection(int32 id, int32 start, int32 end) override {
168 rfh_->AccessibilitySetTextSelection(id, start, end);
169 }
170
171 private:
172 content::RenderFrameHost* rfh_;
173
174 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostActionAdapter);
175 };
176
177 } // namespace
178
67 // Helper class that receives accessibility data from |WebContents|. 179 // Helper class that receives accessibility data from |WebContents|.
68 class AutomationWebContentsObserver 180 class AutomationWebContentsObserver
69 : public content::WebContentsObserver, 181 : public content::WebContentsObserver,
70 public content::WebContentsUserData<AutomationWebContentsObserver> { 182 public content::WebContentsUserData<AutomationWebContentsObserver> {
71 public: 183 public:
72 ~AutomationWebContentsObserver() override {} 184 ~AutomationWebContentsObserver() override {}
73 185
74 // content::WebContentsObserver overrides. 186 // content::WebContentsObserver overrides.
75 void AccessibilityEventReceived( 187 void AccessibilityEventReceived(
76 const std::vector<content::AXEventNotificationDetails>& details) 188 const std::vector<content::AXEventNotificationDetails>& details)
(...skipping 17 matching lines...) Expand all
94 AutomationWebContentsObserver( 206 AutomationWebContentsObserver(
95 content::WebContents* web_contents) 207 content::WebContents* web_contents)
96 : content::WebContentsObserver(web_contents), 208 : content::WebContentsObserver(web_contents),
97 browser_context_(web_contents->GetBrowserContext()) {} 209 browser_context_(web_contents->GetBrowserContext()) {}
98 210
99 content::BrowserContext* browser_context_; 211 content::BrowserContext* browser_context_;
100 212
101 DISALLOW_COPY_AND_ASSIGN(AutomationWebContentsObserver); 213 DISALLOW_COPY_AND_ASSIGN(AutomationWebContentsObserver);
102 }; 214 };
103 215
104 // Helper class that implements an action adapter for a |RenderFrameHost|.
105 class RenderFrameHostActionAdapter : public AutomationActionAdapter {
106 public:
107 explicit RenderFrameHostActionAdapter(content::RenderFrameHost* rfh)
108 : rfh_(rfh) {}
109
110 virtual ~RenderFrameHostActionAdapter() {}
111
112 // AutomationActionAdapter implementation.
113 void DoDefault(int32 id) override { rfh_->AccessibilityDoDefaultAction(id); }
114
115 void Focus(int32 id) override { rfh_->AccessibilitySetFocus(id); }
116
117 void MakeVisible(int32 id) override {
118 rfh_->AccessibilityScrollToMakeVisible(id, gfx::Rect());
119 }
120
121 void SetSelection(int32 id, int32 start, int32 end) override {
122 rfh_->AccessibilitySetTextSelection(id, start, end);
123 }
124
125 private:
126 content::RenderFrameHost* rfh_;
127
128 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostActionAdapter);
129 };
130
131 ExtensionFunction::ResponseAction 216 ExtensionFunction::ResponseAction
132 AutomationInternalEnableTabFunction::Run() { 217 AutomationInternalEnableTabFunction::Run() {
133 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 218 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
134 EXTENSION_FUNCTION_VALIDATE(automation_info); 219 EXTENSION_FUNCTION_VALIDATE(automation_info);
135 220
136 using api::automation_internal::EnableTab::Params; 221 using api::automation_internal::EnableTab::Params;
137 scoped_ptr<Params> params(Params::Create(*args_)); 222 scoped_ptr<Params> params(Params::Create(*args_));
138 EXTENSION_FUNCTION_VALIDATE(params.get()); 223 EXTENSION_FUNCTION_VALIDATE(params.get());
139 content::WebContents* contents = NULL; 224 content::WebContents* contents = NULL;
140 if (params->tab_id.get()) { 225 if (params->tab_id.get()) {
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 if (!automation_info || !automation_info->desktop) 354 if (!automation_info || !automation_info->desktop)
270 return RespondNow(Error("desktop permission must be requested")); 355 return RespondNow(Error("desktop permission must be requested"));
271 356
272 AutomationManagerAsh::GetInstance()->Enable(browser_context()); 357 AutomationManagerAsh::GetInstance()->Enable(browser_context());
273 return RespondNow(NoArguments()); 358 return RespondNow(NoArguments());
274 #else 359 #else
275 return RespondNow(Error("getDesktop is unsupported by this platform")); 360 return RespondNow(Error("getDesktop is unsupported by this platform"));
276 #endif // defined(OS_CHROMEOS) 361 #endif // defined(OS_CHROMEOS)
277 } 362 }
278 363
364 // static
365 int AutomationInternalQuerySelectorFunction::query_request_id_counter_ = 0;
366
367 ExtensionFunction::ResponseAction
368 AutomationInternalQuerySelectorFunction::Run() {
369 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
370 EXTENSION_FUNCTION_VALIDATE(automation_info);
371
372 using api::automation_internal::QuerySelector::Params;
373 scoped_ptr<Params> params(Params::Create(*args_));
374 EXTENSION_FUNCTION_VALIDATE(params.get());
375
376 if (params->args.tree_id == kDesktopTreeID) {
377 return RespondNow(
378 Error("querySelector queries may not be used on the desktop."));
379 }
380 AXTreeIDRegistry::FrameID frame_id =
381 AXTreeIDRegistry::GetInstance()->GetFrameID(params->args.tree_id);
382 content::RenderFrameHost* rfh =
383 content::RenderFrameHost::FromID(frame_id.first, frame_id.second);
384 if (!rfh)
385 return RespondNow(Error("querySelector query sent on destroyed tree."));
386
387 content::WebContents* contents =
388 content::WebContents::FromRenderFrameHost(rfh);
389
390 int request_id = query_request_id_counter_++;
391 base::string16 selector = base::UTF8ToUTF16(params->args.selector);
392
393 // QuerySelectorHandler handles IPCs and deletes itself on completion.
394 new QuerySelectorHandler(
395 contents, request_id, params->args.automation_node_id, selector,
396 base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this));
397
398 return RespondLater();
399 }
400
401 void AutomationInternalQuerySelectorFunction::OnResponse(
402 const std::string& error,
403 int result_acc_obj_id) {
404 if (!error.empty()) {
405 Respond(Error(error));
406 return;
407 }
408
409 Respond(OneArgument(new base::FundamentalValue(result_acc_obj_id)));
410 }
411
279 } // namespace extensions 412 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698