Skip to content

Commit 6896671

Browse files
authored
JCL-426: Normalize URI resource identifiers (#777)
1 parent 290a73f commit 6896671

File tree

7 files changed

+22
-11
lines changed

7 files changed

+22
-11
lines changed

access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredential.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public class AccessCredential {
6464
*/
6565
protected AccessCredential(final URI identifier, final String credential,
6666
final CredentialData data, final CredentialMetadata metadata) {
67-
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null");
67+
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null").normalize();
6868
this.credential = Objects.requireNonNull(credential, "credential may not be null!");
6969
Objects.requireNonNull(data, "credential data may not be null!");
7070
Objects.requireNonNull(metadata, "credential metadata may not be null!");

api/src/main/java/com/inrupt/client/NonRDFSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected NonRDFSource(final URI identifier, final String contentType, final Inp
6363
*/
6464
protected NonRDFSource(final URI identifier, final String contentType, final InputStream entity,
6565
final Headers headers) {
66-
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null!");
66+
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null!").normalize();
6767
this.contentType = Objects.requireNonNull(contentType, "contentType may not be null!");
6868
this.entity = Objects.requireNonNull(entity, "entity may not be null!");
6969
this.headers = headers == null ? Headers.empty() : headers;

api/src/main/java/com/inrupt/client/RDFSource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.io.InputStream;
3131
import java.io.OutputStream;
3232
import java.net.URI;
33+
import java.util.Objects;
3334

3435
import org.apache.commons.rdf.api.Dataset;
3536
import org.apache.commons.rdf.api.RDF;
@@ -102,8 +103,8 @@ protected RDFSource(final URI identifier, final RDFSyntax syntax, final Dataset
102103
protected RDFSource(final URI identifier, final RDFSyntax syntax, final Dataset dataset, final Headers headers) {
103104
super(dataset == null ? rdf.createDataset() : dataset);
104105
this.headers = headers == null ? Headers.empty() : headers;
105-
this.identifier = identifier;
106-
this.syntax = syntax;
106+
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null!").normalize();
107+
this.syntax = Objects.requireNonNull(syntax);
107108
}
108109

109110
@Override

api/src/main/java/com/inrupt/client/Request.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public static Builder newBuilder(final URI uri) {
117117

118118
Request(final URI uri, final String method, final Map<String, List<String>> headers,
119119
final BodyPublisher publisher, final Duration timeout) {
120-
this.requestUri = Objects.requireNonNull(uri, "Request URI may not be null!");
120+
this.requestUri = Objects.requireNonNull(uri, "Request URI may not be null!").normalize();
121121
this.requestMethod = Objects.requireNonNull(method, "Request method may not be null!");
122122
this.requestHeaders = Headers.of(Objects.requireNonNull(headers, "Request headers may not be null!"));
123123
this.requestTimeout = timeout;

api/src/main/java/com/inrupt/client/util/URIBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public URI build() {
111111
schemeSpecificPart.append(String.join("&", queryParams));
112112
}
113113
try {
114-
return new URI(scheme, schemeSpecificPart.toString(), uriFragment);
114+
return new URI(scheme, schemeSpecificPart.toString(), uriFragment).normalize();
115115
} catch (final URISyntaxException ex) {
116116
throw new IllegalArgumentException("Invalid URI value", ex);
117117
}

api/src/test/java/com/inrupt/client/util/URIBuilderTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,13 @@ void testBuildNullBlankPath() {
142142

143143
assertEquals(expected, URIBuilder.newBuilder(uri).path(null).path("").path("/data/").build());
144144
}
145+
146+
@Test
147+
void testNormalized() {
148+
final URI uri = URI.create("https://storage.example/container1/../container2/");
149+
final URI expected = URI.create("https://storage.example/container2/");
150+
151+
assertNotEquals(expected, uri);
152+
assertEquals(expected, URIBuilder.newBuilder(uri).build());
153+
}
145154
}

solid/src/main/java/com/inrupt/client/solid/SolidClient.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,11 @@ public <T extends Resource> CompletionStage<T> read(final URI identifier, final
130130
defaultHeaders.firstValue(USER_AGENT).ifPresent(agent -> builder.setHeader(USER_AGENT, agent));
131131
headers.firstValue(USER_AGENT).ifPresent(agent -> builder.setHeader(USER_AGENT, agent));
132132

133-
return client.send(builder.build(), Response.BodyHandlers.ofByteArray())
133+
final Request request = builder.build();
134+
return client.send(request, Response.BodyHandlers.ofByteArray())
134135
.thenApply(response -> {
135136
if (response.statusCode() >= ERROR_STATUS) {
136-
throw SolidClientException.handle("Unable to read resource at " + identifier, identifier,
137+
throw SolidClientException.handle("Unable to read resource at " + request.uri(), request.uri(),
137138
response.statusCode(), response.headers(), new String(response.body()));
138139
} else {
139140
final String contentType = response.headers().firstValue(CONTENT_TYPE)
@@ -142,8 +143,8 @@ public <T extends Resource> CompletionStage<T> read(final URI identifier, final
142143
// Check that this is an RDFSoure
143144
if (RDFSource.class.isAssignableFrom(clazz)) {
144145
final Dataset dataset = SolidResourceHandlers.buildDataset(contentType, response.body(),
145-
identifier.toString()).orElse(null);
146-
final T obj = construct(identifier, clazz, dataset, response.headers());
146+
request.uri().toString()).orElse(null);
147+
final T obj = construct(request.uri(), clazz, dataset, response.headers());
147148
final ValidationResult res = RDFSource.class.cast(obj).validate();
148149
if (!res.isValid()) {
149150
throw new DataMappingException(
@@ -153,7 +154,7 @@ public <T extends Resource> CompletionStage<T> read(final URI identifier, final
153154
return obj;
154155
// Otherwise, create a non-RDF-bearing resource
155156
} else {
156-
return construct(identifier, clazz, contentType,
157+
return construct(request.uri(), clazz, contentType,
157158
new ByteArrayInputStream(response.body()), response.headers());
158159
}
159160
} catch (final ReflectiveOperationException ex) {

0 commit comments

Comments
 (0)