react-native-blob-util 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.eslintrc.js +56 -56
  2. package/LICENSE +21 -21
  3. package/Migration.md +41 -41
  4. package/NuGet.config +11 -11
  5. package/README.md +1109 -1104
  6. package/android/gradle.properties +1 -1
  7. package/android/src/main/AndroidManifest.xml +37 -37
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +57 -57
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConst.java +20 -20
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +9 -9
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilImpl.java +431 -431
  12. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilProgressConfig.java +39 -39
  13. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +1014 -1014
  14. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +98 -98
  15. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +166 -166
  16. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -19
  17. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileProvider.java +4 -4
  18. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -70
  19. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/PathResolver.java +223 -223
  20. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/Tls12SocketFactory.java +68 -68
  21. package/android/src/main/res/values/strings.xml +3 -3
  22. package/android/src/main/res/xml/provider_paths.xml +12 -12
  23. package/android.js +58 -58
  24. package/class/ReactNativeBlobUtilCanceledFetchError.js +9 -9
  25. package/class/ReactNativeBlobUtilFile.js +5 -5
  26. package/class/ReactNativeBlobUtilReadStream.js +84 -84
  27. package/class/ReactNativeBlobUtilSession.js +68 -68
  28. package/class/ReactNativeBlobUtilWriteStream.js +50 -50
  29. package/class/StatefulPromise.js +7 -7
  30. package/codegenSpecs/NativeBlobUtils.js +86 -86
  31. package/components/Fetch.onPress.js +10 -10
  32. package/components/Fetch.when.js +15 -15
  33. package/fetch.js +350 -350
  34. package/fs.js +480 -480
  35. package/index.js +64 -64
  36. package/index.js.flow +192 -192
  37. package/index.web.js +1 -1
  38. package/ios/PrivacyInfo.xcprivacy +28 -28
  39. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.h +55 -55
  40. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.mm +992 -992
  41. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +405 -405
  42. package/ios/ReactNativeBlobUtilConst.h +58 -58
  43. package/ios/ReactNativeBlobUtilConst.mm +47 -47
  44. package/ios/ReactNativeBlobUtilFS.h +108 -108
  45. package/ios/ReactNativeBlobUtilFS.mm +1064 -1064
  46. package/ios/ReactNativeBlobUtilFileTransformer.h +23 -23
  47. package/ios/ReactNativeBlobUtilFileTransformer.mm +20 -20
  48. package/ios/ReactNativeBlobUtilNetwork.h +49 -49
  49. package/ios/ReactNativeBlobUtilNetwork.mm +159 -159
  50. package/ios/ReactNativeBlobUtilProgress.h +32 -32
  51. package/ios/ReactNativeBlobUtilProgress.mm +57 -57
  52. package/ios/ReactNativeBlobUtilReqBuilder.h +37 -37
  53. package/ios/ReactNativeBlobUtilReqBuilder.mm +292 -292
  54. package/ios/ReactNativeBlobUtilRequest.h +48 -48
  55. package/ios/ReactNativeBlobUtilRequest.mm +584 -584
  56. package/ios.js +61 -61
  57. package/json-stream.js +42 -42
  58. package/lib/oboe-browser.js +2703 -2703
  59. package/mediacollection.js +36 -36
  60. package/package.json +68 -68
  61. package/polyfill/Blob.js +362 -362
  62. package/polyfill/Event.js +11 -11
  63. package/polyfill/EventTarget.js +78 -78
  64. package/polyfill/Fetch.js +219 -219
  65. package/polyfill/File.js +27 -27
  66. package/polyfill/FileReader.js +91 -91
  67. package/polyfill/ProgressEvent.js +32 -32
  68. package/polyfill/XMLHttpRequest.js +466 -466
  69. package/polyfill/XMLHttpRequestEventTarget.js +126 -126
  70. package/polyfill/index.js +11 -11
  71. package/react-native-blob-util.podspec +48 -48
  72. package/types.js +69 -69
  73. package/utils/log.js +40 -40
  74. package/utils/unicode.js +7 -7
  75. package/utils/uri.js +33 -33
  76. package/utils/uuid.js +4 -4
  77. package/windows/ExperimentalFeatures.props +33 -33
  78. package/windows/README.md +2 -2
  79. package/windows/ReactNativeBlobUtil/PropertySheet.props +15 -15
  80. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1836 -1836
  81. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.def +3 -3
  82. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +372 -372
  83. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +139 -139
  84. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +43 -43
  85. package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +20 -20
  86. package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +24 -24
  87. package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +9 -9
  88. package/windows/ReactNativeBlobUtil/codegen/.clang-format +1 -1
  89. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsDataTypes.g.h +42 -42
  90. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsSpec.g.h +353 -353
  91. package/windows/ReactNativeBlobUtil/packages.config +3 -3
  92. package/windows/ReactNativeBlobUtil/packages.lock.json +59 -59
  93. package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
  94. package/windows/ReactNativeBlobUtil/pch.h +30 -30
  95. package/windows/ReactNativeBlobUtil/resource.h +5 -5
  96. package/windows/ReactNativeBlobUtil/targetver.h +8 -8
  97. package/windows/ReactNativeBlobUtil.sln +43 -43
@@ -1,466 +1,466 @@
1
- // Copyright 2016 wkh237@github. All rights reserved.
2
- // Use of this source code is governed by a MIT-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import XMLHttpRequestEventTarget from './XMLHttpRequestEventTarget.js';
6
- import Log from '../utils/log.js';
7
- import Blob from './Blob.js';
8
- import ProgressEvent from './ProgressEvent.js';
9
- import URIUtil from "../utils/uri";
10
- import {config} from "../fetch";
11
-
12
- const log = new Log('XMLHttpRequest');
13
-
14
-
15
- log.disable();
16
- // log.level(3)
17
-
18
- const UNSENT = 0;
19
- const OPENED = 1;
20
- const HEADERS_RECEIVED = 2;
21
- const LOADING = 3;
22
- const DONE = 4;
23
-
24
- export default class XMLHttpRequest extends XMLHttpRequestEventTarget {
25
-
26
- _onreadystatechange: () => void;
27
-
28
- upload: XMLHttpRequestEventTarget = new XMLHttpRequestEventTarget();
29
- static binaryContentTypes: Array<string> = [
30
- 'image/', 'video/', 'audio/'
31
- ];
32
-
33
- // readonly
34
- _readyState: number = UNSENT;
35
- _uriType: 'net' | 'file' = 'net';
36
- _response: any = '';
37
- _responseText: any = '';
38
- _responseHeaders: any = {};
39
- _responseType: '' | 'arraybuffer' | 'blob' | 'json' | 'text' = '';
40
- // TODO : not suppoted ATM
41
- _responseURL: null = '';
42
- _responseXML: null = '';
43
- _status: number = 0;
44
- _statusText: string = '';
45
- _timeout: number = 60000;
46
- _sendFlag: boolean = false;
47
- _uploadStarted: boolean = false;
48
- _increment: boolean = false;
49
-
50
- // ReactNativeBlobUtil compatible data structure
51
- _config: ReactNativeBlobUtilConfig = {};
52
- _url: any;
53
- _method: string;
54
- _headers: any = {
55
- 'Content-Type': 'text/plain'
56
- };
57
- _cleanUp: () => void = null;
58
- _body: any;
59
-
60
- // ReactNativeBlobUtil promise object, which has `progress`, `uploadProgress`, and
61
- // `cancel` methods.
62
- _task: any;
63
-
64
- // constants
65
- get UNSENT() {
66
- return UNSENT;
67
- }
68
-
69
- get OPENED() {
70
- return OPENED;
71
- }
72
-
73
- get HEADERS_RECEIVED() {
74
- return HEADERS_RECEIVED;
75
- }
76
-
77
- get LOADING() {
78
- return LOADING;
79
- }
80
-
81
- get DONE() {
82
- return DONE;
83
- }
84
-
85
- static get UNSENT() {
86
- return UNSENT;
87
- }
88
-
89
- static get OPENED() {
90
- return OPENED;
91
- }
92
-
93
- static get HEADERS_RECEIVED() {
94
- return HEADERS_RECEIVED;
95
- }
96
-
97
- static get LOADING() {
98
- return LOADING;
99
- }
100
-
101
- static get DONE() {
102
- return DONE;
103
- }
104
-
105
- static setLog(level: number) {
106
- if (level === -1)
107
- log.disable();
108
- else
109
- log.level(level);
110
- }
111
-
112
- static addBinaryContentType(substr: string) {
113
- for (let i in XMLHttpRequest.binaryContentTypes) {
114
- if (new RegExp(substr, 'i').test(XMLHttpRequest.binaryContentTypes[i])) {
115
- return;
116
- }
117
- }
118
- XMLHttpRequest.binaryContentTypes.push(substr);
119
-
120
- }
121
-
122
- static removeBinaryContentType(val) {
123
- for (let i in XMLHttpRequest.binaryContentTypes) {
124
- if (new RegExp(substr, 'i').test(XMLHttpRequest.binaryContentTypes[i])) {
125
- XMLHttpRequest.binaryContentTypes.splice(i, 1);
126
- return;
127
- }
128
- }
129
- }
130
-
131
- constructor() {
132
- log.verbose('XMLHttpRequest constructor called');
133
- super();
134
- }
135
-
136
-
137
- /**
138
- * XMLHttpRequest.open, always async, user and password not supported. When
139
- * this method invoked, headers should becomes empty again.
140
- * @param {string} method Request method
141
- * @param {string} url Request URL
142
- * @param {true} async Always async
143
- * @param {any} user NOT SUPPORTED
144
- * @param {any} password NOT SUPPORTED
145
- */
146
- open(method: string, url: string, async: true, user: any, password: any) {
147
- log.verbose('XMLHttpRequest open ', method, url, async, user, password);
148
- this._method = method;
149
- this._url = url;
150
- this._headers = {};
151
- this._increment = URIUtil.isJSONStreamURI(this._url);
152
- this._url = this._url.replace(/^JSONStream\:\/\//, '');
153
- this._dispatchReadStateChange(XMLHttpRequest.OPENED);
154
- }
155
-
156
- /**
157
- * Invoke this function to send HTTP request, and set body.
158
- * @param {any} body Body in ReactNativeBlobUtil flavor
159
- */
160
- send(body) {
161
-
162
- this._body = body;
163
-
164
- if (this._readyState !== XMLHttpRequest.OPENED)
165
- throw 'InvalidStateError : XMLHttpRequest is not opened yet.';
166
- let promise = Promise.resolve();
167
- this._sendFlag = true;
168
- log.verbose('XMLHttpRequest send ', body);
169
- let {_method, _url, _headers} = this;
170
- log.verbose('sending request with args', _method, _url, _headers, body);
171
- log.verbose(typeof body, body instanceof FormData);
172
-
173
- if (body instanceof FormData) {
174
- log.debug('creating blob and setting header from FormData instance');
175
- body = new Blob(body);
176
- this._headers['Content-Type'] = `multipart/form-data; boundary=${body.multipartBoundary}`;
177
- }
178
-
179
- if (body instanceof Blob) {
180
- log.debug('sending blob body', body._blobCreated);
181
- promise = new Promise((resolve, reject) => {
182
- body.onCreated((blob) => {
183
- // when the blob is derived (not created by RN developer), the blob
184
- // will be released after XMLHttpRequest sent
185
- if (blob.isDerived) {
186
- this._cleanUp = () => {
187
- blob.close();
188
- };
189
- }
190
- log.debug('body created send request');
191
- body = URIUtil.wrap(blob.getReactNativeBlobUtilRef());
192
- resolve();
193
- });
194
- });
195
- }
196
- else if (typeof body === 'object') {
197
- body = JSON.stringify(body);
198
- promise = Promise.resolve();
199
- }
200
- else {
201
- body = body ? body.toString() : body;
202
- promise = Promise.resolve();
203
- }
204
-
205
- promise.then(() => {
206
- log.debug('send request invoke', body);
207
- for (let h in _headers) {
208
- _headers[h] = _headers[h].toString();
209
- }
210
-
211
- this._task = config({
212
- auto: true,
213
- timeout: this._timeout,
214
- increment: this._increment,
215
- binaryContentTypes: XMLHttpRequest.binaryContentTypes
216
- })
217
- .fetch(_method, _url, _headers, body);
218
- this._task
219
- .stateChange(this._headerReceived)
220
- .uploadProgress(this._uploadProgressEvent)
221
- .progress(this._progressEvent)
222
- .catch(this._onError)
223
- .then(this._onDone);
224
-
225
- });
226
- }
227
-
228
- overrideMimeType(mime: string) {
229
- log.verbose('XMLHttpRequest overrideMimeType', mime);
230
- this._headers['Content-Type'] = mime;
231
- }
232
-
233
- setRequestHeader(name, value) {
234
- log.verbose('XMLHttpRequest set header', name, value);
235
- if (this._readyState !== OPENED || this._sendFlag) {
236
- throw `InvalidStateError : Calling setRequestHeader in wrong state ${this._readyState}`;
237
- }
238
- // UNICODE SHOULD NOT PASS
239
- if (typeof name !== 'string' || /[^\u0000-\u00ff]/.test(name)) {
240
- throw 'TypeError : header field name should be a string';
241
- }
242
- //
243
- let invalidPatterns = [
244
- /[\(\)\>\<\@\,\:\\\/\[\]\?\=\}\{\s\ \u007f\;\t\0\v\r]/,
245
- /tt/
246
- ];
247
- for (let pattern of invalidPatterns) {
248
- if (pattern.test(name) || typeof name !== 'string') {
249
- throw `SyntaxError : Invalid header field name ${name}`;
250
- }
251
- }
252
- this._headers[name] = value;
253
- }
254
-
255
- abort() {
256
- log.verbose('XMLHttpRequest abort ');
257
- if (!this._task)
258
- return;
259
- this._task.cancel((err) => {
260
- let e = {
261
- timeStamp: Date.now(),
262
- };
263
- if (this.onabort)
264
- this.onabort();
265
- if (err) {
266
- e.detail = err;
267
- e.type = 'error';
268
- this.dispatchEvent('error', e);
269
- }
270
- else {
271
- e.type = 'abort';
272
- this.dispatchEvent('abort', e);
273
- }
274
- });
275
- }
276
-
277
- getResponseHeader(field: string): string | null {
278
- log.verbose('XMLHttpRequest get header', field, this._responseHeaders);
279
- if (!this._responseHeaders)
280
- return null;
281
- return this._responseHeaders[field] || this._responseHeaders[field.toLowerCase()] || null;
282
-
283
- }
284
-
285
- getAllResponseHeaders(): string | null {
286
- log.verbose('XMLHttpRequest get all headers', this._responseHeaders);
287
- if (!this._responseHeaders)
288
- return '';
289
- let result = '';
290
- let respHeaders = this.responseHeaders;
291
- for (let i in respHeaders) {
292
- result += `${i}: ${respHeaders[i]}${String.fromCharCode(0x0D, 0x0A)}`;
293
- }
294
- return result.substr(0, result.length - 2);
295
- }
296
-
297
- _headerReceived = (e) => {
298
- log.debug('header received ', this._task.taskId, e);
299
- this.responseURL = this._url;
300
- if (e.state === "2" && e.taskId === this._task.taskId) {
301
- this._responseHeaders = e.headers;
302
- this._statusText = e.status;
303
- this._status = Math.floor(e.status);
304
- this._dispatchReadStateChange(XMLHttpRequest.HEADERS_RECEIVED);
305
- }
306
- }
307
-
308
- _uploadProgressEvent = (send: number, total: number) => {
309
- if (!this._uploadStarted) {
310
- this.upload.dispatchEvent('loadstart');
311
- this._uploadStarted = true;
312
- }
313
- if (send >= total)
314
- this.upload.dispatchEvent('load');
315
- this.upload.dispatchEvent('progress', new ProgressEvent(true, send, total));
316
- }
317
-
318
- _progressEvent = (send: number, total: number, chunk: string) => {
319
- log.verbose(this.readyState);
320
- if (this._readyState === XMLHttpRequest.HEADERS_RECEIVED)
321
- this._dispatchReadStateChange(XMLHttpRequest.LOADING);
322
- let lengthComputable = false;
323
- if (total && total >= 0)
324
- lengthComputable = true;
325
- let e = new ProgressEvent(lengthComputable, send, total);
326
-
327
- if (this._increment) {
328
- this._responseText += chunk;
329
- }
330
- this.dispatchEvent('progress', e);
331
- }
332
-
333
- _onError = (err) => {
334
- let statusCode = Math.floor(this.status);
335
- if (statusCode >= 100 && statusCode !== 408) {
336
- return;
337
- }
338
- log.debug('XMLHttpRequest error', err);
339
- this._statusText = err;
340
- this._status = String(err).match(/\d+/);
341
- this._status = this._status ? Math.floor(this.status) : 404;
342
- this._dispatchReadStateChange(XMLHttpRequest.DONE);
343
- if (err && String(err.message).match(/(timed\sout|timedout)/) || this._status == 408) {
344
- this.dispatchEvent('timeout');
345
- }
346
- this.dispatchEvent('loadend');
347
- this.dispatchEvent('error', {
348
- type: 'error',
349
- detail: err
350
- });
351
- this.clearEventListeners();
352
- }
353
-
354
- _onDone = (resp) => {
355
- log.debug('XMLHttpRequest done', this._url, resp, this);
356
- this._statusText = this._status;
357
- let responseDataReady = () => {
358
- log.debug('request done state = 4');
359
- this.dispatchEvent('load');
360
- this.dispatchEvent('loadend');
361
- this._dispatchReadStateChange(XMLHttpRequest.DONE);
362
- this.clearEventListeners();
363
- };
364
- if (resp) {
365
- let info = resp.respInfo || {};
366
- log.debug(this._url, info, info.respType);
367
- switch (this._responseType) {
368
- case 'blob' :
369
- resp.blob().then((b) => {
370
- this._responseText = resp.text();
371
- this._response = b;
372
- responseDataReady();
373
- });
374
- break;
375
- case 'arraybuffer':
376
- // TODO : to array buffer
377
- break;
378
- case 'json':
379
- this._response = resp.json();
380
- this._responseText = resp.text();
381
- break;
382
- default :
383
- this._responseText = resp.text();
384
- this._response = this.responseText;
385
- responseDataReady();
386
- break;
387
- }
388
- }
389
-
390
- }
391
-
392
- _dispatchReadStateChange(state) {
393
- this._readyState = state;
394
- if (typeof this._onreadystatechange === 'function')
395
- this._onreadystatechange();
396
- }
397
-
398
- set onreadystatechange(fn: () => void) {
399
- log.verbose('XMLHttpRequest set onreadystatechange', fn);
400
- this._onreadystatechange = fn;
401
- }
402
-
403
- get onreadystatechange() {
404
- return this._onreadystatechange;
405
- }
406
-
407
- get readyState() {
408
- log.verbose('get readyState', this._readyState);
409
- return this._readyState;
410
- }
411
-
412
- get status() {
413
- log.verbose('get status', this._status);
414
- return this._status;
415
- }
416
-
417
- get statusText() {
418
- log.verbose('get statusText', this._statusText);
419
- return this._statusText;
420
- }
421
-
422
- get response() {
423
- log.verbose('get response', this._response);
424
- return this._response;
425
- }
426
-
427
- get responseText() {
428
- log.verbose('get responseText', this._responseText);
429
- return this._responseText;
430
- }
431
-
432
- get responseURL() {
433
- log.verbose('get responseURL', this._responseURL);
434
- return this._responseURL;
435
- }
436
-
437
- get responseHeaders() {
438
- log.verbose('get responseHeaders', this._responseHeaders);
439
- return this._responseHeaders;
440
- }
441
-
442
- set timeout(val) {
443
- this._timeout = val * 1000;
444
- log.verbose('set timeout', this._timeout);
445
- }
446
-
447
- get timeout() {
448
- log.verbose('get timeout', this._timeout);
449
- return this._timeout;
450
- }
451
-
452
- set responseType(val) {
453
- log.verbose('set response type', this._responseType);
454
- this._responseType = val;
455
- }
456
-
457
- get responseType() {
458
- log.verbose('get response type', this._responseType);
459
- return this._responseType;
460
- }
461
-
462
- static get isRNFBPolyfill() {
463
- return true;
464
- }
465
-
466
- }
1
+ // Copyright 2016 wkh237@github. All rights reserved.
2
+ // Use of this source code is governed by a MIT-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import XMLHttpRequestEventTarget from './XMLHttpRequestEventTarget.js';
6
+ import Log from '../utils/log.js';
7
+ import Blob from './Blob.js';
8
+ import ProgressEvent from './ProgressEvent.js';
9
+ import URIUtil from "../utils/uri";
10
+ import {config} from "../fetch";
11
+
12
+ const log = new Log('XMLHttpRequest');
13
+
14
+
15
+ log.disable();
16
+ // log.level(3)
17
+
18
+ const UNSENT = 0;
19
+ const OPENED = 1;
20
+ const HEADERS_RECEIVED = 2;
21
+ const LOADING = 3;
22
+ const DONE = 4;
23
+
24
+ export default class XMLHttpRequest extends XMLHttpRequestEventTarget {
25
+
26
+ _onreadystatechange: () => void;
27
+
28
+ upload: XMLHttpRequestEventTarget = new XMLHttpRequestEventTarget();
29
+ static binaryContentTypes: Array<string> = [
30
+ 'image/', 'video/', 'audio/'
31
+ ];
32
+
33
+ // readonly
34
+ _readyState: number = UNSENT;
35
+ _uriType: 'net' | 'file' = 'net';
36
+ _response: any = '';
37
+ _responseText: any = '';
38
+ _responseHeaders: any = {};
39
+ _responseType: '' | 'arraybuffer' | 'blob' | 'json' | 'text' = '';
40
+ // TODO : not suppoted ATM
41
+ _responseURL: null = '';
42
+ _responseXML: null = '';
43
+ _status: number = 0;
44
+ _statusText: string = '';
45
+ _timeout: number = 60000;
46
+ _sendFlag: boolean = false;
47
+ _uploadStarted: boolean = false;
48
+ _increment: boolean = false;
49
+
50
+ // ReactNativeBlobUtil compatible data structure
51
+ _config: ReactNativeBlobUtilConfig = {};
52
+ _url: any;
53
+ _method: string;
54
+ _headers: any = {
55
+ 'Content-Type': 'text/plain'
56
+ };
57
+ _cleanUp: () => void = null;
58
+ _body: any;
59
+
60
+ // ReactNativeBlobUtil promise object, which has `progress`, `uploadProgress`, and
61
+ // `cancel` methods.
62
+ _task: any;
63
+
64
+ // constants
65
+ get UNSENT() {
66
+ return UNSENT;
67
+ }
68
+
69
+ get OPENED() {
70
+ return OPENED;
71
+ }
72
+
73
+ get HEADERS_RECEIVED() {
74
+ return HEADERS_RECEIVED;
75
+ }
76
+
77
+ get LOADING() {
78
+ return LOADING;
79
+ }
80
+
81
+ get DONE() {
82
+ return DONE;
83
+ }
84
+
85
+ static get UNSENT() {
86
+ return UNSENT;
87
+ }
88
+
89
+ static get OPENED() {
90
+ return OPENED;
91
+ }
92
+
93
+ static get HEADERS_RECEIVED() {
94
+ return HEADERS_RECEIVED;
95
+ }
96
+
97
+ static get LOADING() {
98
+ return LOADING;
99
+ }
100
+
101
+ static get DONE() {
102
+ return DONE;
103
+ }
104
+
105
+ static setLog(level: number) {
106
+ if (level === -1)
107
+ log.disable();
108
+ else
109
+ log.level(level);
110
+ }
111
+
112
+ static addBinaryContentType(substr: string) {
113
+ for (let i in XMLHttpRequest.binaryContentTypes) {
114
+ if (new RegExp(substr, 'i').test(XMLHttpRequest.binaryContentTypes[i])) {
115
+ return;
116
+ }
117
+ }
118
+ XMLHttpRequest.binaryContentTypes.push(substr);
119
+
120
+ }
121
+
122
+ static removeBinaryContentType(val) {
123
+ for (let i in XMLHttpRequest.binaryContentTypes) {
124
+ if (new RegExp(substr, 'i').test(XMLHttpRequest.binaryContentTypes[i])) {
125
+ XMLHttpRequest.binaryContentTypes.splice(i, 1);
126
+ return;
127
+ }
128
+ }
129
+ }
130
+
131
+ constructor() {
132
+ log.verbose('XMLHttpRequest constructor called');
133
+ super();
134
+ }
135
+
136
+
137
+ /**
138
+ * XMLHttpRequest.open, always async, user and password not supported. When
139
+ * this method invoked, headers should becomes empty again.
140
+ * @param {string} method Request method
141
+ * @param {string} url Request URL
142
+ * @param {true} async Always async
143
+ * @param {any} user NOT SUPPORTED
144
+ * @param {any} password NOT SUPPORTED
145
+ */
146
+ open(method: string, url: string, async: true, user: any, password: any) {
147
+ log.verbose('XMLHttpRequest open ', method, url, async, user, password);
148
+ this._method = method;
149
+ this._url = url;
150
+ this._headers = {};
151
+ this._increment = URIUtil.isJSONStreamURI(this._url);
152
+ this._url = this._url.replace(/^JSONStream\:\/\//, '');
153
+ this._dispatchReadStateChange(XMLHttpRequest.OPENED);
154
+ }
155
+
156
+ /**
157
+ * Invoke this function to send HTTP request, and set body.
158
+ * @param {any} body Body in ReactNativeBlobUtil flavor
159
+ */
160
+ send(body) {
161
+
162
+ this._body = body;
163
+
164
+ if (this._readyState !== XMLHttpRequest.OPENED)
165
+ throw 'InvalidStateError : XMLHttpRequest is not opened yet.';
166
+ let promise = Promise.resolve();
167
+ this._sendFlag = true;
168
+ log.verbose('XMLHttpRequest send ', body);
169
+ let {_method, _url, _headers} = this;
170
+ log.verbose('sending request with args', _method, _url, _headers, body);
171
+ log.verbose(typeof body, body instanceof FormData);
172
+
173
+ if (body instanceof FormData) {
174
+ log.debug('creating blob and setting header from FormData instance');
175
+ body = new Blob(body);
176
+ this._headers['Content-Type'] = `multipart/form-data; boundary=${body.multipartBoundary}`;
177
+ }
178
+
179
+ if (body instanceof Blob) {
180
+ log.debug('sending blob body', body._blobCreated);
181
+ promise = new Promise((resolve, reject) => {
182
+ body.onCreated((blob) => {
183
+ // when the blob is derived (not created by RN developer), the blob
184
+ // will be released after XMLHttpRequest sent
185
+ if (blob.isDerived) {
186
+ this._cleanUp = () => {
187
+ blob.close();
188
+ };
189
+ }
190
+ log.debug('body created send request');
191
+ body = URIUtil.wrap(blob.getReactNativeBlobUtilRef());
192
+ resolve();
193
+ });
194
+ });
195
+ }
196
+ else if (typeof body === 'object') {
197
+ body = JSON.stringify(body);
198
+ promise = Promise.resolve();
199
+ }
200
+ else {
201
+ body = body ? body.toString() : body;
202
+ promise = Promise.resolve();
203
+ }
204
+
205
+ promise.then(() => {
206
+ log.debug('send request invoke', body);
207
+ for (let h in _headers) {
208
+ _headers[h] = _headers[h].toString();
209
+ }
210
+
211
+ this._task = config({
212
+ auto: true,
213
+ timeout: this._timeout,
214
+ increment: this._increment,
215
+ binaryContentTypes: XMLHttpRequest.binaryContentTypes
216
+ })
217
+ .fetch(_method, _url, _headers, body);
218
+ this._task
219
+ .stateChange(this._headerReceived)
220
+ .uploadProgress(this._uploadProgressEvent)
221
+ .progress(this._progressEvent)
222
+ .catch(this._onError)
223
+ .then(this._onDone);
224
+
225
+ });
226
+ }
227
+
228
+ overrideMimeType(mime: string) {
229
+ log.verbose('XMLHttpRequest overrideMimeType', mime);
230
+ this._headers['Content-Type'] = mime;
231
+ }
232
+
233
+ setRequestHeader(name, value) {
234
+ log.verbose('XMLHttpRequest set header', name, value);
235
+ if (this._readyState !== OPENED || this._sendFlag) {
236
+ throw `InvalidStateError : Calling setRequestHeader in wrong state ${this._readyState}`;
237
+ }
238
+ // UNICODE SHOULD NOT PASS
239
+ if (typeof name !== 'string' || /[^\u0000-\u00ff]/.test(name)) {
240
+ throw 'TypeError : header field name should be a string';
241
+ }
242
+ //
243
+ let invalidPatterns = [
244
+ /[\(\)\>\<\@\,\:\\\/\[\]\?\=\}\{\s\ \u007f\;\t\0\v\r]/,
245
+ /tt/
246
+ ];
247
+ for (let pattern of invalidPatterns) {
248
+ if (pattern.test(name) || typeof name !== 'string') {
249
+ throw `SyntaxError : Invalid header field name ${name}`;
250
+ }
251
+ }
252
+ this._headers[name] = value;
253
+ }
254
+
255
+ abort() {
256
+ log.verbose('XMLHttpRequest abort ');
257
+ if (!this._task)
258
+ return;
259
+ this._task.cancel((err) => {
260
+ let e = {
261
+ timeStamp: Date.now(),
262
+ };
263
+ if (this.onabort)
264
+ this.onabort();
265
+ if (err) {
266
+ e.detail = err;
267
+ e.type = 'error';
268
+ this.dispatchEvent('error', e);
269
+ }
270
+ else {
271
+ e.type = 'abort';
272
+ this.dispatchEvent('abort', e);
273
+ }
274
+ });
275
+ }
276
+
277
+ getResponseHeader(field: string): string | null {
278
+ log.verbose('XMLHttpRequest get header', field, this._responseHeaders);
279
+ if (!this._responseHeaders)
280
+ return null;
281
+ return this._responseHeaders[field] || this._responseHeaders[field.toLowerCase()] || null;
282
+
283
+ }
284
+
285
+ getAllResponseHeaders(): string | null {
286
+ log.verbose('XMLHttpRequest get all headers', this._responseHeaders);
287
+ if (!this._responseHeaders)
288
+ return '';
289
+ let result = '';
290
+ let respHeaders = this.responseHeaders;
291
+ for (let i in respHeaders) {
292
+ result += `${i}: ${respHeaders[i]}${String.fromCharCode(0x0D, 0x0A)}`;
293
+ }
294
+ return result.substr(0, result.length - 2);
295
+ }
296
+
297
+ _headerReceived = (e) => {
298
+ log.debug('header received ', this._task.taskId, e);
299
+ this.responseURL = this._url;
300
+ if (e.state === "2" && e.taskId === this._task.taskId) {
301
+ this._responseHeaders = e.headers;
302
+ this._statusText = e.status;
303
+ this._status = Math.floor(e.status);
304
+ this._dispatchReadStateChange(XMLHttpRequest.HEADERS_RECEIVED);
305
+ }
306
+ }
307
+
308
+ _uploadProgressEvent = (send: number, total: number) => {
309
+ if (!this._uploadStarted) {
310
+ this.upload.dispatchEvent('loadstart');
311
+ this._uploadStarted = true;
312
+ }
313
+ if (send >= total)
314
+ this.upload.dispatchEvent('load');
315
+ this.upload.dispatchEvent('progress', new ProgressEvent(true, send, total));
316
+ }
317
+
318
+ _progressEvent = (send: number, total: number, chunk: string) => {
319
+ log.verbose(this.readyState);
320
+ if (this._readyState === XMLHttpRequest.HEADERS_RECEIVED)
321
+ this._dispatchReadStateChange(XMLHttpRequest.LOADING);
322
+ let lengthComputable = false;
323
+ if (total && total >= 0)
324
+ lengthComputable = true;
325
+ let e = new ProgressEvent(lengthComputable, send, total);
326
+
327
+ if (this._increment) {
328
+ this._responseText += chunk;
329
+ }
330
+ this.dispatchEvent('progress', e);
331
+ }
332
+
333
+ _onError = (err) => {
334
+ let statusCode = Math.floor(this.status);
335
+ if (statusCode >= 100 && statusCode !== 408) {
336
+ return;
337
+ }
338
+ log.debug('XMLHttpRequest error', err);
339
+ this._statusText = err;
340
+ this._status = String(err).match(/\d+/);
341
+ this._status = this._status ? Math.floor(this.status) : 404;
342
+ this._dispatchReadStateChange(XMLHttpRequest.DONE);
343
+ if (err && String(err.message).match(/(timed\sout|timedout)/) || this._status == 408) {
344
+ this.dispatchEvent('timeout');
345
+ }
346
+ this.dispatchEvent('loadend');
347
+ this.dispatchEvent('error', {
348
+ type: 'error',
349
+ detail: err
350
+ });
351
+ this.clearEventListeners();
352
+ }
353
+
354
+ _onDone = (resp) => {
355
+ log.debug('XMLHttpRequest done', this._url, resp, this);
356
+ this._statusText = this._status;
357
+ let responseDataReady = () => {
358
+ log.debug('request done state = 4');
359
+ this.dispatchEvent('load');
360
+ this.dispatchEvent('loadend');
361
+ this._dispatchReadStateChange(XMLHttpRequest.DONE);
362
+ this.clearEventListeners();
363
+ };
364
+ if (resp) {
365
+ let info = resp.respInfo || {};
366
+ log.debug(this._url, info, info.respType);
367
+ switch (this._responseType) {
368
+ case 'blob' :
369
+ resp.blob().then((b) => {
370
+ this._responseText = resp.text();
371
+ this._response = b;
372
+ responseDataReady();
373
+ });
374
+ break;
375
+ case 'arraybuffer':
376
+ // TODO : to array buffer
377
+ break;
378
+ case 'json':
379
+ this._response = resp.json();
380
+ this._responseText = resp.text();
381
+ break;
382
+ default :
383
+ this._responseText = resp.text();
384
+ this._response = this.responseText;
385
+ responseDataReady();
386
+ break;
387
+ }
388
+ }
389
+
390
+ }
391
+
392
+ _dispatchReadStateChange(state) {
393
+ this._readyState = state;
394
+ if (typeof this._onreadystatechange === 'function')
395
+ this._onreadystatechange();
396
+ }
397
+
398
+ set onreadystatechange(fn: () => void) {
399
+ log.verbose('XMLHttpRequest set onreadystatechange', fn);
400
+ this._onreadystatechange = fn;
401
+ }
402
+
403
+ get onreadystatechange() {
404
+ return this._onreadystatechange;
405
+ }
406
+
407
+ get readyState() {
408
+ log.verbose('get readyState', this._readyState);
409
+ return this._readyState;
410
+ }
411
+
412
+ get status() {
413
+ log.verbose('get status', this._status);
414
+ return this._status;
415
+ }
416
+
417
+ get statusText() {
418
+ log.verbose('get statusText', this._statusText);
419
+ return this._statusText;
420
+ }
421
+
422
+ get response() {
423
+ log.verbose('get response', this._response);
424
+ return this._response;
425
+ }
426
+
427
+ get responseText() {
428
+ log.verbose('get responseText', this._responseText);
429
+ return this._responseText;
430
+ }
431
+
432
+ get responseURL() {
433
+ log.verbose('get responseURL', this._responseURL);
434
+ return this._responseURL;
435
+ }
436
+
437
+ get responseHeaders() {
438
+ log.verbose('get responseHeaders', this._responseHeaders);
439
+ return this._responseHeaders;
440
+ }
441
+
442
+ set timeout(val) {
443
+ this._timeout = val * 1000;
444
+ log.verbose('set timeout', this._timeout);
445
+ }
446
+
447
+ get timeout() {
448
+ log.verbose('get timeout', this._timeout);
449
+ return this._timeout;
450
+ }
451
+
452
+ set responseType(val) {
453
+ log.verbose('set response type', this._responseType);
454
+ this._responseType = val;
455
+ }
456
+
457
+ get responseType() {
458
+ log.verbose('get response type', this._responseType);
459
+ return this._responseType;
460
+ }
461
+
462
+ static get isRNFBPolyfill() {
463
+ return true;
464
+ }
465
+
466
+ }