RESTController.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  2. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  3. var _ParseError = _interopRequireDefault(require("./ParseError"));
  4. var _promiseUtils = require("./promiseUtils");
  5. var uuidv4 = require('./uuid');
  6. var XHR = null;
  7. if (typeof XMLHttpRequest !== 'undefined') {
  8. XHR = XMLHttpRequest;
  9. }
  10. var useXDomainRequest = false;
  11. if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) {
  12. useXDomainRequest = true;
  13. }
  14. function ajaxIE9(method, url, data, headers, options) {
  15. return new Promise(function (resolve, reject) {
  16. var xdr = new XDomainRequest();
  17. xdr.onload = function () {
  18. var response;
  19. try {
  20. response = JSON.parse(xdr.responseText);
  21. } catch (e) {
  22. reject(e);
  23. }
  24. if (response) {
  25. resolve({
  26. response: response
  27. });
  28. }
  29. };
  30. xdr.onerror = xdr.ontimeout = function () {
  31. var fakeResponse = {
  32. responseText: JSON.stringify({
  33. code: _ParseError.default.X_DOMAIN_REQUEST,
  34. error: "IE's XDomainRequest does not supply error info."
  35. })
  36. };
  37. reject(fakeResponse);
  38. };
  39. xdr.onprogress = function () {
  40. if (options && typeof options.progress === 'function') {
  41. options.progress(xdr.responseText);
  42. }
  43. };
  44. xdr.open(method, url);
  45. xdr.send(data);
  46. if (options && typeof options.requestTask === 'function') {
  47. options.requestTask(xdr);
  48. }
  49. });
  50. }
  51. var RESTController = {
  52. ajax: function (method, url, data, headers, options) {
  53. if (useXDomainRequest) {
  54. return ajaxIE9(method, url, data, headers, options);
  55. }
  56. var promise = (0, _promiseUtils.resolvingPromise)();
  57. var isIdempotent = _CoreManager.default.get('IDEMPOTENCY') && ['POST', 'PUT'].includes(method);
  58. var requestId = isIdempotent ? uuidv4() : '';
  59. var attempts = 0;
  60. (function dispatch() {
  61. if (XHR == null) {
  62. throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.');
  63. }
  64. var handled = false;
  65. var xhr = new XHR();
  66. xhr.onreadystatechange = function () {
  67. if (xhr.readyState !== 4 || handled || xhr._aborted) {
  68. return;
  69. }
  70. handled = true;
  71. if (xhr.status >= 200 && xhr.status < 300) {
  72. var response;
  73. try {
  74. response = JSON.parse(xhr.responseText);
  75. if (typeof xhr.getResponseHeader === 'function') {
  76. if ((xhr.getAllResponseHeaders() || '').includes('x-parse-job-status-id: ')) {
  77. response = xhr.getResponseHeader('x-parse-job-status-id');
  78. }
  79. if ((xhr.getAllResponseHeaders() || '').includes('x-parse-push-status-id: ')) {
  80. response = xhr.getResponseHeader('x-parse-push-status-id');
  81. }
  82. }
  83. } catch (e) {
  84. promise.reject(e.toString());
  85. }
  86. if (response) {
  87. promise.resolve({
  88. response: response,
  89. status: xhr.status,
  90. xhr: xhr
  91. });
  92. }
  93. } else if (xhr.status >= 500 || xhr.status === 0) {
  94. if (++attempts < _CoreManager.default.get('REQUEST_ATTEMPT_LIMIT')) {
  95. var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts));
  96. setTimeout(dispatch, delay);
  97. } else if (xhr.status === 0) {
  98. promise.reject('Unable to connect to the Parse API');
  99. } else {
  100. promise.reject(xhr);
  101. }
  102. } else {
  103. promise.reject(xhr);
  104. }
  105. };
  106. headers = headers || {};
  107. if (typeof headers['Content-Type'] !== 'string') {
  108. headers['Content-Type'] = 'text/plain';
  109. }
  110. if (_CoreManager.default.get('IS_NODE')) {
  111. headers['User-Agent'] = 'Parse/' + _CoreManager.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')';
  112. }
  113. if (isIdempotent) {
  114. headers['X-Parse-Request-Id'] = requestId;
  115. }
  116. if (_CoreManager.default.get('SERVER_AUTH_TYPE') && _CoreManager.default.get('SERVER_AUTH_TOKEN')) {
  117. headers['Authorization'] = _CoreManager.default.get('SERVER_AUTH_TYPE') + ' ' + _CoreManager.default.get('SERVER_AUTH_TOKEN');
  118. }
  119. var customHeaders = _CoreManager.default.get('REQUEST_HEADERS');
  120. for (var key in customHeaders) {
  121. headers[key] = customHeaders[key];
  122. }
  123. if (options && typeof options.progress === 'function') {
  124. var handleProgress = function handleProgress(type, event) {
  125. if (event.lengthComputable) {
  126. options.progress(event.loaded / event.total, event.loaded, event.total, {
  127. type: type
  128. });
  129. } else {
  130. options.progress(null, null, null, {
  131. type: type
  132. });
  133. }
  134. };
  135. xhr.onprogress = function (event) {
  136. handleProgress('download', event);
  137. };
  138. if (xhr.upload) {
  139. xhr.upload.onprogress = function (event) {
  140. handleProgress('upload', event);
  141. };
  142. }
  143. }
  144. xhr.open(method, url, true);
  145. for (var h in headers) {
  146. xhr.setRequestHeader(h, headers[h]);
  147. }
  148. xhr.onabort = function () {
  149. promise.resolve({
  150. response: {
  151. results: []
  152. },
  153. status: 0,
  154. xhr: xhr
  155. });
  156. };
  157. xhr.send(data);
  158. if (options && typeof options.requestTask === 'function') {
  159. options.requestTask(xhr);
  160. }
  161. })();
  162. return promise;
  163. },
  164. request: function request(method, path, data, options) {
  165. options = options || {};
  166. var url = _CoreManager.default.get('SERVER_URL');
  167. if (url[url.length - 1] !== '/') {
  168. url += '/';
  169. }
  170. url += path;
  171. var payload = {};
  172. if (data && typeof data === 'object') {
  173. for (var k in data) {
  174. payload[k] = data[k];
  175. }
  176. }
  177. var context = options.context;
  178. if (context !== undefined) {
  179. payload._context = context;
  180. }
  181. if (method !== 'POST') {
  182. payload._method = method;
  183. method = 'POST';
  184. }
  185. payload._ApplicationId = _CoreManager.default.get('APPLICATION_ID');
  186. var jsKey = _CoreManager.default.get('JAVASCRIPT_KEY');
  187. if (jsKey) {
  188. payload._JavaScriptKey = jsKey;
  189. }
  190. payload._ClientVersion = _CoreManager.default.get('VERSION');
  191. var useMasterKey = options.useMasterKey;
  192. if (typeof useMasterKey === 'undefined') {
  193. useMasterKey = _CoreManager.default.get('USE_MASTER_KEY');
  194. }
  195. if (useMasterKey) {
  196. if (_CoreManager.default.get('MASTER_KEY')) {
  197. delete payload._JavaScriptKey;
  198. payload._MasterKey = _CoreManager.default.get('MASTER_KEY');
  199. } else {
  200. throw new Error('Cannot use the Master Key, it has not been provided.');
  201. }
  202. }
  203. if (_CoreManager.default.get('FORCE_REVOCABLE_SESSION')) {
  204. payload._RevocableSession = '1';
  205. }
  206. var installationId = options.installationId;
  207. var installationIdPromise;
  208. if (installationId && typeof installationId === 'string') {
  209. installationIdPromise = Promise.resolve(installationId);
  210. } else {
  211. var installationController = _CoreManager.default.getInstallationController();
  212. installationIdPromise = installationController.currentInstallationId();
  213. }
  214. return installationIdPromise.then(function (iid) {
  215. payload._InstallationId = iid;
  216. var userController = _CoreManager.default.getUserController();
  217. if (options && typeof options.sessionToken === 'string') {
  218. return Promise.resolve(options.sessionToken);
  219. } else if (userController) {
  220. return userController.currentUserAsync().then(function (user) {
  221. if (user) {
  222. return Promise.resolve(user.getSessionToken());
  223. }
  224. return Promise.resolve(null);
  225. });
  226. }
  227. return Promise.resolve(null);
  228. }).then(function (token) {
  229. if (token) {
  230. payload._SessionToken = token;
  231. }
  232. var payloadString = JSON.stringify(payload);
  233. return RESTController.ajax(method, url, payloadString, {}, options).then(function (_ref) {
  234. var response = _ref.response,
  235. status = _ref.status;
  236. if (options.returnStatus) {
  237. return Object.assign({}, response, {
  238. _status: status
  239. });
  240. } else {
  241. return response;
  242. }
  243. });
  244. }).catch(RESTController.handleError);
  245. },
  246. handleError: function handleError(response) {
  247. var error;
  248. if (response && response.responseText) {
  249. try {
  250. var errorJSON = JSON.parse(response.responseText);
  251. error = new _ParseError.default(errorJSON.code, errorJSON.error);
  252. } catch (e) {
  253. error = new _ParseError.default(_ParseError.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText);
  254. }
  255. } else {
  256. var message = response.message ? response.message : response;
  257. error = new _ParseError.default(_ParseError.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + JSON.stringify(message));
  258. }
  259. return Promise.reject(error);
  260. },
  261. _setXHR: function _setXHR(xhr) {
  262. XHR = xhr;
  263. },
  264. _getXHR: function _getXHR() {
  265. return XHR;
  266. }
  267. };
  268. module.exports = RESTController;