nativemessagingtransport_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.net.xpc.NativeMessagingTransportTest');
  15. goog.setTestOnly('goog.net.xpc.NativeMessagingTransportTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.events');
  18. goog.require('goog.net.xpc');
  19. goog.require('goog.net.xpc.CfgFields');
  20. goog.require('goog.net.xpc.CrossPageChannel');
  21. goog.require('goog.net.xpc.CrossPageChannelRole');
  22. goog.require('goog.net.xpc.NativeMessagingTransport');
  23. goog.require('goog.testing.jsunit');
  24. // This test only tests the native messaing transport protocol version 2.
  25. // Testing of previous versions and of backward/forward compatibility is done
  26. // in crosspagechannel_test.html.
  27. function tearDown() {
  28. goog.net.xpc.NativeMessagingTransport.activeCount_ = {};
  29. goog.events.removeAll(window.postMessage ? window : document, 'message');
  30. }
  31. function testConstructor() {
  32. var xpc = getTestChannel();
  33. var t = new goog.net.xpc.NativeMessagingTransport(
  34. xpc, 'http://g.com:80', undefined /* opt_domHelper */,
  35. false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */);
  36. assertEquals('http://g.com:80', t.peerHostname_);
  37. var t = new goog.net.xpc.NativeMessagingTransport(
  38. xpc, null /* peerHostName */, undefined /* opt_domHelper */,
  39. false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */);
  40. assertEquals('*', t.peerHostname_);
  41. t.dispose();
  42. }
  43. function testConstructorDom() {
  44. var xpc = getTestChannel();
  45. var t = new goog.net.xpc.NativeMessagingTransport(
  46. xpc, 'http://g.com:80', goog.dom.getDomHelper(),
  47. false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */);
  48. assertEquals('http://g.com:80', t.peerHostname_);
  49. var t = new goog.net.xpc.NativeMessagingTransport(
  50. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  51. 2 /* opt_protocolVersion */);
  52. assertEquals('*', t.peerHostname_);
  53. t.dispose();
  54. }
  55. function testDispose() {
  56. var xpc = getTestChannel();
  57. var listenedObj = window.postMessage ? window : document;
  58. var t0 = new goog.net.xpc.NativeMessagingTransport(
  59. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  60. 2 /* opt_protocolVersion */);
  61. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  62. t0.dispose();
  63. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  64. var t1 = new goog.net.xpc.NativeMessagingTransport(
  65. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  66. 2 /* opt_protocolVersion */);
  67. t1.connect();
  68. t1.dispose();
  69. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  70. var t2 = new goog.net.xpc.NativeMessagingTransport(
  71. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  72. 2 /* opt_protocolVersion */);
  73. var t3 = new goog.net.xpc.NativeMessagingTransport(
  74. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  75. 2 /* opt_protocolVersion */);
  76. t2.connect();
  77. t3.connect();
  78. t2.dispose();
  79. assertEquals(1, goog.events.removeAll(listenedObj, 'message'));
  80. }
  81. function testDisposeWithDom() {
  82. var xpc = getTestChannel(goog.dom.getDomHelper());
  83. var listenedObj = window.postMessage ? window : document;
  84. var t0 = new goog.net.xpc.NativeMessagingTransport(
  85. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  86. 2 /* opt_protocolVersion */);
  87. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  88. t0.dispose();
  89. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  90. var t1 = new goog.net.xpc.NativeMessagingTransport(
  91. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  92. 2 /* opt_protocolVersion */);
  93. t1.connect();
  94. t1.dispose();
  95. assertEquals(0, goog.events.removeAll(listenedObj, 'message'));
  96. var t2 = new goog.net.xpc.NativeMessagingTransport(
  97. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  98. 2 /* opt_protocolVersion */);
  99. var t3 = new goog.net.xpc.NativeMessagingTransport(
  100. xpc, null /* peerHostName */, false /* opt_oneSidedHandshake */,
  101. 2 /* opt_protocolVersion */);
  102. t2.connect();
  103. t3.connect();
  104. t2.dispose();
  105. assertEquals(1, goog.events.removeAll(listenedObj, 'message'));
  106. }
  107. function testBogusMessages() {
  108. var e = createMockEvent('origin_unknown', 'bogus_message');
  109. assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  110. e = createMockEvent('origin_unknown', 'bogus|message');
  111. assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  112. e = createMockEvent('origin_unknown', 'bogus|message:data');
  113. assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  114. }
  115. function testSendingMessagesToUnconnectedInnerPeer() {
  116. var xpc = getTestChannel();
  117. var serviceResult, payloadResult;
  118. xpc.xpcDeliver = function(service, payload) {
  119. serviceResult = service;
  120. payloadResult = payload;
  121. };
  122. // Construct an unconnected inner peer.
  123. xpc.getRole = function() { return goog.net.xpc.CrossPageChannelRole.INNER; };
  124. xpc.isConnected = function() { return false; };
  125. var t = new goog.net.xpc.NativeMessagingTransport(
  126. xpc, 'http://g.com', false /* opt_oneSidedHandshake */,
  127. 2 /* opt_protocolVersion */);
  128. // Test a valid message.
  129. var e = createMockEvent(
  130. 'origin_unknown', 'test_channel|test_service:test_payload');
  131. assertTrue(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  132. assertEquals('test_service', serviceResult);
  133. assertEquals('test_payload', payloadResult);
  134. assertEquals(
  135. 'Ensure channel name has not been changed.', 'test_channel',
  136. t.channel_.name);
  137. // Test that sending a SETUP message from an untrusted origin doesn't update
  138. // the channel name. This is a regression test for b/33746803.
  139. var e = createMockEvent('untrusted_origin', 'new_channel|tp:SETUP');
  140. assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  141. assertEquals(
  142. 'Channel name should not change from untrusted origin', 'test_channel',
  143. t.channel_.name);
  144. // Test updating a stale inner peer.
  145. var e = createMockEvent('trusted_origin', 'new_channel|tp:SETUP');
  146. assertTrue(goog.net.xpc.NativeMessagingTransport.messageReceived_(e));
  147. assertEquals('tp', serviceResult);
  148. assertEquals('SETUP', payloadResult);
  149. assertEquals(
  150. 'Ensure channel name has been updated.', 'new_channel', t.channel_.name);
  151. t.dispose();
  152. }
  153. function testSignalConnected_innerFrame() {
  154. checkSignalConnected(false /* oneSidedHandshake */, true /* innerFrame */);
  155. }
  156. function testSignalConnected_outerFrame() {
  157. checkSignalConnected(false /* oneSidedHandshake */, false /* innerFrame */);
  158. }
  159. function testSignalConnected_singleSided_innerFrame() {
  160. checkSignalConnected(true /* oneSidedHandshake */, true /* innerFrame */);
  161. }
  162. function testSignalConnected_singleSided_outerFrame() {
  163. checkSignalConnected(true /* oneSidedHandshake */, false /* innerFrame */);
  164. }
  165. function checkSignalConnected(
  166. oneSidedHandshake, innerFrame, peerProtocolVersion, protocolVersion) {
  167. var xpc = getTestChannel();
  168. var connected = false;
  169. xpc.notifyConnected = function() {
  170. if (connected) {
  171. fail();
  172. } else {
  173. connected = true;
  174. }
  175. };
  176. xpc.getRole = function() {
  177. return innerFrame ? goog.net.xpc.CrossPageChannelRole.INNER :
  178. goog.net.xpc.CrossPageChannelRole.OUTER;
  179. };
  180. xpc.isConnected = function() { return false; };
  181. var transport = new goog.net.xpc.NativeMessagingTransport(
  182. xpc, 'http://g.com', undefined /* opt_domHelper */,
  183. oneSidedHandshake /* opt_oneSidedHandshake */, 2 /* protocolVerion */);
  184. var sentPayloads = [];
  185. transport.send = function(service, payload) {
  186. assertEquals(goog.net.xpc.TRANSPORT_SERVICE_, service);
  187. sentPayloads.push(payload);
  188. };
  189. function assertSent(payloads) {
  190. assertArrayEquals(payloads, sentPayloads);
  191. sentPayloads = [];
  192. }
  193. var endpointId = transport.endpointId_;
  194. var peerEndpointId1 = 'abc123';
  195. var peerEndpointId2 = 'def234';
  196. assertFalse(connected);
  197. if (!oneSidedHandshake || innerFrame) {
  198. transport.transportServiceHandler(
  199. goog.net.xpc.SETUP_NTPV2 + ',' + peerEndpointId1);
  200. transport.transportServiceHandler(goog.net.xpc.SETUP);
  201. assertSent([goog.net.xpc.SETUP_ACK_NTPV2]);
  202. assertFalse(connected);
  203. transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2);
  204. assertSent([]);
  205. assertTrue(connected);
  206. } else {
  207. transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2);
  208. assertSent([]);
  209. assertFalse(connected);
  210. transport.transportServiceHandler(
  211. goog.net.xpc.SETUP_NTPV2 + ',' + peerEndpointId1);
  212. transport.transportServiceHandler(goog.net.xpc.SETUP);
  213. assertSent([goog.net.xpc.SETUP_ACK_NTPV2]);
  214. assertTrue(connected);
  215. }
  216. // Verify that additional transport service traffic doesn't cause duplicate
  217. // notifications.
  218. transport.transportServiceHandler(
  219. goog.net.xpc.SETUP_NTPV2 + ',' + peerEndpointId1);
  220. transport.transportServiceHandler(goog.net.xpc.SETUP);
  221. assertSent([goog.net.xpc.SETUP_ACK_NTPV2]);
  222. transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2);
  223. assertSent([]);
  224. // Simulate a reconnection by sending a SETUP message from a frame with a
  225. // different endpoint id. No further connection callbacks should fire, but
  226. // a new SETUP message should be triggered.
  227. transport.transportServiceHandler(
  228. goog.net.xpc.SETUP_NTPV2 + ',' + peerEndpointId2);
  229. transport.transportServiceHandler(goog.net.xpc.SETUP);
  230. assertSent([
  231. goog.net.xpc.SETUP_ACK_NTPV2, goog.net.xpc.SETUP_NTPV2 + ',' + endpointId
  232. ]);
  233. transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2);
  234. assertSent([]);
  235. }
  236. /**
  237. * Creates a Mock Event object used to test browser events.
  238. * @param {string} origin The URI origin, or '*', of the event.
  239. * @param {string} data The data to associate with the event.
  240. * @return {Object} The created object representing a browser event.
  241. */
  242. function createMockEvent(origin, data) {
  243. var event = {};
  244. event.getBrowserEvent = function() {
  245. return {origin: origin, data: data};
  246. };
  247. return event;
  248. }
  249. function getTestChannel(opt_domHelper) {
  250. var cfg = {};
  251. cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = 'test_channel';
  252. cfg[goog.net.xpc.CfgFields.PEER_HOSTNAME] = 'trusted_origin';
  253. return new goog.net.xpc.CrossPageChannel(
  254. cfg, opt_domHelper, undefined /* opt_domHelper */,
  255. false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */);
  256. }