blob: f9dae5203709c07e322749799163a6a73c36bc06 [file] [log] [blame]
// Copyright 2015 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/child/permissions/permission_dispatcher.h"
#include "content/child/worker_task_runner.h"
#include "content/public/common/service_registry.h"
#include "third_party/WebKit/public/platform/WebURL.h"
namespace content {
namespace {
PermissionName GetPermissionName(blink::WebPermissionType type) {
switch (type) {
case blink::WebPermissionTypeGeolocation:
return PERMISSION_NAME_GEOLOCATION;
case blink::WebPermissionTypeNotifications:
return PERMISSION_NAME_NOTIFICATIONS;
case blink::WebPermissionTypePushNotifications:
return PERMISSION_NAME_PUSH_NOTIFICATIONS;
case blink::WebPermissionTypeMidiSysEx:
return PERMISSION_NAME_MIDI_SYSEX;
default:
// The default statement is only there to prevent compilation failures if
// WebPermissionType enum gets extended.
NOTREACHED();
return PERMISSION_NAME_GEOLOCATION;
}
}
blink::WebPermissionStatus GetWebPermissionStatus(PermissionStatus status) {
switch (status) {
case PERMISSION_STATUS_GRANTED:
return blink::WebPermissionStatusGranted;
case PERMISSION_STATUS_DENIED:
return blink::WebPermissionStatusDenied;
case PERMISSION_STATUS_ASK:
return blink::WebPermissionStatusPrompt;
}
NOTREACHED();
return blink::WebPermissionStatusDenied;
}
const int kNoWorkerThread = 0;
} // anonymous namespace
PermissionDispatcher::CallbackInformation::CallbackInformation(
blink::WebPermissionQueryCallback* callback,
int worker_thread_id)
: callback_(callback),
worker_thread_id_(worker_thread_id) {
}
blink::WebPermissionQueryCallback*
PermissionDispatcher::CallbackInformation::callback() const {
return callback_.get();
}
int PermissionDispatcher::CallbackInformation::worker_thread_id() const {
return worker_thread_id_;
}
blink::WebPermissionQueryCallback*
PermissionDispatcher::CallbackInformation::ReleaseCallback() {
return callback_.release();
}
PermissionDispatcher::CallbackInformation::~CallbackInformation() {
}
PermissionDispatcher::PermissionDispatcher(ServiceRegistry* service_registry)
: service_registry_(service_registry) {
}
PermissionDispatcher::~PermissionDispatcher() {
}
void PermissionDispatcher::queryPermission(
blink::WebPermissionType type,
const blink::WebURL& origin,
blink::WebPermissionQueryCallback* callback) {
QueryPermissionInternal(
type, origin.string().utf8(), callback, kNoWorkerThread);
}
void PermissionDispatcher::QueryPermissionForWorker(
blink::WebPermissionType type,
const std::string& origin,
blink::WebPermissionQueryCallback* callback,
int worker_thread_id) {
QueryPermissionInternal(type, origin, callback, worker_thread_id);
}
void PermissionDispatcher::QueryPermissionInternal(
blink::WebPermissionType type,
const std::string& origin,
blink::WebPermissionQueryCallback* callback,
int worker_thread_id) {
// We need to save the |callback| in an IDMap so if |this| gets deleted, the
// callback will not leak. In the case of |this| gets deleted, the
// |permission_service_| pipe will be destroyed too so OnQueryPermission will
// not be called.
int request_id = pending_callbacks_.Add(
new CallbackInformation(callback, worker_thread_id));
if (!permission_service_.get())
service_registry_->ConnectToRemoteService(&permission_service_);
permission_service_->HasPermission(
GetPermissionName(type),
origin,
base::Bind(&PermissionDispatcher::OnQueryPermission,
base::Unretained(this),
request_id));
}
void PermissionDispatcher::OnQueryPermission(int request_id,
PermissionStatus result) {
CallbackInformation* callback_information =
pending_callbacks_.Lookup(request_id);
DCHECK(callback_information && callback_information->callback());
scoped_ptr<blink::WebPermissionStatus> status(
new blink::WebPermissionStatus(GetWebPermissionStatus(result)));
if (callback_information->worker_thread_id() != kNoWorkerThread) {
blink::WebPermissionQueryCallback* callback =
callback_information->ReleaseCallback();
int worker_thread_id = callback_information->worker_thread_id();
pending_callbacks_.Remove(request_id);
// If the worker is no longer running, ::PostTask() will return false and
// gracefully fail, destroying the callback too.
WorkerTaskRunner::Instance()->PostTask(
worker_thread_id,
base::Bind(&PermissionDispatcher::RunCallbackOnWorkerThread,
base::Unretained(callback),
base::Passed(&status)));
return;
}
callback_information->callback()->onSuccess(status.release());
pending_callbacks_.Remove(request_id);
}
// static
void PermissionDispatcher::RunCallbackOnWorkerThread(
blink::WebPermissionQueryCallback* callback,
scoped_ptr<blink::WebPermissionStatus> status) {
callback->onSuccess(status.release());
delete callback;
}
} // namespace content