Skip to content

Commit

Permalink
Use ConcurrentHashMap for handling concurrent Android websockets, and…
Browse files Browse the repository at this point in the history
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 #17884

Differential Revision: D6954038

Pulled By: hramos

fbshipit-source-id: b346d80d7568996b8819c0de54552abb534cbfae
  • Loading branch information
sunweiyang authored and facebook-github-bot committed Feb 9, 2018
1 parent 01a58d1 commit 1a790f8
Showing 1 changed file with 55 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand All @@ -48,8 +49,8 @@ public interface ContentHandler {
void onMessage(ByteString byteString, WritableMap params);
}

private final Map<Integer, WebSocket> mWebSocketConnections = new HashMap<>();
private final Map<Integer, ContentHandler> mContentHandlers = new HashMap<>();
private final Map<Integer, WebSocket> mWebSocketConnections = new ConcurrentHashMap<>();
private final Map<Integer, ContentHandler> mContentHandlers = new ConcurrentHashMap<>();

private ReactContext mReactContext;
private ForwardingCookieHandler mCookieHandler;
Expand Down Expand Up @@ -224,8 +225,19 @@ public void close(int code, String reason, int id) {
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);
Expand All @@ -238,8 +250,19 @@ public void send(String message, int id) {
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));
Expand All @@ -251,8 +274,19 @@ public void sendBinary(String base64String, int id) {
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);
Expand All @@ -265,8 +299,19 @@ public void sendBinary(ByteString byteString, int id) {
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);
Expand Down

0 comments on commit 1a790f8

Please sign in to comment.