// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/extension_function.h" #include "base/json/json_writer.h" #include "base/logging.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/chrome_render_message_filter.h" #include "chrome/common/extensions/extension_messages.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/user_metrics.h" #include "content/common/content_notification_types.h" #include "content/common/notification_source.h" #include "content/common/result_codes.h" // static void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) { x->Destruct(); } UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( UIThreadExtensionFunction* function) : function_(function) { registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, Source(function->render_view_host())); } void UIThreadExtensionFunction::RenderViewHostTracker::Observe( int type, const NotificationSource& source, const NotificationDetails& details) { CHECK(type == content::NOTIFICATION_RENDER_VIEW_HOST_DELETED); CHECK(Source(source).ptr() == function_->render_view_host()); function_->SetRenderViewHost(NULL); } ExtensionFunction::ExtensionFunction() : request_id_(-1), profile_(NULL), has_callback_(false), include_incognito_(false), user_gesture_(false), args_(NULL), bad_message_(false) { } ExtensionFunction::~ExtensionFunction() { } UIThreadExtensionFunction* ExtensionFunction::AsUIThreadExtensionFunction() { return NULL; } IOThreadExtensionFunction* ExtensionFunction::AsIOThreadExtensionFunction() { return NULL; } void ExtensionFunction::SetArgs(const ListValue* args) { DCHECK(!args_.get()); // Should only be called once. args_.reset(args->DeepCopy()); } const std::string ExtensionFunction::GetResult() { std::string json; // Some functions might not need to return any results. if (result_.get()) base::JSONWriter::Write(result_.get(), false, &json); return json; } const std::string ExtensionFunction::GetError() { return error_; } void ExtensionFunction::Run() { if (!RunImpl()) SendResponse(false); } bool ExtensionFunction::HasOptionalArgument(size_t index) { Value* value; return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL); } void ExtensionFunction::SendResponseImpl(base::ProcessHandle process, IPC::Message::Sender* ipc_sender, int routing_id, bool success) { DCHECK(ipc_sender); if (bad_message_) { HandleBadMessage(process); return; } ipc_sender->Send(new ExtensionMsg_Response( routing_id, request_id_, success, GetResult(), GetError())); } void ExtensionFunction::HandleBadMessage(base::ProcessHandle process) { LOG(ERROR) << "bad extension message " << name_ << " : terminating renderer."; if (RenderProcessHost::run_renderer_in_process()) { // In single process mode it is better if we don't suicide but just crash. CHECK(false); } else { NOTREACHED(); UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); if (process) base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false); } } UIThreadExtensionFunction::UIThreadExtensionFunction() : render_view_host_(NULL), profile_(NULL) { } UIThreadExtensionFunction::~UIThreadExtensionFunction() { } UIThreadExtensionFunction* UIThreadExtensionFunction::AsUIThreadExtensionFunction() { return this; } void UIThreadExtensionFunction::Destruct() const { BrowserThread::DeleteOnUIThread::Destruct(this); } void UIThreadExtensionFunction::SetRenderViewHost( RenderViewHost* render_view_host) { render_view_host_ = render_view_host; tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); } Browser* UIThreadExtensionFunction::GetCurrentBrowser() { return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_); } void UIThreadExtensionFunction::SendResponse(bool success) { if (!render_view_host_ || !dispatcher()) return; SendResponseImpl(render_view_host_->process()->GetHandle(), render_view_host_, render_view_host_->routing_id(), success); } IOThreadExtensionFunction::IOThreadExtensionFunction() : routing_id_(-1) { } IOThreadExtensionFunction::~IOThreadExtensionFunction() { } IOThreadExtensionFunction* IOThreadExtensionFunction::AsIOThreadExtensionFunction() { return this; } void IOThreadExtensionFunction::Destruct() const { BrowserThread::DeleteOnIOThread::Destruct(this); } void IOThreadExtensionFunction::SendResponse(bool success) { if (!ipc_sender()) return; SendResponseImpl(ipc_sender()->peer_handle(), ipc_sender(), routing_id_, success); } AsyncExtensionFunction::AsyncExtensionFunction() { } AsyncExtensionFunction::~AsyncExtensionFunction() { } SyncExtensionFunction::SyncExtensionFunction() { } SyncExtensionFunction::~SyncExtensionFunction() { } void SyncExtensionFunction::Run() { SendResponse(RunImpl()); } SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() { } SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() { } void SyncIOThreadExtensionFunction::Run() { SendResponse(RunImpl()); }