| /* Copyright 2013 The Chromium Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| /** |
| * @fileoverview |
| * The sandbox side of the application/sandbox WCS interface, used by the |
| * sandbox to exchange messages with the application. |
| */ |
| |
| 'use strict'; |
| |
| /** @suppress {duplicate} */ |
| var remoting = remoting || {}; |
| |
| /** @constructor */ |
| remoting.WcsSandboxContent = function() { |
| /** |
| * @type {Window} |
| * @private |
| */ |
| this.parentWindow_ = null; |
| /** |
| * @type {number} |
| * @private |
| */ |
| this.nextXhrId_ = 0; |
| /** |
| * @type {Object.<number, XMLHttpRequest>} |
| * @private |
| */ |
| this.pendingXhrs_ = {}; |
| |
| window.addEventListener('message', this.onMessage_.bind(this), false); |
| }; |
| |
| /** |
| * Event handler to process messages from the application. |
| * |
| * @param {Event} event |
| */ |
| remoting.WcsSandboxContent.prototype.onMessage_ = function(event) { |
| this.parentWindow_ = event.source; |
| |
| switch (event.data['command']) { |
| |
| case 'proxyXhrs': |
| // Since the WCS driver code constructs XHRs directly, the only |
| // mechanism for proxying them is to replace the XMLHttpRequest |
| // constructor. |
| XMLHttpRequest = remoting.XMLHttpRequestProxy; |
| break; |
| |
| case 'sendIq': |
| /** @type {string} */ |
| var stanza = event.data['stanza']; |
| if (stanza === undefined) { |
| console.error('sendIq: missing IQ stanza.'); |
| break; |
| } |
| if (remoting.wcs) { |
| remoting.wcs.sendIq(stanza); |
| } else { |
| console.error('Dropping IQ stanza:', stanza); |
| } |
| break; |
| |
| case 'setAccessToken': |
| /** @type {string} */ |
| var token = event.data['token']; |
| if (token === undefined) { |
| console.error('setAccessToken: missing access token.'); |
| break; |
| } |
| // The WCS driver JS requires that remoting.wcsLoader be a global |
| // variable, so it can't be a member of this class. |
| // TODO(jamiewalch): remoting.wcs doesn't need to be global and should |
| // be made a member (http://crbug.com/172348). |
| if (remoting.wcs) { |
| remoting.wcs.updateAccessToken(token); |
| } else if (!remoting.wcsLoader) { |
| remoting.wcsLoader = new remoting.WcsLoader(); |
| remoting.wcsLoader.start(token, |
| this.onLocalJid_.bind(this), |
| this.onError_.bind(this)); |
| } |
| break; |
| |
| case 'xhrStateChange': |
| /** @type {number} */ |
| var id = event.data['id']; |
| if (id === undefined) { |
| console.error('xhrStateChange: missing id.'); |
| break; |
| } |
| var pendingXhr = this.pendingXhrs_[id]; |
| if (!pendingXhr) { |
| console.error('xhrStateChange: unrecognized id:', id); |
| break; |
| } |
| /** @type {XMLHttpRequest} */ |
| var xhr = event.data['xhr']; |
| if (xhr === undefined) { |
| console.error('xhrStateChange: missing xhr'); |
| break; |
| } |
| for (var member in xhr) { |
| pendingXhr[member] = xhr[member]; |
| } |
| if (xhr.readyState == 4) { |
| delete this.pendingXhrs_[id]; |
| } |
| if (pendingXhr.onreadystatechange) { |
| pendingXhr.onreadystatechange(); |
| } |
| break; |
| |
| default: |
| console.error('Unexpected message:', event.data['command'], event.data); |
| } |
| }; |
| |
| /** |
| * Callback method to indicate that the WCS driver has loaded and provide the |
| * full JID of the client. |
| * |
| * @param {string} clientJid The full JID of the WCS client. |
| * @private |
| */ |
| remoting.WcsSandboxContent.prototype.onLocalJid_ = function(clientJid) { |
| remoting.wcs.setOnIq(this.onIq_.bind(this)); |
| var message = { |
| 'command': 'onLocalJid', |
| 'clientJid': clientJid |
| }; |
| this.parentWindow_.postMessage(message, '*'); |
| }; |
| |
| /** |
| * Callback method to indicate that something went wrong loading the WCS driver. |
| * |
| * @param {remoting.Error} error Details of the error. |
| * @private |
| */ |
| remoting.WcsSandboxContent.prototype.onError_ = function(error) { |
| var message = { |
| 'command': 'onError', |
| 'error': error |
| }; |
| this.parentWindow_.postMessage(message, '*'); |
| }; |
| |
| /** |
| * Forward an XHR to the container process to send. This is analogous to XHR's |
| * send method. |
| * |
| * @param {remoting.XMLHttpRequestProxy} xhr The XHR to send. |
| * @return {number} The unique ID allocated to the XHR. Used to abort it. |
| */ |
| remoting.WcsSandboxContent.prototype.sendXhr = function(xhr) { |
| var id = this.nextXhrId_++; |
| this.pendingXhrs_[id] = xhr; |
| var message = { |
| 'command': 'sendXhr', |
| 'id': id, |
| 'parameters': xhr.sandbox_ipc |
| }; |
| this.parentWindow_.postMessage(message, '*'); |
| delete xhr.sandbox_ipc; |
| return id; |
| }; |
| |
| /** |
| * Abort a forwarded XHR. This is analogous to XHR's abort method. |
| * |
| * @param {number} id The unique ID of the XHR to abort, as returned by sendXhr. |
| */ |
| remoting.WcsSandboxContent.prototype.abortXhr = function(id) { |
| if (!this.pendingXhrs_[id]) { |
| // The XHR is removed when it reaches the "ready" state. Calling abort |
| // subsequently is unusual, but legal, so just silently ignore the request |
| // in this case. |
| return; |
| } |
| var message = { |
| 'command': 'abortXhr', |
| 'id': id |
| }; |
| this.parentWindow_.postMessage(message, '*'); |
| }; |
| |
| /** |
| * Callback to indicate than an IQ stanza has been received from the WCS |
| * driver, and should be forwarded to the main process. |
| * |
| * @param {string} stanza |
| * @private |
| */ |
| remoting.WcsSandboxContent.prototype.onIq_ = function(stanza) { |
| remoting.wcs.setOnIq(this.onIq_.bind(this)); |
| var message = { |
| 'command': 'onIq', |
| 'stanza': stanza |
| }; |
| this.parentWindow_.postMessage(message, '*'); |
| }; |
| |
| /** |
| * Entry point for the WCS sandbox process. |
| */ |
| function onSandboxInit() { |
| // The WCS code registers for a couple of events that aren't supported in |
| // Apps V2, so ignore those for now. |
| var oldAEL = window.addEventListener; |
| window.addEventListener = function(type, listener, useCapture) { |
| if (type == 'beforeunload' || type == 'unload') { |
| return; |
| } |
| oldAEL(type, listener, useCapture); |
| }; |
| |
| remoting.settings = new remoting.Settings(); |
| remoting.sandboxContent = new remoting.WcsSandboxContent(); |
| } |
| |
| window.addEventListener('load', onSandboxInit, false); |
| |
| /** @type {remoting.WcsSandboxContent} */ |
| remoting.sandboxContent = null; |