Cancel the permission request when webview navigates to different page or reload.

BUG=373352

Review URL: https://codereview.chromium.org/288463003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271650 0039d316-1c4b-4281-b951-d872f2087c98
parent 3f159621
// Copyright 2014 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.
package org.chromium.android_webview.test;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.permission.AwPermissionRequest;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.net.test.util.TestWebServer;
import java.util.concurrent.Callable;
/**
* Test MediaAccessPermissionRequest.
*/
public class MediaAccessPermissionRequestTest extends AwTestBase {
private static class OnPermissionRequestHelper extends CallbackHelper {
private boolean mCanceled;
public void notifyCanceled() {
mCanceled = true;
notifyCalled();
}
public boolean canceled() {
return mCanceled;
}
}
private final String mData = "<html> <script> " +
"var constraints = {audio: true, video: true};" +
"var video = document.querySelector('video');" +
"function successCallback(stream) {" +
"window.document.title = 'grant';" +
"if (window.URL) {" +
"video.src = window.URL.createObjectURL(stream);" +
"} else {" +
"video.src = stream;" +
"}" +
"}" +
"function errorCallback(error){" +
"window.document.title = 'deny';" +
"console.log('navigator.getUserMedia error: ', error);" +
"}" +
"navigator.webkitGetUserMedia(constraints, successCallback, errorCallback)" +
" </script><body>" +
"<video autoplay></video>" +
"</body></html>";
private TestWebServer mTestWebServer;
private String mWebRTCPage;
@Override
protected void setUp() throws Exception {
super.setUp();
mTestWebServer = new TestWebServer(false);
mWebRTCPage = mTestWebServer.setResponse("/WebRTC", mData,
CommonResources.getTextHtmlHeaders(true));
}
@Override
protected void tearDown() throws Exception {
mTestWebServer.shutdown();
mTestWebServer = null;
super.tearDown();
}
@Feature({"AndroidWebView"})
@SmallTest
public void testGrantAccess() throws Throwable {
final OnPermissionRequestHelper helper = new OnPermissionRequestHelper();
TestAwContentsClient contentsClient =
new TestAwContentsClient() {
@Override
public void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
awPermissionRequest.grant();
helper.notifyCalled();
}
};
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
enableJavaScriptOnUiThread(awContents);
int callCount = helper.getCallCount();
loadUrlAsync(awContents, mWebRTCPage, null);
helper.waitForCallback(callCount);
pollTitleAs("grant", awContents);
}
@Feature({"AndroidWebView"})
@SmallTest
public void testDenyAccess() throws Throwable {
final OnPermissionRequestHelper helper = new OnPermissionRequestHelper();
TestAwContentsClient contentsClient =
new TestAwContentsClient() {
@Override
public void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
awPermissionRequest.deny();
helper.notifyCalled();
}
};
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
enableJavaScriptOnUiThread(awContents);
int callCount = helper.getCallCount();
loadUrlAsync(awContents, mWebRTCPage, null);
helper.waitForCallback(callCount);
pollTitleAs("deny", awContents);
}
private void pollTitleAs(final String title, final AwContents awContents)
throws Exception {
poll(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return title.equals(getTitleOnUiThread(awContents));
}
});
}
@Feature({"AndroidWebView"})
@SmallTest
public void testCancelPermission() throws Throwable {
final OnPermissionRequestHelper helper = new OnPermissionRequestHelper();
TestAwContentsClient contentsClient =
new TestAwContentsClient() {
@Override
public void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
// Don't respond and wait for the request canceled.
helper.notifyCalled();
}
@Override
public void onPermissionRequestCanceled(
AwPermissionRequest awPermissionRequest) {
helper.notifyCanceled();
}
};
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
enableJavaScriptOnUiThread(awContents);
int callCount = helper.getCallCount();
loadUrlAsync(awContents, mWebRTCPage, null);
helper.waitForCallback(callCount);
callCount = helper.getCallCount();
// Load the same page again, the previous request should be canceled.
loadUrlAsync(awContents, mWebRTCPage, null);
helper.waitForCallback(callCount);
assert (helper.canceled());
}
}
...@@ -169,7 +169,8 @@ AwContents::AwContents(scoped_ptr<WebContents> web_contents) ...@@ -169,7 +169,8 @@ AwContents::AwContents(scoped_ptr<WebContents> web_contents)
render_view_host_ext_.reset( render_view_host_ext_.reset(
new AwRenderViewHostExt(this, web_contents_.get())); new AwRenderViewHostExt(this, web_contents_.get()));
permission_request_handler_.reset(new PermissionRequestHandler(this)); permission_request_handler_.reset(
new PermissionRequestHandler(this, web_contents_.get()));
AwAutofillManagerDelegate* autofill_manager_delegate = AwAutofillManagerDelegate* autofill_manager_delegate =
AwAutofillManagerDelegate::FromWebContents(web_contents_.get()); AwAutofillManagerDelegate::FromWebContents(web_contents_.get());
......
...@@ -9,19 +9,35 @@ ...@@ -9,19 +9,35 @@
#include "android_webview/native/permission/permission_request_handler_client.h" #include "android_webview/native/permission/permission_request_handler_client.h"
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/bind.h" #include "base/bind.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
using base::android::ScopedJavaLocalRef; using base::android::ScopedJavaLocalRef;
namespace android_webview { namespace android_webview {
namespace {
int GetActiveEntryID(content::WebContents* web_contents) {
if (!web_contents) return 0;
content::NavigationEntry* active_entry =
web_contents->GetController().GetActiveEntry();
return active_entry ? active_entry->GetUniqueID() : 0;
}
} // namespace
PermissionRequestHandler::PermissionRequestHandler( PermissionRequestHandler::PermissionRequestHandler(
PermissionRequestHandlerClient* client) PermissionRequestHandlerClient* client, content::WebContents* web_contents)
: client_(client) { : content::WebContentsObserver(web_contents),
client_(client),
contents_unique_id_(GetActiveEntryID(web_contents)) {
} }
PermissionRequestHandler::~PermissionRequestHandler() { PermissionRequestHandler::~PermissionRequestHandler() {
for (RequestIterator i = requests_.begin(); i != requests_.end(); ++i) CancelAllRequests();
CancelRequest(i);
} }
void PermissionRequestHandler::SendRequest( void PermissionRequestHandler::SendRequest(
...@@ -64,6 +80,18 @@ void PermissionRequestHandler::PreauthorizePermission(const GURL& origin, ...@@ -64,6 +80,18 @@ void PermissionRequestHandler::PreauthorizePermission(const GURL& origin,
preauthorized_permission_[key] |= resources; preauthorized_permission_[key] |= resources;
} }
void PermissionRequestHandler::NavigationEntryCommitted(
const content::LoadCommittedDetails& details) {
const content::PageTransition transition = details.entry->GetTransitionType();
if (details.is_navigation_to_different_page() ||
content::PageTransitionStripQualifier(transition) ==
content::PAGE_TRANSITION_RELOAD ||
contents_unique_id_ != details.entry->GetUniqueID()) {
CancelAllRequests();
contents_unique_id_ = details.entry->GetUniqueID();
}
}
PermissionRequestHandler::RequestIterator PermissionRequestHandler::RequestIterator
PermissionRequestHandler::FindRequest(const GURL& origin, PermissionRequestHandler::FindRequest(const GURL& origin,
int64 resources) { int64 resources) {
...@@ -87,6 +115,11 @@ void PermissionRequestHandler::CancelRequest(RequestIterator i) { ...@@ -87,6 +115,11 @@ void PermissionRequestHandler::CancelRequest(RequestIterator i) {
delete i->get(); delete i->get();
} }
void PermissionRequestHandler::CancelAllRequests() {
for (RequestIterator i = requests_.begin(); i != requests_.end(); ++i)
CancelRequest(i);
}
void PermissionRequestHandler::PruneRequests() { void PermissionRequestHandler::PruneRequests() {
for (RequestIterator i = requests_.begin(); i != requests_.end();) { for (RequestIterator i = requests_.begin(); i != requests_.end();) {
if (!i->get()) if (!i->get())
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace android_webview { namespace android_webview {
...@@ -22,9 +23,10 @@ class PermissionRequestHandlerClient; ...@@ -22,9 +23,10 @@ class PermissionRequestHandlerClient;
// requests. // requests.
// It is owned by AwContents and has 1x1 mapping to AwContents. All methods // It is owned by AwContents and has 1x1 mapping to AwContents. All methods
// are running on UI thread. // are running on UI thread.
class PermissionRequestHandler { class PermissionRequestHandler : public content::WebContentsObserver {
public: public:
PermissionRequestHandler(PermissionRequestHandlerClient* aw_contents); PermissionRequestHandler(PermissionRequestHandlerClient* client,
content::WebContents* aw_contents);
virtual ~PermissionRequestHandler(); virtual ~PermissionRequestHandler();
// Send the given |request| to PermissionRequestHandlerClient. // Send the given |request| to PermissionRequestHandlerClient.
...@@ -36,6 +38,10 @@ class PermissionRequestHandler { ...@@ -36,6 +38,10 @@ class PermissionRequestHandler {
// Allow |origin| to access the |resources|. // Allow |origin| to access the |resources|.
void PreauthorizePermission(const GURL& origin, int64 resources); void PreauthorizePermission(const GURL& origin, int64 resources);
// WebContentsObserver
virtual void NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) OVERRIDE;
private: private:
friend class TestPermissionRequestHandler; friend class TestPermissionRequestHandler;
...@@ -48,6 +54,8 @@ class PermissionRequestHandler { ...@@ -48,6 +54,8 @@ class PermissionRequestHandler {
// Cancel the given request. // Cancel the given request.
void CancelRequest(RequestIterator i); void CancelRequest(RequestIterator i);
void CancelAllRequests();
// Remove the invalid requests from requests_. // Remove the invalid requests from requests_.
void PruneRequests(); void PruneRequests();
...@@ -61,6 +69,10 @@ class PermissionRequestHandler { ...@@ -61,6 +69,10 @@ class PermissionRequestHandler {
std::map<std::string, int64> preauthorized_permission_; std::map<std::string, int64> preauthorized_permission_;
// The unique id of the active NavigationEntry of the WebContents that we were
// opened for. Used to help expire on requests.
int contents_unique_id_;
DISALLOW_COPY_AND_ASSIGN(PermissionRequestHandler); DISALLOW_COPY_AND_ASSIGN(PermissionRequestHandler);
}; };
......
...@@ -106,7 +106,7 @@ class TestPermissionRequestHandlerClient : ...@@ -106,7 +106,7 @@ class TestPermissionRequestHandlerClient :
class TestPermissionRequestHandler : public PermissionRequestHandler { class TestPermissionRequestHandler : public PermissionRequestHandler {
public: public:
TestPermissionRequestHandler(PermissionRequestHandlerClient* client) TestPermissionRequestHandler(PermissionRequestHandlerClient* client)
: PermissionRequestHandler(client) { : PermissionRequestHandler(client, NULL) {
} }
const std::vector<base::WeakPtr<AwPermissionRequest> > requests() { const std::vector<base::WeakPtr<AwPermissionRequest> > requests() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment