001/**
002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package com.mybatisflex.core.audit.http;
017
018import com.mybatisflex.core.util.StringUtil;
019import org.apache.ibatis.logging.LogFactory;
020
021import javax.net.ssl.*;
022import java.io.IOException;
023import java.io.InputStreamReader;
024import java.io.OutputStream;
025import java.io.UnsupportedEncodingException;
026import java.net.HttpURLConnection;
027import java.net.URL;
028import java.net.URLEncoder;
029import java.security.KeyManagementException;
030import java.security.NoSuchAlgorithmException;
031import java.security.NoSuchProviderException;
032import java.security.cert.CertificateException;
033import java.security.cert.X509Certificate;
034import java.util.Map;
035import java.util.Map.Entry;
036
037
038public class HttpUtil {
039
040    private static final String POST = "POST";
041
042
043    private static String CHARSET = "UTF-8";
044    private static int connectTimeout = 15000;    // 连接超时,单位毫秒
045    private static int readTimeout = 15000;        // 读取超时,单位毫秒
046
047    private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();
048
049    private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new TrustAnyHostnameVerifier();
050
051    /**
052     * https 域名校验
053     */
054    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
055        @Override
056        public boolean verify(String hostname, SSLSession session) {
057            return true;
058        }
059    }
060
061    /**
062     * https 证书管理
063     */
064    private static class TrustAnyTrustManager implements X509TrustManager {
065        @Override
066        public X509Certificate[] getAcceptedIssuers() {
067            return null;
068        }
069
070        @Override
071        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
072        }
073
074        @Override
075        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
076        }
077    }
078
079
080    private static SSLSocketFactory initSSLSocketFactory() {
081        try {
082            TrustManager[] tm = {new HttpUtil.TrustAnyTrustManager()};
083            SSLContext sslContext = SSLContext.getInstance("TLS");    // ("TLS", "SunJSSE");
084            sslContext.init(null, tm, new java.security.SecureRandom());
085            return sslContext.getSocketFactory();
086        } catch (Exception e) {
087            throw new RuntimeException(e);
088        }
089    }
090
091    public static void setCharSet(String charSet) {
092        if (StringUtil.isBlank(charSet)) {
093            throw new IllegalArgumentException("charSet can not be blank.");
094        }
095        HttpUtil.CHARSET = charSet;
096    }
097
098    public static void setConnectTimeout(int connectTimeout) {
099        HttpUtil.connectTimeout = connectTimeout;
100    }
101
102    public static void setReadTimeout(int readTimeout) {
103        HttpUtil.readTimeout = readTimeout;
104    }
105
106    private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
107        URL _url = new URL(url);
108        HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
109        if (conn instanceof HttpsURLConnection) {
110            ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
111            ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier);
112        }
113
114        conn.setRequestMethod(method);
115        conn.setDoOutput(true);
116        conn.setDoInput(true);
117
118        conn.setConnectTimeout(connectTimeout);
119        conn.setReadTimeout(readTimeout);
120
121        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
122
123        if (headers != null && !headers.isEmpty()) {
124            for (Entry<String, String> entry : headers.entrySet()) {
125                conn.setRequestProperty(entry.getKey(), entry.getValue());
126            }
127        }
128
129        return conn;
130    }
131
132
133    /**
134     * Send POST request
135     */
136    public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {
137        HttpURLConnection conn = null;
138        try {
139            conn = getHttpConnection(buildUrlQuery(url, queryParas), POST, headers);
140            conn.connect();
141
142            if (data != null) {
143                try (OutputStream out = conn.getOutputStream()) {
144                    out.write(data.getBytes(CHARSET));
145                    out.flush();
146                }
147            }
148            return readString(conn);
149        } catch (IOException e) {
150            LogFactory.getLog(HttpUtil.class).error("post error.", e);
151            return null;
152        } catch (Exception e) {
153            throw new RuntimeException(e);
154        } finally {
155            if (conn != null) {
156                conn.disconnect();
157            }
158        }
159    }
160
161    public static String post(String url, Map<String, String> queryParas, String data) {
162        return post(url, queryParas, data, null);
163    }
164
165    public static String post(String url, String data, Map<String, String> headers) {
166        return post(url, null, data, headers);
167    }
168
169    public static String post(String url, String data) {
170        return post(url, null, data, null);
171    }
172
173    private static String readString(HttpURLConnection conn) throws IOException {
174        try (InputStreamReader isr = new InputStreamReader(conn.getInputStream(), CHARSET)) {
175            StringBuilder ret = new StringBuilder();
176            char[] buf = new char[1024];
177            for (int num; (num = isr.read(buf, 0, buf.length)) != -1; ) {
178                ret.append(buf, 0, num);
179            }
180            return ret.toString();
181        }
182    }
183
184
185    private static String buildUrlQuery(String url, Map<String, String> queryParas) {
186        if (queryParas == null || queryParas.isEmpty()) {
187            return url;
188        }
189
190        StringBuilder sb = new StringBuilder(url);
191        boolean isFirst;
192        if (url.indexOf('?') == -1) {
193            isFirst = true;
194            sb.append('?');
195        } else {
196            isFirst = false;
197        }
198
199        for (Entry<String, String> entry : queryParas.entrySet()) {
200            if (isFirst) {
201                isFirst = false;
202            } else {
203                sb.append('&');
204            }
205
206            String key = entry.getKey();
207            String value = entry.getValue();
208            if (StringUtil.isNotBlank(value)) {
209                try {
210                    value = URLEncoder.encode(value, CHARSET);
211                } catch (UnsupportedEncodingException e) {
212                    throw new RuntimeException(e);
213                }
214            }
215            sb.append(key).append('=').append(value);
216        }
217        return sb.toString();
218    }
219
220
221}
222
223
224
225
226
227