diff --git a/fcrepo-auth-common/src/test/resources/spring-test/rest.xml b/fcrepo-auth-common/src/test/resources/spring-test/rest.xml
index 54fe5b4332..69b46f1c8d 100644
--- a/fcrepo-auth-common/src/test/resources/spring-test/rest.xml
+++ b/fcrepo-auth-common/src/test/resources/spring-test/rest.xml
@@ -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">
+
+
diff --git a/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraHttpConfiguration.java b/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraHttpConfiguration.java
new file mode 100644
index 0000000000..ea6880c0fe
--- /dev/null
+++ b/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraHttpConfiguration.java
@@ -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;
+ }
+}
diff --git a/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraLdp.java b/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraLdp.java
index 88a99f00e8..d559d0f8a7 100644
--- a/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraLdp.java
+++ b/fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraLdp.java
@@ -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;
@@ -105,6 +106,8 @@ public class FedoraLdp extends ContentExposingResource {
@PathParam("path") protected String externalPath;
+ @Inject private FedoraHttpConfiguration httpConfiguration;
+
/**
* Default JAX-RS entry point
*/
@@ -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;
@@ -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()) {
diff --git a/fcrepo-http-api/src/main/resources/META-INF/spring/rest.xml b/fcrepo-http-api/src/main/resources/META-INF/spring/rest.xml
index 58c04ee109..15d989499b 100644
--- a/fcrepo-http-api/src/main/resources/META-INF/spring/rest.xml
+++ b/fcrepo-http-api/src/main/resources/META-INF/spring/rest.xml
@@ -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">
+
+
diff --git a/fcrepo-http-api/src/test/java/org/fcrepo/http/api/FedoraLdpTest.java b/fcrepo-http-api/src/test/java/org/fcrepo/http/api/FedoraLdpTest.java
index bb48d9d94e..9664656d6c 100644
--- a/fcrepo-http-api/src/test/java/org/fcrepo/http/api/FedoraLdpTest.java
+++ b/fcrepo-http-api/src/test/java/org/fcrepo/http/api/FedoraLdpTest.java
@@ -124,6 +124,9 @@ public class FedoraLdpTest {
@Mock
private BinaryService mockBinaryService;
+ @Mock
+ private FedoraHttpConfiguration mockHttpConfiguration;
+
@Before
public void setUp() throws Exception {
initMocks(this);
@@ -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);
@@ -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());
}
@@ -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 _:c ."), null, null);
+ toInputStream("_:a _:c ."), null, null, null);
assertEquals(CREATED.getStatusCode(), actual.getStatus());
verify(mockObject).replaceProperties(eq(identifierConverter), any(Model.class), any(RdfStream.class));
@@ -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());
}
@@ -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 _:c ."), null, null);
+ toInputStream("_:a _: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 _:c ."), null, null, null);
+
+ }
+
@Test
public void testPatchObject() throws Exception {
diff --git a/fcrepo-http-api/src/test/resources/spring-test/master.xml b/fcrepo-http-api/src/test/resources/spring-test/master.xml
index cce76bb746..86c98c2e63 100644
--- a/fcrepo-http-api/src/test/resources/spring-test/master.xml
+++ b/fcrepo-http-api/src/test/resources/spring-test/master.xml
@@ -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">
-
+
diff --git a/fcrepo-http-api/src/test/resources/spring-test/rest.xml b/fcrepo-http-api/src/test/resources/spring-test/rest.xml
index 03b063f340..c03147737a 100644
--- a/fcrepo-http-api/src/test/resources/spring-test/rest.xml
+++ b/fcrepo-http-api/src/test/resources/spring-test/rest.xml
@@ -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">
+
+
diff --git a/fcrepo-integration-ldp/src/test/resources/application.properties b/fcrepo-integration-ldp/src/test/resources/application.properties
new file mode 100644
index 0000000000..41ccf9431e
--- /dev/null
+++ b/fcrepo-integration-ldp/src/test/resources/application.properties
@@ -0,0 +1 @@
+fcrepo.http.ldp.putRequiresIfMatch = true
\ No newline at end of file
diff --git a/fcrepo-integration-ldp/src/test/resources/spring-test/rest.xml b/fcrepo-integration-ldp/src/test/resources/spring-test/rest.xml
index e886ff0ba0..c75ebb0684 100644
--- a/fcrepo-integration-ldp/src/test/resources/spring-test/rest.xml
+++ b/fcrepo-integration-ldp/src/test/resources/spring-test/rest.xml
@@ -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">
+
+