Browse Source

Send HTTP 400 on input RDF parsing error.

Stefano Cossu 4 years ago
parent
commit
9d542f1391

+ 4 - 0
lakesuperior/endpoints/ldp.py

@@ -269,6 +269,8 @@ def post_resource(parent_uid):
     try:
         kwargs = _create_args_from_req(slug)
         rsrc = rsrc_api.create(parent_uid, slug, **kwargs)
+    except exc.RdfParsingError as e:
+        return str(e), 400
     except exc.IndigestibleError:
         return (
             f'Unable to parse digest header: {request.headers["digest"]}'
@@ -318,6 +320,8 @@ def put_resource(uid):
     try:
         kwargs = _create_args_from_req(uid)
         evt, rsrc = rsrc_api.create_or_replace(uid, **kwargs)
+    except exc.RdfParsingError as e:
+        return str(e), 400
     except exc.IndigestibleError:
         return (
                 f'Unable to parse digest header: {request.headers["digest"]}',

+ 14 - 1
lakesuperior/exceptions.py

@@ -128,7 +128,20 @@ class ServerManagedTermError(RuntimeError):
 
 
 
-class InvalidTripleError(RuntimeError):
+class RdfParsingError(ValueError):
+    """
+    Raised when a string cannot be parsed as RDF in the given format.
+    """
+    def __init__(self, fmt, parser_msg=''):
+        self.fmt = fmt
+        self.parser_msg = parser_msg
+
+    def __str__(self):
+        return (f'Error parsing RDF in {self.fmt} format: {self.parser_msg}')
+
+
+
+class InvalidTripleError(ValueError):
     '''
     Raised when a triple in a delta is not valid.
 

+ 7 - 4
lakesuperior/model/ldp/ldp_factory.py

@@ -99,10 +99,13 @@ class LdpFactory:
         """
         uri = nsc['fcres'][uid]
         if rdf_data:
-            provided_imr = from_rdf(
-                uri=uri, data=rdf_data,
-                format=rdf_fmt, publicID=nsc['fcres'][uid]
-            )
+            try:
+                provided_imr = from_rdf(
+                        uri=uri, data=rdf_data,
+                        format=rdf_fmt, publicID=nsc['fcres'][uid])
+            except Exception as e:
+                raise exc.RdfParsingError(rdf_fmt, str(e))
+
         elif graph:
             provided_imr = Graph(
                 uri=uri, data={

+ 45 - 0
tests/3_endpoints/test_3_0_ldp.py

@@ -318,6 +318,51 @@ class TestLdp:
         assert isomorphic(gr1, gr2)
 
 
+    def test_put_ldprs_invalid_rdf(self):
+        """
+        Verify that PUTting invalid RDF body returns HTTP 400.
+
+        However, when forcing LDP-RS, invalid RDF is always accepted.
+        """
+        from lakesuperior.endpoints.ldp import rdf_serializable_mimetypes
+
+        rdfstr = b'This is valid RDF because it ends with a period.'
+        for mt in rdf_serializable_mimetypes:
+            rsp_notok = self.client.put(
+                    f'/ldp/{uuid4()}', data=rdfstr, content_type=mt)
+            assert rsp_notok.status_code == 400
+
+            rsp_ok = self.client.put(
+                f'/ldp/{uuid4()}', data=rdfstr, content_type=mt,
+                headers={
+                    'link': '<http://www.w3.org/ns/ldp#NonRDFSource>;rel="type"'
+                }
+            )
+            assert rsp_ok.status_code == 201
+
+
+    def test_post_ldprs_invalid_rdf(self):
+        """
+        Verify that POSTing invalid RDF body returns HTTP 400.
+
+        However, when forcing LDP-RS, invalid RDF is always accepted.
+        """
+        from lakesuperior.endpoints.ldp import rdf_serializable_mimetypes
+
+        rdfstr = b'This is valid RDF because it ends with a period.'
+        for mt in rdf_serializable_mimetypes:
+            rsp_notok = self.client.post(
+                    f'/ldp', data=rdfstr, content_type=mt)
+            assert rsp_notok.status_code == 400
+
+            rsp_ok = self.client.post(
+                f'/ldp', data=rdfstr, content_type=mt,
+                headers={
+                    'link': '<http://www.w3.org/ns/ldp#NonRDFSource>;rel="type"'
+                }
+            )
+            assert rsp_ok.status_code == 201
+
 
     def test_put_mismatched_ldp_rs(self, rnd_img):
         """