io.strimzi.kafka.oauth.common.HttpUtil Maven / Gradle / Ivy
/*
* Copyright 2017-2019, Strimzi authors.
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/
package io.strimzi.kafka.oauth.common;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import static io.strimzi.kafka.oauth.common.IOUtil.copy;
/**
* A helper class that performs all network calls using java.net.HttpURLConnection.
*
* If application uses many concurrent threads initiating many Kafka sessions in parallel, consider setting
* 'http.maxConnections' system property to value closer to the number of parallel sessions.
*
* This value controls the size of internal connection pool per destination in JDK's java.net.HttpURLConnection implementation.
*
* See: https://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html
*/
public class HttpUtil {
private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);
public static T get(URI uri, String authorization, Class responseType) throws IOException {
return request(uri, null, null, authorization, null, null, responseType);
}
public static T get(URI uri, SSLSocketFactory socketFactory, String authorization, Class responseType) throws IOException {
return request(uri, socketFactory, null, authorization, null, null, responseType);
}
public static T get(URI uri, SSLSocketFactory socketFactory, HostnameVerifier hostnameVerifier, String authorization, Class responseType) throws IOException {
return request(uri, socketFactory, hostnameVerifier, authorization, null, null, responseType);
}
public static T post(URI uri, String authorization, String contentType, String body, Class responseType) throws IOException {
return request(uri, null, null, authorization, contentType, body, responseType);
}
public static T post(URI uri, SSLSocketFactory socketFactory, String authorization, String contentType, String body, Class responseType) throws IOException {
return request(uri, socketFactory, null, authorization, contentType, body, responseType);
}
public static T post(URI uri, SSLSocketFactory socketFactory, HostnameVerifier verifier, String authorization, String contentType, String body, Class responseType) throws IOException {
return request(uri, socketFactory, verifier, authorization, contentType, body, responseType);
}
public static void put(URI uri, String authorization, String contentType, String body) throws IOException {
request(uri, null, null, authorization, contentType, body, null);
}
public static void put(URI uri, SSLSocketFactory socketFactory, String authorization, String contentType, String body) throws IOException {
request(uri, socketFactory, null, authorization, contentType, body, null);
}
public static void put(URI uri, SSLSocketFactory socketFactory, HostnameVerifier verifier, String authorization, String contentType, String body) throws IOException {
request(uri, socketFactory, verifier, authorization, contentType, body, null);
}
// Surpressed because of Spotbugs Java 11 bug - https://github.com/spotbugs/spotbugs/issues/756
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
public static T request(URI uri, SSLSocketFactory socketFactory, HostnameVerifier hostnameVerifier, String authorization, String contentType, String body, Class responseType) throws IOException {
HttpURLConnection con;
try {
con = (HttpURLConnection) uri.toURL().openConnection();
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Malformed token endpoint url: " + uri);
}
if (con instanceof HttpsURLConnection) {
HttpsURLConnection scon = (HttpsURLConnection) con;
if (socketFactory != null) {
scon.setSSLSocketFactory(socketFactory);
}
if (hostnameVerifier != null) {
scon.setHostnameVerifier(hostnameVerifier);
}
} else if (socketFactory != null) {
log.warn("SSL socket factory set but url scheme not https ({})", uri);
}
con.setUseCaches(false);
if (body != null) {
con.setDoOutput(true);
}
String method = body == null ? "GET" : responseType != null ? "POST" : "PUT";
con.setRequestMethod(method);
if (authorization != null) {
con.setRequestProperty("Authorization", authorization);
}
con.setRequestProperty("Accept", "application/json");
if (body != null && body.length() > 0) {
if (contentType == null) {
throw new IllegalArgumentException("contentType must be set when body is not null");
}
con.setRequestProperty("Content-Type", contentType);
}
try {
con.connect();
} catch (ConnectException e) {
throw new IOException("Failed to connect to: " + uri, e);
}
if (body != null && body.length() > 0) {
try (OutputStream out = con.getOutputStream()) {
out.write(body.getBytes(StandardCharsets.UTF_8));
}
}
return handleResponse(con, method, uri, responseType);
}
// Surpressed because of Spotbugs Java 11 bug - https://github.com/spotbugs/spotbugs/issues/756
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
private static T handleResponse(HttpURLConnection con, String method, URI uri, Class responseType) throws IOException {
int code = con.getResponseCode();
if (code != 200 && code != 201 && code != 204) {
InputStream err = con.getErrorStream();
if (err != null) {
ByteArrayOutputStream errbuf = new ByteArrayOutputStream(4096);
try {
copy(err, errbuf);
} catch (Exception e) {
log.warn("[IGNORED] Failed to read response body", e);
}
throw new HttpException(method, uri, code, errbuf.toString(StandardCharsets.UTF_8.name()));
} else {
throw new HttpException(method, uri, code, con.getResponseMessage());
}
}
try (InputStream response = con.getInputStream()) {
if (responseType == null) {
response.close();
return null;
}
InputStream is = response;
if (log.isTraceEnabled()) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
IOUtil.copy(response, buffer);
log.trace("Response body for " + method + " " + uri + ": " + buffer.toString("utf-8"));
is = new ByteArrayInputStream(buffer.toByteArray());
}
return JSONUtil.readJSON(is, responseType);
}
// Don't call con.disconnect() in order to allow connection reuse.
//
// The connection pool per destination is determined by http.maxConnections system property.
//
// See also:
// https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html
// https://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html
// https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy