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