-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Blob support for XMLHttpRequest
Summary: This PR is a followup to #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 #11573 Reviewed By: shergin Differential Revision: D6082054 Pulled By: hramos fbshipit-source-id: cc9c174fdefdfaf6e5d9fd7b300120a01a50e8c1
- Loading branch information
1 parent
3fc33bb
commit be56a3e
Showing
40 changed files
with
2,056 additions
and
382 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule BlobManager | ||
* @flow | ||
* @format | ||
*/ | ||
|
||
'use strict'; | ||
|
||
const Blob = require('Blob'); | ||
const BlobRegistry = require('BlobRegistry'); | ||
const {BlobModule} = require('NativeModules'); | ||
|
||
import type {BlobData, BlobOptions} from 'BlobTypes'; | ||
|
||
/*eslint-disable no-bitwise */ | ||
/*eslint-disable eqeqeq */ | ||
|
||
/** | ||
* Based on the rfc4122-compliant solution posted at | ||
* http://stackoverflow.com/questions/105034 | ||
*/ | ||
function uuidv4(): string { | ||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { | ||
const r = (Math.random() * 16) | 0, | ||
v = c == 'x' ? r : (r & 0x3) | 0x8; | ||
return v.toString(16); | ||
}); | ||
} | ||
|
||
/** | ||
* Module to manage blobs. Wrapper around the native blob module. | ||
*/ | ||
class BlobManager { | ||
/** | ||
* If the native blob module is available. | ||
*/ | ||
static isAvailable = !!BlobModule; | ||
|
||
/** | ||
* Create blob from existing array of blobs. | ||
*/ | ||
static createFromParts( | ||
parts: Array<Blob | string>, | ||
options?: BlobOptions, | ||
): Blob { | ||
const blobId = uuidv4(); | ||
const items = parts.map(part => { | ||
if ( | ||
part instanceof ArrayBuffer || | ||
(global.ArrayBufferView && part instanceof global.ArrayBufferView) | ||
) { | ||
throw new Error( | ||
"Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported", | ||
); | ||
} | ||
if (part instanceof Blob) { | ||
return { | ||
data: part.data, | ||
type: 'blob', | ||
}; | ||
} else { | ||
return { | ||
data: String(part), | ||
type: 'string', | ||
}; | ||
} | ||
}); | ||
const size = items.reduce((acc, curr) => { | ||
if (curr.type === 'string') { | ||
return acc + global.unescape(encodeURI(curr.data)).length; | ||
} else { | ||
return acc + curr.data.size; | ||
} | ||
}, 0); | ||
|
||
BlobModule.createFromParts(items, blobId); | ||
|
||
return BlobManager.createFromOptions({ | ||
blobId, | ||
offset: 0, | ||
size, | ||
type: options ? options.type : '', | ||
lastModified: options ? options.lastModified : Date.now(), | ||
}); | ||
} | ||
|
||
/** | ||
* Create blob instance from blob data from native. | ||
* Used internally by modules like XHR, WebSocket, etc. | ||
*/ | ||
static createFromOptions(options: BlobData): Blob { | ||
BlobRegistry.register(options.blobId); | ||
return Object.assign(Object.create(Blob.prototype), {data: options}); | ||
} | ||
|
||
/** | ||
* Deallocate resources for a blob. | ||
*/ | ||
static release(blobId: string): void { | ||
BlobRegistry.unregister(blobId); | ||
if (BlobRegistry.has(blobId)) { | ||
return; | ||
} | ||
BlobModule.release(blobId); | ||
} | ||
|
||
/** | ||
* Inject the blob content handler in the networking module to support blob | ||
* requests and responses. | ||
*/ | ||
static addNetworkingHandler(): void { | ||
BlobModule.addNetworkingHandler(); | ||
} | ||
|
||
/** | ||
* Indicate the websocket should return a blob for incoming binary | ||
* messages. | ||
*/ | ||
static addWebSocketHandler(socketId: number): void { | ||
BlobModule.addWebSocketHandler(socketId); | ||
} | ||
|
||
/** | ||
* Indicate the websocket should no longer return a blob for incoming | ||
* binary messages. | ||
*/ | ||
static removeWebSocketHandler(socketId: number): void { | ||
BlobModule.removeWebSocketHandler(socketId); | ||
} | ||
|
||
/** | ||
* Send a blob message to a websocket. | ||
*/ | ||
static sendOverSocket(blob: Blob, socketId: number): void { | ||
BlobModule.sendOverSocket(blob.data, socketId); | ||
} | ||
} | ||
|
||
module.exports = BlobManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule BlobRegistry | ||
* @flow | ||
* @format | ||
*/ | ||
|
||
const registry: {[key: string]: number} = {}; | ||
|
||
const register = (id: string) => { | ||
if (registry[id]) { | ||
registry[id]++; | ||
} else { | ||
registry[id] = 1; | ||
} | ||
}; | ||
|
||
const unregister = (id: string) => { | ||
if (registry[id]) { | ||
registry[id]--; | ||
if (registry[id] <= 0) { | ||
delete registry[id]; | ||
} | ||
} | ||
}; | ||
|
||
const has = (id: string) => { | ||
return registry[id] && registry[id] > 0; | ||
}; | ||
|
||
module.exports = { | ||
register, | ||
unregister, | ||
has, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.