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 HttpUtil() {}
041
042    private static final String POST = "POST";
043
044
045    private static String CHARSET = "UTF-8";
046    private static int connectTimeout = 15000;    // 连接超时,单位毫秒
047    private static int readTimeout = 15000;        // 读取超时,单位毫秒
048
049    private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();
050
051    private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new TrustAnyHostnameVerifier();
052
053    /**
054     * https 域名校验
055     */
056    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
057        @Override
058        public boolean verify(String hostname, SSLSession session) {
059            return true;
060        }
061    }
062
063    /**
064     * https 证书管理
065     */
066    private static class TrustAnyTrustManager implements X509TrustManager {
067        @Override
068        public X509Certificate[] getAcceptedIssuers() {
069            return null;
070        }
071
072        @Override
073        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
074        }
075
076        @Override
077        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
078        }
079    }
080
081
082    private static SSLSocketFactory initSSLSocketFactory() {
083        try {
084            TrustManager[] tm = {new HttpUtil.TrustAnyTrustManager()};
085            SSLContext sslContext = SSLContext.getInstance("TLS");    // ("TLS", "SunJSSE");
086            sslContext.init(null, tm, new java.security.SecureRandom());
087            return sslContext.getSocketFactory();
088        } catch (Exception e) {
089            throw new RuntimeException(e);
090        }
091    }
092
093    public static void setCharSet(String charSet) {
094        if (StringUtil.isBlank(charSet)) {
095            throw new IllegalArgumentException("charSet can not be blank.");
096        }
097        HttpUtil.CHARSET = charSet;
098    }
099
100    public static void setConnectTimeout(int connectTimeout) {
101        HttpUtil.connectTimeout = connectTimeout;
102    }
103
104    public static void setReadTimeout(int readTimeout) {
105        HttpUtil.readTimeout = readTimeout;
106    }
107
108    private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
109        URL _url = new URL(url);
110        HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
111        if (conn instanceof HttpsURLConnection) {
112            ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
113            ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier);
114        }
115
116        conn.setRequestMethod(method);
117        conn.setDoOutput(true);
118        conn.setDoInput(true);
119
120        conn.setConnectTimeout(connectTimeout);
121        conn.setReadTimeout(readTimeout);
122
123        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
124
125        if (headers != null && !headers.isEmpty()) {
126            for (Entry<String, String> entry : headers.entrySet()) {
127                conn.setRequestProperty(entry.getKey(), entry.getValue());
128            }
129        }
130
131        return conn;
132    }
133
134
135    /**
136     * Send POST request
137     */
138    public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {
139        HttpURLConnection conn = null;
140        try {
141            conn = getHttpConnection(buildUrlQuery(url, queryParas), POST, headers);
142            conn.connect();
143
144            if (data != null) {
145                try (OutputStream out = conn.getOutputStream()) {
146                    out.write(data.getBytes(CHARSET));
147                    out.flush();
148                }
149            }
150            return readString(conn);
151        } catch (IOException e) {
152            LogFactory.getLog(HttpUtil.class).error("post error.", e);
153            return null;
154        } catch (Exception e) {
155            throw new RuntimeException(e);
156        } finally {
157            if (conn != null) {
158                conn.disconnect();
159            }
160        }
161    }
162
163    public static String post(String url, Map<String, String> queryParas, String data) {
164        return post(url, queryParas, data, null);
165    }
166
167    public static String post(String url, String data, Map<String, String> headers) {
168        return post(url, null, data, headers);
169    }
170
171    public static String post(String url, String data) {
172        return post(url, null, data, null);
173    }
174
175    private static String readString(HttpURLConnection conn) throws IOException {
176        try (InputStreamReader isr = new InputStreamReader(conn.getInputStream(), CHARSET)) {
177            StringBuilder ret = new StringBuilder();
178            char[] buf = new char[1024];
179            for (int num; (num = isr.read(buf, 0, buf.length)) != -1; ) {
180                ret.append(buf, 0, num);
181            }
182            return ret.toString();
183        }
184    }
185
186
187    private static String buildUrlQuery(String url, Map<String, String> queryParas) {
188        if (queryParas == null || queryParas.isEmpty()) {
189            return url;
190        }
191
192        StringBuilder sb = new StringBuilder(url);
193        boolean isFirst;
194        if (url.indexOf('?') == -1) {
195            isFirst = true;
196            sb.append('?');
197        } else {
198            isFirst = false;
199        }
200
201        for (Entry<String, String> entry : queryParas.entrySet()) {
202            if (isFirst) {
203                isFirst = false;
204            } else {
205                sb.append('&');
206            }
207
208            String key = entry.getKey();
209            String value = entry.getValue();
210            if (StringUtil.isNotBlank(value)) {
211                try {
212                    value = URLEncoder.encode(value, CHARSET);
213                } catch (UnsupportedEncodingException e) {
214                    throw new RuntimeException(e);
215                }
216            }
217            sb.append(key).append('=').append(value);
218        }
219        return sb.toString();
220    }
221
222
223}
224
225
226
227
228
229