From 8a93a6c2da74c4d34994ca2d657a1aae07a8a3d9 Mon Sep 17 00:00:00 2001 From: Sina Madani Date: Tue, 3 Dec 2024 16:32:47 +0000 Subject: [PATCH] feat: Add support for proxies in HttpConfig (#556) --- CHANGELOG.md | 4 ++ pom.xml | 2 +- .../com/vonage/client/AbstractMethod.java | 3 +- .../java/com/vonage/client/HttpConfig.java | 37 +++++++++++++++++++ .../java/com/vonage/client/HttpWrapper.java | 22 ++++++----- .../com/vonage/client/HttpWrapperTest.java | 24 ++++++++++++ 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78dbe731e..3958c5eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +# [8.15.0] - 2024-12-03 +- Added proxy support to `HttpConfig.Builder` +- Basic auth in header instead of query params in SMS API + # [8.14.0] - 2024-11-14 - Close HTTP responses to prevent resource leaks - Added `RedactResponseException` and deprecated `VonageBadRequestException` diff --git a/pom.xml b/pom.xml index 903f04152..838a54c3d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.vonage server-sdk - 8.14.0 + 8.15.0 Vonage Java Server SDK Java client for Vonage APIs diff --git a/src/main/java/com/vonage/client/AbstractMethod.java b/src/main/java/com/vonage/client/AbstractMethod.java index e2e5367ca..76c5f1825 100644 --- a/src/main/java/com/vonage/client/AbstractMethod.java +++ b/src/main/java/com/vonage/client/AbstractMethod.java @@ -17,6 +17,7 @@ import com.vonage.client.auth.*; import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; @@ -71,7 +72,7 @@ protected ResultT postProcessParsedResponse(ResultT response) { @Override public ResultT execute(RequestT request) throws VonageResponseParseException, VonageClientException { HttpUriRequest httpRequest = applyAuth(makeRequest(request)) - .setHeader("User-Agent", httpWrapper.getUserAgent()) + .setHeader(HttpHeaders.USER_AGENT, httpWrapper.getUserAgent()) .setCharset(StandardCharsets.UTF_8).build(); try (CloseableHttpResponse response = httpWrapper.getHttpClient().execute(httpRequest)) { diff --git a/src/main/java/com/vonage/client/HttpConfig.java b/src/main/java/com/vonage/client/HttpConfig.java index df96168a2..735bc2659 100644 --- a/src/main/java/com/vonage/client/HttpConfig.java +++ b/src/main/java/com/vonage/client/HttpConfig.java @@ -29,11 +29,13 @@ public class HttpConfig { private final int timeoutMillis; private final String customUserAgent, apiBaseUri, restBaseUri, apiEuBaseUri, videoBaseUri; private final Function regionalUriGetter; + private final URI proxy; private HttpConfig(Builder builder) { if ((timeoutMillis = builder.timeoutMillis) < 10) { throw new IllegalArgumentException("Timeout must be greater than 10ms."); } + proxy = builder.proxy; apiBaseUri = builder.apiBaseUri; restBaseUri = builder.restBaseUri; videoBaseUri = builder.videoBaseUri; @@ -89,6 +91,16 @@ public String getCustomUserAgent() { return customUserAgent; } + /** + * Returns the proxy URL to use for the underlying HTTP client configuration. + * + * @return The proxy URI, or {@code null} if not set. + * @since 8.15.0 + */ + public URI getProxy() { + return proxy; + } + @Deprecated public boolean isDefaultApiBaseUri() { return DEFAULT_API_BASE_URI.equals(apiBaseUri); @@ -156,6 +168,7 @@ public static Builder builder() { */ public static class Builder { private int timeoutMillis = 60_000; + private URI proxy; private Function regionalUriGetter = region -> "https://"+region+".vonage.com"; private String customUserAgent, apiBaseUri = DEFAULT_API_BASE_URI, @@ -196,6 +209,30 @@ public Builder timeoutMillis(int timeoutMillis) { return this; } + /** + * Sets the proxy to use for requests. This will route requests through the specified URL. + * + * @param proxy The proxy URI to use as a string. + * @return This builder. + * @since 8.15.0 + * @throws IllegalArgumentException If the proxy URI is invalid. + */ + public Builder proxy(String proxy) { + return proxy(URI.create(proxy)); + } + + /** + * Sets the proxy to use for requests. This will route requests through the specified URL. + * + * @param proxy The proxy URI to use. + * @return This builder. + * @since 8.15.0 + */ + public Builder proxy(URI proxy) { + this.proxy = proxy; + return this; + } + /** * Replaces the URI used in "api" endpoints. * diff --git a/src/main/java/com/vonage/client/HttpWrapper.java b/src/main/java/com/vonage/client/HttpWrapper.java index c9c5384e7..a1e7faadf 100644 --- a/src/main/java/com/vonage/client/HttpWrapper.java +++ b/src/main/java/com/vonage/client/HttpWrapper.java @@ -19,6 +19,7 @@ import com.vonage.client.auth.AuthCollection; import com.vonage.client.auth.AuthMethod; import com.vonage.client.auth.JWTAuthMethod; +import org.apache.http.HttpHost; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.ConnectionConfig; @@ -26,6 +27,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.UUID; @@ -35,7 +37,7 @@ public class HttpWrapper { private static final String CLIENT_NAME = "vonage-java-sdk", - CLIENT_VERSION = "8.14.0", + CLIENT_VERSION = "8.15.0", JAVA_VERSION = System.getProperty("java.version"), USER_AGENT = String.format("%s/%s java/%s", CLIENT_NAME, CLIENT_VERSION, JAVA_VERSION); @@ -131,28 +133,30 @@ protected CloseableHttpClient createHttpClient() { connectionManager.setDefaultMaxPerRoute(200); connectionManager.setMaxTotal(200); connectionManager.setDefaultConnectionConfig( - ConnectionConfig.custom() - .setCharset(StandardCharsets.UTF_8) - .build() + ConnectionConfig.custom().setCharset(StandardCharsets.UTF_8).build() ); connectionManager.setDefaultSocketConfig(SocketConfig.custom().setTcpNoDelay(true).build()); // Need to work out a good value for the following: // threadSafeClientConnManager.setValidateAfterInactivity(); - RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(httpConfig.getTimeoutMillis()) .setConnectionRequestTimeout(httpConfig.getTimeoutMillis()) .setSocketTimeout(httpConfig.getTimeoutMillis()) .build(); - return HttpClientBuilder.create() + HttpClientBuilder clientBuilder = HttpClientBuilder.create() .setConnectionManager(connectionManager) .setUserAgent(getUserAgent()) .setDefaultRequestConfig(requestConfig) - .useSystemProperties() - .disableRedirectHandling() - .build(); + .useSystemProperties().disableRedirectHandling(); + + URI proxy = httpConfig.getProxy(); + if (proxy != null) { + clientBuilder.setProxy(new HttpHost(proxy.getHost(), proxy.getPort(), proxy.getScheme())); + } + + return clientBuilder.build(); } /** diff --git a/src/test/java/com/vonage/client/HttpWrapperTest.java b/src/test/java/com/vonage/client/HttpWrapperTest.java index f496eaab6..3aac855a7 100644 --- a/src/test/java/com/vonage/client/HttpWrapperTest.java +++ b/src/test/java/com/vonage/client/HttpWrapperTest.java @@ -15,6 +15,10 @@ */ package com.vonage.client; +import static com.vonage.client.TestUtils.API_KEY; +import static com.vonage.client.TestUtils.API_SECRET; +import com.vonage.client.application.ApplicationClient; +import com.vonage.client.auth.ApiKeyHeaderAuthMethod; import com.vonage.client.auth.AuthCollection; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; @@ -67,4 +71,24 @@ public void testValidCustomUserAgent() { assertEquals(customUa, wrapper.getHttpConfig().getCustomUserAgent()); assertEquals(defaultUa + " " + customUa, wrapper.getUserAgent()); } + + @Test + public void testProxy() { + var headerAuth = new ApiKeyHeaderAuthMethod(API_KEY, API_SECRET); + wrapper = new HttpWrapper(headerAuth); + assertNull(wrapper.getHttpConfig().getProxy()); + + var appClient = new ApplicationClient(wrapper); + assertThrows(VonageApiResponseException.class, appClient::listApplications); + + wrapper = new HttpWrapper(HttpConfig.builder().proxy("http://localhost:8080").build(), headerAuth); + var proxyUri = wrapper.getHttpConfig().getProxy(); + assertNotNull(proxyUri); + assertEquals("localhost", proxyUri.getHost()); + assertEquals(8080, proxyUri.getPort()); + assertEquals("http", proxyUri.getScheme()); + + appClient = new ApplicationClient(wrapper); + assertThrows(VonageMethodFailedException.class, appClient::listApplications); + } }