Update V8 to version 3.30.4 (based on bleeding_edge revision r24443)
[chromium-blink-merge.git] / remoting / webapp / wcs_sandbox_container.js
blob4104c369b69959f822387f01da7b94579e2d8ecd
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 */
6 /**
7 * @fileoverview
8 * The application side of the application/sandbox WCS interface, used by the
9 * application to exchange messages with the sandbox.
12 'use strict';
14 /** @suppress {duplicate} */
15 var remoting = remoting || {};
17 /**
18 * @param {Window} sandbox The Javascript Window object representing the
19 * sandboxed WCS driver.
20 * @constructor
22 remoting.WcsSandboxContainer = function(sandbox) {
23 /** @private */
24 this.sandbox_ = sandbox;
25 /** @type {?function(string):void}
26 * @private */
27 this.onConnected_ = null;
28 /** @type {function(remoting.Error):void}
29 * @private */
30 this.onError_ = function(error) {};
31 /** @type {?function(string):void}
32 * @private */
33 this.onIq_ = null;
34 /** @type {Object.<number, XMLHttpRequest>}
35 * @private */
36 this.pendingXhrs_ = {};
37 /** @private */
38 this.localJid_ = '';
40 /** @private */
41 this.accessTokenRefreshTimerStarted_ = false;
43 window.addEventListener('message', this.onMessage_.bind(this), false);
45 if (base.isAppsV2()) {
46 var message = {
47 'command': 'proxyXhrs'
49 this.sandbox_.postMessage(message, '*');
53 /**
54 * @param {function(string):void} onConnected Callback to be called when WCS is
55 * connected. May be called synchronously if WCS is already connected.
56 * @param {function(remoting.Error):void} onError called in case of an error.
57 * @return {void} Nothing.
59 remoting.WcsSandboxContainer.prototype.connect = function(
60 onConnected, onError) {
61 this.onError_ = onError;
62 this.ensureAccessTokenRefreshTimer_();
63 if (this.localJid_) {
64 onConnected(this.localJid_);
65 } else {
66 this.onConnected_ = onConnected;
70 /**
71 * @param {?function(string):void} onIq Callback invoked when an IQ stanza is
72 * received.
73 * @return {void} Nothing.
75 remoting.WcsSandboxContainer.prototype.setOnIq = function(onIq) {
76 this.onIq_ = onIq;
79 /**
80 * Refreshes access token and starts a timer to update it periodically.
82 * @private
84 remoting.WcsSandboxContainer.prototype.ensureAccessTokenRefreshTimer_ =
85 function() {
86 if (this.accessTokenRefreshTimerStarted_) {
87 return;
90 this.refreshAccessToken_();
91 setInterval(this.refreshAccessToken_.bind(this), 60 * 1000);
92 this.accessTokenRefreshTimerStarted_ = true;
95 /**
96 * @private
97 * @return {void} Nothing.
99 remoting.WcsSandboxContainer.prototype.refreshAccessToken_ = function() {
100 remoting.identity.callWithToken(
101 this.setAccessToken_.bind(this), this.onError_);
105 * @private
106 * @param {string} token The access token.
107 * @return {void}
109 remoting.WcsSandboxContainer.prototype.setAccessToken_ = function(token) {
110 var message = {
111 'command': 'setAccessToken',
112 'token': token
114 this.sandbox_.postMessage(message, '*');
118 * @param {string} stanza The IQ stanza to send.
119 * @return {void}
121 remoting.WcsSandboxContainer.prototype.sendIq = function(stanza) {
122 var message = {
123 'command': 'sendIq',
124 'stanza': stanza
126 this.sandbox_.postMessage(message, '*');
130 * Event handler to process messages from the sandbox.
132 * @param {Event} event
134 remoting.WcsSandboxContainer.prototype.onMessage_ = function(event) {
135 switch (event.data['command']) {
137 case 'onLocalJid':
138 /** @type {string} */
139 var localJid = event.data['localJid'];
140 if (localJid === undefined) {
141 console.error('onReady: missing localJid');
142 break;
144 this.localJid_ = localJid;
145 if (this.onConnected_) {
146 var callback = this.onConnected_;
147 this.onConnected_ = null;
148 callback(localJid);
150 break;
152 case 'onError':
153 /** @type {remoting.Error} */
154 var error = event.data['error'];
155 if (error === undefined) {
156 console.error('onError: missing error code');
157 break;
159 this.onError_(error);
160 break;
162 case 'onIq':
163 /** @type {string} */
164 var stanza = event.data['stanza'];
165 if (stanza === undefined) {
166 console.error('onIq: missing IQ stanza');
167 break;
169 if (this.onIq_) {
170 this.onIq_(stanza);
172 break;
174 case 'sendXhr':
175 /** @type {number} */
176 var id = event.data['id'];
177 if (id === undefined) {
178 console.error('sendXhr: missing id');
179 break;
181 /** @type {Object} */
182 var parameters = event.data['parameters'];
183 if (parameters === undefined) {
184 console.error('sendXhr: missing parameters');
185 break;
187 /** @type {string} */
188 var method = parameters['method'];
189 if (method === undefined) {
190 console.error('sendXhr: missing method');
191 break;
193 /** @type {string} */
194 var url = parameters['url'];
195 if (url === undefined) {
196 console.error('sendXhr: missing url');
197 break;
199 /** @type {string} */
200 var data = parameters['data'];
201 if (data === undefined) {
202 console.error('sendXhr: missing data');
203 break;
205 /** @type {string|undefined}*/
206 var user = parameters['user'];
207 /** @type {string|undefined}*/
208 var password = parameters['password'];
209 var xhr = new XMLHttpRequest;
210 this.pendingXhrs_[id] = xhr;
211 xhr.open(method, url, true, user, password);
212 /** @type {Object} */
213 var headers = parameters['headers'];
214 if (headers) {
215 for (var header in headers) {
216 xhr.setRequestHeader(header, headers[header]);
219 xhr.onreadystatechange = this.onReadyStateChange_.bind(this, id);
220 xhr.send(data);
221 break;
223 case 'abortXhr':
224 var id = event.data['id'];
225 if (id === undefined) {
226 console.error('abortXhr: missing id');
227 break;
229 var xhr = this.pendingXhrs_[id]
230 if (!xhr) {
231 // It's possible for an abort and a reply to cross each other on the
232 // IPC channel. In that case, we silently ignore the abort.
233 break;
235 xhr.abort();
236 break;
238 default:
239 console.error('Unexpected message:', event.data['command'], event.data);
244 * Return a "copy" of an XHR object suitable for postMessage. Specifically,
245 * remove all non-serializable members such as functions.
247 * @param {XMLHttpRequest} xhr The XHR to serialize.
248 * @return {Object} A serializable version of the input.
250 function sanitizeXhr_(xhr) {
251 /** @type {Object} */
252 var result = {
253 readyState: xhr.readyState,
254 response: xhr.response,
255 responseText: xhr.responseText,
256 responseType: xhr.responseType,
257 responseXML: xhr.responseXML,
258 status: xhr.status,
259 statusText: xhr.statusText,
260 withCredentials: xhr.withCredentials
262 return result;
266 * @param {number} id The unique ID of the XHR for which the state has changed.
267 * @private
269 remoting.WcsSandboxContainer.prototype.onReadyStateChange_ = function(id) {
270 var xhr = this.pendingXhrs_[id];
271 if (!xhr) {
272 // XHRs are only removed when they have completed, in which case no
273 // further callbacks should be received.
274 console.error('Unexpected callback for xhr', id);
275 return;
277 var message = {
278 'command': 'xhrStateChange',
279 'id': id,
280 'xhr': sanitizeXhr_(xhr)
282 this.sandbox_.postMessage(message, '*');
283 if (xhr.readyState == 4) {
284 delete this.pendingXhrs_[id];
288 /** @type {remoting.WcsSandboxContainer} */
289 remoting.wcsSandbox = null;