From e1c39e4bec4d609f32b7e759722273827938afc6 Mon Sep 17 00:00:00 2001 From: Nir Baram <39029087+nirb-jfrog@users.noreply.github.com> Date: Sun, 30 Jun 2019 09:36:04 +0300 Subject: [PATCH] Support adding HTTP request interceptors to the underlying HTTP client (#248) --- .../httpClient/http/HttpBuilderBase.java | 17 ++++++++-- .../client/ArtifactoryClientBuilder.java | 21 +++++++++++- .../artifactory/client/ArtifactoryTests.java | 32 ++++++++++++++++++- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/httpClient/src/main/java/org/jfrog/artifactory/client/httpClient/http/HttpBuilderBase.java b/httpClient/src/main/java/org/jfrog/artifactory/client/httpClient/http/HttpBuilderBase.java index 2c1b916f..5b43a7a3 100644 --- a/httpClient/src/main/java/org/jfrog/artifactory/client/httpClient/http/HttpBuilderBase.java +++ b/httpClient/src/main/java/org/jfrog/artifactory/client/httpClient/http/HttpBuilderBase.java @@ -2,7 +2,9 @@ import org.apache.commons.lang.StringUtils; import org.apache.http.*; -import org.apache.http.auth.*; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; @@ -15,7 +17,10 @@ import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.*; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.DefaultRoutePlanner; import org.apache.http.impl.conn.DefaultSchemePortResolver; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; @@ -27,7 +32,8 @@ import org.jfrog.artifactory.client.httpClient.http.auth.ProxyPreemptiveAuthInterceptor; import javax.net.ssl.SSLContext; -import java.net.*; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; @@ -118,6 +124,11 @@ public T socketTimeout(int soTimeout) { return self(); } + public T addInterceptorLast(HttpRequestInterceptor httpRequestInterceptor) { + builder.addInterceptorLast(httpRequestInterceptor); + return self(); + } + /** * How long to keep connections alive for reuse purposes before ditching them * diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/ArtifactoryClientBuilder.java b/services/src/main/groovy/org/jfrog/artifactory/client/ArtifactoryClientBuilder.java index 7730bc77..d05aa692 100644 --- a/services/src/main/groovy/org/jfrog/artifactory/client/ArtifactoryClientBuilder.java +++ b/services/src/main/groovy/org/jfrog/artifactory/client/ArtifactoryClientBuilder.java @@ -1,10 +1,10 @@ package org.jfrog.artifactory.client; import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpRequestInterceptor; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.ssl.SSLContextBuilder; - import org.jfrog.artifactory.client.httpClient.http.HttpBuilderBase; import org.jfrog.artifactory.client.impl.ArtifactoryImpl; import org.jfrog.artifactory.client.impl.util.ArtifactoryHttpClient; @@ -14,6 +14,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; /** @@ -33,6 +35,7 @@ public class ArtifactoryClientBuilder { private boolean ignoreSSLIssues; private SSLContextBuilder sslContextBuilder; private String accessToken; + private List requestInterceptorList = new ArrayList<>(); protected ArtifactoryClientBuilder() { super(); @@ -95,6 +98,19 @@ public ArtifactoryClientBuilder setAccessToken(String accessToken) { return this; } + /** + * Add an Http request interceptor to the underlying Http client builder used by the artifactory client + *
+ * For further details see + * {@link org.apache.http.impl.client.HttpClientBuilder#addInterceptorLast(org.apache.http.HttpRequestInterceptor)} + * @param httpRequestInterceptor request interceptor that allows manipulating and examining of outgoing requests + * @return ArtifactoryClientBuilder + */ + public ArtifactoryClientBuilder addInterceptorLast(HttpRequestInterceptor httpRequestInterceptor) { + this.requestInterceptorList.add(httpRequestInterceptor); + return this; + } + private CloseableHttpClient createClientBuilder(URI uri) { ArtifactoryHttpClient artifactoryHttpClient = new ArtifactoryHttpClient(); artifactoryHttpClient.hostFromUrl(uri.toString()); @@ -126,6 +142,9 @@ private CloseableHttpClient createClientBuilder(URI uri) { else { artifactoryHttpClient.trustSelfSignCert(!ignoreSSLIssues); } + for (HttpRequestInterceptor httpRequestInterceptor : requestInterceptorList) { + artifactoryHttpClient.addInterceptorLast(httpRequestInterceptor); + } return artifactoryHttpClient.build(); } diff --git a/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTests.java b/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTests.java index 928ee9d4..9c8ac0a1 100644 --- a/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTests.java +++ b/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTests.java @@ -1,8 +1,10 @@ package org.jfrog.artifactory.client; +import org.jfrog.artifactory.client.impl.ArtifactoryRequestImpl; import org.testng.annotations.Test; import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; import static junit.framework.Assert.assertEquals; @@ -80,7 +82,7 @@ public void urlsBuilderTest() throws IOException { assertEquals("", artifactory.getContextName()); artifactory = ArtifactoryClientBuilder.create() - .setUrl("http://abc.com:80/ab/artifactory/webapp/webapp").build(); + .setUrl("http://abc.com:80/ab/artifactory/webapp/webapp").build(); assertEquals("http://abc.com:80", artifactory.getUri()); assertEquals("ab/artifactory/webapp/webapp", artifactory.getContextName()); @@ -124,4 +126,32 @@ public void socketTimeoutBuilderTest() { assertEquals(builder.getSocketTimeout(), new Integer(100)); builder.build(); } + + @Test + public void addInterceptorTest() { + AtomicInteger interceptor1Visits = new AtomicInteger(0); + AtomicInteger interceptor2Visits = new AtomicInteger(0); + ArtifactoryClientBuilder builder = ArtifactoryClientBuilder.create(); + builder.setUrl("http://localhost:7/"); + builder.addInterceptorLast((request, httpContext) -> { + interceptor1Visits.incrementAndGet(); + }); + builder.addInterceptorLast((request, httpContext) -> { + // Verify interceptor1 was called before interceptor2 + assertEquals(interceptor1Visits.intValue(), 1); + interceptor2Visits.incrementAndGet(); + }); + + ArtifactoryRequest req = new ArtifactoryRequestImpl() + .method(ArtifactoryRequest.Method.GET) + .apiUrl("api/security/permissions") + .responseType(ArtifactoryRequest.ContentType.JSON); + + try { + builder.build().restCall(req); + } catch (IOException ignore) { + } + assertEquals(interceptor1Visits.intValue(), 1); + assertEquals(interceptor2Visits.intValue(), 1); + } }