| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 // Custom binding for the webRequestInternal API. | |
| 6 | |
| 7 var binding = require('binding').Binding.create('webRequestInternal'); | |
| 8 var eventBindings = require('event_bindings'); | |
| 9 var sendRequest = require('sendRequest').sendRequest; | |
| 10 var validate = require('schemaUtils').validate; | |
| 11 var utils = require('utils'); | |
| 12 var idGeneratorNatives = requireNative('id_generator'); | |
| 13 | |
| 14 var webRequestInternal; | |
| 15 | |
| 16 function GetUniqueSubEventName(eventName) { | |
| 17 return eventName + "/" + idGeneratorNatives.GetNextId(); | |
| 18 } | |
| 19 | |
| 20 // WebRequestEventImpl object. This is used for special webRequest events | |
| 21 // with extra parameters. Each invocation of addListener creates a new named | |
| 22 // sub-event. That sub-event is associated with the extra parameters in the | |
| 23 // browser process, so that only it is dispatched when the main event occurs | |
| 24 // matching the extra parameters. | |
| 25 // | |
| 26 // Example: | |
| 27 // chrome.webRequest.onBeforeRequest.addListener( | |
| 28 // callback, {urls: 'http://*.google.com/*'}); | |
| 29 // ^ callback will only be called for onBeforeRequests matching the filter. | |
| 30 function WebRequestEventImpl(eventName, opt_argSchemas, opt_extraArgSchemas, | |
| 31 opt_eventOptions, opt_webViewInstanceId) { | |
| 32 if (typeof eventName != 'string') | |
| 33 throw new Error('chrome.WebRequestEvent requires an event name.'); | |
| 34 | |
| 35 this.eventName = eventName; | |
| 36 this.argSchemas = opt_argSchemas; | |
| 37 this.extraArgSchemas = opt_extraArgSchemas; | |
| 38 this.webViewInstanceId = opt_webViewInstanceId || 0; | |
| 39 this.subEvents = []; | |
| 40 this.eventOptions = eventBindings.parseEventOptions(opt_eventOptions); | |
| 41 if (this.eventOptions.supportsRules) { | |
| 42 this.eventForRules = | |
| 43 new eventBindings.Event(eventName, opt_argSchemas, opt_eventOptions, | |
| 44 opt_webViewInstanceId); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 // Test if the given callback is registered for this event. | |
| 49 WebRequestEventImpl.prototype.hasListener = function(cb) { | |
| 50 if (!this.eventOptions.supportsListeners) | |
| 51 throw new Error('This event does not support listeners.'); | |
| 52 return this.findListener_(cb) > -1; | |
| 53 }; | |
| 54 | |
| 55 // Test if any callbacks are registered fur thus event. | |
| 56 WebRequestEventImpl.prototype.hasListeners = function() { | |
| 57 if (!this.eventOptions.supportsListeners) | |
| 58 throw new Error('This event does not support listeners.'); | |
| 59 return this.subEvents.length > 0; | |
| 60 }; | |
| 61 | |
| 62 // Registers a callback to be called when this event is dispatched. If | |
| 63 // opt_filter is specified, then the callback is only called for events that | |
| 64 // match the given filters. If opt_extraInfo is specified, the given optional | |
| 65 // info is sent to the callback. | |
| 66 WebRequestEventImpl.prototype.addListener = | |
| 67 function(cb, opt_filter, opt_extraInfo) { | |
| 68 if (!this.eventOptions.supportsListeners) | |
| 69 throw new Error('This event does not support listeners.'); | |
| 70 // NOTE(benjhayden) New APIs should not use this subEventName trick! It does | |
| 71 // not play well with event pages. See downloads.onDeterminingFilename and | |
| 72 // ExtensionDownloadsEventRouter for an alternative approach. | |
| 73 var subEventName = GetUniqueSubEventName(this.eventName); | |
| 74 // Note: this could fail to validate, in which case we would not add the | |
| 75 // subEvent listener. | |
| 76 validate($Array.slice(arguments, 1), this.extraArgSchemas); | |
| 77 webRequestInternal.addEventListener( | |
| 78 cb, opt_filter, opt_extraInfo, this.eventName, subEventName, | |
| 79 this.webViewInstanceId); | |
| 80 | |
| 81 var subEvent = new eventBindings.Event(subEventName, this.argSchemas); | |
| 82 var subEventCallback = cb; | |
| 83 if (opt_extraInfo && opt_extraInfo.indexOf('blocking') >= 0) { | |
| 84 var eventName = this.eventName; | |
| 85 subEventCallback = function() { | |
| 86 var requestId = arguments[0].requestId; | |
| 87 try { | |
| 88 var result = $Function.apply(cb, null, arguments); | |
| 89 webRequestInternal.eventHandled( | |
| 90 eventName, subEventName, requestId, result); | |
| 91 } catch (e) { | |
| 92 webRequestInternal.eventHandled( | |
| 93 eventName, subEventName, requestId); | |
| 94 throw e; | |
| 95 } | |
| 96 }; | |
| 97 } else if (opt_extraInfo && opt_extraInfo.indexOf('asyncBlocking') >= 0) { | |
| 98 var eventName = this.eventName; | |
| 99 subEventCallback = function() { | |
| 100 var details = arguments[0]; | |
| 101 var requestId = details.requestId; | |
| 102 var handledCallback = function(response) { | |
| 103 webRequestInternal.eventHandled( | |
| 104 eventName, subEventName, requestId, response); | |
| 105 }; | |
| 106 $Function.apply(cb, null, [details, handledCallback]); | |
| 107 }; | |
| 108 } | |
| 109 $Array.push(this.subEvents, | |
| 110 {subEvent: subEvent, callback: cb, subEventCallback: subEventCallback}); | |
| 111 subEvent.addListener(subEventCallback); | |
| 112 }; | |
| 113 | |
| 114 // Unregisters a callback. | |
| 115 WebRequestEventImpl.prototype.removeListener = function(cb) { | |
| 116 if (!this.eventOptions.supportsListeners) | |
| 117 throw new Error('This event does not support listeners.'); | |
| 118 var idx; | |
| 119 while ((idx = this.findListener_(cb)) >= 0) { | |
| 120 var e = this.subEvents[idx]; | |
| 121 e.subEvent.removeListener(e.subEventCallback); | |
| 122 if (e.subEvent.hasListeners()) { | |
| 123 console.error( | |
| 124 'Internal error: webRequest subEvent has orphaned listeners.'); | |
| 125 } | |
| 126 $Array.splice(this.subEvents, idx, 1); | |
| 127 } | |
| 128 }; | |
| 129 | |
| 130 WebRequestEventImpl.prototype.findListener_ = function(cb) { | |
| 131 for (var i in this.subEvents) { | |
| 132 var e = this.subEvents[i]; | |
| 133 if (e.callback === cb) { | |
| 134 if (e.subEvent.hasListener(e.subEventCallback)) | |
| 135 return i; | |
| 136 console.error('Internal error: webRequest subEvent has no callback.'); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 return -1; | |
| 141 }; | |
| 142 | |
| 143 WebRequestEventImpl.prototype.addRules = function(rules, opt_cb) { | |
| 144 if (!this.eventOptions.supportsRules) | |
| 145 throw new Error('This event does not support rules.'); | |
| 146 this.eventForRules.addRules(rules, opt_cb); | |
| 147 }; | |
| 148 | |
| 149 WebRequestEventImpl.prototype.removeRules = | |
| 150 function(ruleIdentifiers, opt_cb) { | |
| 151 if (!this.eventOptions.supportsRules) | |
| 152 throw new Error('This event does not support rules.'); | |
| 153 this.eventForRules.removeRules(ruleIdentifiers, opt_cb); | |
| 154 }; | |
| 155 | |
| 156 WebRequestEventImpl.prototype.getRules = function(ruleIdentifiers, cb) { | |
| 157 if (!this.eventOptions.supportsRules) | |
| 158 throw new Error('This event does not support rules.'); | |
| 159 this.eventForRules.getRules(ruleIdentifiers, cb); | |
| 160 }; | |
| 161 | |
| 162 binding.registerCustomHook(function(api) { | |
| 163 var apiFunctions = api.apiFunctions; | |
| 164 | |
| 165 apiFunctions.setHandleRequest('addEventListener', function() { | |
| 166 var args = $Array.slice(arguments); | |
| 167 sendRequest(this.name, args, this.definition.parameters, | |
| 168 {forIOThread: true}); | |
| 169 }); | |
| 170 | |
| 171 apiFunctions.setHandleRequest('eventHandled', function() { | |
| 172 var args = $Array.slice(arguments); | |
| 173 sendRequest(this.name, args, this.definition.parameters, | |
| 174 {forIOThread: true}); | |
| 175 }); | |
| 176 }); | |
| 177 | |
| 178 var WebRequestEvent = utils.expose('WebRequestEvent', | |
| 179 WebRequestEventImpl, | |
| 180 { functions: [ | |
| 181 'hasListener', | |
| 182 'hasListeners', | |
| 183 'addListener', | |
| 184 'removeListener', | |
| 185 'addRules', | |
| 186 'removeRules', | |
| 187 'getRules' | |
| 188 ] }); | |
| 189 | |
| 190 webRequestInternal = binding.generate(); | |
| 191 exports.binding = webRequestInternal; | |
| 192 exports.WebRequestEvent = WebRequestEvent; | |
| OLD | NEW |