wcs_sandbox_content.js revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1/* Copyright 2013 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 6/** 7 * @fileoverview 8 * The sandbox side of the application/sandbox WCS interface, used by the 9 * sandbox to exchange messages with the application. 10 */ 11 12'use strict'; 13 14/** @suppress {duplicate} */ 15var remoting = remoting || {}; 16 17/** @constructor */ 18remoting.WcsSandboxContent = function() { 19 /** 20 * @type {Window} 21 * @private 22 */ 23 this.parentWindow_ = null; 24 /** 25 * @type {number} 26 * @private 27 */ 28 this.nextXhrId_ = 0; 29 /** 30 * @type {Object.<number, XMLHttpRequest>} 31 * @private 32 */ 33 this.pendingXhrs_ = {}; 34 35 window.addEventListener('message', this.onMessage_.bind(this), false); 36}; 37 38/** 39 * Event handler to process messages from the application. 40 * 41 * @param {Event} event 42 */ 43remoting.WcsSandboxContent.prototype.onMessage_ = function(event) { 44 this.parentWindow_ = event.source; 45 46 switch (event.data['command']) { 47 48 case 'sendIq': 49 /** @type {string} */ 50 var stanza = event.data['stanza']; 51 if (stanza === undefined) { 52 console.error('sendIq: missing IQ stanza.'); 53 break; 54 } 55 if (remoting.wcs) { 56 remoting.wcs.sendIq(stanza); 57 } else { 58 console.error('Dropping IQ stanza:', stanza); 59 } 60 break; 61 62 case 'setAccessToken': 63 /** @type {string} */ 64 var token = event.data['token']; 65 if (token === undefined) { 66 console.error('setAccessToken: missing access token.'); 67 break; 68 } 69 // The WCS driver JS requires that remoting.wcsLoader be a global 70 // variable, so it can't be a member of this class. 71 // TODO(jamiewalch): remoting.wcs doesn't need to be global and should 72 // be made a member (http://crbug.com/172348). 73 if (remoting.wcs) { 74 remoting.wcs.updateAccessToken(token); 75 } else if (!remoting.wcsLoader) { 76 remoting.wcsLoader = new remoting.WcsLoader(); 77 remoting.wcsLoader.start(token, 78 this.onReady_.bind(this), 79 this.onError_.bind(this)); 80 } 81 break; 82 83 case 'xhrStateChange': 84 /** @type {number} */ 85 var id = event.data['id']; 86 if (id === undefined) { 87 console.error('xhrStateChange: missing id.'); 88 break; 89 } 90 var pendingXhr = this.pendingXhrs_[id]; 91 if (!pendingXhr) { 92 console.error('xhrStateChange: unrecognized id:', id); 93 break; 94 } 95 /** @type {XMLHttpRequest} */ 96 var xhr = event.data['xhr']; 97 if (xhr === undefined) { 98 console.error('xhrStateChange: missing xhr'); 99 break; 100 } 101 for (var member in xhr) { 102 pendingXhr[member] = xhr[member]; 103 } 104 if (xhr.readyState == 4) { 105 delete this.pendingXhrs_[id]; 106 } 107 if (pendingXhr.onreadystatechange) { 108 pendingXhr.onreadystatechange(); 109 } 110 break; 111 112 default: 113 console.error('Unexpected message:', event.data['command'], event.data); 114 } 115}; 116 117/** 118 * Callback method to indicate that the WCS driver has loaded and provide the 119 * full JID of the client. 120 * 121 * @param {string} clientJid The full JID of the WCS client. 122 * @private 123 */ 124remoting.WcsSandboxContent.prototype.onReady_ = function(clientJid) { 125 remoting.wcs.setOnIq(this.onIq_.bind(this)); 126 var message = { 127 'command': 'onReady', 128 'clientJid': clientJid 129 }; 130 this.parentWindow_.postMessage(message, '*'); 131}; 132 133/** 134 * Callback method to indicate that something went wrong loading the WCS driver. 135 * 136 * @param {remoting.Error} error Details of the error. 137 * @private 138 */ 139remoting.WcsSandboxContent.prototype.onError_ = function(error) { 140 var message = { 141 'command': 'onError', 142 'error': error 143 }; 144 this.parentWindow_.postMessage(message, '*'); 145}; 146 147/** 148 * Forward an XHR to the container process to send. This is analogous to XHR's 149 * send method. 150 * 151 * @param {remoting.XMLHttpRequestProxy} xhr The XHR to send. 152 * @return {number} The unique ID allocated to the XHR. Used to abort it. 153 */ 154remoting.WcsSandboxContent.prototype.sendXhr = function(xhr) { 155 var id = this.nextXhrId_++; 156 this.pendingXhrs_[id] = xhr; 157 var message = { 158 'command': 'sendXhr', 159 'id': id, 160 'parameters': xhr.sandbox_ipc 161 }; 162 this.parentWindow_.postMessage(message, '*'); 163 delete xhr.sandbox_ipc; 164 return id; 165}; 166 167/** 168 * Abort a forwarded XHR. This is analogous to XHR's abort method. 169 * 170 * @param {number} id The unique ID of the XHR to abort, as returned by sendXhr. 171 */ 172remoting.WcsSandboxContent.prototype.abortXhr = function(id) { 173 if (!this.pendingXhrs_[id]) { 174 // The XHR is removed when it reaches the "ready" state. Calling abort 175 // subsequently is unusual, but legal, so just silently ignore the request 176 // in this case. 177 return; 178 } 179 var message = { 180 'command': 'abortXhr', 181 'id': id 182 }; 183 this.parentWindow_.postMessage(message, '*'); 184}; 185 186/** 187 * Callback to indicate than an IQ stanza has been received from the WCS 188 * driver, and should be forwarded to the main process. 189 * 190 * @param {string} stanza 191 * @private 192 */ 193remoting.WcsSandboxContent.prototype.onIq_ = function(stanza) { 194 remoting.wcs.setOnIq(this.onIq_.bind(this)); 195 var message = { 196 'command': 'onIq', 197 'stanza': stanza 198 }; 199 this.parentWindow_.postMessage(message, '*'); 200}; 201 202/** 203 * Entry point for the WCS sandbox process. 204 */ 205function onSandboxInit() { 206 // The WCS code registers for a couple of events that aren't supported in 207 // Apps V2, so ignore those for now. 208 var oldAEL = window.addEventListener; 209 window.addEventListener = function(type, listener, useCapture) { 210 if (type == 'beforeunload' || type == 'unload') { 211 return; 212 } 213 oldAEL(type, listener, useCapture); 214 }; 215 216 remoting.settings = new remoting.Settings(); 217 remoting.sandboxContent = new remoting.WcsSandboxContent(); 218} 219 220window.addEventListener('load', onSandboxInit, false); 221 222/** @type {remoting.WcsSandboxContent} */ 223remoting.sandboxContent = null;