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

org.aoju.bus.http.Httpd Maven / Gradle / Ivy

/*
 * The MIT License
 *
 * Copyright (c) 2015-2020 aoju.org All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.aoju.bus.http;

import org.aoju.bus.core.io.Sink;
import org.aoju.bus.core.io.Source;
import org.aoju.bus.http.accord.*;
import org.aoju.bus.http.accord.platform.Platform;
import org.aoju.bus.http.cache.Cache;
import org.aoju.bus.http.cache.InternalCache;
import org.aoju.bus.http.metric.CookieJar;
import org.aoju.bus.http.metric.Dispatcher;
import org.aoju.bus.http.metric.EventListener;
import org.aoju.bus.http.metric.Interceptor;
import org.aoju.bus.http.metric.proxy.NullProxySelector;
import org.aoju.bus.http.secure.Authenticator;
import org.aoju.bus.http.secure.CertificateChainCleaner;
import org.aoju.bus.http.secure.CertificatePinner;
import org.aoju.bus.http.secure.OkHostnameVerifier;
import org.aoju.bus.http.socket.RealWebSocket;
import org.aoju.bus.http.socket.WebSocket;
import org.aoju.bus.http.socket.WebSocketListener;

import javax.net.SocketFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 发送HTTP请求辅助类
 * 工厂的{@linkplain NewCall calls},可以用来发送HTTP请求并读取它们的响应
 * 当您创建一个{@code Httpd}实例并将其用于所有HTTP调用时,体现Httpd的性能最佳
 * 这是因为每个客户机都拥有自己的连接池和线程池。重用连接和线程可以减少延迟并节省内存
 * 相反,为每个请求创建一个客户机会浪费空闲池上的资源
 * Httpd还为HTTP/2连接使用守护进程线程。如果它们保持空闲,就会自动退出
 *
 * @author Kimi Liu
 * @version 5.6.5
 * @since JDK 1.8+
 */
public class Httpd implements Cloneable, NewCall.Factory, WebSocket.Factory {

    static final List DEFAULT_PROTOCOLS = org.aoju.bus.http.Builder.immutableList(
            Protocol.HTTP_2, Protocol.HTTP_1_1);

    static final List DEFAULT_CONNECTION_SPECS = org.aoju.bus.http.Builder.immutableList(
            ConnectionSuite.MODERN_TLS, ConnectionSuite.CLEARTEXT);

    static {
        org.aoju.bus.http.Builder.instance = new org.aoju.bus.http.Builder() {
            @Override
            public void addLenient(Headers.Builder builder, String line) {
                builder.addLenient(line);
            }

            @Override
            public void addLenient(Headers.Builder builder, String name, String value) {
                builder.addLenient(name, value);
            }

            @Override
            public void setCache(Builder builder, InternalCache internalCache) {
                builder.setInternalCache(internalCache);
            }

            @Override
            public boolean connectionBecameIdle(
                    ConnectionPool pool, RealConnection connection) {
                return pool.connectionBecameIdle(connection);
            }

            @Override
            public RealConnection get(ConnectionPool pool, Address address,
                                      StreamAllocation streamAllocation, Route route) {
                return pool.get(address, streamAllocation, route);
            }

            @Override
            public boolean equalsNonHost(Address a, Address b) {
                return a.equalsNonHost(b);
            }

            @Override
            public Socket deduplicate(
                    ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
                return pool.deduplicate(address, streamAllocation);
            }

            @Override
            public void put(ConnectionPool pool, RealConnection connection) {
                pool.put(connection);
            }

            @Override
            public RouteDatabase routeDatabase(ConnectionPool connectionPool) {
                return connectionPool.routeDatabase;
            }

            @Override
            public int code(Response.Builder responseBuilder) {
                return responseBuilder.code;
            }

            @Override
            public void apply(ConnectionSuite tlsConfiguration, SSLSocket sslSocket, boolean isFallback) {
                tlsConfiguration.apply(sslSocket, isFallback);
            }

            @Override
            public boolean isInvalidHttpUrlHost(IllegalArgumentException e) {
                return e.getMessage().startsWith(UnoUrl.Builder.INVALID_HOST);
            }

            @Override
            public StreamAllocation streamAllocation(NewCall call) {
                return ((RealCall) call).streamAllocation();
            }

            @Override
            public IOException timeoutExit(NewCall call, IOException e) {
                return ((RealCall) call).timeoutExit(e);
            }

            @Override
            public NewCall newWebSocketCall(Httpd client, Request originalRequest) {
                return RealCall.newRealCall(client, originalRequest, true);
            }
        };
    }

    final Dispatcher dispatcher;
    final Proxy proxy;
    final List protocols;
    final List connectionSuites;
    /**
     * 返回一个不可变的拦截器列表,该列表观察每个调用的完整跨度:
     * 从建立连接之前(如果有的话)到选择响应源之后(源服务器、缓存或两者都有)
     */
    final List interceptors;
    /**
     * 返回观察单个网络请求和响应的不可变拦截器列表。这些拦截器必须
     * 调用{@link Interceptor.Chain#proceed} 只执行一次:网络拦截器短路或重复网络请求是错误的
     */
    final List networkInterceptors;
    final EventListener.Factory eventListenerFactory;
    final ProxySelector proxySelector;
    final CookieJar cookieJar;
    final Cache cache;
    final InternalCache internalCache;
    final SocketFactory socketFactory;
    final SSLSocketFactory sslSocketFactory;
    final CertificateChainCleaner certificateChainCleaner;
    final HostnameVerifier hostnameVerifier;
    final CertificatePinner certificatePinner;
    final Authenticator proxyAuthenticator;
    final Authenticator authenticator;
    final ConnectionPool connectionPool;
    final DnsX dns;
    final boolean followSslRedirects;
    final boolean followRedirects;
    final boolean retryOnConnectionFailure;
    /**
     * 默认调用超时(毫秒).
     */
    final int callTimeout;
    /**
     * 默认连接超时(毫秒).
     */
    final int connectTimeout;
    /**
     * 默认读超时(毫秒).
     */
    final int readTimeout;
    /**
     * 默认写超时(毫秒).
     */
    final int writeTimeout;
    /**
     * Web socket ping间隔(毫秒)
     */
    final int pingInterval;

    public Httpd() {
        this(new Builder());
    }

    Httpd(Builder builder) {
        this.dispatcher = builder.dispatcher;
        this.proxy = builder.proxy;
        this.protocols = builder.protocols;
        this.connectionSuites = builder.connectionSuites;
        this.interceptors = org.aoju.bus.http.Builder.immutableList(builder.interceptors);
        this.networkInterceptors = org.aoju.bus.http.Builder.immutableList(builder.networkInterceptors);
        this.eventListenerFactory = builder.eventListenerFactory;
        this.proxySelector = builder.proxySelector;
        this.cookieJar = builder.cookieJar;
        this.cache = builder.cache;
        this.internalCache = builder.internalCache;
        this.socketFactory = builder.socketFactory;

        boolean isTLS = false;
        for (ConnectionSuite spec : connectionSuites) {
            isTLS = isTLS || spec.isTls();
        }

        if (builder.sslSocketFactory != null || !isTLS) {
            this.sslSocketFactory = builder.sslSocketFactory;
            this.certificateChainCleaner = builder.certificateChainCleaner;
        } else {
            X509TrustManager trustManager = org.aoju.bus.http.secure.X509TrustManager.platformTrustManager();
            this.sslSocketFactory = newSslSocketFactory(trustManager);
            this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
        }

        if (sslSocketFactory != null) {
            Platform.get().configureSslSocketFactory(sslSocketFactory);
        }

        this.hostnameVerifier = builder.hostnameVerifier;
        this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
                certificateChainCleaner);
        this.proxyAuthenticator = builder.proxyAuthenticator;
        this.authenticator = builder.authenticator;
        this.connectionPool = builder.connectionPool;
        this.dns = builder.dns;
        this.followSslRedirects = builder.followSslRedirects;
        this.followRedirects = builder.followRedirects;
        this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
        this.callTimeout = builder.callTimeout;
        this.connectTimeout = builder.connectTimeout;
        this.readTimeout = builder.readTimeout;
        this.writeTimeout = builder.writeTimeout;
        this.pingInterval = builder.pingInterval;

        if (interceptors.contains(null)) {
            throw new IllegalStateException("Null interceptor: " + interceptors);
        }
        if (networkInterceptors.contains(null)) {
            throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
        }
    }

    private static SSLSocketFactory newSslSocketFactory(X509TrustManager trustManager) {
        try {
            SSLContext sslContext = Platform.get().getSSLContext();
            sslContext.init(null, new TrustManager[]{trustManager}, null);
            return sslContext.getSocketFactory();
        } catch (GeneralSecurityException e) {
            throw org.aoju.bus.http.Builder.assertionError("No System TLS", e);
        }
    }

    @Override
    public NewCall newCall(Request request) {
        return RealCall.newRealCall(this, request, false);
    }

    @Override
    public WebSocket newWebSocket(Request request, WebSocketListener listener) {
        RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
        webSocket.connect(this);
        return webSocket;
    }


    public int callTimeoutMillis() {
        return callTimeout;
    }

    public int connectTimeoutMillis() {
        return connectTimeout;
    }

    public int readTimeoutMillis() {
        return readTimeout;
    }

    public int writeTimeoutMillis() {
        return writeTimeout;
    }

    public int pingIntervalMillis() {
        return pingInterval;
    }

    public Proxy proxy() {
        return proxy;
    }

    public ProxySelector proxySelector() {
        return proxySelector;
    }

    public CookieJar cookieJar() {
        return cookieJar;
    }

    public Cache cache() {
        return cache;
    }

    InternalCache internalCache() {
        return cache != null ? cache.internalCache : internalCache;
    }

    public DnsX dns() {
        return dns;
    }

    public SocketFactory socketFactory() {
        return socketFactory;
    }

    public SSLSocketFactory sslSocketFactory() {
        return sslSocketFactory;
    }

    public HostnameVerifier hostnameVerifier() {
        return hostnameVerifier;
    }

    public CertificatePinner certificatePinner() {
        return certificatePinner;
    }

    public Authenticator authenticator() {
        return authenticator;
    }

    public Authenticator proxyAuthenticator() {
        return proxyAuthenticator;
    }

    public ConnectionPool connectionPool() {
        return connectionPool;
    }

    public boolean followSslRedirects() {
        return followSslRedirects;
    }

    public boolean followRedirects() {
        return followRedirects;
    }

    public boolean retryOnConnectionFailure() {
        return retryOnConnectionFailure;
    }

    public Dispatcher dispatcher() {
        return dispatcher;
    }

    public List protocols() {
        return protocols;
    }

    public List connectionSpecs() {
        return connectionSuites;
    }

    public List interceptors() {
        return interceptors;
    }

    public List networkInterceptors() {
        return networkInterceptors;
    }

    public EventListener.Factory eventListenerFactory() {
        return eventListenerFactory;
    }


    public Builder newBuilder() {
        return new Builder(this);
    }

    public static final class Builder {
        final List interceptors = new ArrayList<>();
        final List networkInterceptors = new ArrayList<>();
        Dispatcher dispatcher;
        Proxy proxy;
        List protocols;
        List connectionSuites;

        EventListener.Factory eventListenerFactory;
        ProxySelector proxySelector;
        CookieJar cookieJar;
        Cache cache;
        InternalCache internalCache;
        SocketFactory socketFactory;
        SSLSocketFactory sslSocketFactory;
        CertificateChainCleaner certificateChainCleaner;
        HostnameVerifier hostnameVerifier;
        CertificatePinner certificatePinner;
        Authenticator proxyAuthenticator;
        Authenticator authenticator;
        ConnectionPool connectionPool;
        DnsX dns;
        boolean followSslRedirects;
        boolean followRedirects;
        boolean retryOnConnectionFailure;
        int callTimeout;
        int connectTimeout;
        int readTimeout;
        int writeTimeout;
        int pingInterval;

        public Builder() {
            dispatcher = new Dispatcher();
            protocols = DEFAULT_PROTOCOLS;
            connectionSuites = DEFAULT_CONNECTION_SPECS;
            eventListenerFactory = EventListener.factory(EventListener.NONE);
            proxySelector = ProxySelector.getDefault();
            if (proxySelector == null) {
                proxySelector = new NullProxySelector();
            }
            cookieJar = CookieJar.NO_COOKIES;
            socketFactory = SocketFactory.getDefault();
            hostnameVerifier = OkHostnameVerifier.INSTANCE;
            certificatePinner = CertificatePinner.DEFAULT;
            proxyAuthenticator = Authenticator.NONE;
            authenticator = Authenticator.NONE;
            connectionPool = new ConnectionPool();
            dns = DnsX.SYSTEM;
            followSslRedirects = true;
            followRedirects = true;
            retryOnConnectionFailure = true;
            callTimeout = 0;
            connectTimeout = 10_000;
            readTimeout = 10_000;
            writeTimeout = 10_000;
            pingInterval = 0;
        }

        Builder(Httpd httpd) {
            this.dispatcher = httpd.dispatcher;
            this.proxy = httpd.proxy;
            this.protocols = httpd.protocols;
            this.connectionSuites = httpd.connectionSuites;
            this.interceptors.addAll(httpd.interceptors);
            this.networkInterceptors.addAll(httpd.networkInterceptors);
            this.eventListenerFactory = httpd.eventListenerFactory;
            this.proxySelector = httpd.proxySelector;
            this.cookieJar = httpd.cookieJar;
            this.internalCache = httpd.internalCache;
            this.cache = httpd.cache;
            this.socketFactory = httpd.socketFactory;
            this.sslSocketFactory = httpd.sslSocketFactory;
            this.certificateChainCleaner = httpd.certificateChainCleaner;
            this.hostnameVerifier = httpd.hostnameVerifier;
            this.certificatePinner = httpd.certificatePinner;
            this.proxyAuthenticator = httpd.proxyAuthenticator;
            this.authenticator = httpd.authenticator;
            this.connectionPool = httpd.connectionPool;
            this.dns = httpd.dns;
            this.followSslRedirects = httpd.followSslRedirects;
            this.followRedirects = httpd.followRedirects;
            this.retryOnConnectionFailure = httpd.retryOnConnectionFailure;
            this.callTimeout = httpd.callTimeout;
            this.connectTimeout = httpd.connectTimeout;
            this.readTimeout = httpd.readTimeout;
            this.writeTimeout = httpd.writeTimeout;
            this.pingInterval = httpd.pingInterval;
        }

        /**
         * 设置完成调用的默认超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param timeout 超时时间
         * @param unit    计算单位
         * @return 构造器
         */
        public Builder callTimeout(long timeout, TimeUnit unit) {
            callTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
            return this;
        }

        /**
         * 设置完成调用的默认超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param duration 持续时间
         * @return 构造器
         */
        public Builder callTimeout(Duration duration) {
            callTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置新连接的默认连接超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param timeout 超时时间
         * @param unit    计算单位
         * @return 构造器
         */
        public Builder connectTimeout(long timeout, TimeUnit unit) {
            connectTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
            return this;
        }

        /**
         * 设置新连接的默认连接超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param duration 持续时间
         * @return 构造器
         */
        public Builder connectTimeout(Duration duration) {
            connectTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置新连接的默认读取超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param timeout 超时时间
         * @param unit    计算单位
         * @return 构造器
         * @see Socket#setSoTimeout(int)
         * @see Source#timeout()
         */
        public Builder readTimeout(long timeout, TimeUnit unit) {
            readTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
            return this;
        }

        /**
         * 设置新连接的默认读取超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param duration 持续时间
         * @return 构造器
         * @see Socket#setSoTimeout(int)
         * @see Source#timeout()
         */
        public Builder readTimeout(Duration duration) {
            readTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置新连接的默认写超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param timeout 超时时间
         * @param unit    计算单位
         * @return 构造器
         * @see Sink#timeout()
         */
        public Builder writeTimeout(long timeout, TimeUnit unit) {
            writeTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
            return this;
        }

        /**
         * 设置新连接的默认写超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
         *
         * @param duration 持续时间
         * @return 构造器
         * @see Sink#timeout()
         */
        public Builder writeTimeout(Duration duration) {
            writeTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置此客户端发起的HTTP/2和web套接字ping之间的间隔。使用此命令可自动发送ping帧,直到连接失败或关闭
         * 这将保持连接处于活动状态,并可能检测到连接失败.
         *
         * @param interval 间隔时间
         * @param unit     计算单位
         * @return 构造器
         */
        public Builder pingInterval(long interval, TimeUnit unit) {
            pingInterval = org.aoju.bus.http.Builder.checkDuration("interval", interval, unit);
            return this;
        }

        /**
         * 设置此客户端发起的HTTP/2和web套接字ping之间的间隔。使用此命令可自动发送ping帧,
         * 直到连接失败或关闭。这将保持连接处于活动状态,并可能检测到连接失败.
         *
         * @param duration 持续时间
         * @return 构造器
         */
        public Builder pingInterval(Duration duration) {
            pingInterval = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置此客户端创建的连接将使用的HTTP代理。它优先于{@link #proxySelector},
         * 后者仅在此代理为空(默认为空)时才被启用。要完全禁用代理使用,请调用{@code proxy(proxy . no_proxy)}
         *
         * @param proxy 代理
         * @return 构造器
         */
        public Builder proxy(Proxy proxy) {
            this.proxy = proxy;
            return this;
        }

        /**
         * 如果没有显式指定{@link #proxy proxy},则设置要使用的代理选择策略。代理选择器可以返回多个代理;在这种情况下,
         * 将依次对它们进行测试,直到建立成功的连接.
         *
         * @param proxySelector 代理选择器
         * @return 构造器
         */
        public Builder proxySelector(ProxySelector proxySelector) {
            if (proxySelector == null) throw new NullPointerException("proxySelector == null");
            this.proxySelector = proxySelector;
            return this;
        }

        /**
         * 设置可以接受来自传入HTTP响应的cookie并向传出HTTP请求提供cookie的处理程序.
         *
         * @param cookieJar cookie策略
         * @return 构造器
         */
        public Builder cookieJar(CookieJar cookieJar) {
            if (cookieJar == null) throw new NullPointerException("cookieJar == null");
            this.cookieJar = cookieJar;
            return this;
        }

        /**
         * 设置用于读写缓存的响应的响应缓存.
         *
         * @param internalCache 响应缓存
         */
        void setInternalCache(InternalCache internalCache) {
            this.internalCache = internalCache;
            this.cache = null;
        }

        /**
         * 设置用于读写缓存的响应的响应缓存.
         *
         * @param cache 缓存支持
         * @return 构造器
         */
        public Builder cache(Cache cache) {
            this.cache = cache;
            this.internalCache = null;
            return this;
        }

        /**
         * 设置用于查找主机名的IP地址的DNS服务.
         * 如果未设置,将使用{@link DnsX#SYSTEM system-wide default}DNS
         *
         * @param dns DNS服务
         * @return 构造器
         */
        public Builder dns(DnsX dns) {
            if (dns == null) throw new NullPointerException("dns == null");
            this.dns = dns;
            return this;
        }

        /**
         * 设置用于创建连接的套接字工厂。Httpd只使用无参数的{@link SocketFactory#createSocket()}
         * 方法来创建未连接的套接字。重写这个方法,例如。,允许将套接字绑定到特定的本地地址
         * 如果未设置,将使用{@link SocketFactory#getDefault() system-wide default}socket工厂
         *
         * @param socketFactory socket工厂
         * @return 构造器
         */
        public Builder socketFactory(SocketFactory socketFactory) {
            if (socketFactory == null) throw new NullPointerException("socketFactory == null");
            this.socketFactory = socketFactory;
            return this;
        }

        /**
         * 设置用于保护HTTPS连接的套接字工厂。如果未设置,则使用系统默认值
         *
         * @param sslSocketFactory socket工厂
         * @return 构造器
         */
        public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) {
            if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
            this.sslSocketFactory = sslSocketFactory;
            this.certificateChainCleaner = Platform.get().buildCertificateChainCleaner(sslSocketFactory);
            return this;
        }

        /**
         * 设置用于保护HTTPS连接的套接字工厂和信任管理器。如果未设置,则使用系统默认值
         * 大多数应用程序不应该调用这个方法,而应该使用系统默认值。这些类包含特殊的优化,如果实现被修饰,这些优化可能会丢失
         * 
         * {@code
         *
         *   TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
         *       TrustManagerFactory.getDefaultAlgorithm());
         *   trustManagerFactory.init((KeyStore) null);
         *   TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
         *   if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
         *     throw new IllegalStateException("Unexpected default trust managers:"
         *         + Arrays.toString(trustManagers));
         *   }
         *   X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
         *
         *   SSLContext sslContext = SSLContext.getInstance("TLS");
         *   sslContext.init(null, new TrustManager[] { trustManager }, null);
         *   SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
         *
         *   Httpd client = new Httpd.Builder()
         *       .sslSocketFactory(sslSocketFactory, trustManager)
         *       .build();
         * }
         * 
* * @param sslSocketFactory ssl socket工厂 * @param trustManager X509证书身份验证 * @return 构造器 */ public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); if (trustManager == null) throw new NullPointerException("trustManager == null"); this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); return this; } /** * 设置用于确认响应证书适用于HTTPS连接请求的主机名的验证程序. * 如果未设置,将使用默认的主机名验证器 * * @param hostnameVerifier 验证主机名接口 * @return 构造器 */ public Builder hostnameVerifier(HostnameVerifier hostnameVerifier) { if (hostnameVerifier == null) throw new NullPointerException("hostnameVerifier == null"); this.hostnameVerifier = hostnameVerifier; return this; } /** * 设置限制哪些证书受信任的证书pinner。默认情况下,HTTPS连接仅 * 依赖于{@link #sslSocketFactory SSL套接字工厂}来建立信任。 * 固定证书避免了信任证书颁发机构的需要。 * * @param certificatePinner 证书 * @return 构造器 */ public Builder certificatePinner(CertificatePinner certificatePinner) { if (certificatePinner == null) throw new NullPointerException("certificatePinner == null"); this.certificatePinner = certificatePinner; return this; } /** * 设置用于响应来自源服务器的挑战的验证器。使用{@link #proxyAuthenticator}设置代理服务器的身份验证器. * * @param authenticator 验证器 * @return 构造器 */ public Builder authenticator(Authenticator authenticator) { if (authenticator == null) throw new NullPointerException("authenticator == null"); this.authenticator = authenticator; return this; } /** * 设置用于响应来自代理服务器的挑战的验证器。使用{@link #authenticator}设置源服务器的身份验证器 * 果未设置,将尝试{@linkplain Authenticator#NONE no authentication will be attempted} * * @param proxyAuthenticator 代理验证器 * @return 构造器 */ public Builder proxyAuthenticator(Authenticator proxyAuthenticator) { if (proxyAuthenticator == null) throw new NullPointerException("proxyAuthenticator == null"); this.proxyAuthenticator = proxyAuthenticator; return this; } /** * 设置用于回收HTTP和HTTPS连接的连接池. * 如果未设置,将使用新的连接池 * * @param connectionPool 连接池信息 * @return 构造器 */ public Builder connectionPool(ConnectionPool connectionPool) { if (connectionPool == null) throw new NullPointerException("connectionPool == null"); this.connectionPool = connectionPool; return this; } /** * 让这个客户从HTTPS到HTTPS跟踪和从HTTPS到HTTPS. * 如果未设置,将遵循协议重定向。这与内置的{@code HttpURLConnection}的默认设置不同 * * @param followProtocolRedirects 重定向 * @return 构造器 */ public Builder followSslRedirects(boolean followProtocolRedirects) { this.followSslRedirects = followProtocolRedirects; return this; } /** * 此客户端配置为遵循重定向。如果未设置,将遵循重定向. * * @param followRedirects 重定向 * @return 构造器 */ public Builder followRedirects(boolean followRedirects) { this.followRedirects = followRedirects; return this; } /** * 在遇到连接问题时,将此客户端配置为重试或不重试 * 将此设置为false,以避免在这样做会造成破坏时重试请求 * 在这种情况下,调用应用程序应该自己恢复连接故障. * * @param retryOnConnectionFailure 失败重试 * @return 构造器 */ public Builder retryOnConnectionFailure(boolean retryOnConnectionFailure) { this.retryOnConnectionFailure = retryOnConnectionFailure; return this; } /** * 设置用于设置策略和执行异步请求的调度程序。不能为空. * * @param dispatcher 调度程序分配器 * @return 构造器 */ public Builder dispatcher(Dispatcher dispatcher) { if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null"); this.dispatcher = dispatcher; return this; } /** * 配置此客户端使用的协议以与远程服务器通信。默认情况下,该客户机将选择最有效的传输方式 * 退回到更普遍的协议。应用程序应该只调用这个方法来避免特定的兼容性问题,比如在启用HTTP/2时web服务器的行为不正确. * * @param protocols 使用的协议,按优先顺序排列。如果列表包含{@link Protocol#H2_PRIOR_KNOWLEDGE}, * 那么它必须是唯一的协议,并且不支持HTTPS url。否则列表必须包含{@link Protocol#HTTP_1_1}。 * 该列表不能包含null或{@link Protocol#HTTP_1_0}. * @return 构造器 */ public Builder protocols(List protocols) { // 创建列表的私有副本 protocols = new ArrayList<>(protocols); // 验证该列表包含我们需要的所有内容,没有我们禁止的内容. if (!protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE) && !protocols.contains(Protocol.HTTP_1_1)) { throw new IllegalArgumentException( "protocols must contain h2_prior_knowledge or http/1.1: " + protocols); } if (protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE) && protocols.size() > 1) { throw new IllegalArgumentException( "protocols containing h2_prior_knowledge cannot use other protocols: " + protocols); } if (protocols.contains(Protocol.HTTP_1_0)) { throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols); } if (protocols.contains(null)) { throw new IllegalArgumentException("protocols must not contain null"); } // 删除不再支持的协议 protocols.remove(Protocol.SPDY_3); // 指定为不可修改的列表。这是有效不可变的. this.protocols = Collections.unmodifiableList(protocols); return this; } public Builder connectionSpecs(List connectionSuites) { this.connectionSuites = org.aoju.bus.http.Builder.immutableList(connectionSuites); return this; } /** * 返回一个可修改的拦截器列表,该列表观察每个调用的完整跨度: * 从建立连接之前(如果有的话)到选择响应源之后(源服务器、缓存或两者都有). * * @return 构造器 */ public List interceptors() { return interceptors; } public Builder addInterceptor(Interceptor interceptor) { if (interceptor == null) throw new IllegalArgumentException("interceptor == null"); interceptors.add(interceptor); return this; } /** * 返回观察单个网络请求和响应的可修改的拦截器列表。 * 这些拦截器必须调用{@link Interceptor.Chain#proceed} * 只执行一次:网络拦截器短路或重复网络请求是错误的 * * @return 构造器 */ public List networkInterceptors() { return networkInterceptors; } public Builder addNetworkInterceptor(Interceptor interceptor) { if (interceptor == null) throw new IllegalArgumentException("interceptor == null"); networkInterceptors.add(interceptor); return this; } /** * 配置单个客户机作用域侦听器,该侦听器将接收此客户机的所有分析事件. * * @param eventListener 监听器 * @return 构造器 */ public Builder eventListener(EventListener eventListener) { if (eventListener == null) throw new NullPointerException("eventListener == null"); this.eventListenerFactory = EventListener.factory(eventListener); return this; } /** * 配置工厂以提供每个调用范围的侦听器,这些侦听器将接收此客户机的分析事件 * * @param eventListenerFactory 监听工厂信息 * @return 构造器 */ public Builder eventListenerFactory(EventListener.Factory eventListenerFactory) { if (eventListenerFactory == null) { throw new NullPointerException("eventListenerFactory == null"); } this.eventListenerFactory = eventListenerFactory; return this; } public Httpd build() { return new Httpd(this); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy