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

Side by Side Diff: chrome/browser/automation/automation_extension_function.cc

Issue 366025: Modifying extension automation so that it is done through a particular... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 // Implements AutomationExtensionFunction. 5 // Implements AutomationExtensionFunction.
6 6
7 #include "chrome/browser/automation/automation_extension_function.h" 7 #include "chrome/browser/automation/automation_extension_function.h"
8 8
9 #include "base/json/json_reader.h" 9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h" 10 #include "base/json/json_writer.h"
11 #include "chrome/browser/automation/extension_automation_constants.h" 11 #include "chrome/browser/automation/extension_automation_constants.h"
12 #include "chrome/browser/extensions/extension_function_dispatcher.h" 12 #include "chrome/browser/extensions/extension_function_dispatcher.h"
13 #include "chrome/browser/renderer_host/render_view_host.h" 13 #include "chrome/browser/renderer_host/render_view_host.h"
14 #include "chrome/browser/renderer_host/render_view_host_delegate.h" 14 #include "chrome/browser/renderer_host/render_view_host_delegate.h"
15 #include "chrome/browser/tab_contents/tab_contents.h"
16 #include "chrome/browser/tab_contents/tab_contents_delegate.h"
15 17
16 bool AutomationExtensionFunction::enabled_ = false; 18 TabContents* AutomationExtensionFunction::api_handler_tab_ = NULL;
19 AutomationExtensionFunction::PendingFunctionsMap
20 AutomationExtensionFunction::pending_functions_;
17 21
18 void AutomationExtensionFunction::SetArgs(const Value* args) { 22 void AutomationExtensionFunction::SetArgs(const Value* args) {
23 // Need to JSON-encode for sending over the wire to the automation user.
19 base::JSONWriter::Write(args, false, &args_); 24 base::JSONWriter::Write(args, false, &args_);
20 } 25 }
21 26
22 const std::string AutomationExtensionFunction::GetResult() { 27 const std::string AutomationExtensionFunction::GetResult() {
23 // Our API result passing is done through InterceptMessageFromExternalHost 28 // Already JSON-encoded, so override the base class's implementation.
24 return ""; 29 return json_result_;
25 } 30 }
26 31
27 const std::string AutomationExtensionFunction::GetError() { 32 bool AutomationExtensionFunction::RunImpl() {
28 // Our API result passing is done through InterceptMessageFromExternalHost 33 namespace keys = extension_automation_constants;
29 return "";
30 }
31 34
32 void AutomationExtensionFunction::Run() { 35 DCHECK(api_handler_tab_) <<
33 namespace keys = extension_automation_constants; 36 "Why is this function still enabled if no target tab?";
37 if (!api_handler_tab_) {
38 error_ = "No longer automating functions.";
39 return false;
40 }
34 41
35 // We are being driven through automation, so we send the extension API 42 // We are being driven through automation, so we send the extension API
36 // request over to the automation host. We do this before decoding the 43 // request over to the automation host. We do this before decoding the
37 // 'args' JSON, otherwise we'd be decoding it only to encode it again. 44 // 'args' JSON, otherwise we'd be decoding it only to encode it again.
38 DictionaryValue message_to_host; 45 DictionaryValue message_to_host;
39 message_to_host.SetString(keys::kAutomationNameKey, name_); 46 message_to_host.SetString(keys::kAutomationNameKey, name_);
40 message_to_host.SetString(keys::kAutomationArgsKey, args_); 47 message_to_host.SetString(keys::kAutomationArgsKey, args_);
41 message_to_host.SetInteger(keys::kAutomationRequestIdKey, request_id_); 48 message_to_host.SetInteger(keys::kAutomationRequestIdKey, request_id_);
42 message_to_host.SetBoolean(keys::kAutomationHasCallbackKey, has_callback_); 49 message_to_host.SetBoolean(keys::kAutomationHasCallbackKey, has_callback_);
43 50
44 std::string message; 51 std::string message;
45 base::JSONWriter::Write(&message_to_host, false, &message); 52 base::JSONWriter::Write(&message_to_host, false, &message);
46 dispatcher()->render_view_host_->delegate()->ProcessExternalHostMessage( 53 if (api_handler_tab_->delegate()) {
47 message, keys::kAutomationOrigin, keys::kAutomationRequestTarget); 54 api_handler_tab_->delegate()->ForwardMessageToExternalHost(
55 message, keys::kAutomationOrigin, keys::kAutomationRequestTarget);
56 } else {
57 NOTREACHED() << "ExternalTabContainer is supposed to correctly manage "
58 "lifetime of api_handler_tab_.";
59 }
60
61 // Automation APIs are asynchronous so we need to stick around until
62 // our response comes back. Add ourselves to a static hash map keyed
63 // by request ID. The hash map keeps a reference count on us.
64 DCHECK(pending_functions_.find(request_id_) == pending_functions_.end());
65 pending_functions_[request_id_] = this;
66
67 return true;
48 } 68 }
49 69
50 ExtensionFunction* AutomationExtensionFunction::Factory() { 70 ExtensionFunction* AutomationExtensionFunction::Factory() {
51 return new AutomationExtensionFunction(); 71 return new AutomationExtensionFunction();
52 } 72 }
53 73
54 void AutomationExtensionFunction::SetEnabled( 74 void AutomationExtensionFunction::Enable(
75 TabContents* api_handler_tab,
55 const std::vector<std::string>& functions_enabled) { 76 const std::vector<std::string>& functions_enabled) {
56 if (functions_enabled.size() > 0) { 77 DCHECK(api_handler_tab);
57 std::vector<std::string> function_names; 78 if (api_handler_tab_ && api_handler_tab != api_handler_tab_) {
58 if (functions_enabled.size() == 1 && functions_enabled[0] == "*") { 79 NOTREACHED() << "Don't call with different API handler.";
59 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); 80 return;
60 } else { 81 }
61 function_names = functions_enabled; 82 api_handler_tab_ = api_handler_tab;
62 }
63 83
64 for (std::vector<std::string>::iterator it = function_names.begin(); 84 std::vector<std::string> function_names;
65 it != function_names.end(); it++) { 85 if (functions_enabled.size() == 1 && functions_enabled[0] == "*") {
66 // TODO(joi) Could make this a per-profile change rather than a global 86 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names);
67 // change. Could e.g. have the AutomationExtensionFunction store the
68 // profile pointer and dispatch to the original ExtensionFunction when the
69 // current profile is not that.
70 bool result = ExtensionFunctionDispatcher::OverrideFunction(
71 *it, AutomationExtensionFunction::Factory);
72 LOG_IF(WARNING, !result) << "Failed to override API function: " << *it;
73 }
74 } else { 87 } else {
75 ExtensionFunctionDispatcher::ResetFunctions(); 88 function_names = functions_enabled;
76 } 89 }
90
91 for (std::vector<std::string>::iterator it = function_names.begin();
92 it != function_names.end(); it++) {
93 // TODO(joi) Could make this a per-profile change rather than a global
94 // change. Could e.g. have the AutomationExtensionFunction store the
95 // profile pointer and dispatch to the original ExtensionFunction when the
96 // current profile is not that.
97 bool result = ExtensionFunctionDispatcher::OverrideFunction(
98 *it, AutomationExtensionFunction::Factory);
99 LOG_IF(WARNING, !result) << "Failed to override API function: " << *it;
100 }
101 }
102
103 void AutomationExtensionFunction::Disable() {
104 api_handler_tab_ = NULL;
105 ExtensionFunctionDispatcher::ResetFunctions();
77 } 106 }
78 107
79 bool AutomationExtensionFunction::InterceptMessageFromExternalHost( 108 bool AutomationExtensionFunction::InterceptMessageFromExternalHost(
80 RenderViewHost* view_host, 109 RenderViewHost* view_host,
81 const std::string& message, 110 const std::string& message,
82 const std::string& origin, 111 const std::string& origin,
83 const std::string& target) { 112 const std::string& target) {
84 namespace keys = extension_automation_constants; 113 namespace keys = extension_automation_constants;
85 114
86 if (origin == keys::kAutomationOrigin && 115 // We want only specially-tagged messages passed via the conduit tab.
116 if (api_handler_tab_ &&
117 view_host == api_handler_tab_->render_view_host() &&
118 origin == keys::kAutomationOrigin &&
87 target == keys::kAutomationResponseTarget) { 119 target == keys::kAutomationResponseTarget) {
88 // This is an extension API response being sent back via postMessage, 120 // This is an extension API response being sent back via postMessage,
89 // so redirect it. 121 // so redirect it.
90 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false)); 122 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false));
91 DCHECK(message_value->IsType(Value::TYPE_DICTIONARY)); 123 DCHECK(message_value->IsType(Value::TYPE_DICTIONARY));
92 if (message_value->IsType(Value::TYPE_DICTIONARY)) { 124 if (message_value->IsType(Value::TYPE_DICTIONARY)) {
93 DictionaryValue* message_dict = 125 DictionaryValue* message_dict =
94 reinterpret_cast<DictionaryValue*>(message_value.get()); 126 reinterpret_cast<DictionaryValue*>(message_value.get());
95 127
96 int request_id = -1; 128 int request_id = -1;
97 bool got_value = message_dict->GetInteger(keys::kAutomationRequestIdKey, 129 bool got_value = message_dict->GetInteger(keys::kAutomationRequestIdKey,
98 &request_id); 130 &request_id);
99 DCHECK(got_value); 131 DCHECK(got_value);
100 if (got_value) { 132 if (got_value) {
101 std::string error; 133 std::string error;
102 bool success = !message_dict->GetString(keys::kAutomationErrorKey, 134 bool success = !message_dict->GetString(keys::kAutomationErrorKey,
103 &error); 135 &error);
104 136
105 std::string response; 137 std::string response;
106 got_value = message_dict->GetString(keys::kAutomationResponseKey, 138 got_value = message_dict->GetString(keys::kAutomationResponseKey,
107 &response); 139 &response);
108 DCHECK(!success || got_value); 140 DCHECK(!success || got_value);
109 141
110 // TODO(joi) Once ExtensionFunctionDispatcher supports asynchronous 142 PendingFunctionsMap::iterator it = pending_functions_.find(request_id);
111 // functions, we should use that instead. 143 DCHECK(it != pending_functions_.end());
112 view_host->SendExtensionResponse(request_id, success, 144
113 response, error); 145 if (it != pending_functions_.end()) {
146 scoped_refptr<AutomationExtensionFunction> func = it->second;
147 pending_functions_.erase(it);
148
149 // Our local ref should be the last remaining.
150 DCHECK(func && func->HasOneRef());
151
152 if (func) {
153 func->json_result_ = response;
154 func->error_ = error;
155
156 func->SendResponse(success);
157 }
158 }
114 return true; 159 return true;
115 } 160 }
116 } 161 }
117 } 162 }
118 163
119 return false; 164 return false;
120 } 165 }
OLDNEW
« no previous file with comments | « chrome/browser/automation/automation_extension_function.h ('k') | chrome/browser/automation/automation_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698