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/browser/permission/permission_request_handler.h"
6 
7 #include <utility>
8 
9 #include "android_webview/browser/permission/aw_permission_request.h"
10 #include "android_webview/browser/permission/aw_permission_request_delegate.h"
11 #include "android_webview/browser/permission/permission_request_handler_client.h"
12 #include "base/android/scoped_java_ref.h"
13 #include "base/bind.h"
14 #include "content/public/browser/navigation_details.h"
15 #include "content/public/browser/navigation_entry.h"
16 #include "content/public/browser/web_contents.h"
17 
18 using base::android::ScopedJavaLocalRef;
19 
20 namespace android_webview {
21 
22 namespace {
23 
GetLastCommittedEntryID(content::WebContents * web_contents)24 int GetLastCommittedEntryID(content::WebContents* web_contents) {
25   if (!web_contents)
26     return 0;
27 
28   content::NavigationEntry* entry =
29       web_contents->GetController().GetLastCommittedEntry();
30   return entry ? entry->GetUniqueID() : 0;
31 }
32 
33 }  // namespace
34 
PermissionRequestHandler(PermissionRequestHandlerClient * client,content::WebContents * web_contents)35 PermissionRequestHandler::PermissionRequestHandler(
36     PermissionRequestHandlerClient* client,
37     content::WebContents* web_contents)
38     : content::WebContentsObserver(web_contents),
39       client_(client),
40       contents_unique_id_(GetLastCommittedEntryID(web_contents)) {}
41 
~PermissionRequestHandler()42 PermissionRequestHandler::~PermissionRequestHandler() {
43   CancelAllRequests();
44 }
45 
SendRequest(std::unique_ptr<AwPermissionRequestDelegate> request)46 void PermissionRequestHandler::SendRequest(
47     std::unique_ptr<AwPermissionRequestDelegate> request) {
48   if (Preauthorized(request->GetOrigin(), request->GetResources())) {
49     request->NotifyRequestResult(true);
50     return;
51   }
52 
53   base::WeakPtr<AwPermissionRequest> weak_request;
54   base::android::ScopedJavaLocalRef<jobject> java_peer =
55       AwPermissionRequest::Create(std::move(request), &weak_request);
56   requests_.push_back(weak_request);
57   client_->OnPermissionRequest(java_peer, weak_request.get());
58   PruneRequests();
59 }
60 
CancelRequest(const GURL & origin,int64_t resources)61 void PermissionRequestHandler::CancelRequest(const GURL& origin,
62                                              int64_t resources) {
63   // The request list might have multiple requests with same origin and
64   // resources.
65   RequestIterator i = FindRequest(origin, resources);
66   while (i != requests_.end()) {
67     CancelRequestInternal(i);
68     requests_.erase(i);
69     i = FindRequest(origin, resources);
70   }
71 }
72 
PreauthorizePermission(const GURL & origin,int64_t resources)73 void PermissionRequestHandler::PreauthorizePermission(const GURL& origin,
74                                                       int64_t resources) {
75   if (!resources)
76     return;
77 
78   std::string key = origin.GetOrigin().spec();
79   if (key.empty()) {
80     LOG(ERROR) << "The origin of preauthorization is empty, ignore it.";
81     return;
82   }
83 
84   preauthorized_permission_[key] |= resources;
85 }
86 
NavigationEntryCommitted(const content::LoadCommittedDetails & details)87 void PermissionRequestHandler::NavigationEntryCommitted(
88     const content::LoadCommittedDetails& details) {
89   const ui::PageTransition transition = details.entry->GetTransitionType();
90   if (details.is_navigation_to_different_page() ||
91       ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD) ||
92       contents_unique_id_ != details.entry->GetUniqueID()) {
93     CancelAllRequests();
94     contents_unique_id_ = details.entry->GetUniqueID();
95   }
96 }
97 
FindRequest(const GURL & origin,int64_t resources)98 PermissionRequestHandler::RequestIterator PermissionRequestHandler::FindRequest(
99     const GURL& origin,
100     int64_t resources) {
101   RequestIterator i;
102   for (i = requests_.begin(); i != requests_.end(); ++i) {
103     if (i->get() && i->get()->GetOrigin() == origin &&
104         i->get()->GetResources() == resources) {
105       break;
106     }
107   }
108   return i;
109 }
110 
CancelRequestInternal(RequestIterator i)111 void PermissionRequestHandler::CancelRequestInternal(RequestIterator i) {
112   AwPermissionRequest* request = i->get();
113   if (request) {
114     client_->OnPermissionRequestCanceled(request);
115     request->CancelAndDelete();
116   }
117 }
118 
CancelAllRequests()119 void PermissionRequestHandler::CancelAllRequests() {
120   for (RequestIterator i = requests_.begin(); i != requests_.end(); ++i)
121     CancelRequestInternal(i);
122 }
123 
PruneRequests()124 void PermissionRequestHandler::PruneRequests() {
125   for (RequestIterator i = requests_.begin(); i != requests_.end();) {
126     if (!i->get())
127       i = requests_.erase(i);
128     else
129       ++i;
130   }
131 }
132 
Preauthorized(const GURL & origin,int64_t resources)133 bool PermissionRequestHandler::Preauthorized(const GURL& origin,
134                                              int64_t resources) {
135   std::map<std::string, int64_t>::iterator i =
136       preauthorized_permission_.find(origin.GetOrigin().spec());
137 
138   return i != preauthorized_permission_.end() &&
139          (resources & i->second) == resources;
140 }
141 
142 }  // namespace android_webview
143