-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: WebSocket binaryType handling — stop unconditional Blob interception of binary messages #16173
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
base: main
Are you sure you want to change the base?
Changes from all commits
12ae4c0
ed898e9
ba3935f
9988150
cc4bfe6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "prerelease", | ||
| "comment": "Fix WebSocket binaryType handling — stop unconditional Blob interception of binary messages", | ||
| "packageName": "react-native-windows", | ||
| "email": "gordomacmaster@gmail.com", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,11 +18,49 @@ namespace Microsoft::React { | |
| struct IWebSocketModuleContentHandler { | ||
| virtual ~IWebSocketModuleContentHandler() noexcept {} | ||
|
|
||
| /// Returns true if this handler should process messages for the given socket. | ||
| /// Default returns true for backward compatibility; BlobModule overrides to | ||
| /// check whether binaryType='blob' was set for this socket via addWebSocketHandler. | ||
| /// | ||
| /// WARNING: Subclasses that override Supports() with a stateful or lock-protected | ||
| /// check MUST also override both TryProcessMessage() overloads to perform the | ||
| /// check-and-process atomically. The default TryProcessMessage() calls Supports() | ||
| /// and ProcessMessage() as two separate operations with no lock held between them. | ||
| virtual bool Supports(int64_t /*socketId*/) noexcept { | ||
| return true; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No implementation here. Same for |
||
| } | ||
|
|
||
| virtual void ProcessMessage(std::string &&message, winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept = 0; | ||
|
|
||
| virtual void ProcessMessage( | ||
| std::vector<uint8_t> &&message, | ||
| winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept = 0; | ||
|
|
||
| /// Check Supports() then ProcessMessage() in one call. | ||
| /// Returns true if the message was handled. | ||
| /// | ||
| /// The default implementation does NOT hold any lock across both operations. | ||
| /// Subclasses with a stateful Supports() MUST override these to make the | ||
| /// check-and-process atomic (see BlobWebSocketModuleContentHandler for an example). | ||
| virtual bool TryProcessMessage( | ||
| int64_t socketId, | ||
| std::string &&message, | ||
| winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept { | ||
| if (!Supports(socketId)) | ||
| return false; | ||
| ProcessMessage(std::move(message), params); | ||
| return true; | ||
| } | ||
|
|
||
| virtual bool TryProcessMessage( | ||
| int64_t socketId, | ||
| std::vector<uint8_t> &&message, | ||
| winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept { | ||
| if (!Supports(socketId)) | ||
| return false; | ||
| ProcessMessage(std::move(message), params); | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace Microsoft::React | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,18 +83,20 @@ shared_ptr<IWebSocketResource> WebSocketTurboModule::CreateResource(int64_t id, | |
| if (auto prop = propBag.Get(BlobModuleContentHandlerPropertyId())) | ||
| contentHandler = prop.Value().lock(); | ||
|
|
||
| bool handled = false; | ||
| if (contentHandler) { | ||
| if (isBinary) { | ||
| auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(message)); | ||
| winrt::com_array<uint8_t> arr; | ||
| CryptographicBuffer::CopyToByteArray(buffer, arr); | ||
| auto data = vector<uint8_t>(arr.begin(), arr.end()); | ||
|
|
||
| contentHandler->ProcessMessage(std::move(data), args); | ||
| handled = contentHandler->TryProcessMessage(id, std::move(data), args); | ||
| } else { | ||
| contentHandler->ProcessMessage(string{message}, args); | ||
| handled = contentHandler->TryProcessMessage(id, string{message}, args); | ||
| } | ||
| } else { | ||
| } | ||
| if (!handled) { | ||
| args["data"] = message; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a comment explaining that the content handler takes over the message payload and thus does not use |
||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename as
CanHandleSocket.