JENA-1435: Check service enabled for Content-Type dispatch
Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/9d147708 Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/9d147708 Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/9d147708 Branch: refs/heads/master Commit: 9d147708ed61b7ae5d456711d2b8f28e25d444c6 Parents: 7bc56d8 Author: Andy Seaborne <[email protected]> Authored: Sun Nov 26 17:28:42 2017 +0000 Committer: Andy Seaborne <[email protected]> Committed: Tue Dec 12 10:07:37 2017 +0000 ---------------------------------------------------------------------- .../servlets/ServiceDispatchRegistry.java | 2 + .../jena/fuseki/servlets/ServiceRouter.java | 13 ++++- .../jena/fuseki/embedded/FusekiServer.java | 10 ++-- .../embedded/TestFusekiCustomOperation.java | 57 ++++++++++++++------ 4 files changed, 56 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/9d147708/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceDispatchRegistry.java ---------------------------------------------------------------------- diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceDispatchRegistry.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceDispatchRegistry.java index e714ee1..cc45de4 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceDispatchRegistry.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceDispatchRegistry.java @@ -93,6 +93,8 @@ public class ServiceDispatchRegistry { /** * Register a new {@link Operation}, with its {@code Content-Type} (may be null, * meaning no dispatch by content type), and the implementation handler. + * <p> + * The application needs to enable an operation on a service endpoint. */ public void register(Operation operation, String contentType, ActionService action) { Objects.requireNonNull(operation); http://git-wip-us.apache.org/repos/asf/jena/blob/9d147708/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java ---------------------------------------------------------------------- diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java index a88d211..865dea2 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java @@ -18,6 +18,8 @@ package org.apache.jena.fuseki.servlets; +import java.util.List; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -242,12 +244,19 @@ public abstract class ServiceRouter extends ActionService { // We don't wire in all the RDF syntaxes. // Instead, "Quads" drops through to the default operation. - // This does no have the ";charset=" + // This does not have the ";charset=" String ct = request.getContentType(); if ( ct != null ) { Operation operation = action.getServiceDispatchRegistry().findOperation(ct); - if ( operation != null ) + if ( operation != null ) { + // Check there is a service for this dataset. + List<Endpoint> x = action.getDataService().getEndpoints(operation); + if ( x.isEmpty() ) + ServletOps.errorBadRequest("Malformed request: Content-Type not enabled by an endpoint for this dataset: " + + action.getActionURI() + " : Content-Type: "+ct); return operation; + } + // operation == null : include drop-through for quads/triples on the dataset. } // ---- GET and Accept http://git-wip-us.apache.org/repos/asf/jena/blob/9d147708/jena-fuseki2/jena-fuseki-embedded/src/main/java/org/apache/jena/fuseki/embedded/FusekiServer.java ---------------------------------------------------------------------- diff --git a/jena-fuseki2/jena-fuseki-embedded/src/main/java/org/apache/jena/fuseki/embedded/FusekiServer.java b/jena-fuseki2/jena-fuseki-embedded/src/main/java/org/apache/jena/fuseki/embedded/FusekiServer.java index 67702d3..5bc9102 100644 --- a/jena-fuseki2/jena-fuseki-embedded/src/main/java/org/apache/jena/fuseki/embedded/FusekiServer.java +++ b/jena-fuseki2/jena-fuseki-embedded/src/main/java/org/apache/jena/fuseki/embedded/FusekiServer.java @@ -318,10 +318,8 @@ public class FusekiServer { /** * Add an operation and handler to the server. This does not enable it for any dataset. * <p> - * To associate an operation with a dataset, call {@link #addOperation} after adding the dataset. - * <p> - * (Advanced and experimental option: see - * <a href="http://jena.apache.org/documentation/fuseki2/extend.html>Extending Fuseki</a>) + * To associate an operation with a dataset, call {@link #addOperation} after adding the dataset. + * * @see #addOperation */ public Builder registerOperation(Operation operation, ActionService handler) { @@ -333,9 +331,7 @@ public class FusekiServer { * Add an operation to the server, together with its triggering Content-Type (may be null) and servlet handler. * <p> * To associate an operation with a daatsets, call {@link #addOperation} after adding the dataset. - * <p> - * (Advanced and experimental option: see - * <a href="http://jena.apache.org/documentation/fuseki2/extend.html>Extending Fuseki</a>) + * * @see #addOperation */ public Builder registerOperation(Operation operation, String contentType, ActionService handler) { http://git-wip-us.apache.org/repos/asf/jena/blob/9d147708/jena-fuseki2/jena-fuseki-embedded/src/test/java/org/apache/jena/fuseki/embedded/TestFusekiCustomOperation.java ---------------------------------------------------------------------- diff --git a/jena-fuseki2/jena-fuseki-embedded/src/test/java/org/apache/jena/fuseki/embedded/TestFusekiCustomOperation.java b/jena-fuseki2/jena-fuseki-embedded/src/test/java/org/apache/jena/fuseki/embedded/TestFusekiCustomOperation.java index dcecb26..064e1b2 100644 --- a/jena-fuseki2/jena-fuseki-embedded/src/test/java/org/apache/jena/fuseki/embedded/TestFusekiCustomOperation.java +++ b/jena-fuseki2/jena-fuseki-embedded/src/test/java/org/apache/jena/fuseki/embedded/TestFusekiCustomOperation.java @@ -18,7 +18,7 @@ package org.apache.jena.fuseki.embedded; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -68,7 +68,7 @@ public class TestFusekiCustomOperation { .registerOperation(newOp, contentType, customHandler) .add("/ds", dataService) .build(); - testServer(server, true); + testServer(server, true, true); } @Test @@ -80,7 +80,7 @@ public class TestFusekiCustomOperation { .add("/ds", DatasetGraphFactory.createTxnMem(), true) .addOperation("/ds", endpointName, newOp) .build(); - testServer(server, true); + testServer(server, true, true); } @Test @@ -92,7 +92,7 @@ public class TestFusekiCustomOperation { .add("/ds", DatasetGraphFactory.createTxnMem(), true) .addOperation("/ds", endpointName, newOp) .build(); - testServer(server, false); + testServer(server, true, false); } @Test(expected=FusekiConfigException.class) @@ -114,28 +114,51 @@ public class TestFusekiCustomOperation { .addOperation("/ds", endpointName, newOp); //.build(); } + + public void cfg_bad_ct_not_enabkled_here() { + FusekiServer server = FusekiServer.create() + .setPort(port) + .registerOperation(newOp, "app/special", customHandler) + .add("/ds", DatasetGraphFactory.createTxnMem(), true) + // Unregistered. + .addOperation("/ds", endpointName, newOp) + .build(); + testServer(server, false, false); + } + - private void testServer(FusekiServer server, boolean withContentType) { + private void testServer(FusekiServer server, boolean withEndpoint, boolean withContentType) { try { server.start(); - // Try query (no extension required) + // Try query (no extension required) try(RDFConnection rconn = RDFConnectionFactory.connect(url+"/ds")) { try(QueryExecution qExec = rconn.query("ASK {}")) { qExec.execAsk(); } } - // Service endpoint name : GET - String s1 = HttpOp.execHttpGetString(url+"/ds/"+endpointName); - - // Service endpoint name : POST - try ( TypedInputStream stream = HttpOp.execHttpPostStream(url+"/ds/"+endpointName, "ignored", "", "text/plain") ) { - String x = IOUtils.toString(stream, StandardCharsets.UTF_8); - assertNotNull(x); - } catch (IOException ex) { - IO.exception(ex); + if ( withEndpoint ) { + // Service endpoint name : GET + String s1 = HttpOp.execHttpGetString(url+"/ds/"+endpointName); + + // Service endpoint name : POST + try ( TypedInputStream stream = HttpOp.execHttpPostStream(url+"/ds/"+endpointName, "ignored", "", "text/plain") ) { + String x = IOUtils.toString(stream, StandardCharsets.UTF_8); + assertNotNull(x); + } catch (IOException ex) { + IO.exception(ex); + } + } else { + // No endpoint so we expect a 404. + try { + // Service endpoint name : GET + HttpOp.execHttpGet(url+"/ds/"+endpointName); + fail("Expected to fail HTTP GET"); + } catch (HttpException ex) { + assertEquals(404, ex.getResponseCode()); + } } - + if ( withContentType ) { // Content-type try ( TypedInputStream stream = HttpOp.execHttpPostStream(url+"/ds", contentType, "", "text/plain") ) { @@ -147,7 +170,7 @@ public class TestFusekiCustomOperation { } else { // No Content-Type try ( TypedInputStream stream = HttpOp.execHttpPostStream(url+"/ds", contentType, "", "text/plain") ) { - fail("Managed to use Content-Type"); + fail("Expected to fail HTTP POST using Content-Type"); } catch (HttpException ex) {} // Service endpoint name. DELETE -> fails 405
