Index: chrome/browser/permissions/permission_manager.cc |
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc |
index e39955ab7c364015d180c9bb05e67b771d752814..7eb0dca4ed66e093481f15b2067987b6884c37db 100644 |
--- a/chrome/browser/permissions/permission_manager.cc |
+++ b/chrome/browser/permissions/permission_manager.cc |
@@ -73,12 +73,11 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { |
return CONTENT_SETTINGS_TYPE_DEFAULT; |
} |
-// Helper method that wraps a callback a void(PermissionStatus) |
-// callback into a void(ContentSetting) callback. |
-void PermissionStatusCallbackWrapper( |
+void PermissionRequestResponseCallbackWrapper( |
const base::Callback<void(PermissionStatus)>& callback, |
- ContentSetting content_setting) { |
- callback.Run(ContentSettingToPermissionStatus(content_setting)); |
+ const std::vector<PermissionStatus>& vector) { |
+ DCHECK(vector.size() == 1); |
+ callback.Run(vector[0]); |
} |
// Returns whether the permission has a constant PermissionStatus value (i.e. |
@@ -116,6 +115,22 @@ PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) { |
} // anonymous namespace |
+struct PermissionManager::PendingResponse { |
+ PermissionType type; |
+ PermissionStatus status; |
+ |
+ PendingResponse(PermissionType type, PermissionStatus status) |
+ : type(type), status(status) { |
+ } |
+}; |
+ |
+struct PermissionManager::PendingResponses { |
+ GURL requesting_origin; |
+ size_t count; |
+ size_t pending; |
+ std::vector<PendingResponse> responses; |
+}; |
+ |
struct PermissionManager::Subscription { |
PermissionType permission; |
GURL requesting_origin; |
@@ -125,7 +140,8 @@ struct PermissionManager::Subscription { |
}; |
PermissionManager::PermissionManager(Profile* profile) |
- : profile_(profile) { |
+ : profile_(profile), |
+ weak_ptr_factory_(this) { |
} |
PermissionManager::~PermissionManager() { |
@@ -139,18 +155,34 @@ void PermissionManager::RequestPermission( |
int request_id, |
const GURL& requesting_origin, |
bool user_gesture, |
- const base::Callback<void(PermissionStatus)>& callback) { |
- if (IsConstantPermission(permission)) { |
- callback.Run(GetPermissionStatusForConstantPermission(permission)); |
- return; |
- } |
+ const RequestCallback& callback) { |
+ RequestPermissionInternal( |
+ std::vector<PermissionType>(1, permission), |
+ render_frame_host, |
+ request_id, |
+ requesting_origin, |
+ user_gesture, |
+ base::Bind(&PermissionRequestResponseCallbackWrapper, callback)); |
+} |
- PermissionContextBase* context = PermissionContext::Get(profile_, permission); |
- if (!context) { |
- callback.Run(content::PERMISSION_STATUS_DENIED); |
- return; |
- } |
+void PermissionManager::RequestPermission( |
+ const std::vector<PermissionType>& permissions, |
+ content::RenderFrameHost* render_frame_host, |
+ int request_id, |
+ const GURL& requesting_origin, |
+ bool user_gesture, |
+ const BatchRequestCallback& callback) { |
+ RequestPermissionInternal(permissions, render_frame_host, request_id, |
+ requesting_origin, user_gesture, callback); |
+} |
+void PermissionManager::RequestPermissionInternal( |
+ const std::vector<PermissionType>& permissions, |
+ content::RenderFrameHost* render_frame_host, |
+ int request_id, |
+ const GURL& requesting_origin, |
+ bool user_gesture, |
+ const BatchRequestCallback& callback) { |
int render_process_id = render_frame_host->GetProcess()->GetID(); |
int render_frame_id = render_frame_host->GetRoutingID(); |
const PermissionRequestID request(render_process_id, |
@@ -158,31 +190,104 @@ void PermissionManager::RequestPermission( |
request_id, |
requesting_origin); |
- context->RequestPermission( |
- content::WebContents::FromRenderFrameHost(render_frame_host), |
- request, requesting_origin, user_gesture, |
- base::Bind(&PermissionStatusCallbackWrapper, |
- callback)); |
+ // Pass complete control of the scoped pointer to the map. |
+ // Locally we will use the raw pointer and the response will be removed from |
+ // the map once all the responses return. |
+ scoped_ptr<PendingResponses> scoped_response(new PendingResponses()); |
+ PendingResponses* pending_responses = scoped_response.get(); |
+ pending_responses_.add(request_id, scoped_response.Pass()); |
+ |
+ pending_responses->requesting_origin = requesting_origin; |
+ pending_responses->count = permissions.size(); |
+ pending_responses->pending = permissions.size(); |
+ |
+ for (size_t i = 0; i < permissions.size(); ++i) { |
+ pending_responses->responses.emplace_back( |
+ permissions[i], |
+ content::PERMISSION_STATUS_DENIED); |
+ } |
+ |
+ // The pending responses should all be added to the vector before running |
+ // this loop so duplicate permissions are handled properly. |
+ bool seen_types[static_cast<int>(PermissionType::NUM)] = { false }; |
+ for (size_t i = 0; i < permissions.size(); ++i) { |
+ const PermissionType current_type = permissions[i]; |
+ const int current_type_index = static_cast<int>(current_type); |
+ if (seen_types[current_type_index]) |
+ continue; |
+ seen_types[current_type_index] = true; |
+ |
+ if (IsConstantPermission(current_type)) { |
+ OnRequestResponse(callback, request, pending_responses, i, |
+ GetContentSettingForConstantPermission(current_type)); |
+ continue; |
+ } |
+ |
+ PermissionContextBase* context = |
+ PermissionContext::Get(profile_, current_type); |
+ if (!context) { |
+ OnRequestResponse(callback, request, pending_responses, i, |
+ CONTENT_SETTING_BLOCK); |
+ continue; |
+ } |
+ context->RequestPermission( |
+ content::WebContents::FromRenderFrameHost(render_frame_host), |
+ request, requesting_origin, user_gesture, |
+ base::Bind(&PermissionManager::OnRequestResponse, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ request, |
+ pending_responses, |
+ i)); |
+ } |
+} |
+ |
+void PermissionManager::OnRequestResponse(const BatchRequestCallback& callback, |
+ const PermissionRequestID request, |
+ PendingResponses* pending_responses, |
+ int index, |
+ ContentSetting content_setting) { |
+ PendingResponse& response = pending_responses->responses[index]; |
+ response.status = ContentSettingToPermissionStatus(content_setting); |
+ |
+ for (size_t i = index + 1; i < pending_responses->responses.size(); ++i) { |
+ if (pending_responses->responses[i].type == response.type) { |
+ pending_responses->responses[i].status = response.status; |
+ --pending_responses->pending; |
+ } |
+ } |
+ |
+ if (pending_responses->pending == 1) { |
+ std::vector<PermissionStatus> status; |
+ for (auto response : pending_responses->responses) |
+ status.push_back(response.status); |
+ pending_responses_.erase(request.request_id()); |
+ callback.Run(status); |
+ } |
} |
void PermissionManager::CancelPermissionRequest( |
- PermissionType permission, |
content::RenderFrameHost* render_frame_host, |
- int request_id, |
- const GURL& requesting_origin) { |
- PermissionContextBase* context = PermissionContext::Get(profile_, permission); |
- if (!context) |
- return; |
+ int request_id) { |
+ PendingResponses* pending_responses = |
+ pending_responses_.get(request_id); |
int render_process_id = render_frame_host->GetProcess()->GetID(); |
int render_frame_id = render_frame_host->GetRoutingID(); |
const PermissionRequestID request(render_process_id, |
render_frame_id, |
request_id, |
- requesting_origin); |
+ pending_responses->requesting_origin); |
+ |
+ for (size_t i = 0; i < pending_responses->count; ++i) { |
+ PermissionType type = pending_responses->responses[i].type; |
+ PermissionContextBase* context = PermissionContext::Get(profile_, type); |
+ if (!context) continue; |
- context->CancelPermissionRequest( |
- content::WebContents::FromRenderFrameHost(render_frame_host), request); |
+ context->CancelPermissionRequest( |
+ content::WebContents::FromRenderFrameHost(render_frame_host), request); |
+ } |
+ pending_responses_.erase(request_id); |
} |
void PermissionManager::ResetPermission(PermissionType permission, |
@@ -230,7 +335,7 @@ int PermissionManager::SubscribePermissionStatusChange( |
PermissionType permission, |
const GURL& requesting_origin, |
const GURL& embedding_origin, |
- const base::Callback<void(PermissionStatus)>& callback) { |
+ const RequestCallback& callback) { |
if (subscriptions_.IsEmpty()) |
profile_->GetHostContentSettingsMap()->AddObserver(this); |