Skip to content

Commit

Permalink
Add OPTIONS verb for .../fcr:content requests
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeer committed Sep 4, 2014
1 parent d402657 commit ba90dd7
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 9 deletions.
Expand Up @@ -144,16 +144,24 @@ protected Response getDatastreamContentResponse(final Datastream ds,
.size(ds.getContentSize())
.build();

addResourceOptionsHeaders(servletResponse, subjects, ds);

return builder.type(ds.getMimeType())
.header("Link", "<" + subjects.getSubject(ds.getNode().getPath()) + ">;rel=\"describedby\"")
.header("Link", "<" + LDP_NAMESPACE + "Resource>;rel=\"type\"")
.header("Link", "<" + NON_RDF_SOURCE + ">;rel=\"type\"")
.header("Accept-Ranges", "bytes")
.header("Content-Disposition", contentDisposition)
.cacheControl(cc)
.build();
}

protected static void addResourceOptionsHeaders(final HttpServletResponse servletResponse,
final HttpIdentifierTranslator subjects,
final Datastream ds) throws RepositoryException {

servletResponse.addHeader("Link", "<" + subjects.getSubject(ds.getNode().getPath()) + ">;rel=\"describedby\"");
servletResponse.addHeader("Link", "<" + LDP_NAMESPACE + "Resource>;rel=\"type\"");
servletResponse.addHeader("Link", "<" + NON_RDF_SOURCE + ">;rel=\"type\"");
servletResponse.addHeader("Accept-Ranges", "bytes");
}

/**
* Evaluate the cache control headers for the request to see if it can be served from
* the cache.
Expand Down
Expand Up @@ -30,6 +30,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
Expand All @@ -47,8 +48,10 @@
import java.text.ParseException;
import java.util.List;

import static javax.ws.rs.core.Response.Status.OK;
import static javax.ws.rs.core.Response.created;
import static javax.ws.rs.core.Response.noContent;
import static javax.ws.rs.core.Response.status;
import static org.slf4j.LoggerFactory.getLogger;

/**
Expand All @@ -68,6 +71,42 @@ public class FedoraContent extends ContentExposingResource {

private static final Logger LOGGER = getLogger(FedoraContent.class);


/**
* Outputs information about the supported HTTP methods, etc.
*/
@OPTIONS
@Timed
public Response options(@PathParam("path") final List<PathSegment> pathList,
@Context final HttpServletResponse servletResponse)
throws RepositoryException {


try {
final String path = toPath(pathList);
if (nodeService.exists(session, path)) {

final Datastream ds =
datastreamService.getDatastream(session, path);

final HttpIdentifierTranslator subjects =
new HttpIdentifierTranslator(session, FedoraNodes.class,
uriInfo);
addOptionsHttpHeaders(servletResponse);
addResourceOptionsHeaders(servletResponse, subjects, ds);
}
return status(OK).build();

} finally {
session.logout();
}
}


private void addOptionsHttpHeaders(final HttpServletResponse servletResponse) {
servletResponse.addHeader("Allow", "HEAD,GET,PUT,OPTIONS");
}

/**
* Modify an existing datastream's content
*
Expand Down Expand Up @@ -156,6 +195,9 @@ public Response getContent(@PathParam("path") final List<PathSegment> pathList,
final HttpIdentifierTranslator subjects =
new HttpIdentifierTranslator(session, FedoraNodes.class,
uriInfo);

addOptionsHttpHeaders(servletResponse);

return getDatastreamContentResponse(ds, rangeValue, request, servletResponse,
subjects, session);

Expand Down
Expand Up @@ -212,11 +212,6 @@ public void testGetContent() throws RepositoryException, IOException {
verify(mockSession, never()).save();
final String actualContent =
IOUtils.toString((InputStream) actual.getEntity());
final List<Object> linkHeaders = actual.getMetadata().get("Link");
assertTrue("Expected to find describedby Link header",
linkHeaders.contains("<http://localhost/fcrepo" + path + ">;rel=\"describedby\""));
assertTrue("Expected to find NonRDFSource Link header",
linkHeaders.contains("<" + NON_RDF_SOURCE + ">;rel=\"type\""));
assertEquals("asdf", actualContent);
}

Expand Down
Expand Up @@ -17,19 +17,29 @@

import static java.util.TimeZone.getTimeZone;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.OK;
import static org.fcrepo.kernel.RdfLexicon.NON_RDF_SOURCE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
Expand Down Expand Up @@ -251,6 +261,21 @@ public void testGetDatastreamContent() throws Exception {
assertEquals("urn:sha1:ba6cb22191300aebcfcfb83de9635d6b224677df",
response.getFirstHeader("ETag").getValue().replace("\"", ""));


final List<String> linkHeaders = Lists.transform(
ImmutableList.copyOf(response.getHeaders("Link")), new Function<Header, String>() {
@Override
public String apply(final Header header) {
return header.getValue();
}
}
);

assertTrue("Expected to find describedby Link header",
linkHeaders.contains("<" + serverAddress + pid + "/ds1" + ">;rel=\"describedby\""));
assertTrue("Expected to find NonRDFSource Link header",
linkHeaders.contains("<" + NON_RDF_SOURCE + ">;rel=\"type\""));

final ContentDisposition contentDisposition =
new ContentDisposition(response.getFirstHeader("Content-Disposition").getValue());

Expand Down Expand Up @@ -387,4 +412,33 @@ public void testRangeRequestOpenStart() throws Exception {
EntityUtils.toString(response.getEntity()));
assertEquals("bytes 0-2/20", response.getFirstHeader("Content-Range").getValue());
}

@Test
public void testOptions() throws Exception {
final String pid = getRandomUniquePid();
createObject(pid);

createDatastream(pid, "ds1", "marbles for everyone");
final HttpOptions optionsRequest = new HttpOptions(serverAddress + pid + "/ds1/fcr:content");
final HttpResponse optionsResponse = client.execute(optionsRequest);
assertEquals(OK.getStatusCode(), optionsResponse.getStatusLine().getStatusCode());


final List<String> methods = headerValues(optionsResponse,"Allow");
assertTrue("Should allow HEAD", methods.contains(HttpHead.METHOD_NAME));
assertTrue("Should allow GET", methods.contains(HttpGet.METHOD_NAME));
assertTrue("Should allow PUT", methods.contains(HttpPut.METHOD_NAME));
assertTrue("Should allow OPTIONS", methods.contains(HttpOptions.METHOD_NAME));

}

private static List<String> headerValues( final HttpResponse response, final String headerName ) {
final List<String> values = new ArrayList<String>();
for ( final Header header : response.getHeaders(headerName) ) {
for ( final String elem : header.getValue().split(",") ) {
values.add( elem.trim() );
}
}
return values;
}
}

0 comments on commit ba90dd7

Please sign in to comment.