All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ably.lib.network.DefaultWebSocketClient Maven / Gradle / Ivy

There is a newer version: 1.2.47
Show newest version
package io.ably.lib.network;

import org.java_websocket.WebSocket;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.ServerHandshake;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import java.net.URI;
import java.nio.ByteBuffer;

public class DefaultWebSocketClient extends org.java_websocket.client.WebSocketClient implements WebSocketClient {

    private final WebSocketListener listener;
    private final WebSocketEngineConfig config;

    private boolean shouldExplicitlyVerifyHostname = true;

    public DefaultWebSocketClient(URI serverUri, WebSocketListener listener, WebSocketEngineConfig config) {
        super(serverUri);
        this.listener = listener;
        this.config = config;
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        if (config.isTls() && shouldExplicitlyVerifyHostname && !isHostnameVerified(config.getHost())) {
            close();
        } else {
            listener.onOpen();
        }
    }

    @Override
    public void onMessage(String s) {
        listener.onMessage(s);
    }

    @Override
    public void onMessage(ByteBuffer blob) {
        listener.onMessage(blob);
    }

    /* This allows us to detect a websocket ping, so we don't need Ably pings. */
    @Override
    public void onWebsocketPing(WebSocket conn, Framedata f) {
        /* Call superclass to ensure the pong is sent. */
        super.onWebsocketPing(conn, f);
        listener.onWebsocketPing();
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        listener.onClose(code, reason);
    }

    @Override
    public void onError(Exception e) {
        listener.onError(e);
    }

    @Override
    public void cancel(int code, String reason) {
        closeConnection(code, reason);
    }

    @Override
    protected void onSetSSLParameters(SSLParameters sslParameters) {
        try {
            super.onSetSSLParameters(sslParameters);
            shouldExplicitlyVerifyHostname = false;
        } catch (NoSuchMethodError exception) {
            // This error will be thrown on Android below level 24.
            // When the minSdkVersion will be updated to 24 we should remove this overridden method.
            // https://github.com/TooTallNate/Java-WebSocket/wiki/No-such-method-error-setEndpointIdentificationAlgorithm#workaround
            shouldExplicitlyVerifyHostname = true;
            listener.onOldJavaVersionDetected(exception);
        }
    }

    @Override
    public void send(String text) {
        try {
            super.send(text);
        } catch (WebsocketNotConnectedException e) {
            throw new NotConnectedException(e);
        }
    }

    /**
     * Added because we had to override the onSetSSLParameters() that usually performs this verification.
     * When the minSdkVersion will be updated to 24 we should remove this method and its usages.
     * https://github.com/TooTallNate/Java-WebSocket/wiki/No-such-method-error-setEndpointIdentificationAlgorithm#workaround
     */
    private boolean isHostnameVerified(String hostname) {
        final SSLSession session = getSSLSession();
        if (HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {
            return true;
        } else {
            listener.onError(new IllegalArgumentException("Hostname verification failed, expected " + hostname + ", found " + session.getPeerHost()));
            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy