Commit 89d7ec26 authored by hanxi@chromium.org's avatar hanxi@chromium.org

Plumb file system permission into WebviewGuest.

Two remaining issues:
1. It seems that WebviewGuest doesn't support SharedWorker yet, so this CL
   doesn't include the changes for SharedWorker.
2. To request file system access for operations like getFile(), removeFile() etc., I have to set "unlimitedstorage"
   permission in manifest.json, otherwise will get QuotaExceededError (request persistent storage without "unlimitedstorage" permission). Any idea?  


BUG=343382

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=276251

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276584 0039d316-1c4b-4281-b951-d872f2087c98
parent 1da61cf5
......@@ -1951,6 +1951,43 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_GeolocationRequestGone) {
<< message_;
}
// In following FilesystemAPIRequestFromMainThread* tests, guest request
// filesystem access from main thread of the guest.
// FileSystemAPIRequestFromMainThread* test 1 of 3
IN_PROC_BROWSER_TEST_F(WebViewTest, FileSystemAPIRequestFromMainThreadAllow) {
TestHelper("testAllow", "web_view/filesystem/main", NEEDS_TEST_SERVER);
}
// FileSystemAPIRequestFromMainThread* test 2 of 3.
IN_PROC_BROWSER_TEST_F(WebViewTest, FileSystemAPIRequestFromMainThreadDeny) {
TestHelper("testDeny", "web_view/filesystem/main", NEEDS_TEST_SERVER);
}
// FileSystemAPIRequestFromMainThread* test 3 of 3.
IN_PROC_BROWSER_TEST_F(WebViewTest,
FileSystemAPIRequestFromMainThreadDefaultAllow) {
TestHelper("testDefaultAllow", "web_view/filesystem/main", NEEDS_TEST_SERVER);
}
// In following FilesystemAPIRequestFromWorker* tests, guest create a worker
// to request filesystem access from worker thread.
// FileSystemAPIRequestFromWorker* test 1 of 3
IN_PROC_BROWSER_TEST_F(WebViewTest, FileSystemAPIRequestFromWorkerAllow) {
TestHelper("testAllow", "web_view/filesystem/worker", NEEDS_TEST_SERVER);
}
// FileSystemAPIRequestFromWorker* test 2 of 3.
IN_PROC_BROWSER_TEST_F(WebViewTest, FileSystemAPIRequestFromWorkerDeny) {
TestHelper("testDeny", "web_view/filesystem/worker", NEEDS_TEST_SERVER);
}
// FileSystemAPIRequestFromWorker* test 3 of 3.
IN_PROC_BROWSER_TEST_F(WebViewTest,
FileSystemAPIRequestFromWorkerDefaultAllow) {
TestHelper(
"testDefaultAllow", "web_view/filesystem/worker", NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewTest, ClearData) {
#if defined(OS_WIN)
// Flaky on XP bot http://crbug.com/282674
......
......@@ -6,6 +6,7 @@
#define CHROME_BROWSER_GUEST_VIEW_GUEST_VIEW_H_
#include "chrome/browser/guest_view/guest_view_base.h"
#include "content/public/browser/render_frame_host.h"
// A GuestView is the templated base class for out-of-process frames in the
// chrome layer. GuestView is templated on its derived type to allow for type-
......@@ -26,6 +27,17 @@ class GuestView : public GuestViewBase {
return guest ? guest->As<T>() : NULL;
}
static T* FromFrameID(int render_process_id, int render_frame_id) {
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!render_frame_host) {
return NULL;
}
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
return FromWebContents(web_contents);
}
T* GetOpener() const {
GuestViewBase* guest = GuestViewBase::GetOpener();
if (!guest)
......
......@@ -51,6 +51,7 @@ const char kOldURL[] = "oldUrl";
const char kPermission[] = "permission";
const char kPermissionTypeDialog[] = "dialog";
const char kPermissionTypeDownload[] = "download";
const char kPermissionTypeFileSystem[] = "filesystem";
const char kPermissionTypeGeolocation[] = "geolocation";
const char kPermissionTypeLoadPlugin[] = "loadplugin";
const char kPermissionTypeMedia[] = "media";
......
......@@ -54,6 +54,7 @@ extern const char kOldURL[];
extern const char kPermission[];
extern const char kPermissionTypeDialog[];
extern const char kPermissionTypeDownload[];
extern const char kPermissionTypeFileSystem[];
extern const char kPermissionTypeGeolocation[];
extern const char kPermissionTypeLoadPlugin[];
extern const char kPermissionTypeMedia[];
......
......@@ -8,6 +8,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/extensions/api/web_request/web_request_api.h"
#include "chrome/browser/extensions/api/webview/webview_api.h"
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
......@@ -124,6 +125,8 @@ static std::string PermissionTypeToString(WebViewPermissionType type) {
switch (type) {
case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
return webview::kPermissionTypeDownload;
case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
return webview::kPermissionTypeFileSystem;
case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
return webview::kPermissionTypeGeolocation;
case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
......@@ -295,6 +298,10 @@ void WebViewGuest::RecordUserInitiatedUMA(const PermissionResponseInfo& info,
content::RecordAction(
UserMetricsAction("WebView.PermissionAllow.Download"));
break;
case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
content::RecordAction(
UserMetricsAction("WebView.PermissionAllow.FileSystem"));
break;
case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
content::RecordAction(
UserMetricsAction("WebView.PermissionAllow.Geolocation"));
......@@ -327,6 +334,10 @@ void WebViewGuest::RecordUserInitiatedUMA(const PermissionResponseInfo& info,
content::RecordAction(
UserMetricsAction("WebView.PermissionDeny.Download"));
break;
case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
content::RecordAction(
UserMetricsAction("WebView.PermissionDeny.FileSystem"));
break;
case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
content::RecordAction(
UserMetricsAction("WebView.PermissionDeny.Geolocation"));
......@@ -681,6 +692,28 @@ void WebViewGuest::Reload() {
guest_web_contents()->GetController().Reload(false);
}
void WebViewGuest::RequestFileSystemPermission(
const GURL& url,
bool allowed_by_default,
const base::Callback<void(bool)>& callback) {
base::DictionaryValue request_info;
request_info.Set(guestview::kUrl, base::Value::CreateStringValue(url.spec()));
RequestPermission(
WEB_VIEW_PERMISSION_TYPE_FILESYSTEM,
request_info,
base::Bind(&WebViewGuest::OnWebViewFileSystemPermissionResponse,
base::Unretained(this),
callback),
allowed_by_default);
}
void WebViewGuest::OnWebViewFileSystemPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input) {
callback.Run(allow && attached());
}
void WebViewGuest::RequestGeolocationPermission(
int bridge_id,
const GURL& requesting_frame,
......@@ -852,6 +885,78 @@ bool WebViewGuest::ClearData(const base::Time remove_since,
return true;
}
// static
void WebViewGuest::FileSystemAccessedAsync(int render_process_id,
int render_frame_id,
int request_id,
const GURL& url,
bool blocked_by_policy) {
WebViewGuest* guest =
WebViewGuest::FromFrameID(render_process_id, render_frame_id);
DCHECK(guest);
guest->RequestFileSystemPermission(
url,
!blocked_by_policy,
base::Bind(&WebViewGuest::FileSystemAccessedAsyncResponse,
render_process_id,
render_frame_id,
request_id,
url));
}
// static
void WebViewGuest::FileSystemAccessedAsyncResponse(int render_process_id,
int render_frame_id,
int request_id,
const GURL& url,
bool allowed) {
TabSpecificContentSettings::FileSystemAccessed(
render_process_id, render_frame_id, url, !allowed);
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!render_frame_host)
return;
render_frame_host->Send(
new ChromeViewMsg_RequestFileSystemAccessAsyncResponse(
render_frame_id, request_id, allowed));
}
// static
void WebViewGuest::FileSystemAccessedSync(int render_process_id,
int render_frame_id,
const GURL& url,
bool blocked_by_policy,
IPC::Message* reply_msg) {
WebViewGuest* guest =
WebViewGuest::FromFrameID(render_process_id, render_frame_id);
DCHECK(guest);
guest->RequestFileSystemPermission(
url,
!blocked_by_policy,
base::Bind(&WebViewGuest::FileSystemAccessedSyncResponse,
render_process_id,
render_frame_id,
url,
reply_msg));
}
// static
void WebViewGuest::FileSystemAccessedSyncResponse(int render_process_id,
int render_frame_id,
const GURL& url,
IPC::Message* reply_msg,
bool allowed) {
TabSpecificContentSettings::FileSystemAccessed(
render_process_id, render_frame_id, url, !allowed);
ChromeViewHostMsg_RequestFileSystemAccessSync::WriteReplyParams(reply_msg,
allowed);
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!render_frame_id)
return;
render_frame_host->Send(reply_msg);
}
WebViewGuest::~WebViewGuest() {
}
......
......@@ -196,35 +196,11 @@ class WebViewGuest : public GuestView<WebViewGuest>,
const GURL& requesting_frame,
bool user_gesture,
const base::Callback<void(bool)>& callback);
void OnWebViewGeolocationPermissionResponse(
int bridge_id,
bool user_gesture,
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void CancelGeolocationPermissionRequest(int bridge_id);
void OnWebViewMediaPermissionResponse(
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
bool allow,
const std::string& user_input);
void OnWebViewDownloadPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewPointerLockPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewNewWindowResponse(int new_window_instance_id,
bool allow,
const std::string& user_input);
void RequestFileSystemPermission(const GURL& url,
bool allowed_by_default,
const base::Callback<void(bool)>& callback);
enum PermissionResponseAction {
DENY,
......@@ -267,6 +243,39 @@ class WebViewGuest : public GuestView<WebViewGuest>,
return script_executor_.get();
}
// Called when file system access is requested by the guest content using the
// asynchronous HTML5 file system API. The request is plumbed through the
// <webview> permission request API. The request will be:
// - Allowed if the embedder explicitly allowed it.
// - Denied if the embedder explicitly denied.
// - Determined by the guest's content settings if the embedder does not
// perform an explicit action.
// If access was blocked due to the page's content settings,
// |blocked_by_policy| should be true, and this function should invoke
// OnContentBlocked.
static void FileSystemAccessedAsync(int render_process_id,
int render_frame_id,
int request_id,
const GURL& url,
bool blocked_by_policy);
// Called when file system access is requested by the guest content using the
// synchronous HTML5 file system API in a worker thread or shared worker. The
// request is plumbed through the <webview> permission request API. The
// request will be:
// - Allowed if the embedder explicitly allowed it.
// - Denied if the embedder explicitly denied.
// - Determined by the guest's content settings if the embedder does not
// perform an explicit action.
// If access was blocked due to the page's content settings,
// |blocked_by_policy| should be true, and this function should invoke
// OnContentBlocked.
static void FileSystemAccessedSync(int render_process_id,
int render_frame_id,
const GURL& url,
bool blocked_by_policy,
IPC::Message* reply_msg);
private:
virtual ~WebViewGuest();
......@@ -289,6 +298,50 @@ class WebViewGuest : public GuestView<WebViewGuest>,
static scoped_ptr<base::ListValue> MenuModelToValue(
const ui::SimpleMenuModel& menu_model);
void OnWebViewGeolocationPermissionResponse(
int bridge_id,
bool user_gesture,
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewFileSystemPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewMediaPermissionResponse(
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
bool allow,
const std::string& user_input);
void OnWebViewDownloadPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewPointerLockPermissionResponse(
const base::Callback<void(bool)>& callback,
bool allow,
const std::string& user_input);
void OnWebViewNewWindowResponse(int new_window_instance_id,
bool allow,
const std::string& user_input);
static void FileSystemAccessedAsyncResponse(int render_process_id,
int render_frame_id,
int request_id,
const GURL& url,
bool allowed);
static void FileSystemAccessedSyncResponse(int render_process_id,
int render_frame_id,
const GURL& url,
IPC::Message* reply_msg,
bool allowed);
// WebContentsObserver implementation.
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
......
......@@ -11,6 +11,8 @@ enum WebViewPermissionType {
WEB_VIEW_PERMISSION_TYPE_DOWNLOAD,
WEB_VIEW_PERMISSION_TYPE_FILESYSTEM,
WEB_VIEW_PERMISSION_TYPE_GEOLOCATION,
// JavaScript Dialogs: prompt, alert, confirm
......
......@@ -12,6 +12,12 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/cookie_settings.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/extensions/extension_renderer_state.h"
#if defined(ENABLE_EXTENSIONS)
#include "chrome/browser/guest_view/web_view/web_view_guest.h"
#endif
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/profiles/profile.h"
......@@ -67,8 +73,9 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_V8HeapStats, OnV8HeapStats)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowDatabase, OnAllowDatabase)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowDOMStorage, OnAllowDOMStorage)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestFileSystemAccessSync,
OnRequestFileSystemAccessSync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChromeViewHostMsg_RequestFileSystemAccessSync,
OnRequestFileSystemAccessSync)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestFileSystemAccessAsync,
OnRequestFileSystemAccessAsync)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowIndexedDB, OnAllowIndexedDB)
......@@ -192,14 +199,39 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessSync(
int render_frame_id,
const GURL& origin_url,
const GURL& top_origin_url,
bool* allowed) {
*allowed =
IPC::Message* reply_msg) {
bool allowed =
cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url);
#if defined(ENABLE_EXTENSIONS)
bool is_web_view_guest =
ExtensionRendererState::GetInstance()->IsWebViewRenderer(
render_process_id_);
if (is_web_view_guest) {
// Record access to file system for potential display in UI.
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&WebViewGuest::FileSystemAccessedSync,
render_process_id_,
render_frame_id,
origin_url,
!allowed,
reply_msg));
return;
}
#endif
ChromeViewHostMsg_RequestFileSystemAccessSync::WriteReplyParams(reply_msg,
allowed);
Send(reply_msg);
// Record access to file system for potential display in UI.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
BrowserThread::UI,
FROM_HERE,
base::Bind(&TabSpecificContentSettings::FileSystemAccessed,
render_process_id_, render_frame_id, origin_url, !*allowed));
render_process_id_,
render_frame_id,
origin_url,
!allowed));
}
void ChromeRenderMessageFilter::OnRequestFileSystemAccessAsync(
......@@ -211,20 +243,36 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessAsync(
bool allowed =
cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url);
#if defined(ENABLE_EXTENSIONS)
bool is_web_view_guest =
ExtensionRendererState::GetInstance()->IsWebViewRenderer(
render_process_id_);
if (is_web_view_guest) {
// Record access to file system for potential display in UI.
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&WebViewGuest::FileSystemAccessedAsync,
render_process_id_,
render_frame_id,
request_id,
origin_url,
!allowed));
return;
}
#endif
Send(new ChromeViewMsg_RequestFileSystemAccessAsyncResponse(render_frame_id,
request_id,
allowed));
// Record access to file system for potential display in UI.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
&TabSpecificContentSettings::FileSystemAccessed,
render_process_id_,
render_frame_id,
origin_url,
!allowed));
Send(new ChromeViewMsg_RequestFileSystemAccessAsyncResponse(
render_frame_id,
request_id,
allowed));
BrowserThread::UI,
FROM_HERE,
base::Bind(&TabSpecificContentSettings::FileSystemAccessed,
render_process_id_,
render_frame_id,
origin_url,
!allowed));
}
void ChromeRenderMessageFilter::OnAllowIndexedDB(int render_frame_id,
......
......@@ -75,7 +75,7 @@ class ChromeRenderMessageFilter : public content::BrowserMessageFilter {
void OnRequestFileSystemAccessSync(int render_frame_id,
const GURL& origin_url,
const GURL& top_origin_url,
bool* allowed);
IPC::Message* message);
void OnRequestFileSystemAccessAsync(int render_frame_id,
int request_id,
const GURL& origin_url,
......
......@@ -235,6 +235,25 @@
{ "name": "deny", "description": "Deny the permission request. This is the default behavior if <code>allow</code> is not called." }
]
},
{
"id": "FileSystemPermissionRequest",
"type": "object",
"description": "The type of <code>request</code> object which accompanies a <code>filesystem</code> <a href=\"#event-permissionrequest\">permissionrequest</a></code> DOM event.",
"properties": {
"url": {
"description": "The URL of the frame requesting access to local file system.",
"type": "string"
},
"allowed_by_default": {
"description": "The default permission according to cookie setting. This is the default behaviour if <code>allow</code> is not called",
"type": "bool"
}
},
"functions": [
{ "name": "allow", "description": "Allow the permission request." },
{ "name": "deny", "description": "Deny the permission request." }
]
},
{
"id": "LoadPluginPermissionRequest",
"type": "object",
......@@ -774,7 +793,7 @@
"name": "permission",
"description": "The type of permission being requested.",
"type": "string",
"enum": ["media", "geolocation", "pointerLock", "download", "loadplugin"]
"enum": ["media", "geolocation", "pointerLock", "download", "loadplugin", "filesystem"]
},
{
"name": "requestId",
......
......@@ -828,7 +828,12 @@ WebViewInternal.prototype.setupEventProperty = function(eventName) {
*/
WebViewInternal.prototype.getPermissionTypes = function() {
var permissions =
['media', 'geolocation', 'pointerLock', 'download', 'loadplugin'];
['media',
'geolocation',
'pointerLock',
'download',
'loadplugin',
'filesystem'];
return permissions.concat(this.maybeGetExperimentalPermissions());
};
......
<!--
* 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.
-->
<html>
<body>
<div id="webview-tag-container"></div>
<script src="embedder.js"></script>
</body>
</html>
// 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.
var embedder = {};
embedder.test = {};
embedder.baseGuestURL = '';
embedder.guestURL = '';
window.runTest = function(testName) {
if (!embedder.test.testList[testName]) {
console.log('Incorrect testName: ' + testName);
embedder.test.fail();
return;
}
// Run the test.
embedder.test.testList[testName]();
};
// window.* exported functions end.
/** @private */
embedder.setUp_ = function(config) {
embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
embedder.guestURL = embedder.baseGuestURL +
'/extensions/platform_apps/web_view/filesystem/main' +
'/guest_main.html';
chrome.test.log('Guest url is: ' + embedder.guestURL);
};
/** @private */
embedder.setUpGuest_ = function() {
document.querySelector('#webview-tag-container').innerHTML =
'<webview style="width: 100px; height: 100px;"' +
' src="' + embedder.guestURL + '"' +
' partition = "persist:a"' +
'></webview>';
var webview = document.querySelector('webview');
if (!webview) {
console.log('No <webview> element created');
embedder.test.fail();
}
return webview;
};
embedder.test = {};
embedder.test.succeed = function() {
chrome.test.sendMessage('TEST_PASSED');
};
embedder.test.fail = function() {
chrome.test.sendMessage('TEST_FAILED');
};
embedder.test.assertEq = function(a, b) {
if (a != b) {
console.log('assertion failed: ' + a + ' != ' + b);
embedder.test.fail();
}
};
embedder.test.assertTrue = function(condition) {
if (!condition) {
console.log('assertion failed: true != ' + condition);
embedder.test.fail();
}
};
embedder.test.assertFalse = function(condition) {
if (condition) {
console.log('assertion failed: false != ' + condition);
embedder.test.fail();
}
};
/** @private */
embedder.setUpLoadStop_ = function(webview, testName) {
window.console.log('embedder.setUpLoadStop_');
var onWebViewLoadStop = function(e) {
window.console.log('embedder.onWebViewLoadStop');
// Send post message to <webview> when it's ready to receive them.
var msgArray = ['check-filesystem-permission', '' + testName];
window.console.log('embedder.webview.postMessage');
webview.contentWindow.postMessage(JSON.stringify(msgArray), '*');
};
webview.addEventListener('loadstop', onWebViewLoadStop);
};
/** @private */
embedder.registerAndWaitForPostMessage_ = function(
webview, expectedData) {
var testName = expectedData[0];
var onPostMessageReceived = function(e) {
var data = JSON.parse(e.data);
if (data[0] == '' + testName) {
embedder.test.assertEq(expectedData.length, data.length);
for (var i = 0; i < expectedData.length; ++i) {
embedder.test.assertEq(expectedData[i], data[i]);
}
embedder.test.succeed();
}
};
window.addEventListener('message', onPostMessageReceived);
};
/** @private */
embedder.assertCorrectEvent_ = function(e) {
embedder.test.assertEq('filesystem', e.permission);
embedder.test.assertTrue(!!e.url);
embedder.test.assertTrue(e.url.indexOf(embedder.baseGuestURL) == 0);
};
// Tests begin.
// Once the guest is allowed or denied filesystem, the guest notifies the
// embedder about the fact via post message.
// The embedder has to initiate a post message so that the guest can get a
// reference to embedder to send the reply back.
// Loads a guest which requests filesystem. The embedder explicitly
// allows acccess to filesystem for the guest.
function testAllow() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
chrome.test.log('Embedder notified on permissionRequest');
embedder.assertCorrectEvent_(e);
e.request.allow();
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test1');
embedder.registerAndWaitForPostMessage_(
webview, ['test1', 'access-granted']);
}
// Loads a guest which requests filesystem. The embedder explicitly
// denies access to filesystem for the guest.
function testDeny() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
chrome.test.log('Embedder notified on permissionRequest');
embedder.assertCorrectEvent_(e);
e.request.deny();
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test2');
embedder.registerAndWaitForPostMessage_(
webview, ['test2', 'access-denied']);
}
// Loads a guest which requests filesystem. The embedder does not
// perform an explicit action, and the default permission according
// to cookie setting is allowed.
function testDefaultAllow() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
embedder.assertCorrectEvent_(e);
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test3');
embedder.registerAndWaitForPostMessage_(
webview, ['test3', 'access-granted']);
}
embedder.test.testList = {
'testAllow': testAllow,
'testDeny': testDeny,
'testDefaultAllow': testDefaultAllow
};
onload = function() {
chrome.test.getConfig(function(config) {
embedder.setUp_(config);
chrome.test.sendMessage('Launched');
});
};
<!--
* 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.
-->
<html>
<head>
<script type="text/javascript">
// A guest that requests filesystem.
// Notifies the embedder about the result of the request (success/fail)
// via post message. Note that the embedder has to initiate a postMessage
// first so that guest has a reference to the embedder's window.
// The window reference of the embedder to send post message reply.
var embedderWindowChannel = null;
window.requestFileSystem = window.requestFileSystem ||
window.webkitRequestFileSystem;
window.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL ||
window.webkitResolveLocalFileSystemURL;
var expectedTotalCallbackCount;
var totalCallbackCount;
var successCallbackCount;
var testName = 'uninitialized';
var maybeNotifyEmbedder = function() {
window.console.log('maybeNotifyEmbedder' +
', expectedTotalCallbackCount: ' +
expectedTotalCallbackCount +
', successCallbackCount: ' +
successCallbackCount +
', totalCallbackCount: ' +
totalCallbackCount);
if(expectedTotalCallbackCount == totalCallbackCount) {
var status = (expectedTotalCallbackCount == successCallbackCount) ?
'access-granted' : 'access-denied';
var responseArray = [testName, status];
notifyEmbedder(responseArray);
}
};
var notifyEmbedder = function(msg_array) {
embedderWindowChannel.postMessage(JSON.stringify(msg_array), '*');
};
var startTest = function() {
expectedTotalCallbackCount = 1;
window.console.log('set totalCallbackCount to 0');
totalCallbackCount = 0;
successCallbackCount = 0;
window.console.log('Call requestFileSystemAccess');
requestFileSystemAccess();
};
var requestFileSystemAccess = function() {
window.webkitStorageInfo.requestQuota(PERSISTENT, 1024 * 1024,
function(grantedBytes) {
window.console.log('request Quota granted.');
window.requestFileSystem(window.PERSISTENT, 1024*1024,
onFileSystemSuccess,
onFileSystemFailure);
}, function(e) { window.console.log('Error' + e); });
};
var onFileSystemSuccess = function(filesystem) {
++totalCallbackCount;
++successCallbackCount;
window.console.log('onFileSystemSuccess, successCallbackCount: ' +
successCallbackCount + ', totalCallbackCount: ' +
totalCallbackCount);
maybeNotifyEmbedder();
};
var onFileSystemFailure = function(err) {
++totalCallbackCount;
window.console.log('onFileSystemFailure, totalCallbackCount: ' +
totalCallbackCount);
maybeNotifyEmbedder();
};
var onPostMessageReceived = function(e) {
window.console.log('guest.onPostMessageReceived');
var data = JSON.parse(e.data);
if (data[0] == 'check-filesystem-permission') {
testName = data[1];
embedderWindowChannel = e.source;
// Start the test once we have |embedderWindowChannel|.
startTest();
}
};
addEventListener('message', onPostMessageReceived, false);
</script>
</head>
<body>
<div>This is a guest that requests filesystem.</div>
<script>
window.console.log('Guest loaded');
</script>
</body>
</html>
{
"name": "Platform App Test: <webview> filesystem",
"description": "Loads a guest which requests filesystem",
"version": "1",
"permissions": [
"webview",
"unlimitedStorage"
],
"webview": {
"partitions": [
{
"name": "a",
"accessible_resources": ["*"]
}
]
},
"app": {
"background": {
"scripts": ["test.js"]
}
}
}
// 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.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('embedder.html', {}, function () {});
});
<!--
* 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.
-->
<html>
<body>
<div id="webview-tag-container"></div>
<script src="embedder.js"></script>
</body>
</html>
// 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.
var embedder = {};
embedder.test = {};
embedder.baseGuestURL = '';
embedder.guestURL = '';
window.runTest = function(testName) {
if (!embedder.test.testList[testName]) {
console.log('Incorrect testName: ' + testName);
embedder.test.fail();
return;
}
// Run the test.
embedder.test.testList[testName]();
};
// window.* exported functions end.
/** @private */
embedder.setUp_ = function(config) {
embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
embedder.guestURL = embedder.baseGuestURL +
'/extensions/platform_apps/web_view/filesystem/worker' +
'/guest_worker.html';
chrome.test.log('Guest url is: ' + embedder.guestURL);
};
/** @private */
embedder.setUpGuest_ = function() {
document.querySelector('#webview-tag-container').innerHTML =
'<webview style="width: 100px; height: 100px;"' +
' src="' + embedder.guestURL + '"' +
' partition = "persist:a"' +
'></webview>';
var webview = document.querySelector('webview');
if (!webview) {
console.log('No <webview> element created');
embedder.test.fail();
}
return webview;
};
embedder.test = {};
embedder.test.succeed = function() {
chrome.test.sendMessage('TEST_PASSED');
};
embedder.test.fail = function() {
chrome.test.sendMessage('TEST_FAILED');
};
embedder.test.assertEq = function(a, b) {
if (a != b) {
console.log('assertion failed: ' + a + ' != ' + b);
embedder.test.fail();
}
};
embedder.test.assertTrue = function(condition) {
if (!condition) {
console.log('assertion failed: true != ' + condition);
embedder.test.fail();
}
};
embedder.test.assertFalse = function(condition) {
if (condition) {
console.log('assertion failed: false != ' + condition);
embedder.test.fail();
}
};
/** @private */
embedder.setUpLoadStop_ = function(webview, testName) {
window.console.log('embedder.setUpLoadStop_');
var onWebViewLoadStop = function(e) {
window.console.log('embedder.onWebViewLoadStop');
// Send post message to <webview> when it's ready to receive them.
var msgArray = ['check-filesystem-permission', '' + testName];
window.console.log('embedder.webview.postMessage');
webview.contentWindow.postMessage(JSON.stringify(msgArray), '*');
};
webview.addEventListener('loadstop', onWebViewLoadStop);
};
/** @private */
embedder.registerAndWaitForPostMessage_ = function(
webview, expectedData) {
var testName = expectedData[0];
var onPostMessageReceived = function(e) {
var data = JSON.parse(e.data);
if (data[0] == '' + testName) {
embedder.test.assertEq(expectedData.length, data.length);
for (var i = 0; i < expectedData.length; ++i) {
embedder.test.assertEq(expectedData[i], data[i]);
}
embedder.test.succeed();
}
};
window.addEventListener('message', onPostMessageReceived);
};
/** @private */
embedder.assertCorrectEvent_ = function(e) {
embedder.test.assertEq('filesystem', e.permission);
embedder.test.assertTrue(!!e.url);
embedder.test.assertTrue(e.url.indexOf(embedder.baseGuestURL) == 0);
};
// Tests begin.
// Once the guest is allowed or denied filesystem, the guest notifies the
// embedder about the fact via post message.
// The embedder has to initiate a post message so that the guest can get a
// reference to embedder to send the reply back.
// Loads a guest which create a worker to request filesystem. The embedder
// explicitly allows acccess to filesystem for the guest.
function testAllow() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
chrome.test.log('Embedder notified on permissionRequest');
embedder.assertCorrectEvent_(e);
e.request.allow();
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test1');
embedder.registerAndWaitForPostMessage_(
webview, ['test1', 'access-granted']);
}
// Loads a guest which creates a worker to request filesystem. The embedder
// explicitly denies access to filesystem for the guest.
function testDeny() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
chrome.test.log('Embedder notified on permissionRequest');
embedder.assertCorrectEvent_(e);
e.request.deny();
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test2');
embedder.registerAndWaitForPostMessage_(
webview, ['test2', 'access-denied']);
}
// Loads a guest which creates a worker to request filesystem. The embedder
// does not perform an explicit action, and the default permission according
// to cookie setting is allowed.
function testDefaultAllow() {
var webview = embedder.setUpGuest_();
var onPermissionRequest = function(e) {
embedder.assertCorrectEvent_(e);
};
webview.addEventListener('permissionrequest', onPermissionRequest);
embedder.setUpLoadStop_(webview, 'test3');
embedder.registerAndWaitForPostMessage_(
webview, ['test3', 'access-granted']);
}
embedder.test.testList = {
'testAllow': testAllow,
'testDeny': testDeny,
'testDefaultAllow': testDefaultAllow
};
onload = function() {
chrome.test.getConfig(function(config) {
embedder.setUp_(config);
chrome.test.sendMessage('Launched');
});
};
<!--
* 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.
-->
<html>
<head>
<script type="text/javascript">
// A guest that ceate a worker to request filesystem.
// Notifies the embedder about the result of the request (success/fail)
// via post message. Note that the embedder has to initiate a postMessage
// first so that guest has a reference to the embedder's window.
// The window reference of the embedder to send post message reply.
var embedderWindowChannel = null;
var expectedTotalCallbackCount;
var totalCallbackCount;
var successCallbackCount;
var testName = 'uninitialized';
var maybeNotifyEmbedder = function() {
window.console.log('maybeNotifyEmbedder' +
', expectedTotalCallbackCount: ' +
expectedTotalCallbackCount +
', successCallbackCount: ' +
successCallbackCount +
', totalCallbackCount: ' +
totalCallbackCount);
if(expectedTotalCallbackCount == totalCallbackCount) {
var status = (expectedTotalCallbackCount == successCallbackCount) ?
'access-granted' : 'access-denied';
var responseArray = [testName, status];
notifyEmbedder(responseArray);
}
};
var notifyEmbedder = function(msg_array) {
embedderWindowChannel.postMessage(JSON.stringify(msg_array), '*');
};
var startTest = function() {
expectedTotalCallbackCount = 1;
totalCallbackCount = 0;
successCallbackCount = 0;
window.console.log('Call initWorker');
initWorker();
};
var initWorker = function() {
window.worker = new Worker('worker.js');
worker.addEventListener('message', function(e) {
var data = e.data;
switch (data.type) {
case 'echo':
window.console.log('echo: ' + data.msg);
break;
case 'error':
window.console.log('error: ' + data.msg);
break;
case 'result':
window.console.log('result: ' + data.msg);
successCallbackCount += parseInt(data.msg);
++totalCallbackCount;
maybeNotifyEmbedder();
break;
default:
window.console.log('UNKNOWN MESSAGE FROM WORKER');
break;
}
}, false);
worker.postMessage({'type': 'requestFileSystem'});
};
var onPostMessageReceived = function(e) {
window.console.log('guest.onPostMessageReceived');
var data = JSON.parse(e.data);
if (data[0] == 'check-filesystem-permission') {
testName = data[1];
embedderWindowChannel = e.source;
// Start the test once we have |embedderWindowChannel|.
startTest();
}
};
addEventListener('message', onPostMessageReceived, false);
</script>
</head>
<body>
<div>This is a guest that create a worker to request filesystem.</div>
<script>
window.console.log('Guest loaded');
</script>
</body>
</html>
{
"name": "Platform App Test: <webview> filesystem",
"description": "Loads a guest which requests filesystem",
"version": "1",
"permissions": [
"webview",
"unlimitedStorage"
],
"webview": {
"partitions": [
{
"name": "a",
"accessible_resources": ["*"]
}
]
},
"app": {
"background": {
"scripts": ["test.js"]
}
}
}
// 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.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('embedder.html', {}, function () {});
});
// 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.
self.requestFileSystemSync = self.webkitRequestFileSystemSync ||
self.requestFileSystemSync;
function onError(e) {
postMessage({ 'type': 'error', 'msg': e.toString() });
}
function echoMsg(msg) {
postMessage({'type': 'echo', 'msg': msg});
}
function requestFileSystem() {
try {
echoMsg("call requetFileSystem");
var filesystem = requestFileSystemSync(PERSISTENT, 1024 * 1024 /* 1MB */);
var result = filesystem ? 1 : 0;
postMessage({'type': 'result', 'msg': result});
} catch (e) {
onError(e);
}
}
addEventListener('message', function(e) {
var data = e.data;
switch(data.type) {
case 'echo':
postMessage({'type': 'echo', 'msg': data.msg});
return;
case 'requestFileSystem':
requestFileSystem();
return;
default:
postMessage({'type': 'error', 'msg': 'UNKNOWN MESSAGE TYPE'});
}
});
......@@ -10853,6 +10853,14 @@ should be able to be added at any place in this file.
</description>
</action>
<action name="WebView.PermissionAllow.FileSystem">
<owner>fsamuel@chromium.org</owner>
<owner>hanxi@chromium.org</owner>
<description>
Tracks when the filesystem permission is explicitly allowed on a webview.
</description>
</action>
<action name="WebView.PermissionAllow.Geolocation">
<owner>fsamuel@chromium.org</owner>
<owner>lazyboy@chromium.org</owner>
......@@ -10893,6 +10901,14 @@ should be able to be added at any place in this file.
</description>
</action>
<action name="WebView.PermissionDeny.FileSystem">
<owner>fsamuel@chromium.org</owner>
<owner>hanxi@chromium.org</owner>
<description>
Tracks when the filesystem permission is explicitly denied on a webview.
</description>
</action>
<action name="WebView.PermissionDeny.Geolocation">
<owner>fsamuel@chromium.org</owner>
<owner>lazyboy@chromium.org</owner>
......
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