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