1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/execute_code_in_tab_function.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_service.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module_constants.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/file_reader.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_error_utils.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_messages.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/render_view_host.h"
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/render_view_host.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace keys = extension_tabs_module_constants;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : ALLOW_THIS_IN_INITIALIZER_LIST(registrar_(this)),
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      execute_tab_id_(-1),
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      all_frames_(false) {
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExecuteCodeInTabFunction::RunImpl() {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* script_info;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t number_of_value = script_info->size();
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (number_of_value == 0) {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCodeOrFileToExecuteError;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_code = script_info->HasKey(keys::kCodeKey);
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_file = script_info->HasKey(keys::kFileKey);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (has_code && has_file) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kMoreThanOneValuesError;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (!has_code && !has_file) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCodeOrFileToExecuteError;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  execute_tab_id_ = -1;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If |tab_id| is specified, look for it. Otherwise default to selected tab
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in the current window.
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Value* tab_value = NULL;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_value->IsType(Value::TYPE_NULL)) {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser) {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!ExtensionTabUtil::GetDefaultTab(browser, &contents, &execute_tab_id_))
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      include_incognito(),
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &browser, NULL, &contents, NULL)) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: This can give the wrong answer due to race conditions, but it is OK,
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we check again in the renderer.
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(browser);
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(contents);
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!GetExtension()->CanExecuteScriptOnPage(
8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          contents->tab_contents()->GetURL(), NULL, &error_)) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kAllFramesKey)) {
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string code_string;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kCodeKey)) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetString(keys::kCodeKey, &code_string))
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!code_string.empty()) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!Execute(code_string))
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string relative_path;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kFileKey)) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetString(keys::kFileKey, &relative_path))
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    resource_ = GetExtension()->GetResource(relative_path);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCodeOrFileToExecuteError;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<FileReader> file_reader(new FileReader(
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile)));
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_reader->Start();
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Keep us alive until DidLoadFile is called.
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExecuteCodeInTabFunction::DidLoadFile(bool success,
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const std::string& data) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Execute(data);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX)
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // TODO(viettrungluu): bug: there's no particular reason the path should be
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // UTF-8, in which case this may fail.
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        resource_.relative_path().value());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN)
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        WideToUTF8(resource_.relative_path().value()));
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // OS_WIN
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balance the AddRef taken in RunImpl
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
146201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = ExtensionTabUtil::GetTabById(
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      execute_tab_id_, profile(), include_incognito(), &browser, NULL,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      &contents, NULL) && contents && browser;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!success) {
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = GetExtension();
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!extension) {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_js_code = true;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string function_name = name();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (function_name == TabsInsertCSSFunction::function_name()) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    is_js_code = false;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (function_name != TabsExecuteScriptFunction::function_name()) {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ExtensionMsg_ExecuteCode_Params params;
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.request_id = request_id();
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.extension_id = extension->id();
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.is_javascript = is_js_code;
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.code = code_string;
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.all_frames = all_frames_;
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.in_main_world = false;
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents->render_view_host()->Send(new ExtensionMsg_ExecuteCode(
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      contents->render_view_host()->routing_id(), params));
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar_.Observe(contents->tab_contents());
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AddRef();  // balanced in OnExecuteCodeFinished()
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ExecuteCodeInTabFunction::OnMessageReceived(const IPC::Message& message) {
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int message_request_id;
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void* iter = NULL;
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!message.ReadInt(&iter, &message_request_id)) {
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED() << "malformed extension message";
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (message_request_id != request_id())
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_BEGIN_MESSAGE_MAP(ExecuteCodeInTabFunction, message)
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        OnExecuteCodeFinished)
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_END_MESSAGE_MAP()
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExecuteCodeInTabFunction::OnExecuteCodeFinished(int request_id,
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                     bool success,
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                     const std::string& error) {
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!error.empty()) {
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(!success);
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = error;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(success);
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar_.Observe(NULL);
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Release();  // balanced in Execute()
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
221