RequestDispatch.java

package org.jsoup.helper;

import org.jsoup.internal.SharedConstants;
import org.jspecify.annotations.Nullable;

import static org.jsoup.helper.HttpConnection.Request;
import static org.jsoup.helper.HttpConnection.Response;

import java.lang.reflect.Constructor;

/**
 Handles requests using either HttpClient (available in JVM 11+) or HttpURLConnection. During initialization, the
 HttpClientExecutor class is used if it can be instantiated, unless the system property
 {@link SharedConstants#UseHttpClient} is explicitly set to {@code false}.
 */
class RequestDispatch {

    @Nullable
    static Constructor<RequestExecutor> clientConstructor;

    static {
        try {
            //noinspection unchecked
            Class<RequestExecutor> httpClass =
                (Class<RequestExecutor>) Class.forName("org.jsoup.helper.HttpClientExecutor");
            clientConstructor = httpClass.getConstructor(Request.class, Response.class);
        } catch (Exception ignored) {
            // either not on Java11+, or on Android; will provide UrlConnectionExecutor
        }

    }

    static RequestExecutor get(Request request, @Nullable Response previousResponse) {
        boolean useHttpClient = Boolean.parseBoolean(System.getProperty(SharedConstants.UseHttpClient, "true"));

        if (request.sslSocketFactory() != null) // downgrade if a socket factory is set, as it can't be supplied to the HttpClient
            useHttpClient = false;

        if (useHttpClient && clientConstructor != null) {
            try {
                return clientConstructor.newInstance(request, previousResponse);
            } catch (Exception e) {
                return new UrlConnectionExecutor(request, previousResponse);
            }
        } else {
            return new UrlConnectionExecutor(request, previousResponse);
        }
    }
}