Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(332)

Side by Side Diff: remoting/webapp/crd/js/xhr.js

Issue 1133913002: [Chromoting] Move shared webapp JS files from crd/js -> base/js (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/webapp/crd/js/wcs_sandbox_container.js ('k') | remoting/webapp/crd/js/xhr_unittest.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 * @fileoverview
7 * Utility class for making XHRs more pleasant.
8 *
9 * Note: a mock version of this API exists in mock_xhr.js.
10 */
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 (function() {
16
17 'use strict';
18
19 /**
20 * @constructor
21 * @param {remoting.Xhr.Params} params
22 */
23 remoting.Xhr = function(params) {
24 remoting.Xhr.checkParams_(params);
25
26 // Apply URL parameters.
27 var url = params.url;
28 var parameterString = '';
29 if (typeof(params.urlParams) === 'string') {
30 parameterString = params.urlParams;
31 } else if (typeof(params.urlParams) === 'object') {
32 parameterString = remoting.Xhr.urlencodeParamHash(
33 base.copyWithoutNullFields(params.urlParams));
34 }
35 if (parameterString) {
36 url += '?' + parameterString;
37 }
38
39 // Prepare the build modified headers.
40 /** @const */
41 this.headers_ = base.copyWithoutNullFields(params.headers);
42
43 // Convert the content fields to a single text content variable.
44 /** @private {?string} */
45 this.content_ = null;
46 if (params.textContent !== undefined) {
47 this.maybeSetContentType_('text/plain');
48 this.content_ = params.textContent;
49 } else if (params.formContent !== undefined) {
50 this.maybeSetContentType_('application/x-www-form-urlencoded');
51 this.content_ = remoting.Xhr.urlencodeParamHash(params.formContent);
52 } else if (params.jsonContent !== undefined) {
53 this.maybeSetContentType_('application/json');
54 this.content_ = JSON.stringify(params.jsonContent);
55 }
56
57 // Apply the oauthToken field.
58 if (params.oauthToken !== undefined) {
59 this.setAuthToken_(params.oauthToken);
60 }
61
62 /** @private @const {boolean} */
63 this.acceptJson_ = params.acceptJson || false;
64 if (this.acceptJson_) {
65 this.maybeSetHeader_('Accept', 'application/json');
66 }
67
68 // Apply useIdentity field.
69 /** @const {boolean} */
70 this.useIdentity_ = params.useIdentity || false;
71
72 /** @private @const {!XMLHttpRequest} */
73 this.nativeXhr_ = new XMLHttpRequest();
74 this.nativeXhr_.onreadystatechange = this.onReadyStateChange_.bind(this);
75 this.nativeXhr_.withCredentials = params.withCredentials || false;
76 this.nativeXhr_.open(params.method, url, true);
77
78 /** @private {base.Deferred<!remoting.Xhr.Response>} */
79 this.deferred_ = null;
80 };
81
82 /**
83 * Starts and HTTP request and gets a promise that is resolved when
84 * the request completes.
85 *
86 * Any error that prevents sending the request causes the promise to
87 * be rejected.
88 *
89 * NOTE: Calling this method more than once will return the same
90 * promise and not start a new request, despite what the name
91 * suggests.
92 *
93 * @return {!Promise<!remoting.Xhr.Response>}
94 */
95 remoting.Xhr.prototype.start = function() {
96 if (this.deferred_ == null) {
97 this.deferred_ = new base.Deferred();
98
99 // Send the XHR, possibly after getting an OAuth token.
100 var that = this;
101 if (this.useIdentity_) {
102 remoting.identity.getToken().then(function(token) {
103 base.debug.assert(that.nativeXhr_.readyState == 1);
104 that.setAuthToken_(token);
105 that.sendXhr_();
106 }).catch(function(error) {
107 that.deferred_.reject(error);
108 });
109 } else {
110 this.sendXhr_();
111 }
112 }
113 return this.deferred_.promise();
114 };
115
116 /**
117 * The set of possible fields in remoting.Xhr.Params.
118 * @const
119 */
120 var ALLOWED_PARAMS = [
121 'method',
122 'url',
123 'urlParams',
124 'textContent',
125 'formContent',
126 'jsonContent',
127 'headers',
128 'withCredentials',
129 'oauthToken',
130 'useIdentity',
131 'acceptJson'
132 ];
133
134 /**
135 * @param {remoting.Xhr.Params} params
136 * @throws {Error} if params are invalid
137 * @private
138 */
139 remoting.Xhr.checkParams_ = function(params) {
140 // Provide a sensible error message when the user misspells a
141 // parameter name, since the compiler won't catch it.
142 for (var field in params) {
143 if (ALLOWED_PARAMS.indexOf(field) == -1) {
144 throw new Error('unknow parameter: ' + field);
145 }
146 }
147
148 if (params.urlParams) {
149 if (params.url.indexOf('?') != -1) {
150 throw new Error('URL may not contain "?" when urlParams is set');
151 }
152 if (params.url.indexOf('#') != -1) {
153 throw new Error('URL may not contain "#" when urlParams is set');
154 }
155 }
156
157 if ((Number(params.textContent !== undefined) +
158 Number(params.formContent !== undefined) +
159 Number(params.jsonContent !== undefined)) > 1) {
160 throw new Error(
161 'may only specify one of textContent, formContent, and jsonContent');
162 }
163
164 if (params.useIdentity && params.oauthToken !== undefined) {
165 throw new Error('may not specify both useIdentity and oauthToken');
166 }
167
168 if ((params.useIdentity || params.oauthToken !== undefined) &&
169 params.headers &&
170 params.headers['Authorization'] != null) {
171 throw new Error(
172 'may not specify useIdentity or oauthToken ' +
173 'with an Authorization header');
174 }
175 };
176
177 /**
178 * @param {string} token
179 * @private
180 */
181 remoting.Xhr.prototype.setAuthToken_ = function(token) {
182 this.setHeader_('Authorization', 'Bearer ' + token);
183 };
184
185 /**
186 * @param {string} type
187 * @private
188 */
189 remoting.Xhr.prototype.maybeSetContentType_ = function(type) {
190 this.maybeSetHeader_('Content-type', type + '; charset=UTF-8');
191 };
192
193 /**
194 * @param {string} key
195 * @param {string} value
196 * @private
197 */
198 remoting.Xhr.prototype.setHeader_ = function(key, value) {
199 var wasSet = this.maybeSetHeader_(key, value);
200 base.debug.assert(wasSet);
201 };
202
203 /**
204 * @param {string} key
205 * @param {string} value
206 * @return {boolean}
207 * @private
208 */
209 remoting.Xhr.prototype.maybeSetHeader_ = function(key, value) {
210 if (!(key in this.headers_)) {
211 this.headers_[key] = value;
212 return true;
213 }
214 return false;
215 };
216
217 /** @private */
218 remoting.Xhr.prototype.sendXhr_ = function() {
219 for (var key in this.headers_) {
220 this.nativeXhr_.setRequestHeader(
221 key, /** @type {string} */ (this.headers_[key]));
222 }
223 this.nativeXhr_.send(this.content_);
224 this.content_ = null; // for gc
225 };
226
227 /**
228 * @private
229 */
230 remoting.Xhr.prototype.onReadyStateChange_ = function() {
231 var xhr = this.nativeXhr_;
232 if (xhr.readyState == 4) {
233 // See comments at remoting.Xhr.Response.
234 this.deferred_.resolve(remoting.Xhr.Response.fromXhr_(
235 xhr, this.acceptJson_));
236 }
237 };
238
239 /**
240 * The response-related parts of an XMLHttpRequest. Note that this
241 * class is not just a facade for XMLHttpRequest; it saves the value
242 * of the |responseText| field becuase once onReadyStateChange_
243 * (above) returns, the value of |responseText| is reset to the empty
244 * string! This is a documented anti-feature of the XMLHttpRequest
245 * API.
246 *
247 * @constructor
248 * @param {number} status
249 * @param {string} statusText
250 * @param {?string} url
251 * @param {string} text
252 * @param {boolean} allowJson
253 */
254 remoting.Xhr.Response = function(
255 status, statusText, url, text, allowJson) {
256 /**
257 * The HTTP status code.
258 * @const {number}
259 */
260 this.status = status;
261
262 /**
263 * The HTTP status description.
264 * @const {string}
265 */
266 this.statusText = statusText;
267
268 /**
269 * The response URL, if any.
270 * @const {?string}
271 */
272 this.url = url;
273
274 /** @private {string} */
275 this.text_ = text;
276
277 /** @private @const */
278 this.allowJson_ = allowJson;
279
280 /** @private {*|undefined} */
281 this.json_ = undefined;
282 };
283
284 /**
285 * @param {!XMLHttpRequest} xhr
286 * @param {boolean} allowJson
287 * @return {!remoting.Xhr.Response}
288 */
289 remoting.Xhr.Response.fromXhr_ = function(xhr, allowJson) {
290 return new remoting.Xhr.Response(
291 xhr.status,
292 xhr.statusText,
293 xhr.responseURL,
294 xhr.responseText || '',
295 allowJson);
296 };
297
298 /**
299 * @return {boolean} True if the response code is outside the 200-299
300 * range (i.e. success as defined by the HTTP protocol).
301 */
302 remoting.Xhr.Response.prototype.isError = function() {
303 return this.status < 200 || this.status >= 300;
304 };
305
306 /**
307 * @return {string} The text content of the response.
308 */
309 remoting.Xhr.Response.prototype.getText = function() {
310 return this.text_;
311 };
312
313 /**
314 * Get the JSON content of the response. Requires acceptJson to have
315 * been true in the request.
316 * @return {*} The parsed JSON content of the response.
317 */
318 remoting.Xhr.Response.prototype.getJson = function() {
319 base.debug.assert(this.allowJson_);
320 if (this.json_ === undefined) {
321 this.json_ = JSON.parse(this.text_);
322 }
323 return this.json_;
324 };
325
326 /**
327 * Takes an associative array of parameters and urlencodes it.
328 *
329 * @param {Object<string,string>} paramHash The parameter key/value pairs.
330 * @return {string} URLEncoded version of paramHash.
331 */
332 remoting.Xhr.urlencodeParamHash = function(paramHash) {
333 var paramArray = [];
334 for (var key in paramHash) {
335 var value = paramHash[key];
336 if (value != null) {
337 paramArray.push(encodeURIComponent(key) +
338 '=' + encodeURIComponent(value));
339 }
340 }
341 if (paramArray.length > 0) {
342 return paramArray.join('&');
343 }
344 return '';
345 };
346
347 })();
348
349 /**
350 * Parameters for the 'start' function. Unless otherwise noted, all
351 * parameters are optional.
352 *
353 * method: (required) The HTTP method to use.
354 *
355 * url: (required) The URL to request.
356 *
357 * urlParams: Parameters to be appended to the URL. Null-valued
358 * parameters are omitted.
359 *
360 * textContent: Text to be sent as the request body.
361 *
362 * formContent: Data to be URL-encoded and sent as the request body.
363 * Causes Content-type header to be set appropriately.
364 *
365 * jsonContent: Data to be JSON-encoded and sent as the request body.
366 * Causes Content-type header to be set appropriately.
367 *
368 * headers: Additional request headers to be sent. Null-valued
369 * headers are omitted.
370 *
371 * withCredentials: Value of the XHR's withCredentials field.
372 *
373 * oauthToken: An OAuth2 token used to construct an Authentication
374 * header.
375 *
376 * useIdentity: Use identity API to get an OAuth2 token.
377 *
378 * acceptJson: If true, send an Accept header indicating that a JSON
379 * response is expected.
380 *
381 * @typedef {{
382 * method: string,
383 * url:string,
384 * urlParams:(string|Object<string,?string>|undefined),
385 * textContent:(string|undefined),
386 * formContent:(Object|undefined),
387 * jsonContent:(*|undefined),
388 * headers:(Object<string,?string>|undefined),
389 * withCredentials:(boolean|undefined),
390 * oauthToken:(string|undefined),
391 * useIdentity:(boolean|undefined),
392 * acceptJson:(boolean|undefined)
393 * }}
394 */
395 remoting.Xhr.Params;
OLDNEW
« no previous file with comments | « remoting/webapp/crd/js/wcs_sandbox_container.js ('k') | remoting/webapp/crd/js/xhr_unittest.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698