Implement Blob support for XMLHttpRequest

Summary:
This PR is a followup to https://github.com/facebook/react-native/pull/11417 and should be merged after that one is merged.

  1. Add support for creating blobs from strings, not just other blobs
  1. Add the `File` constructor which is a superset of `Blob`
  1. Add the `FileReader` API which can be used to read blobs as strings or data url (base64)
  1. Add support for uploading and downloading blobs via `XMLHttpRequest` and `fetch`
  1. Add ability to download local files on Android so you can do `fetch(uri).then(res => res.blob())` to get a blob for a local file (iOS already supported this)

  1. Clone the repo https://github.com/expo/react-native-blob-test
  1. Change the `package.json` and update `react-native` dependency to point to this branch, then run `npm install`
  1. Run the `server.js` file with `node server.js`
  1. Open the `index.common.js` file and replace `localhost` with your computer's IP address
  1. Start the packager with `yarn start` and run the app on your device

If everything went well, all tests should pass, and you should see a screen like this:

![screen shot 2017-06-08 at 7 53 08 pm](https://user-images.githubusercontent.com/1174278/26936407-435bbce2-4c8c-11e7-9ae3-eb104e46961e.png)!

Pull to rerun all tests or tap on specific test to re-run it

  [GENERAL] [FEATURE] [Blob] - Implement blob support for XMLHttpRequest
Closes https://github.com/facebook/react-native/pull/11573

Reviewed By: shergin

Differential Revision: D6082054

Pulled By: hramos

fbshipit-source-id: cc9c174fdefdfaf6e5d9fd7b300120a01a50e8c1
This commit is contained in:
Satyajit Sahoo
2018-01-26 09:17:11 -08:00
committed by Facebook Github Bot
parent 3fc33bb54f
commit be56a3efee
40 changed files with 2060 additions and 386 deletions
+23 -8
View File
@@ -23,9 +23,11 @@ const invariant = require('fbjs/lib/invariant');
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
const warning = require('fbjs/lib/warning');
const BlobManager = require('BlobManager');
type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
type Response = ?Object | string;
export type NativeResponseType = 'base64' | 'blob' | 'text';
export type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
export type Response = ?Object | string;
type XHRInterceptor = {
requestSent(
@@ -54,6 +56,11 @@ type XHRInterceptor = {
): void,
};
// The native blob module is optional so inject it here if available.
if (BlobManager.isAvailable) {
BlobManager.addNetworkingHandler();
}
const UNSENT = 0;
const OPENED = 1;
const HEADERS_RECEIVED = 2;
@@ -200,6 +207,10 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) {
SUPPORTED_RESPONSE_TYPES[responseType] || responseType === 'document',
`The provided value '${responseType}' is unsupported in this environment.`
);
if (responseType === 'blob') {
invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support');
}
this._responseType = responseType;
}
@@ -242,10 +253,11 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) {
break;
case 'blob':
this._cachedResponse = new global.Blob(
[base64.toByteArray(this._response).buffer],
{type: this.getResponseHeader('content-type') || ''}
);
if (typeof this._response === 'object' && this._response) {
this._cachedResponse = BlobManager.createFromOptions(this._response);
} else {
throw new Error(`Invalid response for blob: ${this._response}`);
}
break;
case 'json':
@@ -493,10 +505,13 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) {
(args) => this.__didCompleteResponse(...args)
));
let nativeResponseType = 'text';
if (this._responseType === 'arraybuffer' || this._responseType === 'blob') {
let nativeResponseType: NativeResponseType = 'text';
if (this._responseType === 'arraybuffer') {
nativeResponseType = 'base64';
}
if (this._responseType === 'blob') {
nativeResponseType = 'blob';
}
invariant(this._method, 'Request method needs to be defined.');
invariant(this._url, 'Request URL needs to be defined.');