| OLD | NEW |
| (Empty) |
| 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 // This module implements helper objects for the dialog, newwindow, and | |
| 6 // permissionrequest <webview> events. | |
| 7 | |
| 8 var MessagingNatives = requireNative('messaging_natives'); | |
| 9 var WebViewConstants = require('webViewConstants').WebViewConstants; | |
| 10 var WebViewInternal = require('webViewInternal').WebViewInternal; | |
| 11 | |
| 12 var PERMISSION_TYPES = ['media', | |
| 13 'geolocation', | |
| 14 'pointerLock', | |
| 15 'download', | |
| 16 'loadplugin', | |
| 17 'filesystem']; | |
| 18 | |
| 19 // ----------------------------------------------------------------------------- | |
| 20 // WebViewActionRequest object. | |
| 21 | |
| 22 // Default partial implementation of a webview action request. | |
| 23 function WebViewActionRequest(webViewImpl, event, webViewEvent, interfaceName) { | |
| 24 this.webViewImpl = webViewImpl; | |
| 25 this.event = event; | |
| 26 this.webViewEvent = webViewEvent; | |
| 27 this.interfaceName = interfaceName; | |
| 28 this.guestInstanceId = this.webViewImpl.guest.getId(); | |
| 29 this.requestId = event.requestId; | |
| 30 this.actionTaken = false; | |
| 31 } | |
| 32 | |
| 33 // Performs the default action for the request. | |
| 34 WebViewActionRequest.prototype.defaultAction = function() { | |
| 35 // Do nothing if the action has already been taken or the requester is | |
| 36 // already gone (in which case its guestInstanceId will be stale). | |
| 37 if (this.actionTaken || | |
| 38 this.guestInstanceId != this.webViewImpl.guest.getId()) { | |
| 39 return; | |
| 40 } | |
| 41 | |
| 42 this.actionTaken = true; | |
| 43 WebViewInternal.setPermission(this.guestInstanceId, this.requestId, | |
| 44 'default', '', function(allowed) { | |
| 45 if (allowed) { | |
| 46 return; | |
| 47 } | |
| 48 this.showWarningMessage(); | |
| 49 }.bind(this)); | |
| 50 }; | |
| 51 | |
| 52 // Called to handle the action request's event. | |
| 53 WebViewActionRequest.prototype.handleActionRequestEvent = function() { | |
| 54 // Construct the interface object and attach it to |webViewEvent|. | |
| 55 var request = this.getInterfaceObject(); | |
| 56 this.webViewEvent[this.interfaceName] = request; | |
| 57 | |
| 58 var defaultPrevented = !this.webViewImpl.dispatchEvent(this.webViewEvent); | |
| 59 // Set |webViewEvent| to null to break the circular reference to |request| so | |
| 60 // that the garbage collector can eventually collect it. | |
| 61 this.webViewEvent = null; | |
| 62 if (this.actionTaken) { | |
| 63 return; | |
| 64 } | |
| 65 | |
| 66 if (defaultPrevented) { | |
| 67 // Track the lifetime of |request| with the garbage collector. | |
| 68 MessagingNatives.BindToGC(request, this.defaultAction.bind(this)); | |
| 69 } else { | |
| 70 this.defaultAction(); | |
| 71 } | |
| 72 }; | |
| 73 | |
| 74 // Displays a warning message when an action request is blocked by default. | |
| 75 WebViewActionRequest.prototype.showWarningMessage = function() { | |
| 76 window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED); | |
| 77 }; | |
| 78 | |
| 79 // This function ensures that each action is taken at most once. | |
| 80 WebViewActionRequest.prototype.validateCall = function() { | |
| 81 if (this.actionTaken) { | |
| 82 throw new Error(this.ERROR_MSG_ACTION_ALREADY_TAKEN); | |
| 83 } | |
| 84 this.actionTaken = true; | |
| 85 }; | |
| 86 | |
| 87 // The following are implemented by the specific action request. | |
| 88 | |
| 89 // Returns the interface object for this action request. | |
| 90 WebViewActionRequest.prototype.getInterfaceObject = undefined; | |
| 91 | |
| 92 // Error/warning messages. | |
| 93 WebViewActionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = undefined; | |
| 94 WebViewActionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED = undefined; | |
| 95 | |
| 96 // ----------------------------------------------------------------------------- | |
| 97 // Dialog object. | |
| 98 | |
| 99 // Represents a dialog box request (e.g. alert()). | |
| 100 function Dialog(webViewImpl, event, webViewEvent) { | |
| 101 WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'dialog'); | |
| 102 | |
| 103 this.handleActionRequestEvent(); | |
| 104 } | |
| 105 | |
| 106 Dialog.prototype.__proto__ = WebViewActionRequest.prototype; | |
| 107 | |
| 108 Dialog.prototype.getInterfaceObject = function() { | |
| 109 return { | |
| 110 ok: function(user_input) { | |
| 111 this.validateCall(); | |
| 112 user_input = user_input || ''; | |
| 113 WebViewInternal.setPermission( | |
| 114 this.guestInstanceId, this.requestId, 'allow', user_input); | |
| 115 }.bind(this), | |
| 116 cancel: function() { | |
| 117 this.validateCall(); | |
| 118 WebViewInternal.setPermission( | |
| 119 this.guestInstanceId, this.requestId, 'deny'); | |
| 120 }.bind(this) | |
| 121 }; | |
| 122 }; | |
| 123 | |
| 124 Dialog.prototype.showWarningMessage = function() { | |
| 125 var VOWELS = ['a', 'e', 'i', 'o', 'u']; | |
| 126 var dialogType = this.event.messageType; | |
| 127 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; | |
| 128 this.WARNING_MSG_REQUEST_BLOCKED = this.WARNING_MSG_REQUEST_BLOCKED. | |
| 129 replace('%1', article).replace('%2', dialogType); | |
| 130 window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED); | |
| 131 }; | |
| 132 | |
| 133 Dialog.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = | |
| 134 WebViewConstants.ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN; | |
| 135 Dialog.prototype.WARNING_MSG_REQUEST_BLOCKED = | |
| 136 WebViewConstants.WARNING_MSG_DIALOG_REQUEST_BLOCKED; | |
| 137 | |
| 138 // ----------------------------------------------------------------------------- | |
| 139 // NewWindow object. | |
| 140 | |
| 141 // Represents a new window request. | |
| 142 function NewWindow(webViewImpl, event, webViewEvent) { | |
| 143 WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'window'); | |
| 144 | |
| 145 this.handleActionRequestEvent(); | |
| 146 } | |
| 147 | |
| 148 NewWindow.prototype.__proto__ = WebViewActionRequest.prototype; | |
| 149 | |
| 150 NewWindow.prototype.getInterfaceObject = function() { | |
| 151 return { | |
| 152 attach: function(webview) { | |
| 153 this.validateCall(); | |
| 154 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') { | |
| 155 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | |
| 156 } | |
| 157 | |
| 158 var webViewImpl = privates(webview).internal; | |
| 159 // Update the partition. | |
| 160 if (this.event.partition) { | |
| 161 webViewImpl.onAttach(this.event.partition); | |
| 162 } | |
| 163 | |
| 164 var attached = webViewImpl.attachWindow(this.event.windowId); | |
| 165 if (!attached) { | |
| 166 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | |
| 167 } | |
| 168 | |
| 169 if (this.guestInstanceId != this.webViewImpl.guest.getId()) { | |
| 170 // If the opener is already gone, then its guestInstanceId will be | |
| 171 // stale. | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 // If the object being passed into attach is not a valid <webview> | |
| 176 // then we will fail and it will be treated as if the new window | |
| 177 // was rejected. The permission API plumbing is used here to clean | |
| 178 // up the state created for the new window if attaching fails. | |
| 179 WebViewInternal.setPermission(this.guestInstanceId, this.requestId, | |
| 180 attached ? 'allow' : 'deny'); | |
| 181 }.bind(this), | |
| 182 discard: function() { | |
| 183 this.validateCall(); | |
| 184 if (!this.guestInstanceId) { | |
| 185 // If the opener is already gone, then we won't have its | |
| 186 // guestInstanceId. | |
| 187 return; | |
| 188 } | |
| 189 WebViewInternal.setPermission( | |
| 190 this.guestInstanceId, this.requestId, 'deny'); | |
| 191 }.bind(this) | |
| 192 }; | |
| 193 }; | |
| 194 | |
| 195 NewWindow.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = | |
| 196 WebViewConstants.ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN; | |
| 197 NewWindow.prototype.WARNING_MSG_REQUEST_BLOCKED = | |
| 198 WebViewConstants.WARNING_MSG_NEWWINDOW_REQUEST_BLOCKED; | |
| 199 | |
| 200 // ----------------------------------------------------------------------------- | |
| 201 // PermissionRequest object. | |
| 202 | |
| 203 // Represents a permission request (e.g. to access the filesystem). | |
| 204 function PermissionRequest(webViewImpl, event, webViewEvent) { | |
| 205 WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'request'); | |
| 206 | |
| 207 if (!this.validPermissionCheck()) { | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 this.handleActionRequestEvent(); | |
| 212 } | |
| 213 | |
| 214 PermissionRequest.prototype.__proto__ = WebViewActionRequest.prototype; | |
| 215 | |
| 216 PermissionRequest.prototype.getInterfaceObject = function() { | |
| 217 return { | |
| 218 allow: function() { | |
| 219 this.validateCall(); | |
| 220 WebViewInternal.setPermission( | |
| 221 this.guestInstanceId, this.requestId, 'allow'); | |
| 222 }.bind(this), | |
| 223 deny: function() { | |
| 224 this.validateCall(); | |
| 225 WebViewInternal.setPermission( | |
| 226 this.guestInstanceId, this.requestId, 'deny'); | |
| 227 }.bind(this) | |
| 228 }; | |
| 229 }; | |
| 230 | |
| 231 PermissionRequest.prototype.showWarningMessage = function() { | |
| 232 window.console.warn( | |
| 233 this.WARNING_MSG_REQUEST_BLOCKED.replace('%1', this.event.permission)); | |
| 234 }; | |
| 235 | |
| 236 // Checks that the requested permission is valid. Returns true if valid. | |
| 237 PermissionRequest.prototype.validPermissionCheck = function() { | |
| 238 if (PERMISSION_TYPES.indexOf(this.event.permission) < 0) { | |
| 239 // The permission type is not allowed. Trigger the default response. | |
| 240 this.defaultAction(); | |
| 241 return false; | |
| 242 } | |
| 243 return true; | |
| 244 }; | |
| 245 | |
| 246 PermissionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = | |
| 247 WebViewConstants.ERROR_MSG_PERMISSION_ACTION_ALREADY_TAKEN; | |
| 248 PermissionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED = | |
| 249 WebViewConstants.WARNING_MSG_PERMISSION_REQUEST_BLOCKED; | |
| 250 | |
| 251 // ----------------------------------------------------------------------------- | |
| 252 | |
| 253 var WebViewActionRequests = { | |
| 254 WebViewActionRequest: WebViewActionRequest, | |
| 255 Dialog: Dialog, | |
| 256 NewWindow: NewWindow, | |
| 257 PermissionRequest: PermissionRequest | |
| 258 }; | |
| 259 | |
| 260 exports.WebViewActionRequests = WebViewActionRequests; | |
| OLD | NEW |