From 99ab845a5cf0fe3463ff39b03373b95d4f5c0fac Mon Sep 17 00:00:00 2001 From: Hailey Date: Wed, 25 Sep 2024 04:47:54 -0700 Subject: [PATCH] convert `NSNull` to `nil` before checking `type` in `readAsDataURL` (#46635) Summary: This issue original arose out of https://github.com/bluesky-social/social-app/issues/5100. Copying the description (with my general understanding of the problem) from the patch PR to here as well. There's a crash that comes up in the following, pretty specific scenario: - Have a response that has an empty body - Do not include a `content-type` header in the response - Set the `x-content-type-options` header to `nosniff` RN handles the response for a request in this block of code: https://github.com/facebook/react-native/blob/303e0ed7641409acf2d852c077f6be426afd7a0c/packages/react-native/Libraries/Blob/RCTBlobManager.mm#L314-L326 Here, we see that values of `nil` - which `[response MIMEType]` will return when no `content-type` is provided in the response and the actual type cannot be determined (https://developer.apple.com/documentation/foundation/nsurlresponse/1411613-mimetype) - gets converted to `NSNull` by `RCTNullIfNil`. When we get back over to `readAsDataURL`, we see that we grab the type from the dictionary and check if its `nil` before calling `length` on the string. https://github.com/facebook/react-native/blob/303e0ed7641409acf2d852c077f6be426afd7a0c/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm#L74-L77 However, this check is dubious, because the value will never actually be `nil`. It will always either be `NSString` or `NSNull` because of the `RCTNullIfNil` call made above and `[RCTConvert NSString]` seems to just return the input if it is `NSNull`. ## Changelog: [IOS] [FIXED] - Convert `NSNull` to `nil` before checking `type` in `readAsDataURL` Pull Request resolved: https://github.com/facebook/react-native/pull/46635 Test Plan: This is a little awkward to test, but essentially this comes up in the following scenario that is described (and "tested" as being fixed by tweaking) in https://github.com/bluesky-social/social-app/issues/5100. I have personally tested by using Cloudflare rules to add/remove that particular header from an empty body response. You could also test this with a little local web server if you want. ### Before https://github.com/user-attachments/assets/deb86c68-2251-4fef-9705-a1c93584e83e ### After https://github.com/user-attachments/assets/9ffab11b-b2c8-4a83-afd6-0a55fed3ae9b Reviewed By: dmytrorykun Differential Revision: D63381947 Pulled By: cipolleschi fbshipit-source-id: b2b4944d998133611592eed8d112faa6195587bd --- .../react-native/Libraries/Blob/RCTFileReaderModule.mm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm b/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm index caa554029f735e..8356a2a8f485a9 100644 --- a/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm +++ b/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm @@ -72,9 +72,10 @@ @implementation RCTFileReaderModule nil); } else { NSString *type = [RCTConvert NSString:blob[@"type"]]; - NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@", - type != nil && [type length] > 0 ? type : @"application/octet-stream", - [data base64EncodedStringWithOptions:0]]; + NSString *text = [NSString + stringWithFormat:@"data:%@;base64,%@", + ![type isEqual:[NSNull null]] && [type length] > 0 ? type : @"application/octet-stream", + [data base64EncodedStringWithOptions:0]]; resolve(text); }