Skip to content

Commit

Permalink
Add Spring-based configuration to toggle LDP strict handling of PUT r…
Browse files Browse the repository at this point in the history
…equests

without an If-Match header
  • Loading branch information
cbeer committed Oct 18, 2014
1 parent 1021593 commit 3dd1eac
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 6 deletions.
2 changes: 2 additions & 0 deletions fcrepo-auth-common/src/test/resources/spring-test/rest.xml
Expand Up @@ -6,6 +6,8 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:property-placeholder />

<bean class="org.fcrepo.http.commons.session.SessionFactory"/>

<!-- Mints PIDs-->
Expand Down
@@ -0,0 +1,38 @@
/**
* Copyright 2014 DuraSpace, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.http.api;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* @author cabeer
* @since 10/17/14
*/
@Component
public class FedoraHttpConfiguration {

@Value("${fcrepo.http.ldp.putRequiresIfMatch:false}")
private boolean putRequiresIfMatch;

/**
* Should PUT requests require an If-Match header?
* @return
*/
public boolean putRequiresIfMatch() {
return putRequiresIfMatch;
}
}
Expand Up @@ -18,6 +18,7 @@
import com.codahale.metrics.annotation.Timed;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.jena.riot.RiotException;
import org.fcrepo.http.commons.domain.ContentLocation;
import org.fcrepo.http.commons.domain.PATCH;
Expand Down Expand Up @@ -105,6 +106,8 @@ public class FedoraLdp extends ContentExposingResource {

@PathParam("path") protected String externalPath;

@Inject private FedoraHttpConfiguration httpConfiguration;

/**
* Default JAX-RS entry point
*/
Expand Down Expand Up @@ -216,7 +219,8 @@ public Response createOrReplaceObjectRdf(
@HeaderParam("Content-Type") final MediaType requestContentType,
@ContentLocation final InputStream requestBodyStream,
@QueryParam("checksum") final String checksum,
@HeaderParam("Content-Disposition") final ContentDisposition contentDisposition)
@HeaderParam("Content-Disposition") final ContentDisposition contentDisposition,
@HeaderParam("If-Match") final String ifMatch)
throws InvalidChecksumException, IOException {

final FedoraResource resource;
Expand All @@ -239,6 +243,10 @@ public Response createOrReplaceObjectRdf(
response = created(location).entity(location.toString());
}

if (httpConfiguration.putRequiresIfMatch() && StringUtils.isBlank(ifMatch) && !resource.isNew()) {
throw new ClientErrorException("An If-Match header is required", 428);
}

evaluateRequestPreconditions(request, servletResponse, resource, session);

if (requestBodyStream == null && !resource.isNew()) {
Expand Down
2 changes: 2 additions & 0 deletions fcrepo-http-api/src/main/resources/META-INF/spring/rest.xml
Expand Up @@ -6,6 +6,8 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:property-placeholder />

<bean class="org.fcrepo.http.commons.session.SessionFactory" />

<!-- Mints PIDs-->
Expand Down
Expand Up @@ -124,6 +124,9 @@ public class FedoraLdpTest {
@Mock
private BinaryService mockBinaryService;

@Mock
private FedoraHttpConfiguration mockHttpConfiguration;

@Before
public void setUp() throws Exception {
initMocks(this);
Expand All @@ -144,6 +147,9 @@ public void setUp() throws Exception {
setField(testObj, "nodeService", mockNodeService);
setField(testObj, "objectService", mockObjectService);
setField(testObj, "binaryService", mockBinaryService);
setField(testObj, "httpConfiguration", mockHttpConfiguration);

when(mockHttpConfiguration.putRequiresIfMatch()).thenReturn(false);

when(mockObject.getEtagValue()).thenReturn("");
when(mockObject.getPath()).thenReturn(path);
Expand Down Expand Up @@ -519,7 +525,7 @@ public void testPutNewObject() throws Exception {
when(mockNodeService.exists(mockSession, "/some/path")).thenReturn(false);
when(mockObjectService.findOrCreateObject(mockSession, "/some/path")).thenReturn(mockObject);

final Response actual = testObj.createOrReplaceObjectRdf(null, null, null, null);
final Response actual = testObj.createOrReplaceObjectRdf(null, null, null, null, null);

assertEquals(CREATED.getStatusCode(), actual.getStatus());
}
Expand All @@ -534,7 +540,7 @@ public void testPutNewObjectWithRdf() throws Exception {
when(mockObjectService.findOrCreateObject(mockSession, "/some/path")).thenReturn(mockObject);

final Response actual = testObj.createOrReplaceObjectRdf(NTRIPLES_TYPE,
toInputStream("_:a <info:x> _:c ."), null, null);
toInputStream("_:a <info:x> _:c ."), null, null, null);

assertEquals(CREATED.getStatusCode(), actual.getStatus());
verify(mockObject).replaceProperties(eq(identifierConverter), any(Model.class), any(RdfStream.class));
Expand All @@ -549,7 +555,7 @@ public void testPutNewBinary() throws Exception {
when(mockBinaryService.findOrCreateBinary(mockSession, "/some/path")).thenReturn(mockBinary);

final Response actual = testObj.createOrReplaceObjectRdf(TEXT_PLAIN_TYPE,
toInputStream("xyz"), null, null);
toInputStream("xyz"), null, null, null);

assertEquals(CREATED.getStatusCode(), actual.getStatus());
}
Expand All @@ -566,12 +572,28 @@ public void testPutReplaceRdfObject() throws Exception {
when(mockObjectService.findOrCreateObject(mockSession, "/some/path")).thenReturn(mockObject);

final Response actual = testObj.createOrReplaceObjectRdf(NTRIPLES_TYPE,
toInputStream("_:a <info:x> _:c ."), null, null);
toInputStream("_:a <info:x> _:c ."), null, null, null);

assertEquals(NO_CONTENT.getStatusCode(), actual.getStatus());
verify(mockObject).replaceProperties(eq(identifierConverter), any(Model.class), any(RdfStream.class));
}

@Test(expected = ClientErrorException.class)
public void testPutWithStrictIfMatchHandling() throws Exception {

when(mockHttpConfiguration.putRequiresIfMatch()).thenReturn(true);
final FedoraObject mockObject = (FedoraObject)setResource(FedoraObject.class);
doReturn(mockObject).when(testObj).resource();
when(mockObject.isNew()).thenReturn(false);

when(mockNodeService.exists(mockSession, "/some/path")).thenReturn(true);
when(mockObjectService.findOrCreateObject(mockSession, "/some/path")).thenReturn(mockObject);

testObj.createOrReplaceObjectRdf(NTRIPLES_TYPE,
toInputStream("_:a <info:x> _:c ."), null, null, null);

}

@Test
public void testPatchObject() throws Exception {

Expand Down
2 changes: 1 addition & 1 deletion fcrepo-http-api/src/test/resources/spring-test/master.xml
Expand Up @@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!-- Master context for the test application. -->

<import resource="classpath:/spring-test/repo.xml"/>
Expand Down
2 changes: 2 additions & 0 deletions fcrepo-http-api/src/test/resources/spring-test/rest.xml
Expand Up @@ -6,6 +6,8 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:property-placeholder />

<bean class="org.fcrepo.http.commons.session.SessionFactory"/>

<!-- Mints PIDs-->
Expand Down
@@ -0,0 +1 @@
fcrepo.http.ldp.putRequiresIfMatch = true
Expand Up @@ -6,6 +6,8 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:property-placeholder location="classpath:application.properties"/>

<bean class="org.fcrepo.http.commons.session.SessionFactory"/>

<!-- Mints PIDs-->
Expand Down

0 comments on commit 3dd1eac

Please sign in to comment.