Skip to content

Commit 067ee8f

Browse files
authored
Support for lastEndpointUri() in Webclient responses (#7113)
* Support for lastEndpointUri() in Webclient responses. This method can be used to obtain the final redirect URI of the corresponding request. Tests updated. * Lazy conversion to URI.
1 parent 8479515 commit 067ee8f

File tree

7 files changed

+43
-3
lines changed

7 files changed

+43
-3
lines changed

nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ UriHelper uriHelper() {
286286
private Http2ClientResponse readResponse(Http2ClientStream stream) {
287287
Http2Headers headers = stream.readHeaders();
288288

289-
return new ClientResponseImpl(headers, stream);
289+
return new ClientResponseImpl(headers, stream, uri);
290290
}
291291

292292
private byte[] entityBytes(Object entity) {

nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientResponseImpl.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,21 +16,26 @@
1616

1717
package io.helidon.nima.http2.webclient;
1818

19+
import java.net.URI;
20+
1921
import io.helidon.common.http.ClientResponseHeaders;
2022
import io.helidon.common.http.Headers;
2123
import io.helidon.common.http.Http;
2224
import io.helidon.nima.http.media.ReadableEntity;
2325
import io.helidon.nima.http2.Http2Headers;
26+
import io.helidon.nima.webclient.UriHelper;
2427

2528
class ClientResponseImpl implements Http2ClientResponse {
2629
private final Http.Status responseStatus;
2730
private final ClientResponseHeaders responseHeaders;
31+
private final UriHelper lastEndpointUri;
2832
private Http2ClientStream stream;
2933

30-
ClientResponseImpl(Http2Headers headers, Http2ClientStream stream) {
34+
ClientResponseImpl(Http2Headers headers, Http2ClientStream stream, UriHelper lastEndpointUri) {
3135
this.responseStatus = headers.status();
3236
this.responseHeaders = ClientResponseHeaders.create(headers.httpHeaders());
3337
this.stream = stream;
38+
this.lastEndpointUri = lastEndpointUri;
3439
}
3540

3641
@Override
@@ -48,6 +53,11 @@ public ReadableEntity entity() {
4853
return stream.entity().copy(() -> this.stream = null);
4954
}
5055

56+
@Override
57+
public URI lastEndpointUri() {
58+
return lastEndpointUri.toUri();
59+
}
60+
5161
@Override
5262
public void close() {
5363
if (stream != null) {

nima/tests/integration/webclient/webclient/src/test/java/io/helidon/nima/webclient/http1/ClientRequestImplTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ void testRedirect() {
300300
try (Http1ClientResponse response = injectedHttp1client.put("/redirect")
301301
.submit("Test entity")) {
302302
assertThat(response.status(), is(Http.Status.OK_200));
303+
assertThat(response.lastEndpointUri().getPath(), is("/afterRedirect"));
303304
assertThat(response.as(String.class), is(EXPECTED_GET_AFTER_REDIRECT_STRING));
304305
}
305306
}
@@ -314,6 +315,7 @@ void testRedirectKeepMethod() {
314315

315316
try (Http1ClientResponse response = injectedHttp1client.put("/redirectKeepMethod")
316317
.submit("Test entity")) {
318+
assertThat(response.lastEndpointUri().getPath(), is("/afterRedirect"));
317319
assertThat(response.status(), is(Http.Status.NO_CONTENT_204));
318320
}
319321
}

nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientResponse.java

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.helidon.nima.webclient;
1818

1919
import java.io.InputStream;
20+
import java.net.URI;
2021

2122
import io.helidon.common.GenericType;
2223
import io.helidon.common.http.Headers;
@@ -84,6 +85,13 @@ default <T extends Source<?>> void source(GenericType<T> sourceType, T source) {
8485
throw new UnsupportedOperationException("No source available for " + sourceType);
8586
}
8687

88+
/**
89+
* URI of the last request. (after redirection)
90+
*
91+
* @return last URI
92+
*/
93+
URI lastEndpointUri();
94+
8795
/**
8896
* Closes the response.
8997
* This may have no impact on the underlying connection.

nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/UriHelper.java

+9
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ public String toString() {
9494
return scheme + "://" + authority + (path.startsWith("/") ? "" : "/") + path;
9595
}
9696

97+
/**
98+
* Convert instance to {@link java.net.URI}.
99+
*
100+
* @return the converted URI
101+
*/
102+
public URI toUri() {
103+
return URI.create(toString());
104+
}
105+
97106
/**
98107
* Scheme of this URI.
99108
*

nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ private ClientResponseImpl invokeServices(WebClientService.Chain callChain,
381381
serviceResponse.reader(),
382382
mediaContext,
383383
clientConfig.mediaTypeParserMode(),
384+
uri,
384385
complete);
385386
}
386387

nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientResponseImpl.java

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.helidon.nima.webclient.http1;
1818

19+
import java.net.URI;
1920
import java.nio.charset.StandardCharsets;
2021
import java.util.List;
2122
import java.util.ServiceLoader;
@@ -42,6 +43,7 @@
4243
import io.helidon.nima.http.media.ReadableEntityBase;
4344
import io.helidon.nima.webclient.ClientConnection;
4445
import io.helidon.nima.webclient.ClientResponseEntity;
46+
import io.helidon.nima.webclient.UriHelper;
4547
import io.helidon.nima.webclient.http.spi.Source;
4648
import io.helidon.nima.webclient.http.spi.SourceHandlerProvider;
4749

@@ -70,6 +72,7 @@ class ClientResponseImpl implements Http1ClientResponse {
7072
private final List<String> trailerNames;
7173
// Media type parsing mode configured on client.
7274
private final ParserMode parserMode;
75+
private final UriHelper lastEndpointUri;
7376

7477
private ClientConnection connection;
7578
private long entityLength;
@@ -83,6 +86,7 @@ class ClientResponseImpl implements Http1ClientResponse {
8386
DataReader reader,
8487
MediaContext mediaContext,
8588
ParserMode parserMode,
89+
UriHelper lastEndpointUri,
8690
CompletableFuture<Void> whenComplete) {
8791
this.responseStatus = responseStatus;
8892
this.requestHeaders = requestHeaders;
@@ -92,6 +96,7 @@ class ClientResponseImpl implements Http1ClientResponse {
9296
this.mediaContext = mediaContext;
9397
this.parserMode = parserMode;
9498
this.channelId = connection.channelId();
99+
this.lastEndpointUri = lastEndpointUri;
95100
this.whenComplete = whenComplete;
96101

97102
if (responseHeaders.contains(Header.CONTENT_LENGTH)) {
@@ -214,6 +219,11 @@ private ReadableEntity entity(ClientRequestHeaders requestHeaders,
214219
return ReadableEntityBase.empty();
215220
}
216221

222+
@Override
223+
public URI lastEndpointUri() {
224+
return lastEndpointUri.toUri();
225+
}
226+
217227
private BufferData readEntityChunked(int estimate) {
218228
int endOfChunkSize = reader.findNewLine(256);
219229
if (endOfChunkSize == 256) {

0 commit comments

Comments
 (0)