Index: content/browser/browser_plugin/browser_plugin_guest.cc |
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc |
index 301fa0647581969a7533b58424880edcbb1a4f32..d9b86594d2bde61efa51f4b9767510e981b2c720 100644 |
--- a/content/browser/browser_plugin/browser_plugin_guest.cc |
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc |
@@ -55,103 +55,7 @@ namespace content { |
// static |
BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL; |
-// Parent class for the various types of permission requests, each of which |
-// should be able to handle the response to their permission request. |
-class BrowserPluginGuest::PermissionRequest : |
- public base::RefCounted<BrowserPluginGuest::PermissionRequest> { |
- public: |
- void Respond(bool should_allow, const std::string& user_input) { |
- if (!guest_) |
- return; |
- RespondImpl(should_allow, user_input); |
- } |
- virtual bool AllowedByDefault() const { |
- return false; |
- } |
- protected: |
- explicit PermissionRequest(const base::WeakPtr<BrowserPluginGuest>& guest) |
- : guest_(guest) { |
- RecordAction( |
- base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest")); |
- } |
- virtual ~PermissionRequest() {} |
- |
- virtual void RespondImpl(bool should_allow, |
- const std::string& user_input) = 0; |
- // Friend RefCounted so that the dtor can be non-public. |
- friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>; |
- |
- base::WeakPtr<BrowserPluginGuest> guest_; |
-}; |
- |
-class BrowserPluginGuest::NewWindowRequest : public PermissionRequest { |
- public: |
- NewWindowRequest(const base::WeakPtr<BrowserPluginGuest>& guest, |
- int instance_id) |
- : PermissionRequest(guest), |
- instance_id_(instance_id) { |
- RecordAction( |
- base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow")); |
- } |
- |
- virtual void RespondImpl(bool should_allow, |
- const std::string& user_input) OVERRIDE { |
- int embedder_render_process_id = |
- guest_->embedder_web_contents()->GetRenderProcessHost()->GetID(); |
- guest_->GetBrowserPluginGuestManager()-> |
- MaybeGetGuestByInstanceIDOrKill( |
- instance_id_, |
- embedder_render_process_id, |
- base::Bind(&BrowserPluginGuest::NewWindowRequest::RespondInternal, |
- base::Unretained(this), |
- should_allow)); |
- } |
- |
- private: |
- virtual ~NewWindowRequest() {} |
- |
- void RespondInternal(bool should_allow, |
- WebContents* guest_web_contents) { |
- if (!guest_web_contents) { |
- VLOG(0) << "Guest not found. Instance ID: " << instance_id_; |
- return; |
- } |
- |
- BrowserPluginGuest* guest = |
- static_cast<WebContentsImpl*>(guest_web_contents)-> |
- GetBrowserPluginGuest(); |
- DCHECK(guest); |
- // If we do not destroy the guest then we allow the new window. |
- if (!should_allow) |
- guest->Destroy(); |
- } |
- |
- int instance_id_; |
-}; |
- |
namespace { |
-std::string WindowOpenDispositionToString( |
- WindowOpenDisposition window_open_disposition) { |
- switch (window_open_disposition) { |
- case IGNORE_ACTION: |
- return "ignore"; |
- case SAVE_TO_DISK: |
- return "save_to_disk"; |
- case CURRENT_TAB: |
- return "current_tab"; |
- case NEW_BACKGROUND_TAB: |
- return "new_background_tab"; |
- case NEW_FOREGROUND_TAB: |
- return "new_foreground_tab"; |
- case NEW_WINDOW: |
- return "new_window"; |
- case NEW_POPUP: |
- return "new_popup"; |
- default: |
- NOTREACHED() << "Unknown Window Open Disposition"; |
- return "ignore"; |
- } |
-} |
} // namespace |
@@ -201,7 +105,6 @@ BrowserPluginGuest::BrowserPluginGuest( |
embedder_visible_(true), |
auto_size_enabled_(false), |
copy_request_id_(0), |
- next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID), |
has_render_view_(has_render_view), |
last_seen_auto_size_enabled_(false), |
is_in_destruction_(false), |
@@ -225,116 +128,9 @@ bool BrowserPluginGuest::AddMessageToConsole(WebContents* source, |
return true; |
} |
-void BrowserPluginGuest::DestroyUnattachedWindows() { |
- // Destroy() reaches in and removes the BrowserPluginGuest from its opener's |
- // pending_new_windows_ set. To avoid mutating the set while iterating, we |
- // create a copy of the pending new windows set and iterate over the copy. |
- PendingWindowMap pending_new_windows(pending_new_windows_); |
- // Clean up unattached new windows opened by this guest. |
- for (PendingWindowMap::const_iterator it = pending_new_windows.begin(); |
- it != pending_new_windows.end(); ++it) { |
- it->first->Destroy(); |
- } |
- // All pending windows should be removed from the set after Destroy() is |
- // called on all of them. |
- DCHECK(pending_new_windows_.empty()); |
-} |
- |
-void BrowserPluginGuest::LoadURLWithParams(const GURL& url, |
- const Referrer& referrer, |
- PageTransition transition_type, |
- WebContents* web_contents) { |
- NavigationController::LoadURLParams load_url_params(url); |
- load_url_params.referrer = referrer; |
- load_url_params.transition_type = transition_type; |
- load_url_params.extra_headers = std::string(); |
- if (delegate_ && delegate_->IsOverridingUserAgent()) { |
- load_url_params.override_user_agent = |
- NavigationController::UA_OVERRIDE_TRUE; |
- } |
- web_contents->GetController().LoadURLWithParams(load_url_params); |
-} |
- |
-void BrowserPluginGuest::RespondToPermissionRequest( |
- int request_id, |
- bool should_allow, |
- const std::string& user_input) { |
- RequestMap::iterator request_itr = permission_request_map_.find(request_id); |
- if (request_itr == permission_request_map_.end()) { |
- VLOG(0) << "Not a valid request ID."; |
- return; |
- } |
- request_itr->second->Respond(should_allow, user_input); |
- permission_request_map_.erase(request_itr); |
-} |
- |
-void BrowserPluginGuest::RequestPermission( |
- BrowserPluginPermissionType permission_type, |
- scoped_refptr<BrowserPluginGuest::PermissionRequest> request, |
- const base::DictionaryValue& request_info) { |
- if (!delegate_) { |
- // Let the stack unwind before we deny the permission request so that |
- // objects held by the permission request are not destroyed immediately |
- // after creation. This is to allow those same objects to be accessed again |
- // in the same scope without fear of use after freeing. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&BrowserPluginGuest::PermissionRequest::Respond, |
- request, false, "")); |
- } |
- |
- int request_id = ++next_permission_request_id_; |
- permission_request_map_[request_id] = request; |
- |
- BrowserPluginGuestDelegate::PermissionResponseCallback callback = |
- base::Bind(&BrowserPluginGuest::RespondToPermissionRequest, |
- AsWeakPtr(), |
- request_id); |
- delegate_->RequestPermission( |
- permission_type, request_info, callback, request->AllowedByDefault()); |
-} |
- |
-BrowserPluginGuest* BrowserPluginGuest::CreateNewGuestWindow( |
- const OpenURLParams& params) { |
- BrowserPluginGuestManager* guest_manager = |
- GetBrowserPluginGuestManager(); |
- |
- // Allocate a new instance ID for the new guest. |
- int instance_id = guest_manager->GetNextInstanceID(); |
- |
- // Set the attach params to use the same partition as the opener. |
- // We pull the partition information from the site's URL, which is of the form |
- // guest://site/{persist}?{partition_name}. |
- const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL(); |
- |
- // The new guest gets a copy of this guest's extra params so that the content |
- // embedder exposes the same API for this guest as its opener. |
- scoped_ptr<base::DictionaryValue> extra_params( |
- extra_attach_params_->DeepCopy()); |
- const std::string& storage_partition_id = site_url.query(); |
- bool persist_storage = |
- site_url.path().find("persist") != std::string::npos; |
- WebContents* new_guest_web_contents = |
- guest_manager->CreateGuest(GetWebContents()->GetSiteInstance(), |
- instance_id, |
- storage_partition_id, |
- persist_storage, |
- extra_params.Pass()); |
- BrowserPluginGuest* new_guest = |
- static_cast<WebContentsImpl*>(new_guest_web_contents)-> |
- GetBrowserPluginGuest(); |
- if (new_guest->delegate_) |
- new_guest->delegate_->SetOpener(GetWebContents()); |
- |
- // Take ownership of |new_guest|. |
- pending_new_windows_.insert( |
- std::make_pair(new_guest, NewWindowInfo(params.url, std::string()))); |
- |
- // Request permission to show the new window. |
- RequestNewWindowPermission(params.disposition, gfx::Rect(), |
- params.user_gesture, new_guest->GetWebContents()); |
- |
- return new_guest; |
+void BrowserPluginGuest::WillDestroy(WebContents* web_contents) { |
+ DCHECK_EQ(web_contents, GetWebContents()); |
+ is_in_destruction_ = true; |
} |
base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() { |
@@ -356,11 +152,9 @@ void BrowserPluginGuest::EmbedderDestroyed() { |
} |
void BrowserPluginGuest::Destroy() { |
- is_in_destruction_ = true; |
- if (!attached() && GetOpener()) |
- GetOpener()->pending_new_windows_.erase(this); |
- DestroyUnattachedWindows(); |
- delete GetWebContents(); |
+ if (!delegate_) |
+ return; |
+ delegate_->Destroy(); |
} |
bool BrowserPluginGuest::OnMessageReceivedFromEmbedder( |
@@ -464,10 +258,9 @@ void BrowserPluginGuest::Initialize( |
if (!params.src.empty()) { |
// params.src will be validated in BrowserPluginGuest::OnNavigateGuest. |
OnNavigateGuest(instance_id_, params.src); |
+ has_render_view_ = true; |
} |
- has_render_view_ = true; |
- |
WebPreferences prefs = GetWebContents()->GetWebkitPrefs(); |
prefs.navigate_on_drag_drop = false; |
GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs); |
@@ -508,39 +301,37 @@ BrowserPluginGuest* BrowserPluginGuest::Create( |
int instance_id, |
SiteInstance* guest_site_instance, |
WebContentsImpl* web_contents, |
- scoped_ptr<base::DictionaryValue> extra_params) { |
+ scoped_ptr<base::DictionaryValue> extra_params, |
+ BrowserPluginGuest* opener) { |
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create")); |
BrowserPluginGuest* guest = NULL; |
if (factory_) { |
guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents); |
} else { |
- guest = new BrowserPluginGuest(instance_id, false, web_contents); |
+ guest = new BrowserPluginGuest(instance_id, |
+ web_contents->opener() != NULL, |
+ web_contents); |
} |
- guest->extra_attach_params_.reset(extra_params->DeepCopy()); |
- web_contents->SetBrowserPluginGuest(guest); |
- BrowserPluginGuestDelegate* delegate = NULL; |
- GetContentClient()->browser()->GuestWebContentsCreated( |
- guest_site_instance, web_contents, NULL, &delegate, extra_params.Pass()); |
- guest->SetDelegate(delegate); |
- return guest; |
-} |
- |
-// static |
-BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener( |
- int instance_id, |
- bool has_render_view, |
- WebContentsImpl* web_contents, |
- BrowserPluginGuest* opener) { |
- BrowserPluginGuest* guest = |
- new BrowserPluginGuest( |
- instance_id, has_render_view, web_contents); |
web_contents->SetBrowserPluginGuest(guest); |
+ WebContents* opener_web_contents = NULL; |
+ if (opener) { |
+ opener_web_contents = opener->GetWebContents(); |
+ guest_site_instance = opener_web_contents->GetSiteInstance(); |
+ } |
BrowserPluginGuestDelegate* delegate = NULL; |
GetContentClient()->browser()->GuestWebContentsCreated( |
- opener->GetWebContents()->GetSiteInstance(), |
- web_contents, opener->GetWebContents(), &delegate, |
- scoped_ptr<base::DictionaryValue>()); |
- guest->SetDelegate(delegate); |
+ instance_id, |
+ guest_site_instance, |
+ web_contents, |
+ opener_web_contents, |
+ &delegate, |
+ extra_params.Pass()); |
+ if (delegate) { |
+ delegate->RegisterDestructionCallback( |
+ base::Bind(&BrowserPluginGuest::WillDestroy, |
+ base::Unretained(guest))); |
+ guest->SetDelegate(delegate); |
+ } |
return guest; |
} |
@@ -550,17 +341,6 @@ RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() { |
return embedder_web_contents_->GetRenderWidgetHostView(); |
} |
-BrowserPluginGuest* BrowserPluginGuest::GetOpener() const { |
- if (!delegate_) |
- return NULL; |
- |
- WebContents* opener = delegate_->GetOpener(); |
- if (!opener) |
- return NULL; |
- |
- return static_cast<WebContentsImpl*>(opener)->GetBrowserPluginGuest(); |
-} |
- |
void BrowserPluginGuest::UpdateVisibility() { |
OnSetVisibility(instance_id_, visible()); |
} |
@@ -598,10 +378,11 @@ void BrowserPluginGuest::AddNewContents(WebContents* source, |
const gfx::Rect& initial_pos, |
bool user_gesture, |
bool* was_blocked) { |
- if (was_blocked) |
- *was_blocked = false; |
- RequestNewWindowPermission(disposition, initial_pos, user_gesture, |
- static_cast<WebContentsImpl*>(new_contents)); |
+ if (!delegate_) |
+ return; |
+ |
+ delegate_->AddNewContents(source, new_contents, disposition, |
+ initial_pos, user_gesture, was_blocked); |
} |
void BrowserPluginGuest::CanDownload( |
@@ -695,29 +476,9 @@ void BrowserPluginGuest::FindReply(WebContents* contents, |
WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source, |
const OpenURLParams& params) { |
- // If the guest wishes to navigate away prior to attachment then we save the |
- // navigation to perform upon attachment. Navigation initializes a lot of |
- // state that assumes an embedder exists, such as RenderWidgetHostViewGuest. |
- // Navigation also resumes resource loading which we don't want to allow |
- // until attachment. |
- if (!attached()) { |
- PendingWindowMap::iterator it = |
- GetOpener()->pending_new_windows_.find(this); |
- if (it == GetOpener()->pending_new_windows_.end()) |
- return NULL; |
- const NewWindowInfo& old_target_url = it->second; |
- NewWindowInfo new_window_info(params.url, old_target_url.name); |
- new_window_info.changed = new_window_info.url != old_target_url.url; |
- it->second = new_window_info; |
+ if (!delegate_) |
return NULL; |
- } |
- if (params.disposition == CURRENT_TAB) { |
- // This can happen for cross-site redirects. |
- LoadURLWithParams(params.url, params.referrer, params.transition, source); |
- return source; |
- } |
- |
- return CreateNewGuestWindow(params)->GetWebContents(); |
+ return delegate_->OpenURLFromTab(source, params); |
} |
void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents, |
@@ -728,15 +489,17 @@ void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents, |
WebContentsImpl* new_contents_impl = |
static_cast<WebContentsImpl*>(new_contents); |
BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest(); |
- if (guest->delegate_) |
- guest->delegate_->SetOpener(GetWebContents()); |
std::string guest_name = base::UTF16ToUTF8(frame_name); |
guest->name_ = guest_name; |
- // Take ownership of the new guest until it is attached to the embedder's DOM |
- // tree to avoid leaking a guest if this guest is destroyed before attaching |
- // the new guest. |
- pending_new_windows_.insert( |
- std::make_pair(guest, NewWindowInfo(target_url, guest_name))); |
+ |
+ if (!delegate_) |
+ return; |
+ |
+ delegate_->WebContentsCreated(source_contents, |
+ opener_render_frame_id, |
+ frame_name, |
+ target_url, |
+ new_contents); |
} |
void BrowserPluginGuest::RendererUnresponsive(WebContents* source) { |
@@ -782,38 +545,6 @@ bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const { |
size.height() <= max_auto_size_.height(); |
} |
-void BrowserPluginGuest::RequestNewWindowPermission( |
- WindowOpenDisposition disposition, |
- const gfx::Rect& initial_bounds, |
- bool user_gesture, |
- WebContentsImpl* new_contents) { |
- BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest(); |
- PendingWindowMap::iterator it = pending_new_windows_.find(guest); |
- if (it == pending_new_windows_.end()) |
- return; |
- const NewWindowInfo& new_window_info = it->second; |
- |
- base::DictionaryValue request_info; |
- request_info.Set(browser_plugin::kInitialHeight, |
- base::Value::CreateIntegerValue(initial_bounds.height())); |
- request_info.Set(browser_plugin::kInitialWidth, |
- base::Value::CreateIntegerValue(initial_bounds.width())); |
- request_info.Set(browser_plugin::kTargetURL, |
- base::Value::CreateStringValue(new_window_info.url.spec())); |
- request_info.Set(browser_plugin::kName, |
- base::Value::CreateStringValue(new_window_info.name)); |
- request_info.Set(browser_plugin::kWindowID, |
- base::Value::CreateIntegerValue(guest->instance_id())); |
- request_info.Set(browser_plugin::kWindowOpenDisposition, |
- base::Value::CreateStringValue( |
- WindowOpenDispositionToString(disposition))); |
- |
- RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW, |
- new NewWindowRequest(weak_ptr_factory_.GetWeakPtr(), |
- guest->instance_id()), |
- request_info); |
-} |
- |
void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) { |
if (!attached()) { |
// Some pages such as data URLs, javascript URLs, and about:blank |
@@ -916,8 +647,6 @@ void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) { |
default: |
break; |
} |
- // TODO(fsamuel): Consider whether we should be clearing |
- // |permission_request_map_| here. |
if (delegate_) |
delegate_->GuestProcessGone(status); |
} |
@@ -991,8 +720,6 @@ void BrowserPluginGuest::Attach( |
if (attached()) |
return; |
- extra_attach_params_.reset(extra_params.DeepCopy()); |
- |
// Clear parameters that get inherited from the opener. |
params.storage_partition_id.clear(); |
params.persist_storage = false; |
@@ -1009,23 +736,6 @@ void BrowserPluginGuest::Attach( |
new_view->CreateViewForWidget(web_contents()->GetRenderViewHost()); |
} |
- // We need to do a navigation here if the target URL has changed between |
- // the time the WebContents was created and the time it was attached. |
- // We also need to do an initial navigation if a RenderView was never |
- // created for the new window in cases where there is no referrer. |
- PendingWindowMap::iterator it = GetOpener()->pending_new_windows_.find(this); |
- if (it != GetOpener()->pending_new_windows_.end()) { |
- const NewWindowInfo& new_window_info = it->second; |
- if (new_window_info.changed || !has_render_view_) |
- params.src = it->second.url.spec(); |
- } else { |
- NOTREACHED(); |
- } |
- |
- // Once a new guest is attached to the DOM of the embedder page, then the |
- // lifetime of the new guest is no longer managed by the opener guest. |
- GetOpener()->pending_new_windows_.erase(this); |
- |
// The guest's frame name takes precedence over the BrowserPlugin's name. |
// The guest's frame name is assigned in |
// BrowserPluginGuest::WebContentsCreated. |
@@ -1205,38 +915,11 @@ void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) { |
mouse_locked_ = true; |
} |
-void BrowserPluginGuest::OnNavigateGuest( |
- int instance_id, |
- const std::string& src) { |
- GURL url = delegate_ ? delegate_->ResolveURL(src) : GURL(src); |
- |
- // Do not allow navigating a guest to schemes other than known safe schemes. |
- // This will block the embedder trying to load unwanted schemes, e.g. |
- // chrome://settings. |
- bool scheme_is_blocked = |
- (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme( |
- url.scheme()) && |
- !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme( |
- url.scheme())) || |
- url.SchemeIs(kJavaScriptScheme); |
- if (scheme_is_blocked || !url.is_valid()) { |
- if (delegate_) { |
- std::string error_type; |
- base::RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::", |
- &error_type); |
- delegate_->LoadAbort(true /* is_top_level */, url, error_type); |
- } |
+void BrowserPluginGuest::OnNavigateGuest(int instance_id, |
+ const std::string& src) { |
+ if (!delegate_) |
return; |
- } |
- |
- GURL validated_url(url); |
- GetWebContents()->GetRenderProcessHost()->FilterURL(false, &validated_url); |
- // As guests do not swap processes on navigation, only navigations to |
- // normal web URLs are supported. No protocol handlers are installed for |
- // other schemes (e.g., WebUI or extensions), and no permissions or bindings |
- // can be granted to the guest process. |
- LoadURLWithParams(validated_url, Referrer(), PAGE_TRANSITION_AUTO_TOPLEVEL, |
- GetWebContents()); |
+ delegate_->NavigateGuest(src); |
} |
void BrowserPluginGuest::OnPluginDestroyed(int instance_id) { |