001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (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 io.jboot.components.http;
017
018import io.jboot.utils.StrUtil;
019
020import javax.net.ssl.SSLContext;
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.FileNotFoundException;
024import java.io.InputStream;
025import java.net.Proxy;
026import java.util.LinkedHashMap;
027import java.util.Map;
028
029/**
030 * httpRequest
031 */
032public class JbootHttpRequest {
033
034    public static final String METHOD_GET = "GET";
035    public static final String METHOD_POST = "POST";
036
037    public static final String METHOD_HEAD = "HEAD";
038    public static final String METHOD_OPTIONS = "OPTIONS";
039    public static final String METHOD_PUT = "PUT";
040    public static final String METHOD_PATCH = "PATCH";
041    public static final String METHOD_DELETE = "DELETE";
042    public static final String METHOD_TRACE = "TRACE";
043
044    public static final int READ_TIME_OUT = 1000 * 10; // 10秒
045    public static final int CONNECT_TIME_OUT = 1000 * 5; // 5秒
046    public static final String CHAR_SET = "UTF-8";
047
048    public static final String CONTENT_TYPE_TEXT = "text/plain; charset=utf-8";
049    public static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8";
050    public static final String CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded; charset=utf-8";
051
052    private String requestUrl;
053
054    private Map<String, String> headers;
055    private Map<String, Object> params;
056
057
058    private String method = METHOD_GET;
059    private String charset = CHAR_SET;
060
061    private boolean multipartFormData = false;
062
063    private String certPath;
064    private String certPass;
065
066    private int readTimeOut;
067    private int connectTimeOut;
068    private String contentType;
069
070
071    private File downloadFile;
072    private String bodyContent;
073
074    // 如果某些时候只是为了去读取 http 头信息,而不需要 http body,可以配置为 false
075    private boolean readBody = true;
076
077    // 遇到重定向是否自动跟随
078    private boolean instanceFollowRedirects = false;
079
080    // 自定义 sslContext
081    private SSLContext sslContext;
082
083    // 自定义 http 代理
084    private HttpProxyInfo httpProxyInfo;
085
086    // 是否自动重定向(手动实现的,而非)
087    private boolean autoRedirect = true;
088
089    // 最大的重定向次数
090    private int maxRedirectCount = 3;
091
092    // 当前的重定向次数
093    private int currentRedirectCount = 0;
094
095
096    public static JbootHttpRequest create(String url) {
097        return new JbootHttpRequest(url);
098    }
099
100    public static JbootHttpRequest create(String url, String method) {
101        JbootHttpRequest request = new JbootHttpRequest(url);
102        request.setMethod(method);
103        return request;
104    }
105
106    public static JbootHttpRequest create(String url, Map<String, Object> params) {
107        JbootHttpRequest request = new JbootHttpRequest(url);
108        request.setParams(params);
109        return request;
110    }
111
112    public static JbootHttpRequest create(String url, Map<String, Object> params, String method) {
113        JbootHttpRequest request = new JbootHttpRequest(url);
114        request.setMethod(method);
115        request.setParams(params);
116        return request;
117    }
118
119    public JbootHttpRequest() {
120        JbootHttpConfig config = JbootHttpManager.me().getHttpConfig();
121
122        if (StrUtil.isNotBlank(config.getCertPath())) {
123            this.certPath = config.getCertPath();
124        }
125        if (StrUtil.isNotBlank(config.getCertPass())) {
126            this.certPass = config.getCertPass();
127        }
128
129        this.readTimeOut = config.getReadTimeOut();
130        this.connectTimeOut = config.getConnectTimeOut();
131        this.contentType = config.getContentType();
132        this.httpProxyInfo = config.getHttpProxyInfo();
133    }
134
135    public JbootHttpRequest(String url) {
136        this();
137        this.requestUrl = url;
138    }
139
140
141    public void addParam(String key, Object value) {
142        if (params == null) {
143            params = new LinkedHashMap<>();
144        }
145        if (value instanceof File) {
146            setMultipartFormData(true);
147        }
148        params.put(key, value);
149    }
150
151    public void addParams(Map<String, Object> map) {
152        if (params == null) {
153            params = new LinkedHashMap<>();
154        }
155        for (Map.Entry<String, Object> entry : map.entrySet()) {
156            if (entry.getValue() == null) {
157                continue;
158            }
159            if (entry.getValue() instanceof File) {
160                setMultipartFormData(true);
161            }
162
163            params.put(entry.getKey(), entry.getValue());
164        }
165    }
166
167    public void setRequestUrl(String requestUrl) {
168        this.requestUrl = requestUrl;
169    }
170
171    public String getCertPath() {
172        return certPath;
173    }
174
175    public InputStream getCertInputStream() throws FileNotFoundException {
176        if (StrUtil.isBlank(certPath)) {
177            return null;
178        }
179
180        if (certPath.toLowerCase().startsWith("classpath:")) {
181
182            String path = certPath.substring(10).trim();
183            InputStream inStream = getClassLoader().getResourceAsStream(path);
184
185            if (inStream == null) {
186                inStream = getClassLoader().getResourceAsStream("webapp/" + path);
187            }
188
189            if (inStream == null) {
190                throw new FileNotFoundException("Can not load resource: " + path + " in classpath.");
191            } else {
192                return inStream;
193            }
194        } else {
195            return new FileInputStream(certPath);
196        }
197    }
198
199    private ClassLoader getClassLoader() {
200        ClassLoader ret = Thread.currentThread().getContextClassLoader();
201        return ret != null ? ret : getClass().getClassLoader();
202    }
203
204    public void setCertPath(String certPath) {
205        this.certPath = certPath;
206    }
207
208    public String getCertPass() {
209        return certPass;
210    }
211
212    public void setCertPass(String certPass) {
213        this.certPass = certPass;
214    }
215
216    public String getMethod() {
217        return method;
218    }
219
220    public void setMethod(String method) {
221        this.method = method;
222    }
223
224
225    public int getReadTimeOut() {
226        return readTimeOut;
227    }
228
229    public void setReadTimeOut(int readTimeOut) {
230        this.readTimeOut = readTimeOut;
231    }
232
233    public int getConnectTimeOut() {
234        return connectTimeOut;
235    }
236
237    public void setConnectTimeOut(int connectTimeOut) {
238        this.connectTimeOut = connectTimeOut;
239    }
240
241    public String getRequestUrl() {
242        return requestUrl;
243    }
244
245    public Map<String, String> getHeaders() {
246        return headers;
247    }
248
249    public String getHeader(String name){
250        return headers != null ? headers.get(name) : null;
251    }
252
253    public void setHeaders(Map<String, String> headers) {
254        this.headers = headers;
255    }
256
257    public void addHeader(String key, String value) {
258        if (headers == null) {
259            headers = new LinkedHashMap<>();
260        }
261        headers.put(key, value);
262    }
263
264    public void addHeaders(Map<String, String> headers) {
265        if (headers == null || headers.isEmpty()) {
266            return;
267        }
268
269        if (this.headers == null) {
270            this.headers = new LinkedHashMap<>();
271        }
272        this.headers.putAll(headers);
273    }
274
275    public Map<String, Object> getParams() {
276        return params;
277    }
278
279    public void setParams(Map<String, Object> params) {
280        if (params == null) {
281            return;
282        }
283        for (Map.Entry<String, Object> entry : params.entrySet()) {
284            if (entry.getValue() == null) {
285                continue;
286            }
287            if (entry.getValue() instanceof File) {
288                setMultipartFormData(true);
289            }
290        }
291        this.params = params;
292    }
293
294    public boolean isPostRequest() {
295        return METHOD_POST.equalsIgnoreCase(method);
296    }
297
298    public boolean isPutRequest() {
299        return METHOD_PUT.equalsIgnoreCase(method);
300    }
301
302    public boolean isPostOrPutRequest() {
303        return isPostRequest() || isPutRequest();
304    }
305
306    public String getCharset() {
307        return charset;
308    }
309
310    public void setCharset(String charset) {
311        this.charset = charset;
312    }
313
314    public boolean isMultipartFormData() {
315        return multipartFormData;
316    }
317
318    public void setMultipartFormData(boolean multipartFormData) {
319        this.multipartFormData = multipartFormData;
320    }
321
322    public File getDownloadFile() {
323        return downloadFile;
324    }
325
326    public void setDownloadFile(File downloadFile) {
327        this.downloadFile = downloadFile;
328    }
329
330    public String getContentType() {
331        return contentType;
332    }
333
334    public void setContentType(String contentType) {
335        this.contentType = contentType;
336    }
337
338
339    public String getBodyContent() {
340        return bodyContent;
341    }
342
343    public String getUploadBodyString() {
344        if (bodyContent != null) {
345            return bodyContent;
346        } else {
347            return buildParams();
348        }
349    }
350
351    public void setBodyContent(String bodyContent) {
352        this.bodyContent = bodyContent;
353    }
354
355
356    private String buildParams() {
357        return StrUtil.mapToQueryString(getParams());
358    }
359
360
361    public void appendParasToUrl() {
362        String params = buildParams();
363
364        if (StrUtil.isBlank(params)) {
365            return;
366        }
367
368        String originUrl = getRequestUrl();
369        if (originUrl.contains("?")) {
370            originUrl = originUrl + "&" + params;
371        } else {
372            originUrl = originUrl + "?" + params;
373        }
374
375        setRequestUrl(originUrl);
376    }
377
378
379    public boolean isHttps() {
380        return requestUrl != null && requestUrl.toLowerCase().startsWith("https");
381    }
382
383    public boolean isReadBody() {
384        return readBody;
385    }
386
387    public void setReadBody(boolean readBody) {
388        this.readBody = readBody;
389    }
390
391    public boolean isInstanceFollowRedirects() {
392        return instanceFollowRedirects;
393    }
394
395    public void setInstanceFollowRedirects(boolean instanceFollowRedirects) {
396        this.instanceFollowRedirects = instanceFollowRedirects;
397    }
398
399    public SSLContext getSslContext() {
400        return sslContext;
401    }
402
403    public void setSslContext(SSLContext sslContext) {
404        this.sslContext = sslContext;
405    }
406
407    public HttpProxyInfo getHttpProxyInfo() {
408        return httpProxyInfo;
409    }
410
411    public void setHttpProxyInfo(HttpProxyInfo httpProxyInfo) {
412        this.httpProxyInfo = httpProxyInfo;
413    }
414
415    public Proxy getProxy() {
416        return httpProxyInfo != null ? httpProxyInfo.getProxy() : null;
417    }
418
419    public boolean isAutoRedirect() {
420        return autoRedirect;
421    }
422
423    public void setAutoRedirect(boolean autoRedirect) {
424        this.autoRedirect = autoRedirect;
425    }
426
427    public int getMaxRedirectCount() {
428        return maxRedirectCount;
429    }
430
431    public void setMaxRedirectCount(int maxRedirectCount) {
432        this.maxRedirectCount = maxRedirectCount;
433    }
434
435    public int getCurrentRedirectCount() {
436        return currentRedirectCount;
437    }
438
439    public void setCurrentRedirectCount(int currentRedirectCount) {
440        this.currentRedirectCount = currentRedirectCount;
441    }
442}