From 1a790f8703d44c2322000dbf40a55678ca8a436a Mon Sep 17 00:00:00 2001 From: Wei Sun Date: Fri, 9 Feb 2018 14:29:27 -0800 Subject: [PATCH] =?UTF-8?q?Use=20ConcurrentHashMap=20for=20handling=20conc?= =?UTF-8?q?urrent=20Android=20websockets,=20and=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: … prevent unknown websocket IDs from crashing on Android (show warning on development builds instead) This PR addresses #3346; an unknown websocket ID should produce a warning during development, but not cause crashes in production RN apps. This PR was created by satya164's request, and was inspired by tanthanh289's suggestion on #3346's thread. On Android, create a websocket using a service like Pusher (`pusher-js` npm package) or manually, and then induce removal of its websocket ID. Result should be a red warning screen during development, and no crash in the app's release variant. [ANDROID] [BUGFIX] [WebSocket] - Prevent unknown websocket IDs from crashing on Android Closes https://github.com/facebook/react-native/pull/17884 Differential Revision: D6954038 Pulled By: hramos fbshipit-source-id: b346d80d7568996b8819c0de54552abb534cbfae --- .../modules/websocket/WebSocketModule.java | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index 2bfae94e7..c7b6c8bbe 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -27,6 +27,7 @@ import com.facebook.react.modules.network.ForwardingCookieHandler; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.concurrent.ConcurrentHashMap; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -48,8 +49,8 @@ public final class WebSocketModule extends ReactContextBaseJavaModule { void onMessage(ByteString byteString, WritableMap params); } - private final Map mWebSocketConnections = new HashMap<>(); - private final Map mContentHandlers = new HashMap<>(); + private final Map mWebSocketConnections = new ConcurrentHashMap<>(); + private final Map mContentHandlers = new ConcurrentHashMap<>(); private ReactContext mReactContext; private ForwardingCookieHandler mCookieHandler; @@ -224,8 +225,19 @@ public final class WebSocketModule extends ReactContextBaseJavaModule { public void send(String message, int id) { WebSocket client = mWebSocketConnections.get(id); if (client == null) { - // This is a programmer error - throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); + // This is a programmer error -- display development warning + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("message", "client is null"); + sendEvent("websocketFailed", params); + params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", 0); + params.putString("reason", "client is null"); + sendEvent("websocketClosed", params); + mWebSocketConnections.remove(id); + mContentHandlers.remove(id); + return; } try { client.send(message); @@ -238,8 +250,19 @@ public final class WebSocketModule extends ReactContextBaseJavaModule { public void sendBinary(String base64String, int id) { WebSocket client = mWebSocketConnections.get(id); if (client == null) { - // This is a programmer error - throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); + // This is a programmer error -- display development warning + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("message", "client is null"); + sendEvent("websocketFailed", params); + params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", 0); + params.putString("reason", "client is null"); + sendEvent("websocketClosed", params); + mWebSocketConnections.remove(id); + mContentHandlers.remove(id); + return; } try { client.send(ByteString.decodeBase64(base64String)); @@ -251,8 +274,19 @@ public final class WebSocketModule extends ReactContextBaseJavaModule { public void sendBinary(ByteString byteString, int id) { WebSocket client = mWebSocketConnections.get(id); if (client == null) { - // This is a programmer error - throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); + // This is a programmer error -- display development warning + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("message", "client is null"); + sendEvent("websocketFailed", params); + params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", 0); + params.putString("reason", "client is null"); + sendEvent("websocketClosed", params); + mWebSocketConnections.remove(id); + mContentHandlers.remove(id); + return; } try { client.send(byteString); @@ -265,8 +299,19 @@ public final class WebSocketModule extends ReactContextBaseJavaModule { public void ping(int id) { WebSocket client = mWebSocketConnections.get(id); if (client == null) { - // This is a programmer error - throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); + // This is a programmer error -- display development warning + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("message", "client is null"); + sendEvent("websocketFailed", params); + params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", 0); + params.putString("reason", "client is null"); + sendEvent("websocketClosed", params); + mWebSocketConnections.remove(id); + mContentHandlers.remove(id); + return; } try { client.send(ByteString.EMPTY);