| 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);
|
|
|
|
|