-
Notifications
You must be signed in to change notification settings - Fork 210
fix(react-native): upload files through Expo SDK 57's fetch #1921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
76 changes: 54 additions & 22 deletions
76
tests/e2e/languages/react-native/shims/expo-file-system.js
This file contains hidden or 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 |
|---|---|---|
| @@ -1,28 +1,60 @@ | ||
| const notImplemented = (name) => () => { | ||
| throw new Error( | ||
| `expo-file-system shim: ${name} was called, but uploads are not exercised by this test harness.` | ||
| ); | ||
| // Serves files over HTTP from the test server so the SDK's upload code can | ||
| // read them the way it reads a device file in Expo. | ||
| const written = new Map(); | ||
|
|
||
| const bytesOf = async (uri) => { | ||
| if (written.has(uri)) { | ||
| return written.get(uri); | ||
| } | ||
| const response = await fetch(uri); | ||
| return new Uint8Array(await response.arrayBuffer()); | ||
| }; | ||
|
|
||
| const toBase64 = (bytes) => { | ||
| let binary = ""; | ||
| for (let index = 0; index < bytes.length; index += 0x8000) { | ||
| binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000)); | ||
| } | ||
| return btoa(binary); | ||
| }; | ||
|
|
||
| export const EncodingType = { UTF8: "utf8", Base64: "base64" }; | ||
| export const documentDirectory = ""; | ||
| export const cacheDirectory = ""; | ||
|
|
||
| export const getInfoAsync = async (uri) => { | ||
| const bytes = await bytesOf(uri); | ||
| return { exists: true, size: bytes.length, uri }; | ||
| }; | ||
|
|
||
| export const EncodingType = { UTF8: 'utf8', Base64: 'base64' }; | ||
| export const documentDirectory = ''; | ||
| export const cacheDirectory = ''; | ||
| export const readAsStringAsync = async (uri, options = {}) => { | ||
| const bytes = await bytesOf(uri); | ||
| const position = options.position ?? 0; | ||
| const length = options.length ?? bytes.length - position; | ||
| const slice = bytes.subarray(position, position + length); | ||
| return options.encoding === EncodingType.Base64 | ||
| ? toBase64(slice) | ||
| : new TextDecoder().decode(slice); | ||
| }; | ||
|
|
||
| export const getInfoAsync = notImplemented('getInfoAsync'); | ||
| export const readAsStringAsync = notImplemented('readAsStringAsync'); | ||
| export const writeAsStringAsync = notImplemented('writeAsStringAsync'); | ||
| export const deleteAsync = notImplemented('deleteAsync'); | ||
| export const uploadAsync = notImplemented('uploadAsync'); | ||
| export const FileSystemUploadType = { BINARY_CONTENT: 0, MULTIPART: 1 }; | ||
| export const writeAsStringAsync = async (uri, data, options = {}) => { | ||
| const bytes = | ||
| options.encoding === EncodingType.Base64 | ||
| ? Uint8Array.from(atob(data), (character) => character.charCodeAt(0)) | ||
| : new TextEncoder().encode(data); | ||
| written.set(uri, bytes); | ||
| }; | ||
|
|
||
| export const deleteAsync = async (uri) => { | ||
| written.delete(uri); | ||
| }; | ||
|
|
||
| export default { | ||
| EncodingType, | ||
| documentDirectory, | ||
| cacheDirectory, | ||
| getInfoAsync, | ||
| readAsStringAsync, | ||
| writeAsStringAsync, | ||
| deleteAsync, | ||
| uploadAsync, | ||
| FileSystemUploadType, | ||
| EncodingType, | ||
| documentDirectory, | ||
| cacheDirectory, | ||
| getInfoAsync, | ||
| readAsStringAsync, | ||
| writeAsStringAsync, | ||
| deleteAsync, | ||
| }; |
This file contains hidden or 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,40 @@ | ||
| // Reproduces the part of Expo's native runtime that uploads go through since | ||
| // Expo SDK 57 made expo/fetch the global fetch: React Native's FormData, Expo's | ||
| // FormData patch, and Expo's multipart body encoder. Only the transport is the | ||
| // browser's fetch, sending the bytes Expo would hand to its native request. | ||
| // | ||
| // Expo ships these as TypeScript sources only, so the test build transpiles | ||
| // them out of node_modules with esbuild before bundling. | ||
| import { installFormDataPatch } from "./expo/winter/FormData"; | ||
| import { | ||
| normalizeBodyInitAsync, | ||
| normalizeHeadersInit, | ||
| overrideHeaders, | ||
| } from "./expo/winter/fetch/RequestUtils"; | ||
|
|
||
| class ReactNativeFormData { | ||
| constructor() { | ||
| this._parts = []; | ||
| } | ||
|
|
||
| append(key, value) { | ||
| this._parts.push([key, value]); | ||
| } | ||
| } | ||
|
|
||
| globalThis.FormData = ReactNativeFormData; | ||
| installFormDataPatch(globalThis.FormData); | ||
|
|
||
| const browserFetch = globalThis.fetch.bind(globalThis); | ||
|
|
||
| globalThis.fetch = async (input, init = {}) => { | ||
| if (!(init.body instanceof globalThis.FormData)) { | ||
| return browserFetch(input, init); | ||
| } | ||
| const { body, overriddenHeaders } = await normalizeBodyInitAsync(init.body); | ||
| const headers = overrideHeaders( | ||
| normalizeHeadersInit(init.headers), | ||
| overriddenHeaders ?? [], | ||
| ); | ||
| return browserFetch(input, { ...init, headers, body }); | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.