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

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

Issue 1055313002: Added mock_xhr module w/ unit tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview 6 * @fileoverview
7 * Utility class for making XHRs more pleasant. 7 * Utility class for making XHRs more pleasant.
8 *
9 * Note: a mock version of this API exists in mock_xhr.js.
8 */ 10 */
9 11
10 'use strict'; 12 'use strict';
11 13
12 /** @suppress {duplicate} */ 14 /** @suppress {duplicate} */
13 var remoting = remoting || {}; 15 var remoting = remoting || {};
14 16
15 /** 17 /**
16 * @constructor 18 * @constructor
17 * @param {remoting.Xhr.Params} params 19 * @param {remoting.Xhr.Params} params
18 */ 20 */
19 remoting.Xhr = function(params) { 21 remoting.Xhr = function(params) {
20 remoting.Xhr.checkParams_(params); 22 remoting.Xhr.checkParams_(params);
21 23
22 // Apply URL parameters. 24 // Apply URL parameters.
23 var url = params.url; 25 var url = params.url;
24 var parameterString = ''; 26 var parameterString = '';
25 if (typeof(params.urlParams) === 'string') { 27 if (typeof(params.urlParams) === 'string') {
26 parameterString = params.urlParams; 28 parameterString = params.urlParams;
27 } else if (typeof(params.urlParams) === 'object') { 29 } else if (typeof(params.urlParams) === 'object') {
28 parameterString = remoting.Xhr.urlencodeParamHash( 30 parameterString = remoting.Xhr.urlencodeParamHash(
29 remoting.Xhr.removeNullFields_(params.urlParams)); 31 base.copyWithoutNullFields(params.urlParams));
30 } 32 }
31 if (parameterString) { 33 if (parameterString) {
32 url += '?' + parameterString; 34 url += '?' + parameterString;
33 } 35 }
34 36
35 // Prepare the build modified headers. 37 // Prepare the build modified headers.
36 /** @const */ 38 /** @const */
37 this.headers_ = remoting.Xhr.removeNullFields_(params.headers); 39 this.headers_ = base.copyWithoutNullFields(params.headers);
38 40
39 // Convert the content fields to a single text content variable. 41 // Convert the content fields to a single text content variable.
40 /** @private {?string} */ 42 /** @private {?string} */
41 this.content_ = null; 43 this.content_ = null;
42 if (params.textContent !== undefined) { 44 if (params.textContent !== undefined) {
43 this.maybeSetContentType_('text/plain'); 45 this.maybeSetContentType_('text/plain');
44 this.content_ = params.textContent; 46 this.content_ = params.textContent;
45 } else if (params.formContent !== undefined) { 47 } else if (params.formContent !== undefined) {
46 this.maybeSetContentType_('application/x-www-form-urlencoded'); 48 this.maybeSetContentType_('application/x-www-form-urlencoded');
47 this.content_ = remoting.Xhr.urlencodeParamHash(params.formContent); 49 this.content_ = remoting.Xhr.urlencodeParamHash(params.formContent);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 } else { 155 } else {
154 this.sendXhr_(); 156 this.sendXhr_();
155 } 157 }
156 } 158 }
157 return this.deferred_.promise(); 159 return this.deferred_.promise();
158 }; 160 };
159 161
160 /** 162 /**
161 * @param {remoting.Xhr.Params} params 163 * @param {remoting.Xhr.Params} params
162 * @throws {Error} if params are invalid 164 * @throws {Error} if params are invalid
165 * @private
163 */ 166 */
164 remoting.Xhr.checkParams_ = function(params) { 167 remoting.Xhr.checkParams_ = function(params) {
165 if (params.urlParams) { 168 if (params.urlParams) {
166 if (params.url.indexOf('?') != -1) { 169 if (params.url.indexOf('?') != -1) {
167 throw new Error('URL may not contain "?" when urlParams is set'); 170 throw new Error('URL may not contain "?" when urlParams is set');
168 } 171 }
169 if (params.url.indexOf('#') != -1) { 172 if (params.url.indexOf('#') != -1) {
170 throw new Error('URL may not contain "#" when urlParams is set'); 173 throw new Error('URL may not contain "#" when urlParams is set');
171 } 174 }
172 } 175 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 if (!(key in this.headers_)) { 230 if (!(key in this.headers_)) {
228 this.headers_[key] = value; 231 this.headers_[key] = value;
229 return true; 232 return true;
230 } 233 }
231 return false; 234 return false;
232 }; 235 };
233 236
234 /** @private */ 237 /** @private */
235 remoting.Xhr.prototype.sendXhr_ = function() { 238 remoting.Xhr.prototype.sendXhr_ = function() {
236 for (var key in this.headers_) { 239 for (var key in this.headers_) {
237 this.nativeXhr_.setRequestHeader(key, this.headers_[key]); 240 this.nativeXhr_.setRequestHeader(
241 key, /** @type {string} */ (this.headers_[key]));
238 } 242 }
239 this.nativeXhr_.send(this.content_); 243 this.nativeXhr_.send(this.content_);
240 this.content_ = null; // for gc 244 this.content_ = null; // for gc
241 }; 245 };
242 246
243 /** 247 /**
244 * @private 248 * @private
245 */ 249 */
246 remoting.Xhr.prototype.onReadyStateChange_ = function() { 250 remoting.Xhr.prototype.onReadyStateChange_ = function() {
247 var xhr = this.nativeXhr_; 251 var xhr = this.nativeXhr_;
248 if (xhr.readyState == 4) { 252 if (xhr.readyState == 4) {
249 // See comments at remoting.Xhr.Response. 253 // See comments at remoting.Xhr.Response.
250 this.deferred_.resolve(new remoting.Xhr.Response( 254 this.deferred_.resolve(remoting.Xhr.Response.fromXhr_(
251 xhr, this.acceptJson_)); 255 xhr, this.acceptJson_));
252 } 256 }
253 }; 257 };
254 258
255 /** 259 /**
256 * The response-related parts of an XMLHttpRequest. Note that this 260 * The response-related parts of an XMLHttpRequest. Note that this
257 * class is not just a facade for XMLHttpRequest; it saves the value 261 * class is not just a facade for XMLHttpRequest; it saves the value
258 * of the |responseText| field becuase once onReadyStateChange_ 262 * of the |responseText| field becuase once onReadyStateChange_
259 * (above) returns, the value of |responseText| is reset to the empty 263 * (above) returns, the value of |responseText| is reset to the empty
260 * string! This is a documented anti-feature of the XMLHttpRequest 264 * string! This is a documented anti-feature of the XMLHttpRequest
261 * API. 265 * API.
262 * 266 *
263 * @constructor 267 * @constructor
264 * @param {!XMLHttpRequest} xhr 268 * @param {number} status
269 * @param {string} statusText
270 * @param {?string} url
271 * @param {string} text
265 * @param {boolean} allowJson 272 * @param {boolean} allowJson
266 */ 273 */
267 remoting.Xhr.Response = function(xhr, allowJson) { 274 remoting.Xhr.Response = function(
268 /** @private @const */ 275 status, statusText, url, text, allowJson) {
269 this.allowJson_ = allowJson;
270
271 /** 276 /**
272 * The HTTP status code. 277 * The HTTP status code.
273 * @const {number} 278 * @const {number}
274 */ 279 */
275 this.status = xhr.status; 280 this.status = status;
276 281
277 /** 282 /**
278 * The HTTP status description. 283 * The HTTP status description.
279 * @const {string} 284 * @const {string}
280 */ 285 */
281 this.statusText = xhr.statusText; 286 this.statusText = statusText;
282 287
283 /** 288 /**
284 * The response URL, if any. 289 * The response URL, if any.
285 * @const {?string} 290 * @const {?string}
286 */ 291 */
287 this.url = xhr.responseURL; 292 this.url = url;
288 293
289 /** @private {string} */ 294 /** @private {string} */
290 this.text_ = xhr.responseText || ''; 295 this.text_ = text;
296
297 /** @private @const */
298 this.allowJson_ = allowJson;
291 299
292 /** @private {*|undefined} */ 300 /** @private {*|undefined} */
293 this.json_ = undefined; 301 this.json_ = undefined;
294 }; 302 };
295 303
296 /** 304 /**
305 * @param {!XMLHttpRequest} xhr
306 * @param {boolean} allowJson
307 * @return {!remoting.Xhr.Response}
308 */
309 remoting.Xhr.Response.fromXhr_ = function(xhr, allowJson) {
310 return new remoting.Xhr.Response(
311 xhr.status,
312 xhr.statusText,
313 xhr.responseURL,
314 xhr.responseText || '',
315 allowJson);
316 };
317
318 /**
297 * @return {boolean} True if the response code is outside the 200-299 319 * @return {boolean} True if the response code is outside the 200-299
298 * range (i.e. success as defined by the HTTP protocol). 320 * range (i.e. success as defined by the HTTP protocol).
299 */ 321 */
300 remoting.Xhr.Response.prototype.isError = function() { 322 remoting.Xhr.Response.prototype.isError = function() {
301 return this.status < 200 || this.status >= 300; 323 return this.status < 200 || this.status >= 300;
302 }; 324 };
303 325
304 /** 326 /**
305 * @return {string} The text content of the response. 327 * @return {string} The text content of the response.
306 */ 328 */
307 remoting.Xhr.Response.prototype.getText = function() { 329 remoting.Xhr.Response.prototype.getText = function() {
308 return this.text_; 330 return this.text_;
309 }; 331 };
310 332
311 /** 333 /**
312 * Get the JSON content of the response. Requires acceptJson to have 334 * Get the JSON content of the response. Requires acceptJson to have
313 * been true in the request. 335 * been true in the request.
314 * @return {*} The parsed JSON content of the response. 336 * @return {*} The parsed JSON content of the response.
315 */ 337 */
316 remoting.Xhr.Response.prototype.getJson = function() { 338 remoting.Xhr.Response.prototype.getJson = function() {
317 base.debug.assert(this.allowJson_); 339 base.debug.assert(this.allowJson_);
318 if (this.json_ === undefined) { 340 if (this.json_ === undefined) {
319 this.json_ = JSON.parse(this.text_); 341 this.json_ = JSON.parse(this.text_);
320 } 342 }
321 return this.json_; 343 return this.json_;
322 }; 344 };
323 345
324 /** 346 /**
325 * Returns a copy of the input object with all null or undefined
John Williams 2015/04/02 23:57:06 Moved to base.js.
326 * fields removed.
327 *
328 * @param {Object<string,?string>|undefined} input
329 * @return {!Object<string,string>}
330 * @private
331 */
332 remoting.Xhr.removeNullFields_ = function(input) {
333 /** @type {!Object<string,string>} */
334 var result = {};
335 if (input) {
336 for (var field in input) {
337 var value = input[field];
338 if (value != null) {
339 result[field] = value;
340 }
341 }
342 }
343 return result;
344 };
345
346 /**
347 * Takes an associative array of parameters and urlencodes it. 347 * Takes an associative array of parameters and urlencodes it.
348 * 348 *
349 * @param {Object<string,string>} paramHash The parameter key/value pairs. 349 * @param {Object<string,string>} paramHash The parameter key/value pairs.
350 * @return {string} URLEncoded version of paramHash. 350 * @return {string} URLEncoded version of paramHash.
351 */ 351 */
352 remoting.Xhr.urlencodeParamHash = function(paramHash) { 352 remoting.Xhr.urlencodeParamHash = function(paramHash) {
353 var paramArray = []; 353 var paramArray = [];
354 for (var key in paramHash) { 354 for (var key in paramHash) {
355 paramArray.push(encodeURIComponent(key) + 355 var value = paramHash[key];
John Williams 2015/04/02 23:57:06 To match semantics of base.copyWithoutNullFields.
356 '=' + encodeURIComponent(paramHash[key])); 356 if (value != null) {
357 paramArray.push(encodeURIComponent(key) +
358 '=' + encodeURIComponent(value));
359 }
357 } 360 }
358 if (paramArray.length > 0) { 361 if (paramArray.length > 0) {
359 return paramArray.join('&'); 362 return paramArray.join('&');
360 } 363 }
361 return ''; 364 return '';
362 }; 365 };
OLDNEW
« remoting/webapp/crd/js/mock_xhr_unittest.js ('K') | « remoting/webapp/crd/js/mock_xhr_unittest.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698