Skip to content

Commit 7e1eb49

Browse files
authored
Improved support for Link header handling (#1129)
Resolves #1125 This makes it possible for clients to send multiple Link headers while not having to worry about ordering. All irrelevant header values will be filtered out.
1 parent 52f85a5 commit 7e1eb49

File tree

6 files changed

+49
-24
lines changed

6 files changed

+49
-24
lines changed

core/common/src/main/java/org/trellisldp/common/TrellisRequest.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.trellisldp.common;
1717

18+
import static java.util.Collections.emptyList;
1819
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
1920
import static javax.ws.rs.core.HttpHeaders.LINK;
2021
import static org.trellisldp.common.HttpConstants.ACCEPT_DATETIME;
@@ -34,6 +35,8 @@
3435
import javax.ws.rs.core.UriBuilder;
3536
import javax.ws.rs.core.UriInfo;
3637

38+
import org.trellisldp.vocabulary.LDP;
39+
3740
/**
3841
* A class representing an HTTP request with various LDP-related headers and query parameters.
3942
*
@@ -110,14 +113,19 @@ public String getSlug() {
110113
}
111114

112115
/**
113-
* Get the Link header.
116+
* Get the first LDP Link header.
114117
*
115-
* @return the Link header
118+
* @return the first LDP Link header
116119
*/
117120
public Link getLink() {
118-
final String link = headers.getFirst(LINK);
119-
if (link != null) {
120-
return Link.valueOf(link);
121+
for (final String header : headers.getOrDefault(LINK, emptyList())) {
122+
final Link link = Link.valueOf(header);
123+
if (Link.TYPE.equals(link.getRel())) {
124+
final String uri = link.getUri().toString();
125+
if (uri.startsWith(LDP.getNamespace()) && !uri.equals(LDP.Resource.getIRIString())) {
126+
return link;
127+
}
128+
}
121129
}
122130
return null;
123131
}

core/common/src/test/java/org/trellisldp/common/TrellisRequestTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ void testLinkHeader() {
208208
final URI uri = create("http://example.com/");
209209
final MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
210210
final MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
211+
headers.add("Link", "<http://www.w3.org/ns/ldp#Resource>; rel=\"type\"");
212+
headers.add("Link", "<http://example.com/SomeType>; rel=\"type\"");
213+
headers.add("Link", "<http://www.w3.org/ns/ldp#BasicContainer>; rel=\"about\"");
211214
final String rawLink = "<http://www.w3.org/ns/ldp#BasicContainer>; rel=\"type\"";
212215
headers.add("Link", rawLink);
213216
final MultivaluedMap<String, String> pathParams = new MultivaluedHashMap<>();
@@ -224,4 +227,27 @@ void testLinkHeader() {
224227
final TrellisRequest req = new TrellisRequest(mockRequest, mockUriInfo, mockHeaders);
225228
assertEquals(Link.valueOf(rawLink), req.getLink());
226229
}
230+
231+
@Test
232+
void testSkippedLinkHeaders() {
233+
final URI uri = create("http://example.com/");
234+
final MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
235+
final MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
236+
headers.add("Link", "<http://www.w3.org/ns/ldp#Resource>; rel=\"type\"");
237+
headers.add("Link", "<http://example.com/SomeType>; rel=\"type\"");
238+
headers.add("Link", "<http://www.w3.org/ns/ldp#BasicContainer>; rel=\"about\"");
239+
final MultivaluedMap<String, String> pathParams = new MultivaluedHashMap<>();
240+
pathParams.add("path", "resource");
241+
242+
when(mockUriInfo.getPath()).thenReturn("resource");
243+
when(mockUriInfo.getPathParameters()).thenReturn(pathParams);
244+
when(mockUriInfo.getQueryParameters()).thenReturn(queryParams);
245+
when(mockUriInfo.getBaseUri()).thenReturn(uri);
246+
when(mockHeaders.getRequestHeaders()).thenReturn(headers);
247+
when(mockRequest.getMethod()).thenReturn(GET);
248+
when(mockHeaders.getAcceptableMediaTypes()).thenReturn(singletonList(RdfMediaType.TEXT_TURTLE_TYPE));
249+
250+
final TrellisRequest req = new TrellisRequest(mockRequest, mockUriInfo, mockHeaders);
251+
assertNull(req.getLink());
252+
}
227253
}

core/http/src/main/java/org/trellisldp/http/impl/PostHandler.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,8 @@ private static RDFSyntax getRdfSyntax(final String contentType, final List<RDFSy
119119
}
120120

121121
private static IRI getLdpType(final Link link, final RDFSyntax syntax, final String contentType) {
122-
if (link != null && Link.TYPE.equals(link.getRel())) {
123-
final String uri = link.getUri().toString();
124-
if (uri.startsWith(LDP.getNamespace())) {
125-
final IRI iri = rdf.createIRI(uri);
126-
if (!LDP.Resource.equals(iri)) {
127-
return iri;
128-
}
129-
}
122+
if (link != null) {
123+
return rdf.createIRI(link.getUri().toString());
130124
}
131125
return contentType != null && syntax == null ? LDP.NonRDFSource : LDP.RDFSource;
132126
}

core/http/src/main/java/org/trellisldp/http/impl/PutHandler.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,8 @@ private IRI getLdpType() {
212212
return getResource().getInteractionModel();
213213
}
214214
final Link link = getRequest().getLink();
215-
if (link != null && Link.TYPE.equals(link.getRel())) {
216-
final String uri = link.getUri().toString();
217-
if (uri.startsWith(LDP.getNamespace()) && !uri.equals(LDP.Resource.getIRIString())) {
218-
return rdf.createIRI(uri);
219-
}
215+
if (link != null) {
216+
return rdf.createIRI(link.getUri().toString());
220217
}
221218
if (getResource() != null) {
222219
return getResource().getInteractionModel();

core/http/src/test/java/org/trellisldp/http/impl/PostHandlerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void testDefaultType2() throws IOException {
130130

131131
@Test
132132
void testDefaultType3() throws IOException {
133-
when(mockTrellisRequest.getLink()).thenReturn(fromUri(LDP.Resource.getIRIString()).rel(TYPE).build());
133+
when(mockTrellisRequest.getLink()).thenReturn(null);
134134

135135
final PostHandler handler = buildPostHandler(RESOURCE_EMPTY, NEW_RESOURCE, null);
136136
try (final Response res = handler.createResource(handler.initialize(mockParent, MISSING_RESOURCE))
@@ -144,7 +144,7 @@ void testDefaultType3() throws IOException {
144144
@Test
145145
void testDefaultType4() throws IOException {
146146
when(mockTrellisRequest.getContentType()).thenReturn(TEXT_PLAIN);
147-
when(mockTrellisRequest.getLink()).thenReturn(fromUri(LDP.Resource.getIRIString()).rel(TYPE).build());
147+
when(mockTrellisRequest.getLink()).thenReturn(null);
148148

149149
final PostHandler handler = buildPostHandler(RESOURCE_SIMPLE, NEW_RESOURCE, null);
150150
try (final Response res = handler.createResource(handler.initialize(mockParent, MISSING_RESOURCE))

core/http/src/test/java/org/trellisldp/http/impl/PutHandlerTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,10 @@ void testNoVersioning() {
145145
}
146146

147147
@Test
148-
void testPutLdpResourceDefaultType() {
148+
void testPutNoLdpLinkType() {
149149
when(mockTrellisRequest.getPath()).thenReturn(RESOURCE_NAME);
150150
when(mockTrellisRequest.getContentType()).thenReturn(TEXT_TURTLE);
151-
when(mockTrellisRequest.getLink()).thenReturn(fromUri(LDP.Resource.getIRIString()).rel(TYPE).build());
151+
when(mockTrellisRequest.getLink()).thenReturn(null);
152152

153153
final PutHandler handler = buildPutHandler(RESOURCE_TURTLE, null, false);
154154
try (final Response res = handler.setResource(handler.initialize(mockParent, mockResource))
@@ -214,10 +214,10 @@ void testPutLdpResourceContainerUncontained() throws IOException {
214214
}
215215

216216
@Test
217-
void testPutLdpBinaryResourceWithLdprLink() {
217+
void testPutLdpBinaryResourceNoLdpLink() {
218218
when(mockResource.getInteractionModel()).thenReturn(LDP.NonRDFSource);
219219
when(mockTrellisRequest.getContentType()).thenReturn(TEXT_PLAIN);
220-
when(mockTrellisRequest.getLink()).thenReturn(fromUri(LDP.Resource.getIRIString()).rel(TYPE).build());
220+
when(mockTrellisRequest.getLink()).thenReturn(null);
221221

222222
final PutHandler handler = buildPutHandler(RESOURCE_SIMPLE, null);
223223
try (final Response res = handler.setResource(handler.initialize(mockParent, mockResource))

0 commit comments

Comments
 (0)