feat: break apart HttpClient
This commit is contained in:
parent
86f100da8e
commit
01f1fdf188
|
@ -1,25 +1,12 @@
|
|||
package io.gitlab.jfronny.commons.http.client;
|
||||
|
||||
import io.gitlab.jfronny.commons.data.Either;
|
||||
import io.gitlab.jfronny.commons.serialize.Serializer;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.*;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class HttpClient {
|
||||
private static String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36";
|
||||
private static final String PROXY_AUTH;
|
||||
private static final java.net.http.HttpClient CLIENT;
|
||||
protected static String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36";
|
||||
protected static final String PROXY_AUTH;
|
||||
protected static final java.net.http.HttpClient CLIENT;
|
||||
|
||||
static {
|
||||
// Enables HTTPS proxying
|
||||
|
@ -53,274 +40,23 @@ public class HttpClient {
|
|||
userAgent = hostname;
|
||||
}
|
||||
|
||||
private enum Method {
|
||||
GET,
|
||||
POST,
|
||||
PUT,
|
||||
PATCH,
|
||||
DELETE
|
||||
public static RequestBuilder get(String url) throws URISyntaxException {
|
||||
return new RequestBuilder(Method.GET, url);
|
||||
}
|
||||
|
||||
private enum ResponseHandlingMode {
|
||||
IGNORE_ALL, HANDLE_REDIRECTS, HANDLE_ALL
|
||||
public static RequestBuilder post(String url) throws URISyntaxException {
|
||||
return new RequestBuilder(Method.POST, url);
|
||||
}
|
||||
|
||||
public static class Request {
|
||||
private static final Predicate<String> CURSEFORGE_API = Pattern.compile("(?:http(s)?://)?addons-ecs\\.forgesvc\\.net/api/+").asMatchPredicate();
|
||||
private final String url;
|
||||
private final HttpRequest.Builder builder;
|
||||
private Method method;
|
||||
private int sent = 0;
|
||||
private int retryAfterDefault = 5000;
|
||||
private int retryAfterMax = 15000;
|
||||
private int retryLimit = 3;
|
||||
private ResponseHandlingMode responseHandlingMode = ResponseHandlingMode.HANDLE_ALL;
|
||||
private List<Exception> retryExceptions = null;
|
||||
|
||||
private Request(Method method, String url) throws URISyntaxException {
|
||||
this.url = url.replace(" ", "%20");
|
||||
this.builder = HttpRequest.newBuilder()
|
||||
.uri(new URI(this.url));
|
||||
this.method = method;
|
||||
userAgent(userAgent);
|
||||
}
|
||||
|
||||
public Request bearer(String token) {
|
||||
builder.header("Authorization", "Bearer " + token);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request header(String name, String value) {
|
||||
builder.header(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request setHeader(String name, String value) {
|
||||
builder.setHeader(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request ignoreAll() {
|
||||
responseHandlingMode = ResponseHandlingMode.IGNORE_ALL;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request handleRedirects() {
|
||||
responseHandlingMode = ResponseHandlingMode.HANDLE_REDIRECTS;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request configureRetryAfter(int defaultDelay, int maxDelay) {
|
||||
if (defaultDelay < 1) throw new IllegalArgumentException("defaultDelay must be greater than zero");
|
||||
if (maxDelay < defaultDelay) throw new IllegalArgumentException("maxDelay must be greater than or equal to defaultDelay");
|
||||
retryAfterDefault = defaultDelay;
|
||||
retryAfterMax = maxDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request setRetryLimit(int limit) {
|
||||
if (limit < 0) throw new IllegalArgumentException("limit must be greater than or zero");
|
||||
retryLimit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request userAgent(String value) {
|
||||
return setHeader("User-Agent", value);
|
||||
}
|
||||
|
||||
public Request bodyString(String string) {
|
||||
builder.header("Content-Type", "text/plain");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request bodyForm(String string) {
|
||||
builder.header("Content-Type", "application/x-www-form-urlencoded");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request bodyForm(Map<String, String> entries) {
|
||||
return bodyForm(entries.entrySet()
|
||||
.stream()
|
||||
.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + '=' + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
|
||||
.collect(Collectors.joining("&")));
|
||||
}
|
||||
|
||||
public Request bodyJson(String string) {
|
||||
builder.header("Content-Type", "application/json");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Request bodySerialized(Object object) throws IOException {
|
||||
Serializer serializer = Serializer.getInstance();
|
||||
builder.header("Content-Type", serializer.getFormatMime());
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(serializer.serialize(object)));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> _sendResponse(String accept, HttpResponse.BodyHandler<T> responseBodyHandler) throws IOException {
|
||||
sent++;
|
||||
if (sent > retryLimit) {
|
||||
IOException e = new IOException("Attempted to reconnect/redirect " + sent + " times, which is more than the permitted " + retryLimit + ". Stopping");
|
||||
if (retryExceptions != null) for (Exception ex : retryExceptions) e.addSuppressed(ex);
|
||||
throw e;
|
||||
}
|
||||
builder.header("Accept", accept);
|
||||
if (method != null) builder.method(method.name(), HttpRequest.BodyPublishers.noBody());
|
||||
if (PROXY_AUTH != null) builder.header("Proxy-Authorization", PROXY_AUTH);
|
||||
|
||||
HttpResponse<T> res;
|
||||
try {
|
||||
res = CLIENT.send(builder.build(), responseBodyHandler);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Could not send request", e);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
if (message != null && message.contains("GOAWAY received")) {
|
||||
return handleRetryAfter(accept, responseBodyHandler, retryAfterDefault);
|
||||
} else throw new IOException("Could not send request", e);
|
||||
}
|
||||
if (responseHandlingMode == ResponseHandlingMode.IGNORE_ALL) return res;
|
||||
if (res.statusCode() / 100 == 2) return res;
|
||||
Optional<String> location = res.headers().firstValue("location");
|
||||
Optional<Integer> retryAfter = res.headers().firstValue("Retry-After").flatMap(s -> {
|
||||
try {
|
||||
return Optional.of(Integer.parseInt(s));
|
||||
} catch (NumberFormatException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
});
|
||||
final String exceptionSuffix = " (URL=" + url + ")";
|
||||
return switch (res.statusCode()) {
|
||||
case 429 -> {
|
||||
// Rate limit
|
||||
yield handleRetryAfter(accept, responseBodyHandler, retryAfter.map(s -> s * 1000).orElse(retryAfterDefault));
|
||||
}
|
||||
case 302, 307 -> {
|
||||
// Redirect
|
||||
if (location.isPresent() && method == Method.GET) {
|
||||
try {
|
||||
yield get(location.get())._sendResponse(accept, responseBodyHandler);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IOException("Could not follow redirect" + exceptionSuffix, e);
|
||||
}
|
||||
}
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new IOException("Unexpected redirect: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
case 500, 502, 503, 504, 507 -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
// CurseForge serverside error
|
||||
if (CURSEFORGE_API.test(url)) {
|
||||
yield handleRetryAfter(accept, responseBodyHandler, Math.min(1000, retryAfterMax));
|
||||
}
|
||||
throw new IOException("Unexpected serverside error: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
case 404 -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new FileNotFoundException("Didn't find anything under that url" + exceptionSuffix);
|
||||
}
|
||||
default -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new IOException("Unexpected return method: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> handleRetryAfter(String accept, HttpResponse.BodyHandler<T> responseBodyHandler, int millis) throws IOException {
|
||||
if (millis > retryAfterMax) throw new HttpTimeoutException("Wait time specified by Retry-After is too long: " + millis);
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Could not sleep before resending request" + e);
|
||||
}
|
||||
return this._sendResponse(accept, responseBodyHandler);
|
||||
}
|
||||
|
||||
private <T> T unwrap(HttpResponse<T> response) throws IOException {
|
||||
return response.body();
|
||||
}
|
||||
|
||||
public void send() throws IOException {
|
||||
unwrap(sendResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Void> sendResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.discarding());
|
||||
}
|
||||
|
||||
public InputStream sendInputStream() throws IOException {
|
||||
return unwrap(sendInputStreamResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<InputStream> sendInputStreamResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofInputStream());
|
||||
}
|
||||
|
||||
public Reader sendReader() throws IOException {
|
||||
return unwrap(sendReaderResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Reader> sendReaderResponse() throws IOException {
|
||||
return _sendResponse("*/*", ReaderHandler.of());
|
||||
}
|
||||
|
||||
public String sendString() throws IOException {
|
||||
return unwrap(sendStringResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<String> sendStringResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofString());
|
||||
}
|
||||
|
||||
public Stream<String> sendLines() throws IOException {
|
||||
return unwrap(sendLinesResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Stream<String>> sendLinesResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofLines());
|
||||
}
|
||||
|
||||
public <T> T sendSerialized(Type type) throws IOException {
|
||||
Either<T, IOException> tmp = unwrap(sendSerializedResponse(type));
|
||||
if (tmp == null) return null;
|
||||
if (tmp.isLeft()) return tmp.left();
|
||||
throw new IOException("Could not deserialize", tmp.right());
|
||||
}
|
||||
|
||||
public <T> HttpResponse<Either<T, IOException>> sendSerializedResponse(Type type) throws IOException {
|
||||
return _sendResponse(Serializer.getInstance().getFormatMime(), SerializedHandler.of(Serializer.getInstance(), type));
|
||||
}
|
||||
public static RequestBuilder put(String url) throws URISyntaxException {
|
||||
return new RequestBuilder(Method.PUT, url);
|
||||
}
|
||||
|
||||
public static Request get(String url) throws URISyntaxException {
|
||||
return new Request(Method.GET, url);
|
||||
public static RequestBuilder patch(String url) throws URISyntaxException {
|
||||
return new RequestBuilder(Method.PATCH, url);
|
||||
}
|
||||
|
||||
public static Request post(String url) throws URISyntaxException {
|
||||
return new Request(Method.POST, url);
|
||||
}
|
||||
|
||||
public static Request put(String url) throws URISyntaxException {
|
||||
return new Request(Method.PUT, url);
|
||||
}
|
||||
|
||||
public static Request patch(String url) throws URISyntaxException {
|
||||
return new Request(Method.PATCH, url);
|
||||
}
|
||||
|
||||
public static Request delete(String url) throws URISyntaxException {
|
||||
return new Request(Method.DELETE, url);
|
||||
public static RequestBuilder delete(String url) throws URISyntaxException {
|
||||
return new RequestBuilder(Method.DELETE, url);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.gitlab.jfronny.commons.http.client;
|
||||
|
||||
enum Method {
|
||||
GET,
|
||||
POST,
|
||||
PUT,
|
||||
PATCH,
|
||||
DELETE
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
package io.gitlab.jfronny.commons.http.client;
|
||||
|
||||
import io.gitlab.jfronny.commons.data.Either;
|
||||
import io.gitlab.jfronny.commons.serialize.Serializer;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RequestBuilder {
|
||||
private static final Predicate<String> CURSEFORGE_API = Pattern.compile("(?:http(s)?://)?addons-ecs\\.forgesvc\\.net/api/+").asMatchPredicate();
|
||||
private final String url;
|
||||
private final HttpRequest.Builder builder;
|
||||
private Method method;
|
||||
private int sent = 0;
|
||||
private int retryAfterDefault = 5000;
|
||||
private int retryAfterMax = 15000;
|
||||
private int retryLimit = 3;
|
||||
private ResponseHandlingMode responseHandlingMode = ResponseHandlingMode.HANDLE_ALL;
|
||||
private List<Exception> retryExceptions = null;
|
||||
|
||||
protected RequestBuilder(Method method, String url) throws URISyntaxException {
|
||||
this.url = url.replace(" ", "%20");
|
||||
this.builder = HttpRequest.newBuilder()
|
||||
.uri(new URI(this.url));
|
||||
this.method = method;
|
||||
userAgent(HttpClient.userAgent);
|
||||
}
|
||||
|
||||
public RequestBuilder bearer(String token) {
|
||||
builder.header("Authorization", "Bearer " + token);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder header(String name, String value) {
|
||||
builder.header(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder setHeader(String name, String value) {
|
||||
builder.setHeader(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder ignoreAll() {
|
||||
responseHandlingMode = ResponseHandlingMode.IGNORE_ALL;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder handleRedirects() {
|
||||
responseHandlingMode = ResponseHandlingMode.HANDLE_REDIRECTS;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder configureRetryAfter(int defaultDelay, int maxDelay) {
|
||||
if (defaultDelay < 1) throw new IllegalArgumentException("defaultDelay must be greater than zero");
|
||||
if (maxDelay < defaultDelay)
|
||||
throw new IllegalArgumentException("maxDelay must be greater than or equal to defaultDelay");
|
||||
retryAfterDefault = defaultDelay;
|
||||
retryAfterMax = maxDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder setRetryLimit(int limit) {
|
||||
if (limit < 0) throw new IllegalArgumentException("limit must be greater than or zero");
|
||||
retryLimit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder userAgent(String value) {
|
||||
return setHeader("User-Agent", value);
|
||||
}
|
||||
|
||||
public RequestBuilder bodyString(String string) {
|
||||
builder.header("Content-Type", "text/plain");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder bodyForm(String string) {
|
||||
builder.header("Content-Type", "application/x-www-form-urlencoded");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder bodyForm(Map<String, String> entries) {
|
||||
return bodyForm(entries.entrySet()
|
||||
.stream()
|
||||
.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + '=' + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
|
||||
.collect(Collectors.joining("&")));
|
||||
}
|
||||
|
||||
public RequestBuilder bodyJson(String string) {
|
||||
builder.header("Content-Type", "application/json");
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(string));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBuilder bodySerialized(Object object) throws IOException {
|
||||
Serializer serializer = Serializer.getInstance();
|
||||
builder.header("Content-Type", serializer.getFormatMime());
|
||||
builder.method(method.name(), HttpRequest.BodyPublishers.ofString(serializer.serialize(object)));
|
||||
method = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> _sendResponse(String accept, HttpResponse.BodyHandler<T> responseBodyHandler) throws IOException {
|
||||
sent++;
|
||||
if (sent > retryLimit) {
|
||||
IOException e = new IOException("Attempted to reconnect/redirect " + sent + " times, which is more than the permitted " + retryLimit + ". Stopping");
|
||||
if (retryExceptions != null) for (Exception ex : retryExceptions) e.addSuppressed(ex);
|
||||
throw e;
|
||||
}
|
||||
builder.header("Accept", accept);
|
||||
if (method != null) builder.method(method.name(), HttpRequest.BodyPublishers.noBody());
|
||||
if (HttpClient.PROXY_AUTH != null) builder.header("Proxy-Authorization", HttpClient.PROXY_AUTH);
|
||||
|
||||
HttpResponse<T> res;
|
||||
try {
|
||||
res = HttpClient.CLIENT.send(builder.build(), responseBodyHandler);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Could not send request", e);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
if (message != null && message.contains("GOAWAY received")) {
|
||||
return handleRetryAfter(accept, responseBodyHandler, retryAfterDefault);
|
||||
} else throw new IOException("Could not send request", e);
|
||||
}
|
||||
if (responseHandlingMode == ResponseHandlingMode.IGNORE_ALL) return res;
|
||||
if (res.statusCode() / 100 == 2) return res;
|
||||
Optional<String> location = res.headers().firstValue("location");
|
||||
Optional<Integer> retryAfter = res.headers().firstValue("Retry-After").flatMap(s -> {
|
||||
try {
|
||||
return Optional.of(Integer.parseInt(s));
|
||||
} catch (NumberFormatException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
});
|
||||
final String exceptionSuffix = " (URL=" + url + ")";
|
||||
return switch (res.statusCode()) {
|
||||
case 429 -> {
|
||||
// Rate limit
|
||||
yield handleRetryAfter(accept, responseBodyHandler, retryAfter.map(s -> s * 1000).orElse(retryAfterDefault));
|
||||
}
|
||||
case 302, 307 -> {
|
||||
// Redirect
|
||||
if (location.isPresent() && method == Method.GET) {
|
||||
try {
|
||||
yield HttpClient.get(location.get())._sendResponse(accept, responseBodyHandler);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IOException("Could not follow redirect" + exceptionSuffix, e);
|
||||
}
|
||||
}
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new IOException("Unexpected redirect: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
case 500, 502, 503, 504, 507 -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
// CurseForge serverside error
|
||||
if (CURSEFORGE_API.test(url)) {
|
||||
yield handleRetryAfter(accept, responseBodyHandler, Math.min(1000, retryAfterMax));
|
||||
}
|
||||
throw new IOException("Unexpected serverside error: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
case 404 -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new FileNotFoundException("Didn't find anything under that url" + exceptionSuffix);
|
||||
}
|
||||
default -> {
|
||||
if (responseHandlingMode == ResponseHandlingMode.HANDLE_REDIRECTS) yield res;
|
||||
throw new IOException("Unexpected return method: " + res.statusCode() + exceptionSuffix);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> handleRetryAfter(String accept, HttpResponse.BodyHandler<T> responseBodyHandler, int millis) throws IOException {
|
||||
if (millis > retryAfterMax)
|
||||
throw new HttpTimeoutException("Wait time specified by Retry-After is too long: " + millis);
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Could not sleep before resending request" + e);
|
||||
}
|
||||
return this._sendResponse(accept, responseBodyHandler);
|
||||
}
|
||||
|
||||
private <T> T unwrap(HttpResponse<T> response) throws IOException {
|
||||
return response.body();
|
||||
}
|
||||
|
||||
public void send() throws IOException {
|
||||
unwrap(sendResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Void> sendResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.discarding());
|
||||
}
|
||||
|
||||
public InputStream sendInputStream() throws IOException {
|
||||
return unwrap(sendInputStreamResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<InputStream> sendInputStreamResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofInputStream());
|
||||
}
|
||||
|
||||
public Reader sendReader() throws IOException {
|
||||
return unwrap(sendReaderResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Reader> sendReaderResponse() throws IOException {
|
||||
return _sendResponse("*/*", ReaderHandler.of());
|
||||
}
|
||||
|
||||
public String sendString() throws IOException {
|
||||
return unwrap(sendStringResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<String> sendStringResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofString());
|
||||
}
|
||||
|
||||
public Stream<String> sendLines() throws IOException {
|
||||
return unwrap(sendLinesResponse());
|
||||
}
|
||||
|
||||
public HttpResponse<Stream<String>> sendLinesResponse() throws IOException {
|
||||
return _sendResponse("*/*", HttpResponse.BodyHandlers.ofLines());
|
||||
}
|
||||
|
||||
public <T> T sendSerialized(Type type) throws IOException {
|
||||
Either<T, IOException> tmp = unwrap(sendSerializedResponse(type));
|
||||
if (tmp == null) return null;
|
||||
if (tmp.isLeft()) return tmp.left();
|
||||
throw new IOException("Could not deserialize", tmp.right());
|
||||
}
|
||||
|
||||
public <T> HttpResponse<Either<T, IOException>> sendSerializedResponse(Type type) throws IOException {
|
||||
return _sendResponse(Serializer.getInstance().getFormatMime(), SerializedHandler.of(Serializer.getInstance(), type));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package io.gitlab.jfronny.commons.http.client;
|
||||
|
||||
enum ResponseHandlingMode {
|
||||
IGNORE_ALL, HANDLE_REDIRECTS, HANDLE_ALL
|
||||
}
|
Loading…
Reference in New Issue