1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "android_webview/native/permission/permission_request_handler.h"
6
7#include "android_webview/native/permission/aw_permission_request.h"
8#include "android_webview/native/permission/aw_permission_request_delegate.h"
9#include "android_webview/native/permission/permission_request_handler_client.h"
10#include "base/android/scoped_java_ref.h"
11#include "base/bind.h"
12#include "content/public/browser/navigation_details.h"
13#include "content/public/browser/navigation_entry.h"
14#include "content/public/browser/web_contents.h"
15
16using base::android::ScopedJavaLocalRef;
17
18namespace android_webview {
19
20namespace {
21
22int GetActiveEntryID(content::WebContents* web_contents) {
23  if (!web_contents) return 0;
24
25  content::NavigationEntry* active_entry =
26      web_contents->GetController().GetActiveEntry();
27  return active_entry ? active_entry->GetUniqueID() : 0;
28}
29
30}  // namespace
31
32PermissionRequestHandler::PermissionRequestHandler(
33    PermissionRequestHandlerClient* client, content::WebContents* web_contents)
34    : content::WebContentsObserver(web_contents),
35      client_(client),
36      contents_unique_id_(GetActiveEntryID(web_contents)) {
37}
38
39PermissionRequestHandler::~PermissionRequestHandler() {
40  CancelAllRequests();
41}
42
43void PermissionRequestHandler::SendRequest(
44    scoped_ptr<AwPermissionRequestDelegate> request) {
45  if (Preauthorized(request->GetOrigin(), request->GetResources())) {
46    request->NotifyRequestResult(true);
47    return;
48  }
49
50  AwPermissionRequest* aw_request = new AwPermissionRequest(request.Pass());
51  requests_.push_back(
52      base::WeakPtr<AwPermissionRequest>(aw_request->GetWeakPtr()));
53  client_->OnPermissionRequest(aw_request);
54  PruneRequests();
55}
56
57void PermissionRequestHandler::CancelRequest(const GURL& origin,
58                                             int64 resources) {
59  // The request list might have multiple requests with same origin and
60  // resources.
61  RequestIterator i = FindRequest(origin, resources);
62  while (i != requests_.end()) {
63    CancelRequest(i);
64    requests_.erase(i);
65    i = FindRequest(origin, resources);
66  }
67}
68
69void PermissionRequestHandler::PreauthorizePermission(const GURL& origin,
70                                                      int64 resources) {
71  if (!resources)
72    return;
73
74  std::string key = origin.GetOrigin().spec();
75  if (key.empty()) {
76    LOG(ERROR) << "The origin of preauthorization is empty, ignore it.";
77    return;
78  }
79
80  preauthorized_permission_[key] |= resources;
81}
82
83void PermissionRequestHandler::NavigationEntryCommitted(
84    const content::LoadCommittedDetails& details) {
85  const ui::PageTransition transition = details.entry->GetTransitionType();
86  if (details.is_navigation_to_different_page() ||
87      ui::PageTransitionStripQualifier(transition) ==
88      ui::PAGE_TRANSITION_RELOAD ||
89      contents_unique_id_ != details.entry->GetUniqueID()) {
90    CancelAllRequests();
91    contents_unique_id_ = details.entry->GetUniqueID();
92  }
93}
94
95PermissionRequestHandler::RequestIterator
96PermissionRequestHandler::FindRequest(const GURL& origin,
97                                      int64 resources) {
98  RequestIterator i;
99  for (i = requests_.begin(); i != requests_.end(); ++i) {
100    if (i->get() && i->get()->GetOrigin() == origin &&
101        i->get()->GetResources() == resources) {
102      break;
103    }
104  }
105  return i;
106}
107
108void PermissionRequestHandler::CancelRequest(RequestIterator i) {
109  if (i->get())
110    client_->OnPermissionRequestCanceled(i->get());
111  // The request's grant()/deny() could be called upon
112  // OnPermissionRequestCanceled. Delete AwPermissionRequest if it still
113  // exists.
114  if (i->get())
115    delete i->get();
116}
117
118void PermissionRequestHandler::CancelAllRequests() {
119  for (RequestIterator i = requests_.begin(); i != requests_.end(); ++i)
120    CancelRequest(i);
121}
122
123void PermissionRequestHandler::PruneRequests() {
124  for (RequestIterator i = requests_.begin(); i != requests_.end();) {
125    if (!i->get())
126      i = requests_.erase(i);
127    else
128      ++i;
129  }
130}
131
132bool PermissionRequestHandler::Preauthorized(const GURL& origin,
133                                              int64 resources) {
134  std::map<std::string, int64>::iterator i =
135      preauthorized_permission_.find(origin.GetOrigin().spec());
136
137  return i != preauthorized_permission_.end() &&
138      (resources & i->second) == resources;
139}
140
141}  // namespace android_webivew
142