| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // chrome.runtime.messaging API implementation. | 5 // chrome.runtime.messaging API implementation. |
| 6 // TODO(robwu): Fix this indentation. |
| 6 | 7 |
| 7 // TODO(kalman): factor requiring chrome out of here. | 8 // TODO(kalman): factor requiring chrome out of here. |
| 8 var chrome = requireNative('chrome').GetChrome(); | 9 var chrome = requireNative('chrome').GetChrome(); |
| 9 var Event = require('event_bindings').Event; | 10 var Event = require('event_bindings').Event; |
| 10 var lastError = require('lastError'); | 11 var lastError = require('lastError'); |
| 11 var logActivity = requireNative('activityLogger'); | 12 var logActivity = requireNative('activityLogger'); |
| 12 var logging = requireNative('logging'); | 13 var logging = requireNative('logging'); |
| 13 var messagingNatives = requireNative('messaging_natives'); | 14 var messagingNatives = requireNative('messaging_natives'); |
| 14 var processNatives = requireNative('process'); | 15 var processNatives = requireNative('process'); |
| 15 var utils = require('utils'); | 16 var utils = require('utils'); |
| 16 var messagingUtils = require('messaging_utils'); | 17 var messagingUtils = require('messaging_utils'); |
| 17 | 18 |
| 18 // The reserved channel name for the sendRequest/send(Native)Message APIs. | 19 // The reserved channel name for the sendRequest/send(Native)Message APIs. |
| 19 // Note: sendRequest is deprecated. | 20 // Note: sendRequest is deprecated. |
| 20 var kRequestChannel = "chrome.extension.sendRequest"; | 21 var kRequestChannel = "chrome.extension.sendRequest"; |
| 21 var kMessageChannel = "chrome.runtime.sendMessage"; | 22 var kMessageChannel = "chrome.runtime.sendMessage"; |
| 22 var kNativeMessageChannel = "chrome.runtime.sendNativeMessage"; | 23 var kNativeMessageChannel = "chrome.runtime.sendNativeMessage"; |
| 23 | 24 |
| 24 // Map of port IDs to port object. | 25 // Map of port IDs to port object. |
| 25 var ports = {}; | 26 var ports = {__proto__:null}; |
| 26 | 27 |
| 27 // Change even to odd and vice versa, to get the other side of a given | 28 // Change even to odd and vice versa, to get the other side of a given |
| 28 // channel. | 29 // channel. |
| 29 function getOppositePortId(portId) { return portId ^ 1; } | 30 function getOppositePortId(portId) { return portId ^ 1; } |
| 30 | 31 |
| 31 // Port object. Represents a connection to another script context through | 32 // Port object. Represents a connection to another script context through |
| 32 // which messages can be passed. | 33 // which messages can be passed. |
| 33 function PortImpl(portId, opt_name) { | 34 function PortImpl(portId, opt_name) { |
| 34 this.portId_ = portId; | 35 this.portId_ = portId; |
| 35 this.name = opt_name; | 36 this.name = opt_name; |
| 36 | 37 |
| 37 var portSchema = {name: 'port', $ref: 'runtime.Port'}; | 38 // Note: Keep these schemas in sync with the documentation in runtime.json |
| 38 var options = {unmanaged: true}; | 39 var portSchema = { |
| 40 __proto__: null, |
| 41 name: 'port', |
| 42 $ref: 'runtime.Port', |
| 43 }; |
| 44 var messageSchema = { |
| 45 __proto__: null, |
| 46 name: 'message', |
| 47 type: 'any', |
| 48 optional: true, |
| 49 }; |
| 50 var options = { |
| 51 __proto__: null, |
| 52 unmanaged: true, |
| 53 }; |
| 39 this.onDisconnect = new Event(null, [portSchema], options); | 54 this.onDisconnect = new Event(null, [portSchema], options); |
| 40 this.onMessage = new Event( | 55 this.onMessage = new Event(null, [messageSchema, portSchema], options); |
| 41 null, | |
| 42 [{name: 'message', type: 'any', optional: true}, portSchema], | |
| 43 options); | |
| 44 this.onDestroy_ = null; | 56 this.onDestroy_ = null; |
| 45 } | 57 } |
| 58 $Object.setPrototypeOf(PortImpl, null); |
| 59 $Object.setPrototypeOf(PortImpl.prototype, null); |
| 46 | 60 |
| 47 // Sends a message asynchronously to the context on the other end of this | 61 // Sends a message asynchronously to the context on the other end of this |
| 48 // port. | 62 // port. |
| 49 PortImpl.prototype.postMessage = function(msg) { | 63 PortImpl.prototype.postMessage = function(msg) { |
| 50 // JSON.stringify doesn't support a root object which is undefined. | 64 // JSON.stringify doesn't support a root object which is undefined. |
| 51 if (msg === undefined) | 65 if (msg === undefined) |
| 52 msg = null; | 66 msg = null; |
| 53 msg = $JSON.stringify(msg); | 67 msg = $JSON.stringify(msg); |
| 54 if (msg === undefined) { | 68 if (msg === undefined) { |
| 55 // JSON.stringify can fail with unserializable objects. Log an error and | 69 // JSON.stringify can fail with unserializable objects. Log an error and |
| 56 // drop the message. | 70 // drop the message. |
| 57 // | 71 // |
| 58 // TODO(kalman/mpcomplete): it would be better to do the same validation | 72 // TODO(kalman/mpcomplete): it would be better to do the same validation |
| 59 // here that we do for runtime.sendMessage (and variants), i.e. throw an | 73 // here that we do for runtime.sendMessage (and variants), i.e. throw an |
| 60 // schema validation Error, but just maintain the old behaviour until | 74 // schema validation Error, but just maintain the old behaviour until |
| 61 // there's a good reason not to (http://crbug.com/263077). | 75 // there's a good reason not to (http://crbug.com/263077). |
| 62 console.error('Illegal argument to Port.postMessage'); | 76 console.error('Illegal argument to Port.postMessage'); |
| 63 return; | 77 return; |
| 64 } | 78 } |
| 65 messagingNatives.PostMessage(this.portId_, msg); | 79 messagingNatives.PostMessage(this.portId_, msg); |
| 66 }; | 80 }; |
| 67 | 81 |
| 68 // Disconnects the port from the other end. | 82 // Disconnects the port from the other end. |
| 69 PortImpl.prototype.disconnect = function() { | 83 PortImpl.prototype.disconnect = function() { |
| 70 messagingNatives.CloseChannel(this.portId_, true); | 84 messagingNatives.CloseChannel(this.portId_, true); |
| 71 this.destroy_(); | 85 this.destroy_(); |
| 72 }; | 86 }; |
| 73 | 87 |
| 74 PortImpl.prototype.destroy_ = function() { | 88 PortImpl.prototype.destroy_ = function() { |
| 75 if (this.onDestroy_) | 89 if (this.onDestroy_) { |
| 76 this.onDestroy_(); | 90 this.onDestroy_(); |
| 91 this.onDestroy_ = null; |
| 92 } |
| 77 privates(this.onDisconnect).impl.destroy_(); | 93 privates(this.onDisconnect).impl.destroy_(); |
| 78 privates(this.onMessage).impl.destroy_(); | 94 privates(this.onMessage).impl.destroy_(); |
| 79 // TODO(robwu): Remove port lifetime management because it is completely | 95 // TODO(robwu): Remove port lifetime management because it is completely |
| 80 // handled in the browser. The renderer's only roles are | 96 // handled in the browser. The renderer's only roles are |
| 81 // 1) rejecting ports so that the browser knows that the renderer is not | 97 // 1) rejecting ports so that the browser knows that the renderer is not |
| 82 // interested in the port (this is merely an optimization) | 98 // interested in the port (this is merely an optimization) |
| 83 // 2) acknowledging port creations, so that the browser knows that the port | 99 // 2) acknowledging port creations, so that the browser knows that the port |
| 84 // was successfully created (from the perspective of the extension), but | 100 // was successfully created (from the perspective of the extension), but |
| 85 // then closed for some non-fatal reason. | 101 // then closed for some non-fatal reason. |
| 86 // 3) notifying the browser of explicit port closure via .disconnect(). | 102 // 3) notifying the browser of explicit port closure via .disconnect(). |
| (...skipping 20 matching lines...) Expand all Loading... |
| 107 messagingNatives.PortAddRef(portId); | 123 messagingNatives.PortAddRef(portId); |
| 108 return port; | 124 return port; |
| 109 }; | 125 }; |
| 110 | 126 |
| 111 // Helper function for dispatchOnRequest. | 127 // Helper function for dispatchOnRequest. |
| 112 function handleSendRequestError(isSendMessage, | 128 function handleSendRequestError(isSendMessage, |
| 113 responseCallbackPreserved, | 129 responseCallbackPreserved, |
| 114 sourceExtensionId, | 130 sourceExtensionId, |
| 115 targetExtensionId, | 131 targetExtensionId, |
| 116 sourceUrl) { | 132 sourceUrl) { |
| 117 var errorMsg = []; | 133 var errorMsg; |
| 118 var eventName = isSendMessage ? "runtime.onMessage" : "extension.onRequest"; | 134 var eventName = isSendMessage ? 'runtime.onMessage' : 'extension.onRequest'; |
| 119 if (isSendMessage && !responseCallbackPreserved) { | 135 if (isSendMessage && !responseCallbackPreserved) { |
| 120 $Array.push(errorMsg, | 136 errorMsg = |
| 121 "The chrome." + eventName + " listener must return true if you " + | 137 'The chrome.' + eventName + ' listener must return true if you ' + |
| 122 "want to send a response after the listener returns"); | 138 'want to send a response after the listener returns'; |
| 123 } else { | 139 } else { |
| 124 $Array.push(errorMsg, | 140 errorMsg = |
| 125 "Cannot send a response more than once per chrome." + eventName + | 141 'Cannot send a response more than once per chrome.' + eventName + |
| 126 " listener per document"); | 142 ' listener per document'; |
| 127 } | 143 } |
| 128 $Array.push(errorMsg, "(message was sent by extension" + sourceExtensionId); | 144 errorMsg += ' (message was sent by extension' + sourceExtensionId; |
| 129 if (sourceExtensionId != "" && sourceExtensionId != targetExtensionId) | 145 if (sourceExtensionId && sourceExtensionId !== targetExtensionId) |
| 130 $Array.push(errorMsg, "for extension " + targetExtensionId); | 146 errorMsg += ' for extension ' + targetExtensionId; |
| 131 if (sourceUrl != "") | 147 if (sourceUrl) |
| 132 $Array.push(errorMsg, "for URL " + sourceUrl); | 148 errorMsg += ' for URL ' + sourceUrl; |
| 133 lastError.set(eventName, errorMsg.join(" ") + ").", null, chrome); | 149 errorMsg += ').'; |
| 150 lastError.set(eventName, errorMsg, null, chrome); |
| 134 } | 151 } |
| 135 | 152 |
| 136 // Helper function for dispatchOnConnect | 153 // Helper function for dispatchOnConnect |
| 137 function dispatchOnRequest(portId, channelName, sender, | 154 function dispatchOnRequest(portId, channelName, sender, |
| 138 sourceExtensionId, targetExtensionId, sourceUrl, | 155 sourceExtensionId, targetExtensionId, sourceUrl, |
| 139 isExternal) { | 156 isExternal) { |
| 140 var isSendMessage = channelName == kMessageChannel; | 157 var isSendMessage = channelName == kMessageChannel; |
| 141 var requestEvent = null; | 158 var requestEvent = null; |
| 142 if (isSendMessage) { | 159 if (isSendMessage) { |
| 143 if (chrome.runtime) { | 160 if (chrome.runtime) { |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 exports.$set('Port', Port); | 438 exports.$set('Port', Port); |
| 422 exports.$set('createPort', createPort); | 439 exports.$set('createPort', createPort); |
| 423 exports.$set('sendMessageImpl', sendMessageImpl); | 440 exports.$set('sendMessageImpl', sendMessageImpl); |
| 424 exports.$set('sendMessageUpdateArguments', sendMessageUpdateArguments); | 441 exports.$set('sendMessageUpdateArguments', sendMessageUpdateArguments); |
| 425 | 442 |
| 426 // For C++ code to call. | 443 // For C++ code to call. |
| 427 exports.$set('hasPort', hasPort); | 444 exports.$set('hasPort', hasPort); |
| 428 exports.$set('dispatchOnConnect', dispatchOnConnect); | 445 exports.$set('dispatchOnConnect', dispatchOnConnect); |
| 429 exports.$set('dispatchOnDisconnect', dispatchOnDisconnect); | 446 exports.$set('dispatchOnDisconnect', dispatchOnDisconnect); |
| 430 exports.$set('dispatchOnMessage', dispatchOnMessage); | 447 exports.$set('dispatchOnMessage', dispatchOnMessage); |
| OLD | NEW |