react-native-macos/Libraries
Arthur Lee f78526ce3d Avoid re-encoding images when uploading local files (#31457)
Summary:
Fixes https://github.com/facebook/react-native/issues/27099

When you upload a local file using XHR + the `FormData` API, RN uses `RCTNetworkTask` to retrieve the image file data from the local filesystem (request URL is a file:// URL) ([code pointer](https://github.com/facebook/react-native/blob/master/Libraries/Network/RCTNetworking.mm#L398)). As a result, if you are uploading a local image file that is in the app's directory `RCTNetworkTask` will end up using `RCTLocalAssetImageLoader` to load the image, which reads the image into a `UIImage` and then re-encodes it using `UIImageJPEGRepresentation` with a compression quality of 1.0, which is the higest ([code pointer](4c5182c1cc/Libraries/Image/RCTImageLoader.mm (L1114))). Not only is this unnecessary, it ends up inflating the size of the jpg if it had been previously compressed to a lower quality.

With this PR, this issue is fixed by forcing the `RCTFileRequestHandler` to be used when retrieving local files for upload, regardless of whether they are images or not. As a result, any file to be uploaded gets read into `NSData` which is the format needed when appending to the multipart body.
I considered fixing this by modifying the behavior of how the handlers were chosen, but this felt like a safer fix since it will be scoped to just uploads and wont affect image fetching.

## Changelog

[iOS] [Fixed] - Avoid re-encoding images when uploading local files

Pull Request resolved: https://github.com/facebook/react-native/pull/31457

Test Plan:
The repro for this is a bit troublesome, especially because this issue doesn't repro in RNTester. There is [some code](https://github.com/facebook/react-native/blob/master/packages/rn-tester/RNTester/AppDelegate.mm#L220) that is to be overriding the handlers that will be used, excluding the `RCTImageLoader`. I had to repro this in a fresh new RN app.

1. Create a blank RN app
2. Put an image in the folder of the app's install location. This would be similar to where files might be placed after an app downloads or captures an image.
3. Set up a quick express server that accepts multipart form uploads and stores the files
4. Trigger an upload via react native
```
const data = new FormData();
data.append('image', {
  uri:
    '/Users/arthur.lee/Library/Developer/CoreSimulator/Devices/46CDD981 (d0c8cb12f2)-9164-4925-9025-1A76C0D9 (1946aee3d9)F0F5/data/Containers/Bundle/Application/B1E8A764-6221-4EA9-BE9A-2CB1699FD218 (1c92b1cff6)/test.app/test.bundle/compressed.jpg',
  type: 'image/jpeg',
  name: 'image.jpeg',
});

fetch(`http://localhost:3000/upload`, {
  method: 'POST',
  headers: {'Content-Type': 'multipart/form-data'},
  body: data,
}).then(console.log);
```
5. Trigger the upload with and without this patch

Original file:
```
$ ls -lh
total 448
-rw-r--r--  1 arthur.lee  staff   223K Apr 29 17:08 compressed.jpg
```

Uploaded file (with and without patch):
```
$ ls -lh
total 1624
-rw-r--r--@ 1 arthur.lee  staff   584K Apr 29 17:11 image-nopatch.jpeg
-rw-r--r--@ 1 arthur.lee  staff   223K Apr 29 17:20 image-withpatch.jpeg
```

Would appreciate pointers on whether this needs to be tested more extensively

Reviewed By: yungsters

Differential Revision: D28630805

Pulled By: PeteTheHeat

fbshipit-source-id: 606a6091fa3e817966548c5eb84b19cb8b9abb1c
2021-06-14 22:52:58 -07:00
..
ActionSheetIOS Resolve "fatal: not a git repository" error outside of git repositories 2021-04-15 13:30:31 -07:00
Alert Remove Unable to get TurboModule for DialogManagerAndroid warning for iOS 2021-03-26 23:48:28 -07:00
Animated pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
AppState Codemod usages of NativeEventEmitter in react-native-github to only pass a native module on iOS 2021-04-12 06:27:20 -07:00
BatchedBridge pre-suppress Flow errors in xplat ahead of 153 release 2021-06-01 09:01:26 -07:00
Blob Migrate NativeModules to initialize 2021-05-21 14:49:51 -07:00
BugReporting pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
Components RN: Statically Define `ReactNativeStyleAttributes` 2021-06-11 23:52:09 -07:00
Core Fix bug in parseHermesStack.js 2021-06-14 02:57:37 -07:00
DeprecatedPropTypes RN: Cleanup `DeprecatedTextInputPropTypes` 2021-06-11 23:52:09 -07:00
EventEmitter pre-suppress Flow errors in xplat ahead of 153 release 2021-06-01 09:01:26 -07:00
FBLazyVector Migrate xplat autoglob targets (#31400) 2021-04-28 11:07:17 -07:00
HeapCapture Remove "use strict" directive from ES Modules 2021-02-02 11:12:56 -08:00
Image RN: Move `{ => Deprecated}ImageProp{s => Types}` (Android) 2021-06-11 23:52:09 -07:00
Inspector pre-suppress Flow errors in xplat ahead of 153 release 2021-06-01 09:01:26 -07:00
Interaction pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
JSInspector Migrate large amount of modules to flow strict and strict-local 2020-07-22 09:46:16 -07:00
LayoutAnimation LayoutAnimation: don't call non-Fabric configurNext if Fabric is installed 2021-03-23 14:37:25 -07:00
Linking RN: Restore Deprecated Event Methods 2021-03-10 16:06:26 -08:00
LinkingIOS Bump Flipper-Folly to 2.5.3 and RCT-Folly to 2021.04.26.00 2021-04-29 10:39:25 -07:00
Lists pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
LogBox pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
Modal pre-suppress Flow errors in xplat ahead of 153 release 2021-06-01 09:01:26 -07:00
NativeAnimation Migrate RCTNativeAnimatedTurboModule to initialize 2021-05-21 14:49:51 -07:00
NativeComponent Integrate global.__nativeComponentRegistry__hasComponent into NativeComponentRegistry.js 2021-03-09 10:39:20 -08:00
NativeModules/specs Remove "use strict" directive from ES Modules 2021-02-02 11:12:56 -08:00
Network Avoid re-encoding images when uploading local files (#31457) 2021-06-14 22:52:58 -07:00
NewAppScreen Add testID to NewAppScreen Header Component (#31652) 2021-06-04 13:14:48 -07:00
Performance Deprecate markerCancel 2021-03-22 06:46:00 -07:00
PermissionsAndroid feat: add Android 12 BLUETOOTH_[CONNECT/SCAN] to PermissionsAndroid (#31488) 2021-05-19 12:23:39 -07:00
Pressability Update FlowFixMes to use error codes in react-native-github 2021-03-31 18:21:47 -07:00
PushNotificationIOS Bump Flipper-Folly to 2.5.3 and RCT-Folly to 2021.04.26.00 2021-04-29 10:39:25 -07:00
RCTRequired Migrate xplat autoglob targets (#31400) 2021-04-28 11:07:17 -07:00
ReactNative Pass concurrentRoot flag through to renderApplication 2021-06-11 04:23:50 -07:00
ReactPrivate RN: Cleanup `ReactFiberErrorDialog` 2021-05-17 01:04:32 -07:00
Reliability Adding support for cancelOnBackground for UserFlow 2020-12-07 10:49:29 -08:00
Renderer RN: Simplify `ReactNativeStyleAttributes` Type 2021-06-11 23:52:09 -07:00
Settings Bump Flipper-Folly to 2.5.3 and RCT-Folly to 2021.04.26.00 2021-04-29 10:39:25 -07:00
Share Remove "use strict" directive from ES Modules 2021-02-02 11:12:56 -08:00
Storage pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
StyleSheet RN: Simplify `ReactNativeStyleAttributes` Type 2021-06-11 23:52:09 -07:00
SurfaceBackedComponent Migrate remaining call sites to `CKOverlayLayoutComponent` to Builder 2020-10-20 05:58:21 -07:00
SurfaceHostingComponent Back out "Avoid accessing `self.component` on background thread" 2020-12-03 19:09:50 -08:00
Text Bug fix: <TextInput> content is reset when emoji is entered at the max length 2021-06-04 13:40:42 -07:00
TurboModule Remove log info when TurboModule cannot be found 2021-05-27 10:42:34 -07:00
TypeSafety Bump Flipper-Folly to 2.5.3 and RCT-Folly to 2021.04.26.00 2021-04-29 10:39:25 -07:00
Types Make RootTag an opaque type 2021-04-26 22:57:55 -07:00
Utilities RN: Create `useRefEffect` Utility 2021-06-06 17:08:55 -07:00
Vibration Bump Flipper-Folly to 2.5.3 and RCT-Folly to 2021.04.26.00 2021-04-29 10:39:25 -07:00
WebSocket Migrate remaining modules using NativeEventEmitter to only pass the native module on iOS 2021-04-12 06:27:20 -07:00
Wrapper Back out "Rename measure to measureContent and pass it LayoutContext" 2020-03-04 05:01:53 -08:00
YellowBox pre-suppress this typing errors ahead of 154 2021-06-11 14:31:41 -07:00
__flowtests__ Remove "use strict" directive from ES Modules 2021-02-02 11:12:56 -08:00
vendor EventEmitter: Deprecate `removeSubscription` 2021-04-12 12:43:07 -07:00
.npmignore
BUCK Add ios_assume_nonnull flag to react native codegen library (#31543) 2021-05-20 10:07:37 -07:00
Promise.js Conditionalize Promise Polyfill for Hermes 2020-10-19 15:24:38 -07:00
UTFSequence.js Migrate large amount of modules to flow strict and strict-local 2020-07-22 09:46:16 -07:00
promiseRejectionTrackingOptions.js pre-suppress Flow errors in xplat ahead of 153 release 2021-06-01 09:01:26 -07:00