From 8187727b650560cf6aec6e37696eba86ac79b20b Mon Sep 17 00:00:00 2001 From: Aaron Coburn Date: Mon, 6 May 2024 16:16:38 -0500 Subject: [PATCH 1/3] Proper handling of protected resources with RDF body handlers --- .../com/inrupt/client/core/DefaultClient.java | 11 ++++ .../inrupt/client/core/NoBodyResponse.java | 59 +++++++++++++++++++ .../client/core/DefaultClientRdfJenaTest.java | 2 +- .../core/DefaultClientRdfRDF4JTest.java | 2 +- 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/inrupt/client/core/NoBodyResponse.java diff --git a/core/src/main/java/com/inrupt/client/core/DefaultClient.java b/core/src/main/java/com/inrupt/client/core/DefaultClient.java index 852442aaff9..f31235a4b09 100644 --- a/core/src/main/java/com/inrupt/client/core/DefaultClient.java +++ b/core/src/main/java/com/inrupt/client/core/DefaultClient.java @@ -21,6 +21,7 @@ package com.inrupt.client.core; import com.inrupt.client.Client; +import com.inrupt.client.ClientHttpException; import com.inrupt.client.Headers.WwwAuthenticate; import com.inrupt.client.Request; import com.inrupt.client.Response; @@ -84,6 +85,16 @@ public CompletionStage> send(final Request request, .map(token -> httpClient.send(upgradeRequest(request, token), responseBodyHandler)) // Otherwise perform the regular HTTP authorization dance .orElseGet(() -> httpClient.send(request, responseBodyHandler) + .handle((res, err) -> { + if (err instanceof ClientHttpException) { + final ClientHttpException ex = (ClientHttpException) err; + if (ex.getStatusCode() == UNAUTHORIZED) { + return new NoBodyResponse(ex.getUri(), ex.getStatusCode(), ex.getHeaders()); + } + throw ex; + } + return res; + }) .thenCompose(res -> { if (res.statusCode() == UNAUTHORIZED) { final List challenges = WwwAuthenticate diff --git a/core/src/main/java/com/inrupt/client/core/NoBodyResponse.java b/core/src/main/java/com/inrupt/client/core/NoBodyResponse.java new file mode 100644 index 00000000000..055fab53469 --- /dev/null +++ b/core/src/main/java/com/inrupt/client/core/NoBodyResponse.java @@ -0,0 +1,59 @@ +/* + * Copyright Inrupt Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.inrupt.client.core; + +import com.inrupt.client.Headers; +import com.inrupt.client.Response; + +import java.net.URI; + +class NoBodyResponse implements Response { + + private final Headers responseHeaders; + private final int responseStatusCode; + private final URI responseUri; + + public NoBodyResponse(final URI uri, final int statusCode, final Headers headers) { + this.responseHeaders = headers; + this.responseStatusCode = statusCode; + this.responseUri = uri; + } + + @Override + public Headers headers() { + return responseHeaders; + } + + @Override + public URI uri() { + return responseUri; + } + + @Override + public int statusCode() { + return responseStatusCode; + } + + @Override + public T body() { + return (T) null; + } +} diff --git a/core/src/test/java/com/inrupt/client/core/DefaultClientRdfJenaTest.java b/core/src/test/java/com/inrupt/client/core/DefaultClientRdfJenaTest.java index c761713f108..823c94df5bf 100644 --- a/core/src/test/java/com/inrupt/client/core/DefaultClientRdfJenaTest.java +++ b/core/src/test/java/com/inrupt/client/core/DefaultClientRdfJenaTest.java @@ -85,7 +85,7 @@ void testSendOfModelProtectedResource() { .GET() .build(); - final Response response = client.send(request, JenaBodyHandlers.ofModel()) + final Response response = client.send(request, JenaBodyHandlers.ofJenaModel()) .toCompletableFuture().join(); assertEquals(200, response.statusCode()); diff --git a/core/src/test/java/com/inrupt/client/core/DefaultClientRdfRDF4JTest.java b/core/src/test/java/com/inrupt/client/core/DefaultClientRdfRDF4JTest.java index e17f4db0612..2717966a483 100644 --- a/core/src/test/java/com/inrupt/client/core/DefaultClientRdfRDF4JTest.java +++ b/core/src/test/java/com/inrupt/client/core/DefaultClientRdfRDF4JTest.java @@ -86,7 +86,7 @@ void testSendOfModelProtectedResource() { .GET() .build(); - final Response response = client.send(request, RDF4JBodyHandlers.ofModel()) + final Response response = client.send(request, RDF4JBodyHandlers.ofRDF4JModel()) .toCompletableFuture().join(); assertEquals(200, response.statusCode()); From 6eeab68700145adc8967cdabc6a2b48b8c0c23d8 Mon Sep 17 00:00:00 2001 From: Aaron Coburn Date: Tue, 7 May 2024 07:58:26 -0500 Subject: [PATCH 2/3] refactor --- .../com/inrupt/client/core/DefaultClient.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/inrupt/client/core/DefaultClient.java b/core/src/main/java/com/inrupt/client/core/DefaultClient.java index f31235a4b09..3a873dfa257 100644 --- a/core/src/main/java/com/inrupt/client/core/DefaultClient.java +++ b/core/src/main/java/com/inrupt/client/core/DefaultClient.java @@ -85,16 +85,7 @@ public CompletionStage> send(final Request request, .map(token -> httpClient.send(upgradeRequest(request, token), responseBodyHandler)) // Otherwise perform the regular HTTP authorization dance .orElseGet(() -> httpClient.send(request, responseBodyHandler) - .handle((res, err) -> { - if (err instanceof ClientHttpException) { - final ClientHttpException ex = (ClientHttpException) err; - if (ex.getStatusCode() == UNAUTHORIZED) { - return new NoBodyResponse(ex.getUri(), ex.getStatusCode(), ex.getHeaders()); - } - throw ex; - } - return res; - }) + .handle((res, err) -> recover(res, err)) .thenCompose(res -> { if (res.statusCode() == UNAUTHORIZED) { final List challenges = WwwAuthenticate @@ -114,6 +105,7 @@ public CompletionStage> send(final Request request, })); } + Request upgradeRequest(final Request request, final Credential token) { final Request.Builder builder = Request.newBuilder() .uri(request.uri()) @@ -137,6 +129,25 @@ Request upgradeRequest(final Request request, final Credential token) { return builder.build(); } + @SuppressWarnings("unchecked") + static Response recover(final Response res, final Throwable err) throws R { + if (err != null) { + if (err instanceof ClientHttpException) { + final ClientHttpException ex = (ClientHttpException) err; + if (ex.getStatusCode() == UNAUTHORIZED) { + return new NoBodyResponse(ex.getUri(), ex.getStatusCode(), ex.getHeaders()); + } + } else if (err.getCause() instanceof ClientHttpException) { + final ClientHttpException ex = (ClientHttpException) err.getCause(); + if (ex.getStatusCode() == UNAUTHORIZED) { + return new NoBodyResponse(ex.getUri(), ex.getStatusCode(), ex.getHeaders()); + } + } + throw (R) err; + } + return res; + } + public static Client.Builder newBuilder() { return new Builder(); } From 817829298e76e5065c31c9f495a37eebacb82aee Mon Sep 17 00:00:00 2001 From: Aaron Coburn Date: Tue, 7 May 2024 08:33:52 -0500 Subject: [PATCH 3/3] Remove formatting change --- core/src/main/java/com/inrupt/client/core/DefaultClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/com/inrupt/client/core/DefaultClient.java b/core/src/main/java/com/inrupt/client/core/DefaultClient.java index 3a873dfa257..9b1852ca459 100644 --- a/core/src/main/java/com/inrupt/client/core/DefaultClient.java +++ b/core/src/main/java/com/inrupt/client/core/DefaultClient.java @@ -105,7 +105,6 @@ public CompletionStage> send(final Request request, })); } - Request upgradeRequest(final Request request, final Credential token) { final Request.Builder builder = Request.newBuilder() .uri(request.uri())