Skip to content

Commit fbbd3dc

Browse files
committed
Add httpAuthentication API and rename existing to httpAuthenticationWhen
Introduce httpAuthentication(BiFunction) for automatic 401 retry, and rename the predicate-based method to httpAuthenticationWhen for clarity when custom retry conditions are needed. Signed-off-by: raccoonback <[email protected]>
1 parent 09deb86 commit fbbd3dc

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClient.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,21 +1697,55 @@ public final HttpClient wiretap(boolean enable) {
16971697
}
16981698

16991699
/**
1700-
* Configure HTTP authentication for the client with custom authentication logic.
1700+
* Configure HTTP authentication that retries on 401 Unauthorized responses.
17011701
* <p>
17021702
* This method provides a generic authentication framework that allows users to implement
17031703
* their own authentication mechanisms (e.g., Negotiate/SPNEGO, OAuth, Bearer tokens, custom schemes).
1704-
* The framework handles when to apply authentication, while users control how to generate
1705-
* and attach authentication credentials.
1704+
* The framework automatically retries requests when a 401 Unauthorized response is received.
17061705
* </p>
17071706
*
17081707
* <p>Example - Token-based Authentication:</p>
17091708
* <pre>
17101709
* {@code
17111710
* HttpClient client = HttpClient.create()
17121711
* .httpAuthentication(
1713-
* // Retry on 401 Unauthorized responses
1714-
* (req, res) -> res.status().code() == 401,
1712+
* // Add authentication header before request
1713+
* (req, addr) -> {
1714+
* String token = generateAuthToken(addr);
1715+
* req.header(HttpHeaderNames.AUTHORIZATION, "Bearer " + token);
1716+
* return Mono.empty();
1717+
* }
1718+
* );
1719+
* }
1720+
* </pre>
1721+
*
1722+
* @param authenticator applies authentication to the request, receives the request and remote address,
1723+
* returns a Mono that completes when authentication is applied
1724+
* @return a new {@link HttpClient}
1725+
* @since 1.3.0
1726+
* @see #httpAuthenticationWhen(BiPredicate, BiFunction)
1727+
*/
1728+
public final HttpClient httpAuthentication(
1729+
BiFunction<? super HttpClientRequest, ? super SocketAddress, ? extends Mono<Void>> authenticator) {
1730+
return httpAuthenticationWhen(HttpClientConfig.AUTHENTICATION_PREDICATE, authenticator);
1731+
}
1732+
1733+
/**
1734+
* Configure HTTP authentication for the client with custom authentication logic and retry predicate.
1735+
* <p>
1736+
* This method provides a generic authentication framework that allows users to implement
1737+
* their own authentication mechanisms (e.g., Negotiate/SPNEGO, OAuth, Bearer tokens, custom schemes).
1738+
* The framework handles when to apply authentication based on the provided predicate, while users
1739+
* control how to generate and attach authentication credentials.
1740+
* </p>
1741+
*
1742+
* <p>Example - Token-based Authentication with custom retry logic:</p>
1743+
* <pre>
1744+
* {@code
1745+
* HttpClient client = HttpClient.create()
1746+
* .httpAuthenticationWhen(
1747+
* // Custom retry predicate (e.g., retry on 401 or 403)
1748+
* (req, res) -> res.status().code() == 401 || res.status().code() == 403,
17151749
* // Add authentication header before request
17161750
* (req, addr) -> {
17171751
* String token = generateAuthToken(addr);
@@ -1729,7 +1763,7 @@ public final HttpClient wiretap(boolean enable) {
17291763
* @return a new {@link HttpClient}
17301764
* @since 1.3.0
17311765
*/
1732-
public final HttpClient httpAuthentication(
1766+
public final HttpClient httpAuthenticationWhen(
17331767
BiPredicate<HttpClientRequest, HttpClientResponse> predicate,
17341768
BiFunction<? super HttpClientRequest, ? super SocketAddress, ? extends Mono<Void>> authenticator) {
17351769
Objects.requireNonNull(predicate, "predicate");

reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClientConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,9 @@ else if (metricsRecorder instanceof ContextAwareHttpClientMetricsRecorder) {
845845
.codeAsText())
846846
.matches();
847847

848+
static final BiPredicate<HttpClientRequest, HttpClientResponse> AUTHENTICATION_PREDICATE =
849+
(req, res) -> res.status().equals(HttpResponseStatus.UNAUTHORIZED);
850+
848851
static final int h3 = 0b1000;
849852

850853
static final int h2 = 0b010;

reactor-netty-http/src/test/java/reactor/netty/http/client/HttpClientTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3866,7 +3866,7 @@ void testHttpAuthenticationNoRetryWhenPredicateDoesNotMatch() {
38663866
HttpClient client =
38673867
HttpClient.create()
38683868
.port(disposableServer.port())
3869-
.httpAuthentication(
3869+
.httpAuthenticationWhen(
38703870
// Only retry on 401, not 403
38713871
(req, res) -> res.status() == HttpResponseStatus.UNAUTHORIZED,
38723872
(req, addr) -> {
@@ -3916,7 +3916,7 @@ void testHttpAuthenticationWithMonoAuthenticator() {
39163916
HttpClient client =
39173917
HttpClient.create()
39183918
.port(disposableServer.port())
3919-
.httpAuthentication(
3919+
.httpAuthenticationWhen(
39203920
(req, res) -> res.status() == HttpResponseStatus.UNAUTHORIZED,
39213921
(req, addr) -> {
39223922
int callNum = authCallCount.incrementAndGet();
@@ -3964,7 +3964,7 @@ void testHttpAuthenticationMultipleRequests() {
39643964
HttpClient client =
39653965
HttpClient.create()
39663966
.port(disposableServer.port())
3967-
.httpAuthentication(
3967+
.httpAuthenticationWhen(
39683968
(req, res) -> res.status() == HttpResponseStatus.UNAUTHORIZED,
39693969
(req, addr) -> {
39703970
req.header(HttpHeaderNames.AUTHORIZATION, "Bearer valid-token");
@@ -4015,7 +4015,7 @@ void testHttpAuthenticationWithCustomStatusCode() {
40154015
HttpClient client =
40164016
HttpClient.create()
40174017
.port(disposableServer.port())
4018-
.httpAuthentication(
4018+
.httpAuthenticationWhen(
40194019
// Retry on 407 instead of 401
40204020
(req, res) -> res.status() == HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED,
40214021
(req, addr) -> {

0 commit comments

Comments
 (0)