RESTController.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
  3. var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
  4. var _Object$defineProperties = require("@babel/runtime-corejs3/core-js-stable/object/define-properties");
  5. var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors");
  6. var _forEachInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/for-each");
  7. var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
  8. var _filterInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/filter");
  9. var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols");
  10. var _Object$keys = require("@babel/runtime-corejs3/core-js-stable/object/keys");
  11. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
  12. var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/typeof"));
  13. var _setTimeout2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/set-timeout"));
  14. var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
  15. var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
  16. var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
  17. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  18. var _ParseError = _interopRequireDefault(require("./ParseError"));
  19. var _promiseUtils = require("./promiseUtils");
  20. function ownKeys(object, enumerableOnly) {
  21. var keys = _Object$keys(object);
  22. if (_Object$getOwnPropertySymbols) {
  23. var symbols = _Object$getOwnPropertySymbols(object);
  24. enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) {
  25. return _Object$getOwnPropertyDescriptor(object, sym).enumerable;
  26. })), keys.push.apply(keys, symbols);
  27. }
  28. return keys;
  29. }
  30. function _objectSpread(target) {
  31. for (var i = 1; i < arguments.length; i++) {
  32. var _context4, _context5;
  33. var source = null != arguments[i] ? arguments[i] : {};
  34. i % 2 ? _forEachInstanceProperty(_context4 = ownKeys(Object(source), !0)).call(_context4, function (key) {
  35. (0, _defineProperty2.default)(target, key, source[key]);
  36. }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context5 = ownKeys(Object(source))).call(_context5, function (key) {
  37. _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key));
  38. });
  39. }
  40. return target;
  41. }
  42. /**
  43. * Copyright (c) 2015-present, Parse, LLC.
  44. * All rights reserved.
  45. *
  46. * This source code is licensed under the BSD-style license found in the
  47. * LICENSE file in the root directory of this source tree. An additional grant
  48. * of patent rights can be found in the PATENTS file in the same directory.
  49. *
  50. * @flow
  51. */
  52. /* global XMLHttpRequest, XDomainRequest */
  53. var uuidv4 = require('./uuid');
  54. var XHR = null;
  55. if (typeof XMLHttpRequest !== 'undefined') {
  56. XHR = XMLHttpRequest;
  57. }
  58. var useXDomainRequest = false;
  59. if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) {
  60. useXDomainRequest = true;
  61. }
  62. function ajaxIE9(method
  63. /*: string*/
  64. , url
  65. /*: string*/
  66. , data
  67. /*: any*/
  68. , headers
  69. /*:: ?: any*/
  70. , options
  71. /*:: ?: FullOptions*/
  72. ) {
  73. return new _promise.default(function (resolve, reject) {
  74. var xdr = new XDomainRequest();
  75. xdr.onload = function () {
  76. var response;
  77. try {
  78. response = JSON.parse(xdr.responseText);
  79. } catch (e) {
  80. reject(e);
  81. }
  82. if (response) {
  83. resolve({
  84. response: response
  85. });
  86. }
  87. };
  88. xdr.onerror = xdr.ontimeout = function () {
  89. // Let's fake a real error message.
  90. var fakeResponse = {
  91. responseText: (0, _stringify.default)({
  92. code: _ParseError.default.X_DOMAIN_REQUEST,
  93. error: "IE's XDomainRequest does not supply error info."
  94. })
  95. };
  96. reject(fakeResponse);
  97. };
  98. xdr.onprogress = function () {
  99. if (options && typeof options.progress === 'function') {
  100. options.progress(xdr.responseText);
  101. }
  102. };
  103. xdr.open(method, url);
  104. xdr.send(data);
  105. if (options && typeof options.requestTask === 'function') {
  106. options.requestTask(xdr);
  107. }
  108. });
  109. }
  110. var RESTController = {
  111. ajax: function (method
  112. /*: string*/
  113. , url
  114. /*: string*/
  115. , data
  116. /*: any*/
  117. , headers
  118. /*:: ?: any*/
  119. , options
  120. /*:: ?: FullOptions*/
  121. ) {
  122. var _context;
  123. if (useXDomainRequest) {
  124. return ajaxIE9(method, url, data, headers, options);
  125. }
  126. var promise = (0, _promiseUtils.resolvingPromise)();
  127. var isIdempotent = _CoreManager.default.get('IDEMPOTENCY') && (0, _includes.default)(_context = ['POST', 'PUT']).call(_context, method);
  128. var requestId = isIdempotent ? uuidv4() : '';
  129. var attempts = 0;
  130. (function dispatch() {
  131. if (XHR == null) {
  132. throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.');
  133. }
  134. var handled = false;
  135. var xhr = new XHR();
  136. xhr.onreadystatechange = function () {
  137. if (xhr.readyState !== 4 || handled || xhr._aborted) {
  138. return;
  139. }
  140. handled = true;
  141. if (xhr.status >= 200 && xhr.status < 300) {
  142. var response;
  143. try {
  144. response = JSON.parse(xhr.responseText);
  145. if (typeof xhr.getResponseHeader === 'function') {
  146. var _context2, _context3;
  147. if ((0, _includes.default)(_context2 = xhr.getAllResponseHeaders() || '').call(_context2, 'x-parse-job-status-id: ')) {
  148. response = xhr.getResponseHeader('x-parse-job-status-id');
  149. }
  150. if ((0, _includes.default)(_context3 = xhr.getAllResponseHeaders() || '').call(_context3, 'x-parse-push-status-id: ')) {
  151. response = xhr.getResponseHeader('x-parse-push-status-id');
  152. }
  153. }
  154. } catch (e) {
  155. promise.reject(e.toString());
  156. }
  157. if (response) {
  158. promise.resolve({
  159. response: response,
  160. status: xhr.status,
  161. xhr: xhr
  162. });
  163. }
  164. } else if (xhr.status >= 500 || xhr.status === 0) {
  165. // retry on 5XX or node-xmlhttprequest error
  166. if (++attempts < _CoreManager.default.get('REQUEST_ATTEMPT_LIMIT')) {
  167. // Exponentially-growing random delay
  168. var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts));
  169. (0, _setTimeout2.default)(dispatch, delay);
  170. } else if (xhr.status === 0) {
  171. promise.reject('Unable to connect to the Parse API');
  172. } else {
  173. // After the retry limit is reached, fail
  174. promise.reject(xhr);
  175. }
  176. } else {
  177. promise.reject(xhr);
  178. }
  179. };
  180. headers = headers || {};
  181. if (typeof headers['Content-Type'] !== 'string') {
  182. headers['Content-Type'] = 'text/plain'; // Avoid pre-flight
  183. }
  184. if (_CoreManager.default.get('IS_NODE')) {
  185. headers['User-Agent'] = 'Parse/' + _CoreManager.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')';
  186. }
  187. if (isIdempotent) {
  188. headers['X-Parse-Request-Id'] = requestId;
  189. }
  190. if (_CoreManager.default.get('SERVER_AUTH_TYPE') && _CoreManager.default.get('SERVER_AUTH_TOKEN')) {
  191. headers['Authorization'] = _CoreManager.default.get('SERVER_AUTH_TYPE') + ' ' + _CoreManager.default.get('SERVER_AUTH_TOKEN');
  192. }
  193. var customHeaders = _CoreManager.default.get('REQUEST_HEADERS');
  194. for (var key in customHeaders) {
  195. headers[key] = customHeaders[key];
  196. }
  197. function handleProgress(type, event) {
  198. if (options && typeof options.progress === 'function') {
  199. if (event.lengthComputable) {
  200. options.progress(event.loaded / event.total, event.loaded, event.total, {
  201. type: type
  202. });
  203. } else {
  204. options.progress(null, null, null, {
  205. type: type
  206. });
  207. }
  208. }
  209. }
  210. xhr.onprogress = function (event) {
  211. handleProgress('download', event);
  212. };
  213. if (xhr.upload) {
  214. xhr.upload.onprogress = function (event) {
  215. handleProgress('upload', event);
  216. };
  217. }
  218. xhr.open(method, url, true);
  219. for (var h in headers) {
  220. xhr.setRequestHeader(h, headers[h]);
  221. }
  222. xhr.onabort = function () {
  223. promise.resolve({
  224. response: {
  225. results: []
  226. },
  227. status: 0,
  228. xhr: xhr
  229. });
  230. };
  231. xhr.send(data);
  232. if (options && typeof options.requestTask === 'function') {
  233. options.requestTask(xhr);
  234. }
  235. })();
  236. return promise;
  237. },
  238. request: function request(method
  239. /*: string*/
  240. , path
  241. /*: string*/
  242. , data
  243. /*: mixed*/
  244. , options
  245. /*:: ?: RequestOptions*/
  246. ) {
  247. options = options || {};
  248. var url = _CoreManager.default.get('SERVER_URL');
  249. if (url[url.length - 1] !== '/') {
  250. url += '/';
  251. }
  252. url += path;
  253. var payload = {};
  254. if (data && (0, _typeof2.default)(data) === 'object') {
  255. for (var k in data) {
  256. payload[k] = data[k];
  257. }
  258. } // Add context
  259. var context = options.context;
  260. if (context !== undefined) {
  261. payload._context = context;
  262. }
  263. if (method !== 'POST') {
  264. payload._method = method;
  265. method = 'POST';
  266. }
  267. payload._ApplicationId = _CoreManager.default.get('APPLICATION_ID');
  268. var jsKey = _CoreManager.default.get('JAVASCRIPT_KEY');
  269. if (jsKey) {
  270. payload._JavaScriptKey = jsKey;
  271. }
  272. payload._ClientVersion = _CoreManager.default.get('VERSION');
  273. var useMasterKey = options.useMasterKey;
  274. if (typeof useMasterKey === 'undefined') {
  275. useMasterKey = _CoreManager.default.get('USE_MASTER_KEY');
  276. }
  277. if (useMasterKey) {
  278. if (_CoreManager.default.get('MASTER_KEY')) {
  279. delete payload._JavaScriptKey;
  280. payload._MasterKey = _CoreManager.default.get('MASTER_KEY');
  281. } else {
  282. throw new Error('Cannot use the Master Key, it has not been provided.');
  283. }
  284. }
  285. if (_CoreManager.default.get('FORCE_REVOCABLE_SESSION')) {
  286. payload._RevocableSession = '1';
  287. }
  288. var installationId = options.installationId;
  289. var installationIdPromise;
  290. if (installationId && typeof installationId === 'string') {
  291. installationIdPromise = _promise.default.resolve(installationId);
  292. } else {
  293. var installationController = _CoreManager.default.getInstallationController();
  294. installationIdPromise = installationController.currentInstallationId();
  295. }
  296. return installationIdPromise.then(function (iid) {
  297. payload._InstallationId = iid;
  298. var userController = _CoreManager.default.getUserController();
  299. if (options && typeof options.sessionToken === 'string') {
  300. return _promise.default.resolve(options.sessionToken);
  301. } else if (userController) {
  302. return userController.currentUserAsync().then(function (user) {
  303. if (user) {
  304. return _promise.default.resolve(user.getSessionToken());
  305. }
  306. return _promise.default.resolve(null);
  307. });
  308. }
  309. return _promise.default.resolve(null);
  310. }).then(function (token) {
  311. if (token) {
  312. payload._SessionToken = token;
  313. }
  314. var payloadString = (0, _stringify.default)(payload);
  315. return RESTController.ajax(method, url, payloadString, {}, options).then(function (_ref) {
  316. var response = _ref.response,
  317. status = _ref.status;
  318. if (options.returnStatus) {
  319. return _objectSpread(_objectSpread({}, response), {}, {
  320. _status: status
  321. });
  322. } else {
  323. return response;
  324. }
  325. });
  326. }).catch(RESTController.handleError);
  327. },
  328. handleError: function handleError(response) {
  329. // Transform the error into an instance of ParseError by trying to parse
  330. // the error string as JSON
  331. var error;
  332. if (response && response.responseText) {
  333. try {
  334. var errorJSON = JSON.parse(response.responseText);
  335. error = new _ParseError.default(errorJSON.code, errorJSON.error);
  336. } catch (e) {
  337. // If we fail to parse the error text, that's okay.
  338. error = new _ParseError.default(_ParseError.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText);
  339. }
  340. } else {
  341. var message = response.message ? response.message : response;
  342. error = new _ParseError.default(_ParseError.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify.default)(message));
  343. }
  344. return _promise.default.reject(error);
  345. },
  346. _setXHR: function _setXHR(xhr
  347. /*: any*/
  348. ) {
  349. XHR = xhr;
  350. },
  351. _getXHR: function _getXHR() {
  352. return XHR;
  353. }
  354. };
  355. module.exports = RESTController;