loadWithXhr.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*global define*/
  2. define([], function() {
  3. "use strict";
  4. var when = Cesium.when;
  5. var defaultValue = Cesium.defaultValue;
  6. var defined = Cesium.defined;
  7. var DeveloperError = Cesium.DeveloperError;
  8. var RequestErrorEvent = Cesium.RequestErrorEvent;
  9. var RuntimeError = Cesium.RuntimeError;
  10. /**
  11. * Asynchronously loads the given URL. Returns a promise that will resolve to
  12. * the result once loaded, or reject if the URL failed to load. The data is loaded
  13. * using XMLHttpRequest, which means that in order to make requests to another origin,
  14. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  15. *
  16. * @exports loadWithXhr
  17. *
  18. * @param {Object} options Object with the following properties:
  19. * @param {String|Promise.<String>} options.url The URL of the data, or a promise for the URL.
  20. * @param {String} [options.responseType] The type of response. This controls the type of item returned.
  21. * @param {String} [options.method='GET'] The HTTP method to use.
  22. * @param {String} [options.data] The data to send with the request, if any.
  23. * @param {Object} [options.headers] HTTP headers to send with the request, if any.
  24. * @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
  25. * @returns {Promise.<Object>} a promise that will resolve to the requested data when loaded.
  26. *
  27. *
  28. * @example
  29. * // Load a single URL asynchronously. In real code, you should use loadBlob instead.
  30. * Cesium.loadWithXhr({
  31. * url : 'some/url',
  32. * responseType : 'blob'
  33. * }).then(function(blob) {
  34. * // use the data
  35. * }).otherwise(function(error) {
  36. * // an error occurred
  37. * });
  38. *
  39. * @see loadArrayBuffer
  40. * @see loadBlob
  41. * @see loadJson
  42. * @see loadText
  43. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  44. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  45. */
  46. function loadWithXhr(options) {
  47. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  48. //>>includeStart('debug', pragmas.debug);
  49. if (!defined(options.url)) {
  50. throw new DeveloperError('options.url is required.');
  51. }
  52. //>>includeEnd('debug');
  53. var responseType = options.responseType;
  54. var method = defaultValue(options.method, 'GET');
  55. var data = options.data;
  56. var headers = options.headers;
  57. var overrideMimeType = options.overrideMimeType;
  58. return when(options.url, function(url) {
  59. var deferred = when.defer();
  60. loadWithXhr.load(url, responseType, method, data, headers, deferred, overrideMimeType);
  61. return deferred.promise;
  62. });
  63. }
  64. var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
  65. function decodeDataUriText(isBase64, data) {
  66. var result = decodeURIComponent(data);
  67. if (isBase64) {
  68. return atob(result);
  69. }
  70. return result;
  71. }
  72. function decodeDataUriArrayBuffer(isBase64, data) {
  73. var byteString = decodeDataUriText(isBase64, data);
  74. var buffer = new ArrayBuffer(byteString.length);
  75. var view = new Uint8Array(buffer);
  76. for (var i = 0; i < byteString.length; i++) {
  77. view[i] = byteString.charCodeAt(i);
  78. }
  79. return buffer;
  80. }
  81. function decodeDataUri(dataUriRegexResult, responseType) {
  82. responseType = defaultValue(responseType, '');
  83. var mimeType = dataUriRegexResult[1];
  84. var isBase64 = !!dataUriRegexResult[2];
  85. var data = dataUriRegexResult[3];
  86. switch (responseType) {
  87. case '':
  88. case 'text':
  89. return decodeDataUriText(isBase64, data);
  90. case 'arraybuffer':
  91. return decodeDataUriArrayBuffer(isBase64, data);
  92. case 'blob':
  93. var buffer = decodeDataUriArrayBuffer(isBase64, data);
  94. return new Blob([buffer], {
  95. type : mimeType
  96. });
  97. case 'document':
  98. var parser = new DOMParser();
  99. return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
  100. case 'json':
  101. return JSON.parse(decodeDataUriText(isBase64, data));
  102. default:
  103. throw new DeveloperError('Unhandled responseType: ' + responseType);
  104. }
  105. }
  106. // This is broken out into a separate function so that it can be mocked for testing purposes.
  107. loadWithXhr.load = function(url, responseType, method, data, headers, deferred, overrideMimeType) {
  108. var dataUriRegexResult = dataUriRegex.exec(url);
  109. if (dataUriRegexResult !== null) {
  110. deferred.resolve(decodeDataUri(dataUriRegexResult, responseType));
  111. return;
  112. }
  113. var xhr = new XMLHttpRequest();
  114. if (defined(overrideMimeType) && defined(xhr.overrideMimeType)) {
  115. xhr.overrideMimeType(overrideMimeType);
  116. }
  117. xhr.open(method, url, true);
  118. if (defined(headers)) {
  119. for ( var key in headers) {
  120. if (headers.hasOwnProperty(key)) {
  121. xhr.setRequestHeader(key, headers[key]);
  122. }
  123. }
  124. }
  125. if (defined(responseType)) {
  126. xhr.responseType = responseType;
  127. }
  128. xhr.onload = function() {
  129. if (xhr.status >= 200 && xhr.status < 300) {
  130. if (defined(xhr.response)) {
  131. deferred.resolve(xhr.response);
  132. } else {
  133. // busted old browsers.
  134. if (defined(xhr.responseXML) && xhr.responseXML.hasChildNodes()) {
  135. deferred.resolve(xhr.responseXML);
  136. } else if (defined(xhr.responseText)) {
  137. deferred.resolve(xhr.responseText);
  138. } else {
  139. deferred.reject(new RuntimeError('unknown XMLHttpRequest response type.'));
  140. }
  141. }
  142. } else {
  143. deferred.reject(new RequestErrorEvent(xhr.status, xhr.response, xhr.getAllResponseHeaders()));
  144. }
  145. };
  146. xhr.onerror = function(e) {
  147. deferred.reject(new RequestErrorEvent());
  148. };
  149. xhr.send(data);
  150. };
  151. loadWithXhr.defaultLoad = loadWithXhr.load;
  152. return loadWithXhr;
  153. });