From 300b15e604d9b3ff38b6cce6c7f6ae1e0490c266 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Wed, 19 Aug 2020 11:47:31 +0200 Subject: [PATCH] KEYCLOAK-15214 Improve SimpleHTTP - Added support for configuring socket, connect and request timeouts on request level. - Added support for HTTP HEAD and HTTP PATCH methods - Small refactorings --- .../broker/provider/util/SimpleHttp.java | 114 +++++++++++++----- 1 file changed, 86 insertions(+), 28 deletions(-) diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java index 6cc3bc66b5..b1e1a2498f 100755 --- a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java +++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java @@ -27,10 +27,13 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; @@ -66,15 +69,24 @@ import java.util.zip.GZIPInputStream; public class SimpleHttp { private static final ObjectMapper mapper = new ObjectMapper(); + private static final int UNDEFINED_TIMEOUT = -1; - private HttpClient client; + private final HttpClient client; - private String url; - private String method; + private final String url; + private final String method; private Map headers; private Map params; private Object entity; + private int socketTimeOutMillis = UNDEFINED_TIMEOUT; + + private int connectTimeoutMillis = UNDEFINED_TIMEOUT; + + private int connectionRequestTimeoutMillis = UNDEFINED_TIMEOUT; + + private RequestConfig.Builder requestConfigBuilder; + protected SimpleHttp(String url, String method, HttpClient client) { this.client = client; this.url = url; @@ -109,6 +121,14 @@ public class SimpleHttp { return new SimpleHttp(url, "PUT", client); } + public static SimpleHttp doHead(String url, HttpClient client) { + return new SimpleHttp(url, "HEAD", client); + } + + public static SimpleHttp doPatch(String url, HttpClient client) { + return new SimpleHttp(url, "PATCH", client); + } + public SimpleHttp header(String name, String value) { if (headers == null) { headers = new HashMap<>(); @@ -130,6 +150,21 @@ public class SimpleHttp { return this; } + public SimpleHttp socketTimeOutMillis(int timeout) { + this.socketTimeOutMillis = timeout; + return this; + } + + public SimpleHttp connectTimeoutMillis(int timeout) { + this.connectTimeoutMillis = timeout; + return this; + } + + public SimpleHttp connectionRequestTimeoutMillis(int timeout) { + this.connectionRequestTimeoutMillis = timeout; + return this; + } + public SimpleHttp auth(String token) { header("Authorization", "Bearer " + token); return this; @@ -181,27 +216,30 @@ public class SimpleHttp { return makeRequest(); } + private HttpRequestBase createHttpRequest() { + switch(method) { + case "GET": + return new HttpGet(appendParameterToUrl(url)); + case "DELETE": + return new HttpDelete(appendParameterToUrl(url)); + case "HEAD": + return new HttpHead(appendParameterToUrl(url)); + case "PUT": + return new HttpPut(appendParameterToUrl(url)); + case "PATCH": + return new HttpPatch(appendParameterToUrl(url)); + case "POST": + // explicit fall through as we want POST to be the default HTTP method + default: + return new HttpPost(url); + } + } + private Response makeRequest() throws IOException { - boolean get = method.equals("GET"); - boolean post = method.equals("POST"); - boolean put = method.equals("PUT"); - boolean delete = method.equals("DELETE"); - HttpRequestBase httpRequest = new HttpPost(url); + HttpRequestBase httpRequest = createHttpRequest(); - if (get) { - httpRequest = new HttpGet(appendParameterToUrl(url)); - } - - if (delete) { - httpRequest = new HttpDelete(appendParameterToUrl(url)); - } - - if (put) { - httpRequest = new HttpPut(appendParameterToUrl(url)); - } - - if (post || put) { + if (httpRequest instanceof HttpPost || httpRequest instanceof HttpPut || httpRequest instanceof HttpPatch) { if (params != null) { ((HttpEntityEnclosingRequestBase) httpRequest).setEntity(getFormEntityFromParameter()); } else if (entity != null) { @@ -220,12 +258,33 @@ public class SimpleHttp { } } + if (socketTimeOutMillis != UNDEFINED_TIMEOUT) { + requestConfigBuilder().setSocketTimeout(socketTimeOutMillis); + } + + if (connectTimeoutMillis != UNDEFINED_TIMEOUT) { + requestConfigBuilder().setConnectTimeout(connectTimeoutMillis); + } + + if (connectionRequestTimeoutMillis != UNDEFINED_TIMEOUT) { + requestConfigBuilder().setConnectionRequestTimeout(connectionRequestTimeoutMillis); + } + + if (requestConfigBuilder != null) { + httpRequest.setConfig(requestConfigBuilder.build()); + } + return new Response(client.execute(httpRequest)); } - private URI appendParameterToUrl(String url) throws IOException { - URI uri = null; + private RequestConfig.Builder requestConfigBuilder() { + if (requestConfigBuilder == null) { + requestConfigBuilder = RequestConfig.custom(); + } + return requestConfigBuilder; + } + private URI appendParameterToUrl(String url) { try { URIBuilder uriBuilder = new URIBuilder(url); @@ -235,11 +294,10 @@ public class SimpleHttp { } } - uri = uriBuilder.build(); - } catch (URISyntaxException e) { + return uriBuilder.build(); + } catch (URISyntaxException ignored) { + return null; } - - return uri; } private StringEntity getJsonEntity() throws IOException { @@ -260,7 +318,7 @@ public class SimpleHttp { public static class Response { - private HttpResponse response; + private final HttpResponse response; private int statusCode = -1; private String responseString;