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

io.github.wycst.wast.clients.http.url.UrlHttpClientExecutor Maven / Gradle / Ivy

package io.github.wycst.wast.clients.http.url;

import io.github.wycst.wast.clients.http.definition.*;
import io.github.wycst.wast.clients.http.impl.HttpClientResponseImpl;
import io.github.wycst.wast.clients.http.provider.RequestServiceInstance;
import io.github.wycst.wast.clients.http.provider.ServiceInstance;
import io.github.wycst.wast.common.utils.IOUtils;
import io.github.wycst.wast.json.JSON;
import io.github.wycst.wast.log.Log;
import io.github.wycst.wast.log.LogFactory;

import java.io.*;
import java.net.*;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author: wangy
 * @Date: 2020/7/4 10:41
 * @Description:
 */
public class UrlHttpClientExecutor extends AbstractUrlHttpClientExecutor {

    // log
    private Log log = LogFactory.getLog(UrlHttpClientExecutor.class);

    @Override
    public final byte[] fastGetBody(String targetUrl, Map headers) {
        HttpURLConnection connection = null;
        try {
            connection = connection(targetUrl, headers);
            return IOUtils.readBytes(getInputStream(connection));
        } catch (Throwable throwable) {
            throw clientException(throwable);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    @Override
    public InputStream fastGetInputStream(String targetUrl, Map headers) {
        try {
            return getInputStream(connection(targetUrl, headers));
        } catch (Throwable throwable) {
            throw clientException(throwable);
        }
    }

    private HttpClientException clientException(Throwable throwable) {
        if(throwable instanceof HttpClientException) {
            return (HttpClientException) throwable;
        }
        return new HttpClientException(throwable.getMessage(), throwable);
    }

    final HttpURLConnection connection(String targetUrl, Map headers) {
        HttpURLConnection httpConnection;
        try {
            URL url = new URL(targetUrl);
            httpConnection = (HttpURLConnection) url.openConnection();
            httpConnection.setRequestMethod("GET");
            if (headers != null) {
                Set> entries = headers.entrySet();
                for (Map.Entry entry : entries) {
                    httpConnection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            return httpConnection;
        } catch (Throwable throwable) {
            throw new HttpClientException(throwable.getMessage(), throwable);
        }
    }

    final InputStream getInputStream(HttpURLConnection httpConnection) throws IOException {
        InputStream is;
        try {
            int resCode = httpConnection.getResponseCode();
            boolean httpOk = resCode == HttpURLConnection.HTTP_OK;
            if (httpOk) {
                is = httpConnection.getInputStream();
            } else {
                is = httpConnection.getErrorStream();
            }
            if (is == null) {
                is = httpOk ? httpConnection.getErrorStream() : httpConnection.getInputStream();
            }
            return is;
        } catch (Throwable throwable) {
            throw clientException(throwable);
        }
    }

    @Override
    protected HttpClientResponse doExecuteRequest(HttpClientRequest httpRequest) throws Throwable {
        RequestServiceInstance requestServiceInstance = getRequestServiceInstance(httpRequest);
        try {
            return this.doExecuteRequestInstance(requestServiceInstance, httpRequest);
        } catch (Throwable throwable) {
            // Timeout or connection failure
            ServiceInstance serviceInstance = requestServiceInstance.getServiceInstance();
            // if null throw exception
            if (serviceInstance == null) {
                // Non load balancing mode
                throw throwable;
            }

            // load balancing mode keepAlive instance
            boolean keepAliveOnTimeout = isKeepAliveOnTimeout() || httpRequest.isKeepAliveOnTimeout();
            if (keepAliveOnTimeout && throwable instanceof SocketTimeoutException) {
                throw throwable;
            }

            // mark instance disable and switch next instance
            // This step is crucial
            serviceInstance.setAlive(false);
            // Recursive repeated call
            // How to prevent dead circulation ?
            return doExecuteRequest(httpRequest);
        }
    }

    private HttpClientResponse doExecuteRequestInstance(RequestServiceInstance requestServiceInstance, HttpClientRequest httpRequest) throws Throwable {

        URL instanceUrl = requestServiceInstance.getUrl();
        String method = httpRequest.getMethod();
        log.debug("{} {} ", method, instanceUrl);
        HttpClientConfig clientConfig = httpRequest.getHttpClientConfig();
        URL url = parseQueryUrl(instanceUrl, method, clientConfig);
        Proxy proxy = clientConfig.getProxy();
        HttpURLConnection httpConnection = null;
        if (proxy == null) {
            httpConnection = (HttpURLConnection) url.openConnection();
        } else {
            httpConnection = (HttpURLConnection) url.openConnection(proxy);
        }

        httpConnection.setRequestMethod(method);
        httpConnection.setConnectTimeout((int) clientConfig.getMaxConnectTimeout());
        httpConnection.setReadTimeout((int) clientConfig.getMaxReadTimeout());
        httpConnection.setUseCaches(clientConfig.isUseCaches());
        httpConnection.setInstanceFollowRedirects(clientConfig.isFollowRedirect());

        Map header = clientConfig.getHeaders();
        if (header != null) {
            for (Map.Entry entry : header.entrySet()) {
                httpConnection.setRequestProperty(entry.getKey().toLowerCase(), String.valueOf(entry.getValue()));
            }
        }
        httpConnection.setRequestProperty("content-type", clientConfig.getContentType());
        if ("POST".equals(method) || "PUT".equals(method)) {
            postRequestData(clientConfig, httpConnection);
        }
        int resCode = httpConnection.getResponseCode();
        int contentLength = httpConnection.getContentLength();

        String resContentType = httpConnection.getContentType();
        InputStream is = null;
        try {
            boolean httpOk = resCode == HttpURLConnection.HTTP_OK;
            if (httpOk) {
                is = httpConnection.getInputStream();
            } else {
                is = httpConnection.getErrorStream();
            }
            if (is == null) {
                is = httpOk ? httpConnection.getErrorStream() : httpConnection.getInputStream();
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        HttpClientResponse clientResponse = new HttpClientResponseImpl(resCode, httpConnection.getResponseMessage(), is, contentLength);
        clientResponse.setContentType(resContentType);
        clientResponse.setHeaders(httpConnection.getHeaderFields());

        httpConnection.disconnect();

        return clientResponse;
    }

    private void postRequestData(HttpClientConfig clientConfig, HttpURLConnection httpConnection) throws IOException {

        byte[] postData = parsePostRequestData(clientConfig);
        // There is actually no need to set content length here, Content-Length key value will auto calculation and write to the header by HttpURLConnection
        httpConnection.setRequestProperty("content-length", String.valueOf(postData.length));

        // Support IO streaming
        httpConnection.setDoOutput(true);
        httpConnection.connect();

        DataOutputStream dataOutputStream = new DataOutputStream(httpConnection.getOutputStream());
        dataOutputStream.write(postData);

        // flush
        dataOutputStream.flush();
        dataOutputStream.close();

    }

    private byte[] parsePostRequestData(HttpClientConfig clientConfig) throws IOException {

        byte[] requestData = null;
        List clientParameters = clientConfig.getParameterList();
        boolean chunked = clientConfig.isChunked();
        boolean multipart = clientConfig.isMultipart();
        String boundary = clientConfig.getBoundary();
        if (multipart) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            String formDataSeparator = "--" + boundary;
            byte[] lineSign = new byte[]{'\r', '\n'};
            StringBuilder builder = null;
            for (HttpClientParameter clientParameter : clientParameters) {
                baos.write(formDataSeparator.getBytes());
                baos.write(lineSign);

                String name = clientParameter.getName();
                String value = clientParameter.getValue();
                String itemContentType = clientParameter.getContentType();
                long contentLength = clientParameter.getContentLength();

                builder = new StringBuilder();
                if (clientParameter.isFileUpload()) {
                    builder.append("content-disposition: form-data; name=\"").append(name).append("\"; filename=\"").append(value).append("\"\r\n");
                    builder.append("content-transfer-encoding: binary").append("\r\n");
                } else {
                    builder.append("content-disposition: form-data; name=\"").append(name).append("\"\r\n");
                }
                builder.append("content-length: ").append(contentLength).append("\r\n");
                if (itemContentType != null && itemContentType.length() > 0) {
                    builder.append("content-type: ").append(itemContentType).append("\r\n");
                }
                builder.append("\r\n");
                baos.write(builder.toString().getBytes());
                clientParameter.writeContentTo(baos);
                baos.write(lineSign);
            }
            baos.write(("--" + boundary + "--").getBytes());
            baos.write(lineSign);

            requestData = baos.toByteArray();
        } else if (chunked) {

        } else {
            Object requestBody = clientConfig.getRequestBody();
            if (requestBody != null) {
                boolean applicationJson = clientConfig.isApplicationJson();
                if (applicationJson) {
                    String content = requestBody == null ? "" : JSON.toJsonString(requestBody);
                    return content.getBytes();
                } else {
                    if (requestBody instanceof byte[]) {
                        return (byte[]) requestBody;
                    }
                    return requestBody.toString().getBytes();
                }
            } else {
                StringBuilder builder = new StringBuilder();
                int length = clientParameters.size();
                int i = 0;
                for (HttpClientParameter clientParameter : clientParameters) {
                    builder.append(URLEncoder.encode(clientParameter.getName(), "UTF-8")).append('=').append(URLEncoder.encode(clientParameter.getValue(), "UTF-8"));
                    if (i++ < length - 1) {
                        builder.append('&');
                    }
                }
                requestData = builder.toString().getBytes();
            }
        }
        return requestData;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy