Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for dynamic proxy configuration at the HTTP protocol level #3593

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

raccoonback
Copy link
Contributor

@raccoonback raccoonback commented Jan 19, 2025

Motivation

The existing proxy(...) and noProxy() methods are static, applying the same configuration to all requests. In scenarios where proxy behavior needs to change dynamically based on the request (e.g., host-specific proxies, conditional proxy usage), this static approach is insufficient.

The proxyWhen(...) method fills this gap by allowing developers to provide a function that resolves proxy settings dynamically during request execution.

Description

  • Added support for the proxyWhen(BiConsumer<HttpClientConfig, ? super ProxyProvider.TypeSpec>) method to HttpClient.
    • This method enables users to dynamically determine the proxy configuration on a per-request basis using a provided HttpClientConfig function.
    • proxyWhen(...) evaluates the configuration function for each HTTP request, allowing fine-grained control over proxy settings.
  • If proxyWhen(...) is used, any static proxy configurations applied via proxy(...) or noProxy() will be ignored.
  • Internally, it uses deferredConfig to set the proxyProvider at the HttpClientConnect.connect() stage.
HttpClient client = HttpClient.create()
    .proxyWhen((HttpClientConfig config, ProxyProvider.TypeSpec spec) -> {
        if (config.uri().equals("example.com")) {
            spec.type(ProxyProvider.Proxy.HTTP)
                .host("proxy.example.com")
                .port(8080);
        }
    });

client.get()
    .uri("http://example.com")
    .response()
    .block();

Backward Compatibility

  • The new proxyWhen(...) method is additive and does not interfere with existing static configurations unless explicitly used.
  • Static configurations (proxy(...) and noProxy()) remain unchanged and fully functional.

Related Issue

Copy link
Member

@violetagg violetagg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raccoonback Thanks for the PR!

Comment on lines +1647 to +1665
public final HttpClient proxyWhen(BiConsumer<HttpClientConfig, ? super ProxyProvider.TypeSpec> proxyBuilder) {
Objects.requireNonNull(proxyBuilder, "proxyBuilder");
HttpClient dup = duplicate();
dup.configuration()
.deferredConf(
config -> {
ProxyProvider.TypeSpec spec = ProxyProvider.builder();
proxyBuilder.accept(config, spec);

if (((ProxyProvider.Validator) spec).isConfiguredCorrectly()) {
ProxyProvider proxyProvider = ((ProxyProvider.Builder) spec).build();
config.proxyProvider(proxyProvider);
}

return Mono.just(config);
}
);
return dup;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think if we use Mono for the proxy configuration? Imagine that you need to resolve something else before providing the proxy configuration.
Something similar to what we have for the headers e.g. this test case:

.headersWhen(h -> login(disposableServer.port()).map(token -> h.set("Authorization", token)))

Suggested change
public final HttpClient proxyWhen(BiConsumer<HttpClientConfig, ? super ProxyProvider.TypeSpec> proxyBuilder) {
Objects.requireNonNull(proxyBuilder, "proxyBuilder");
HttpClient dup = duplicate();
dup.configuration()
.deferredConf(
config -> {
ProxyProvider.TypeSpec spec = ProxyProvider.builder();
proxyBuilder.accept(config, spec);
if (((ProxyProvider.Validator) spec).isConfiguredCorrectly()) {
ProxyProvider proxyProvider = ((ProxyProvider.Builder) spec).build();
config.proxyProvider(proxyProvider);
}
return Mono.just(config);
}
);
return dup;
}
public final HttpClient proxyWhen(BiFunction<HttpClientConfig, ? super ProxyProvider.TypeSpec,
Mono<? extends ProxyProvider.Builder>> proxyBuilder) {
Objects.requireNonNull(proxyBuilder, "proxyBuilder");
HttpClient dup = duplicate();
dup.configuration().deferredConf(config -> {
Mono<? extends ProxyProvider.Builder> mono = proxyBuilder.apply(config, ProxyProvider.builder());
return mono == Mono.<ProxyProvider.Builder>empty() ?
Mono.just(config) :
mono.map(builder -> {
config.proxyProvider(builder.build());
return config;
});
});
return dup;
}

@violetagg violetagg added the type/enhancement A general enhancement label Jan 21, 2025
@violetagg violetagg added this to the 1.2.3 milestone Jan 21, 2025
@violetagg violetagg linked an issue Jan 21, 2025 that may be closed by this pull request
@violetagg violetagg changed the title Support for dynamic proxy configuration at the HTTP protocol level Support for dynamic proxy configuration at the HTTP protocol level Jan 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HttpClient proxy configuration per request
2 participants