-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
635 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
176 changes: 176 additions & 0 deletions
176
tools/src/main/java/io/github/wooenrico/http/URLConnection/NativeHttpClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package io.github.wooenrico.http.URLConnection; | ||
|
||
|
||
import io.github.wooenrico.InputStreamUtil; | ||
import io.github.wooenrico.http.common.HttpExecutor; | ||
import io.github.wooenrico.http.common.HttpRequest; | ||
import io.github.wooenrico.http.common.HttpResponse; | ||
|
||
import javax.net.ssl.HostnameVerifier; | ||
import javax.net.ssl.HttpsURLConnection; | ||
import javax.net.ssl.SSLContext; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.net.HttpURLConnection; | ||
import java.net.Proxy; | ||
import java.net.URL; | ||
import java.net.URLConnection; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.Executor; | ||
|
||
public class NativeHttpClient implements HttpExecutor { | ||
|
||
private final SSLContext sslContext; | ||
private final HostnameVerifier hostnameVerifier; | ||
private final Proxy proxy; | ||
private final int connectTimeout; | ||
private final int readTimeout; | ||
|
||
public NativeHttpClient(SSLContext sslContext, HostnameVerifier hostnameVerifier, Proxy proxy, int connectTimeout, int readTimeout) { | ||
this.sslContext = sslContext; | ||
this.hostnameVerifier = hostnameVerifier; | ||
this.proxy = proxy; | ||
this.connectTimeout = connectTimeout; | ||
this.readTimeout = readTimeout; | ||
} | ||
|
||
public SSLContext getSslContext() { | ||
return sslContext; | ||
} | ||
|
||
public HostnameVerifier getHostnameVerifier() { | ||
return hostnameVerifier; | ||
} | ||
|
||
public Proxy getProxy() { | ||
return proxy; | ||
} | ||
|
||
public int getConnectTimeout() { | ||
return connectTimeout; | ||
} | ||
|
||
public int getReadTimeout() { | ||
return readTimeout; | ||
} | ||
|
||
public HttpURLConnection getUrlConnection(URL url) throws IOException { | ||
URLConnection connection = | ||
this.proxy == null ? url.openConnection() : url.openConnection(this.proxy); | ||
|
||
if (connection instanceof HttpsURLConnection) { | ||
if (this.sslContext != null) { | ||
((HttpsURLConnection) connection) | ||
.setSSLSocketFactory(this.sslContext.getSocketFactory()); | ||
} | ||
if (this.hostnameVerifier != null) { | ||
((HttpsURLConnection) connection).setHostnameVerifier(this.hostnameVerifier); | ||
} | ||
} | ||
|
||
return (HttpURLConnection) connection; | ||
} | ||
|
||
@Override | ||
public HttpResponse execute(HttpRequest httpRequest) throws IOException { | ||
return doRequest(new URL(httpRequest.getUrl()), httpRequest.getMethod().name(), httpRequest.getHeaders(), httpRequest.getBody()); | ||
} | ||
|
||
@Override | ||
public CompletableFuture<HttpResponse> execute(HttpRequest httpRequest, Executor executor) { | ||
CompletableFuture<HttpResponse> future = new CompletableFuture<>(); | ||
try { | ||
if (executor == null) { | ||
executor = Runnable::run; | ||
} | ||
|
||
executor.execute(() -> { | ||
try { | ||
HttpResponse httpResponse = execute(httpRequest); | ||
future.complete(httpResponse); | ||
} catch (Exception e) { | ||
future.completeExceptionally(e); | ||
} | ||
}); | ||
} catch (Exception e) { | ||
future.completeExceptionally(e); | ||
} | ||
return future; | ||
} | ||
|
||
private HttpResponse doRequest(URL url, String requestMethod, Map<String, String> headers, byte[] body) throws IOException { | ||
|
||
HttpURLConnection connection = getUrlConnection(url); | ||
connection.setConnectTimeout(this.connectTimeout); | ||
connection.setReadTimeout(this.readTimeout); | ||
connection.setDoInput(true); | ||
connection.setRequestMethod(requestMethod); | ||
|
||
if (headers != null) { | ||
headers.forEach(connection::setRequestProperty); | ||
} | ||
|
||
if (body != null && body.length > 0) { | ||
connection.setDoOutput(true); | ||
connection.setFixedLengthStreamingMode(body.length); | ||
|
||
OutputStream outputStream = connection.getOutputStream(); | ||
outputStream.write(body); | ||
outputStream.flush(); | ||
} | ||
|
||
int responseCode = connection.getResponseCode(); | ||
String desc = ""; | ||
String version = ""; | ||
|
||
// HTTP/1.1 404 Not Found | ||
// HTTP/1.0 200 | ||
String statusLine = connection.getHeaderField(0); | ||
|
||
if (statusLine.startsWith("HTTP/1.")) { | ||
|
||
int codeIndex = statusLine.indexOf(' '); | ||
|
||
version = statusLine.substring(0, codeIndex); | ||
|
||
if (codeIndex > 0) { | ||
int phraseIndex = statusLine.indexOf(' ', codeIndex + 1); | ||
if (phraseIndex > 0) { | ||
desc = statusLine.substring(phraseIndex + 1); | ||
} | ||
|
||
if (phraseIndex < 0) | ||
phraseIndex = statusLine.length(); | ||
try { | ||
responseCode = | ||
Integer.parseInt(statusLine.substring(codeIndex + 1, phraseIndex)); | ||
} catch (NumberFormatException ignore) { | ||
} | ||
} | ||
} | ||
|
||
Map<String, List<String>> headerFields = connection.getHeaderFields(); | ||
Map<String, List<String>> headerMap = new HashMap<>(); | ||
for (Map.Entry<String, List<String>> stringListEntry : headerFields.entrySet()) { | ||
String key = stringListEntry.getKey(); | ||
if (key != null) { | ||
headerMap.put(key, stringListEntry.getValue()); | ||
} | ||
} | ||
|
||
InputStream inputStream; | ||
try { | ||
inputStream = connection.getInputStream(); | ||
} catch (IOException e) { | ||
inputStream = connection.getErrorStream(); | ||
} | ||
|
||
byte[] bytes = InputStreamUtil.readAndClose(inputStream); | ||
|
||
return new HttpResponse(responseCode, desc, version, headerMap, bytes); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
tools/src/main/java/io/github/wooenrico/http/URLConnection/NativeHttpClientBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package io.github.wooenrico.http.URLConnection; | ||
|
||
import javax.net.ssl.HostnameVerifier; | ||
import javax.net.ssl.SSLContext; | ||
import java.net.Proxy; | ||
|
||
public class NativeHttpClientBuilder { | ||
private SSLContext sslContext; | ||
private HostnameVerifier hostnameVerifier; | ||
private Proxy proxy; | ||
private int connectTimeout = 5000; | ||
private int readTimeout = 10000; | ||
|
||
public NativeHttpClientBuilder setSslContext(SSLContext sslContext) { | ||
this.sslContext = sslContext; | ||
return this; | ||
} | ||
|
||
public NativeHttpClientBuilder setHostnameVerifier(HostnameVerifier hostnameVerifier) { | ||
this.hostnameVerifier = hostnameVerifier; | ||
return this; | ||
} | ||
|
||
public NativeHttpClientBuilder setProxy(Proxy proxy) { | ||
this.proxy = proxy; | ||
return this; | ||
} | ||
|
||
public NativeHttpClientBuilder setConnectTimeout(int connectTimeout) { | ||
this.connectTimeout = connectTimeout; | ||
return this; | ||
} | ||
|
||
public NativeHttpClientBuilder setReadTimeout(int readTimeout) { | ||
this.readTimeout = readTimeout; | ||
return this; | ||
} | ||
|
||
public SSLContext getSslContext() { | ||
return sslContext; | ||
} | ||
|
||
public HostnameVerifier getHostnameVerifier() { | ||
return hostnameVerifier; | ||
} | ||
|
||
public Proxy getProxy() { | ||
return proxy; | ||
} | ||
|
||
public int getConnectTimeout() { | ||
return connectTimeout; | ||
} | ||
|
||
public int getReadTimeout() { | ||
return readTimeout; | ||
} | ||
|
||
public NativeHttpClient build() { | ||
return new NativeHttpClient(this.sslContext, this.hostnameVerifier, this.proxy, this.connectTimeout, this.readTimeout); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
.../src/main/java/io/github/wooenrico/http/URLConnection/ProxyBasicAuthNativeHttpClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package io.github.wooenrico.http.URLConnection; | ||
|
||
import io.github.wooenrico.http.common.HttpProxy; | ||
|
||
import javax.net.ssl.HostnameVerifier; | ||
import javax.net.ssl.SSLContext; | ||
import java.io.IOException; | ||
import java.net.HttpURLConnection; | ||
import java.net.Proxy; | ||
import java.net.URL; | ||
|
||
public class ProxyBasicAuthNativeHttpClient extends NativeHttpClient { | ||
|
||
public ProxyBasicAuthNativeHttpClient(SSLContext sslContext, HostnameVerifier hostnameVerifier, Proxy proxy, int connectTimeout, int readTimeout) { | ||
super(sslContext, hostnameVerifier, proxy, connectTimeout, readTimeout); | ||
} | ||
|
||
@Override | ||
public HttpURLConnection getUrlConnection(URL url) throws IOException { | ||
HttpURLConnection urlConnection = super.getUrlConnection(url); | ||
|
||
if (getProxy() == null) { | ||
return urlConnection; | ||
} | ||
|
||
if (getProxy() instanceof HttpProxy) { | ||
HttpProxy httpProxy = (HttpProxy) getProxy(); | ||
urlConnection.setRequestProperty(HttpProxy.Proxy_Authorization_Header_Name, | ||
httpProxy.getBasicAuthorization()); | ||
} | ||
|
||
return urlConnection; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...in/java/io/github/wooenrico/http/URLConnection/ProxyBasicAuthNativeHttpClientBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package io.github.wooenrico.http.URLConnection; | ||
|
||
public class ProxyBasicAuthNativeHttpClientBuilder extends NativeHttpClientBuilder { | ||
@Override | ||
public ProxyBasicAuthNativeHttpClient build() { | ||
return new ProxyBasicAuthNativeHttpClient(super.getSslContext(), super.getHostnameVerifier(), super.getProxy(), super.getConnectTimeout(), super.getReadTimeout()); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
tools/src/main/java/io/github/wooenrico/http/common/HttpExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package io.github.wooenrico.http.common; | ||
|
||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.Executor; | ||
|
||
public interface HttpExecutor { | ||
/** | ||
* 执行http 请求 | ||
* | ||
* @param httpRequest http请求内容 | ||
* @return HttpResponse | ||
*/ | ||
HttpResponse execute(HttpRequest httpRequest) throws Exception; | ||
|
||
/** | ||
* 异步执行http请求 | ||
* | ||
* @param httpRequest http请求内容 | ||
* @param executor 线程池 | ||
* @return CompletableFuture<HttpResponse> | ||
*/ | ||
CompletableFuture<HttpResponse> execute(HttpRequest httpRequest, Executor executor); | ||
} |
51 changes: 51 additions & 0 deletions
51
tools/src/main/java/io/github/wooenrico/http/common/HttpProxy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package io.github.wooenrico.http.common; | ||
|
||
import java.net.Proxy; | ||
import java.net.SocketAddress; | ||
import java.util.Base64; | ||
|
||
public class HttpProxy extends Proxy { | ||
|
||
public final static String Proxy_Authorization_Header_Name = "Proxy-Authorization"; | ||
|
||
private String username; | ||
private String password; | ||
|
||
/** | ||
* Creates an entry representing a PROXY connection. | ||
* Certain combinations are illegal. For instance, for types Http, and | ||
* Socks, a SocketAddress <b>must</b> be provided. | ||
* <p> | ||
* Use the {@code Proxy.NO_PROXY} constant | ||
* for representing a direct connection. | ||
* | ||
* @param type the {@code Type} of the proxy | ||
* @param sa the {@code SocketAddress} for that proxy | ||
* @throws IllegalArgumentException when the type and the address are | ||
* incompatible | ||
*/ | ||
public HttpProxy(Type type, SocketAddress sa) { | ||
super(type, sa); | ||
} | ||
|
||
public HttpProxy(Type type, SocketAddress sa, String username, String password) { | ||
super(type, sa); | ||
this.username = username; | ||
this.password = password; | ||
} | ||
|
||
/** | ||
* proxy auth header | ||
* | ||
* @return header value of Proxy-Authorization | ||
*/ | ||
public String getBasicAuthorization() { | ||
if (username == null && password == null) { | ||
return null; | ||
} | ||
|
||
String encodeKey = username + ":" + password; | ||
byte[] encode = Base64.getEncoder().encode(encodeKey.getBytes()); | ||
return "Basic" + " " + new String(encode); | ||
} | ||
} |
Oops, something went wrong.