Allow users to provide a customizer to customize the HttpClient behavior. (#2413)

Fixes #2410

Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
This commit is contained in:
Ryan Baxter
2024-04-29 08:57:28 -04:00
committed by GitHub
parent c372fcf563
commit d2168e90bb
7 changed files with 99 additions and 11 deletions

View File

@@ -62,6 +62,7 @@ import org.springframework.cloud.config.server.environment.EnvironmentWatch;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentProperties;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentRepository;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.HttpClient4BuilderCustomizer;
import org.springframework.cloud.config.server.environment.HttpClientConfigurableHttpConnectionFactory;
import org.springframework.cloud.config.server.environment.HttpClientVaultRestTemplateFactory;
import org.springframework.cloud.config.server.environment.HttpRequestConfigTokenProvider;
@@ -184,11 +185,12 @@ public class EnvironmentRepositoryConfiguration {
Optional<ConfigurableHttpConnectionFactory> jgitHttpConnectionFactory,
Optional<TransportConfigCallback> customTransportConfigCallback,
Optional<GoogleCloudSourceSupport> googleCloudSourceSupport,
GitCredentialsProviderFactory gitCredentialsProviderFactory) {
GitCredentialsProviderFactory gitCredentialsProviderFactory,
List<HttpClient4BuilderCustomizer> customizers) {
final TransportConfigCallbackFactory transportConfigCallbackFactory = new TransportConfigCallbackFactory(
customTransportConfigCallback.orElse(null), googleCloudSourceSupport.orElse(null));
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, jgitHttpConnectionFactory,
transportConfigCallbackFactory, gitCredentialsProviderFactory);
transportConfigCallbackFactory, gitCredentialsProviderFactory, customizers);
}
@Bean

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.config.server.environment;
import java.util.Collections;
import java.util.List;
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
/**
@@ -23,6 +26,11 @@ import org.eclipse.jgit.transport.http.HttpConnectionFactory;
*/
public interface ConfigurableHttpConnectionFactory extends HttpConnectionFactory {
void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties) throws Exception;
default void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
addConfiguration(environmentProperties, Collections.EMPTY_LIST);
}
void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties,
List<HttpClient4BuilderCustomizer> customizers) throws Exception;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2018-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.config.server.environment;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* @author Ryan Baxter
*/
public interface HttpClient4BuilderCustomizer {
/**
* Allows for customization of the HttpClientBuilder before it is created.
* @param httpClientBuilder the HttpClientBuilder to customize
*/
void customize(HttpClientBuilder httpClientBuilder);
}

View File

@@ -54,11 +54,11 @@ public class HttpClientConfigurableHttpConnectionFactory implements Configurable
Map<String, HttpClientBuilder> httpClientBuildersByUri = new LinkedHashMap<>();
@Override
public void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties)
throws GeneralSecurityException {
addHttpClient(environmentProperties);
public void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties,
List<HttpClient4BuilderCustomizer> customizers) throws GeneralSecurityException {
addHttpClient(environmentProperties, customizers);
for (JGitEnvironmentProperties repo : environmentProperties.getRepos().values()) {
addHttpClient(repo);
addHttpClient(repo, customizers);
}
}
@@ -81,9 +81,10 @@ public class HttpClientConfigurableHttpConnectionFactory implements Configurable
}
}
private void addHttpClient(JGitEnvironmentProperties properties) throws GeneralSecurityException {
private void addHttpClient(JGitEnvironmentProperties properties, List<HttpClient4BuilderCustomizer> customizers)
throws GeneralSecurityException {
if (properties.getUri() != null && properties.getUri().startsWith("http")) {
this.httpClientBuildersByUri.put(properties.getUri(), HttpClient4Support.builder(properties));
this.httpClientBuildersByUri.put(properties.getUri(), HttpClient4Support.builder(properties, customizers));
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.config.server.environment;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import io.micrometer.observation.ObservationRegistry;
@@ -42,6 +44,8 @@ public class MultipleJGitEnvironmentRepositoryFactory
private final GitCredentialsProviderFactory gitCredentialsProviderFactory;
private final List<HttpClient4BuilderCustomizer> customizers;
@Deprecated
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment, ConfigServerProperties server,
TransportConfigCallbackFactory transportConfigCallbackFactory) {
@@ -61,11 +65,21 @@ public class MultipleJGitEnvironmentRepositoryFactory
Optional<ConfigurableHttpConnectionFactory> connectionFactory,
TransportConfigCallbackFactory transportConfigCallbackFactory,
GitCredentialsProviderFactory gitCredentialsProviderFactory) {
this(environment, server, connectionFactory, transportConfigCallbackFactory, gitCredentialsProviderFactory,
Collections.EMPTY_LIST);
}
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment, ConfigServerProperties server,
Optional<ConfigurableHttpConnectionFactory> connectionFactory,
TransportConfigCallbackFactory transportConfigCallbackFactory,
GitCredentialsProviderFactory gitCredentialsProviderFactory,
List<HttpClient4BuilderCustomizer> customizers) {
this.environment = environment;
this.server = server;
this.connectionFactory = connectionFactory;
this.transportConfigCallbackFactory = transportConfigCallbackFactory;
this.gitCredentialsProviderFactory = gitCredentialsProviderFactory;
this.customizers = customizers;
}
@Override
@@ -73,7 +87,7 @@ public class MultipleJGitEnvironmentRepositoryFactory
throws Exception {
if (this.connectionFactory.isPresent()) {
HttpTransport.setConnectionFactory(this.connectionFactory.get());
this.connectionFactory.get().addConfiguration(environmentProperties);
this.connectionFactory.get().addConfiguration(environmentProperties, this.customizers);
}
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment,

View File

@@ -18,6 +18,8 @@ package org.springframework.cloud.config.server.support;
import java.net.ProxySelector;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
@@ -34,6 +36,7 @@ import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.cloud.config.server.environment.HttpClient4BuilderCustomizer;
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
import org.springframework.util.CollectionUtils;
@@ -48,6 +51,11 @@ public final class HttpClient4Support {
public static HttpClientBuilder builder(HttpEnvironmentRepositoryProperties environmentProperties)
throws GeneralSecurityException {
return builder(environmentProperties, Collections.EMPTY_LIST);
}
public static HttpClientBuilder builder(HttpEnvironmentRepositoryProperties environmentProperties,
List<HttpClient4BuilderCustomizer> customizers) throws GeneralSecurityException {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
@@ -78,8 +86,10 @@ public final class HttpClient4Support {
httpClientBuilder.disableRedirectHandling();
int timeout = environmentProperties.getTimeout() * 1000;
return httpClientBuilder.setSSLContext(sslContextBuilder.build()).setDefaultRequestConfig(
httpClientBuilder.setSSLContext(sslContextBuilder.build()).setDefaultRequestConfig(
RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).build());
customizers.forEach(customizer -> customizer.customize(httpClientBuilder));
return httpClientBuilder;
}
static class SchemeBasedRoutePlanner4 extends DefaultRoutePlanner {

View File

@@ -31,6 +31,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class HttpClientConfigurableHttpConnectionFactoryTest {
@@ -69,6 +73,23 @@ public class HttpClientConfigurableHttpConnectionFactoryTest {
assertThat(actualHttpClientBuilder).isSameAs(expectedHttpClientBuilder);
}
@Test
public void customizeHttpClient() throws Exception {
String url = "http://localhost/test.git";
MultipleJGitEnvironmentProperties properties = new MultipleJGitEnvironmentProperties();
properties.setUri(url);
HttpClient4BuilderCustomizer customizer = mock(HttpClient4BuilderCustomizer.class);
this.connectionFactory.addConfiguration(properties, List.of(customizer));
HttpConnection actualConnection = this.connectionFactory.create(new URL(url));
HttpClientBuilder expectedHttpClientBuilder = this.connectionFactory.httpClientBuildersByUri.values().stream()
.findFirst().get();
HttpClientBuilder actualHttpClientBuilder = getActualHttpClientBuilder(actualConnection);
assertThat(actualHttpClientBuilder).isSameAs(expectedHttpClientBuilder);
verify(customizer, times(1)).customize(any(HttpClientBuilder.class));
}
@Test
public void longerUrl() throws Exception {
MultipleJGitEnvironmentProperties properties = new MultipleJGitEnvironmentProperties();