// Copyright (c) 2013 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 "content/browser/browser_plugin/browser_plugin_guest_manager.h" #include "content/browser/browser_plugin/browser_plugin_guest.h" #include "content/browser/browser_plugin/browser_plugin_host_factory.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/browser_plugin/browser_plugin_constants.h" #include "content/common/browser_plugin/browser_plugin_messages.h" #include "content/common/content_export.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_plugin_guest_manager_delegate.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/user_metrics.h" #include "content/public/common/content_client.h" #include "content/public/common/result_codes.h" #include "content/public/common/url_constants.h" #include "content/public/common/url_utils.h" #include "net/base/escape.h" namespace content { // static BrowserPluginHostFactory* BrowserPluginGuestManager::factory_ = NULL; BrowserPluginGuestManager::BrowserPluginGuestManager(BrowserContext* context) : context_(context) {} BrowserPluginGuestManagerDelegate* BrowserPluginGuestManager::GetDelegate() const { return context_->GetGuestManagerDelegate(); } BrowserPluginGuestManager::~BrowserPluginGuestManager() { } // static. BrowserPluginGuestManager* BrowserPluginGuestManager::FromBrowserContext( BrowserContext* context) { BrowserPluginGuestManager* guest_manager = static_cast( context->GetUserData( browser_plugin::kBrowserPluginGuestManagerKeyName)); if (!guest_manager) { guest_manager = BrowserPluginGuestManager::Create(context); context->SetUserData(browser_plugin::kBrowserPluginGuestManagerKeyName, guest_manager); } return guest_manager; } // static BrowserPluginGuestManager* BrowserPluginGuestManager::Create( BrowserContext* context) { if (factory_) return factory_->CreateBrowserPluginGuestManager(context); return new BrowserPluginGuestManager(context); } int BrowserPluginGuestManager::GetNextInstanceID() { if (!GetDelegate()) return 0; return GetDelegate()->GetNextInstanceID(); } BrowserPluginGuest* BrowserPluginGuestManager::CreateGuest( SiteInstance* embedder_site_instance, int instance_id, const BrowserPluginHostMsg_Attach_Params& params, scoped_ptr extra_params) { RenderProcessHost* embedder_process_host = embedder_site_instance->GetProcess(); // Validate that the partition id coming from the renderer is valid UTF-8, // since we depend on this in other parts of the code, such as FilePath // creation. If the validation fails, treat it as a bad message and kill the // renderer process. if (!base::IsStringUTF8(params.storage_partition_id)) { content::RecordAction( base::UserMetricsAction("BadMessageTerminate_BPGM")); base::KillProcess( embedder_process_host->GetHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE, false); return NULL; } const GURL& embedder_site_url = embedder_site_instance->GetSiteURL(); const std::string& host = embedder_site_url.host(); std::string url_encoded_partition = net::EscapeQueryParamValue( params.storage_partition_id, false); // The SiteInstance of a given webview tag is based on the fact that it's // a guest process in addition to which platform application the tag // belongs to and what storage partition is in use, rather than the URL // that the tag is being navigated to. GURL guest_site(base::StringPrintf("%s://%s/%s?%s", kGuestScheme, host.c_str(), params.persist_storage ? "persist" : "", url_encoded_partition.c_str())); // If we already have a webview tag in the same app using the same storage // partition, we should use the same SiteInstance so the existing tag and // the new tag can script each other. SiteInstance* guest_site_instance = GetGuestSiteInstance(guest_site); if (!guest_site_instance) { // Create the SiteInstance in a new BrowsingInstance, which will ensure // that webview tags are also not allowed to send messages across // different partitions. guest_site_instance = SiteInstance::CreateForURL( embedder_site_instance->GetBrowserContext(), guest_site); } return WebContentsImpl::CreateGuest( embedder_site_instance->GetBrowserContext(), guest_site_instance, instance_id, extra_params.Pass()); } static void BrowserPluginGuestByInstanceIDCallback( const BrowserPluginGuestManager::GuestByInstanceIDCallback& callback, WebContents* guest_web_contents) { if (!guest_web_contents) { callback.Run(NULL); return; } callback.Run(static_cast(guest_web_contents)-> GetBrowserPluginGuest()); } void BrowserPluginGuestManager::MaybeGetGuestByInstanceIDOrKill( int instance_id, int embedder_render_process_id, const GuestByInstanceIDCallback& callback) const { if (!GetDelegate()) { callback.Run(NULL); return; } GetDelegate()->MaybeGetGuestByInstanceIDOrKill( instance_id, embedder_render_process_id, base::Bind(&BrowserPluginGuestByInstanceIDCallback, callback)); } void BrowserPluginGuestManager::AddGuest(int instance_id, WebContents* guest_web_contents) { if (!GetDelegate()) return; GetDelegate()->AddGuest(instance_id, guest_web_contents); } void BrowserPluginGuestManager::RemoveGuest(int instance_id) { if (!GetDelegate()) return; GetDelegate()->RemoveGuest(instance_id); } static void BrowserPluginGuestMessageCallback(const IPC::Message& message, BrowserPluginGuest* guest) { if (!guest) return; guest->OnMessageReceivedFromEmbedder(message); } void BrowserPluginGuestManager::OnMessageReceived(const IPC::Message& message, int render_process_id) { DCHECK(BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message)); int instance_id = 0; // All allowed messages must have instance_id as their first parameter. PickleIterator iter(message); bool success = iter.ReadInt(&instance_id); DCHECK(success); MaybeGetGuestByInstanceIDOrKill(instance_id, render_process_id, base::Bind(&BrowserPluginGuestMessageCallback, message)); } SiteInstance* BrowserPluginGuestManager::GetGuestSiteInstance( const GURL& guest_site) { if (!GetDelegate()) return NULL; return GetDelegate()->GetGuestSiteInstance(guest_site); } static bool BrowserPluginGuestCallback( const BrowserPluginGuestManager::GuestCallback& callback, WebContents* guest_web_contents) { return callback.Run(static_cast(guest_web_contents) ->GetBrowserPluginGuest()); } bool BrowserPluginGuestManager::ForEachGuest( WebContents* embedder_web_contents, const GuestCallback& callback) { if (!GetDelegate()) return false; return GetDelegate()->ForEachGuest(embedder_web_contents, base::Bind(&BrowserPluginGuestCallback, callback)); } } // namespace content