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

com.aliyun.datahub.client.http.HttpClient Maven / Gradle / Ivy

The newest version!
package com.aliyun.datahub.client.http;

import com.aliyun.datahub.client.auth.Account;
import com.aliyun.datahub.client.http.interceptor.Http2RetryInterceptor;
import com.aliyun.datahub.client.http.interceptor.HttpAuthInterceptor;
import com.aliyun.datahub.client.http.interceptor.HttpCompressInterceptor;
import com.aliyun.datahub.client.http.interceptor.HttpNormalInterceptor;
import com.aliyun.datahub.client.http.listener.RequestTraceListener;
import com.aliyun.datahub.client.http.protocol.ProtocolConverterFactory;
import com.aliyun.datahub.client.model.CompressType;
import okhttp3.Authenticator;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.Retrofit;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.*;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class HttpClient {
    private final static Logger LOGGER = LoggerFactory.getLogger(HttpClient.class);
    private final static long CLIENT_CACHE_TIMEOUT_MS = 60 * 1000;
    private static ConnectionPool connectionPool;
    private static int maxIdleConnections = Integer.MAX_VALUE;
    private static boolean enableRetrofitCache = true;
    private static final TimeoutCache clientMap = new TimeoutCache<>(CLIENT_CACHE_TIMEOUT_MS);

    public static void close() {
        if (connectionPool != null) {
            connectionPool.evictAll();
        }
    }

    public static Retrofit createClient(String endpoint, HttpConfig config, String userAgent, Account account) {
        if (!endpoint.startsWith("http")) {
            endpoint = "http://" + endpoint;
        }
        if (!endpoint.endsWith("/")) {
            endpoint += "/";
        }

        ClientConfig clientConfig = new ClientConfig(endpoint, config, userAgent, account);
        if (!enableRetrofitCache) {
            return newClient(clientConfig);
        } else {
            Retrofit retrofit = clientMap.get(clientConfig);
            if (retrofit == null) {
                synchronized (HttpClient.class) {
                    retrofit = clientMap.get(clientConfig);
                    if (retrofit == null) {
                        retrofit = newClient(clientConfig);
                        clientMap.put(clientConfig, retrofit);
                    }
                }
            }
            return retrofit;
        }
    }

    private static Retrofit newClient(ClientConfig clientConfig) {
        return new Retrofit.Builder()
                .client(buildClient(clientConfig))
                .addConverterFactory(ProtocolConverterFactory.create())
                .baseUrl(clientConfig.endpoint)
                .build();
    }

    private static OkHttpClient buildClient(ClientConfig clientConfig) {
        if (connectionPool == null) {
            connectionPool = new ConnectionPool(maxIdleConnections, 60, TimeUnit.SECONDS);
        }

        HttpConfig config = clientConfig.httpConfig;
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectionPool(connectionPool)
                .followRedirects(config.isFollowRedirects())
                .socketFactory(new NoDelaySocketFactory(config.getNetworkInterface()))
                .readTimeout(config.getReadTimeout(), TimeUnit.MILLISECONDS)
                .writeTimeout(config.getReadTimeout(), TimeUnit.MILLISECONDS)
                .connectTimeout(config.getConnTimeout(), TimeUnit.MILLISECONDS)
                .sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .hostnameVerifier((s, sslSession) -> true)
                .retryOnConnectionFailure(true);

        if (!StringUtils.isEmpty(config.getProxyUri())) {
            String proxyUri = config.getProxyUri();
            int index = proxyUri.lastIndexOf(":");
            String proxyHost = proxyUri.substring(0, index);
            String proxyPortStr = proxyUri.substring(index + 1);
            int proxyPort = StringUtils.isEmpty(proxyPortStr) ? 80 : Integer.valueOf(proxyPortStr);
            builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)))
                    .proxyAuthenticator(new Authenticator() {
                        @Override
                        public Request authenticate(Route route, Response response) throws IOException {
                            String credential = Credentials.basic(config.getProxyUsername(), proxyHost);
                            return response.request().newBuilder()
                                    .header("Proxy-Authorization", credential)
                                    .build();
                        }
                    });
        }

        if (config.isEnableH2C()) {
            builder.protocols(Collections.singletonList(Protocol.H2_PRIOR_KNOWLEDGE));
        }
        if (config.isTraceRequest()) {
            builder.eventListener(new RequestTraceListener());
        }

        // HttpNormalInterceptor <--> HttpCompressInterceptor <--> HttpAuthInterceptor <--> Http2RetryInterceptor
        builder.addInterceptor(new HttpNormalInterceptor(clientConfig.userAgent, clientConfig.httpConfig.getUserHeader()));
        // add interceptors
        if (config.getCompressType() != null && config.getCompressType() != CompressType.NONE) {
            builder.addInterceptor(new HttpCompressInterceptor(config.getCompressType()));
        }
        builder.addInterceptor(new HttpAuthInterceptor(clientConfig.account));

        if (config.isDebugRequest()) {
            builder.addInterceptor(loggingInterceptor());
        }
        if (config.isEnableH2C()) { // add at last
            builder.addInterceptor(new Http2RetryInterceptor());
        }
        return builder.build();
    }

    private static HttpLoggingInterceptor loggingInterceptor() {
        HttpLoggingInterceptor.Logger customLogger = new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                LOGGER.info("DataHubClient: " + message);
            }
        };
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(customLogger);
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return loggingInterceptor;
    }

    public static X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    public static SSLSocketFactory sslSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (GeneralSecurityException ex) {
            LOGGER.warn(ex.toString());
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    public static int getMaxIdleConnections() {
        return maxIdleConnections;
    }

    public static void setMaxIdleConnections(int maxIdleConnections) {
        HttpClient.maxIdleConnections = maxIdleConnections;
    }

    public static boolean isEnableRetrofitCache() {
        return enableRetrofitCache;
    }

    public static void setEnableRetrofitCache(boolean enableRetrofitCache) {
        HttpClient.enableRetrofitCache = enableRetrofitCache;
    }

    private static class ClientConfig {
        private final String endpoint;
        private final HttpConfig httpConfig;

        private final String userAgent;

        private final Account account;

        public ClientConfig(String endpoint, HttpConfig httpConfig, String userAgent, Account account) {
            this.endpoint = endpoint;
            this.httpConfig = httpConfig;
            this.userAgent = userAgent;
            this.account = account;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ClientConfig that = (ClientConfig) o;
            return Objects.equals(endpoint, that.endpoint) && Objects.equals(httpConfig, that.httpConfig) && Objects.equals(userAgent, that.userAgent) && Objects.equals(account, that.account);
        }

        @Override
        public int hashCode() {
            return Objects.hash(endpoint, httpConfig, userAgent, account);
        }
    }

    public static class NoDelaySocketFactory extends SocketFactory {
        private final String networkInterface;
        public NoDelaySocketFactory(String networkInterface) {
            this.networkInterface = networkInterface;
        }

        @Override
        public Socket createSocket() throws SocketException {
            Socket ret = new Socket();
            ret.setTcpNoDelay(true);

            if (!StringUtils.isEmpty(networkInterface)) {
                try {
                    NetworkInterface ni = NetworkInterface.getByName(networkInterface);
                    if (ni == null) {
                        throw new SocketException("Not find interface " + networkInterface);
                    }
                    Enumeration enumeration = ni.getInetAddresses();
                    if (!enumeration.hasMoreElements()) {
                        throw new SocketException("Not find address for " + networkInterface);
                    }
                    ret.bind(new InetSocketAddress(enumeration.nextElement(), 0));
                } catch (Exception e) {
                    throw new SocketException(e.getMessage());
                }
            }
            return ret;
        }

        public Socket createSocket(String host, int port)
                throws IOException {
            Socket socket = createSocket();
            try {
                socket.connect(new InetSocketAddress(host, port));
            } catch (IOException e) {
                socket.close();
                throw e;
            }
            return socket;
        }

        public Socket createSocket(InetAddress address, int port)
                throws IOException {
            Socket socket = createSocket();
            try {
                socket.connect(new InetSocketAddress(address, port));
            } catch (IOException e) {
                socket.close();
                throw e;
            }
            return socket;
        }

        public Socket createSocket(String host, int port,
                                   InetAddress clientAddress, int clientPort)
                throws IOException {
            Socket socket = createSocket();
            try {
                socket.bind(new InetSocketAddress(clientAddress, clientPort));
                socket.connect(new InetSocketAddress(host, port));
            } catch (IOException e) {
                socket.close();
                throw e;
            }
            return socket;
        }

        public Socket createSocket(InetAddress address, int port,
                                   InetAddress clientAddress, int clientPort)
                throws IOException {
            Socket socket = createSocket();
            try {
                socket.bind(new InetSocketAddress(clientAddress, clientPort));
                socket.connect(new InetSocketAddress(address, port));
            } catch (IOException e) {
                socket.close();
                throw e;
            }
            return socket;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy