This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git

commit fa17b52c172d3ed97b48b55624551972d82e0650
Author: Andy Seaborne <[email protected]>
AuthorDate: Thu Nov 7 21:14:18 2024 +0000

    Fix: Servlet SPARQL_Update: POST using a query string
---
 .../java/org/apache/jena/riot/web/HttpNames.java   | 13 ++++---
 .../apache/jena/fuseki/servlets/SPARQL_Update.java | 27 +++++++++++---
 .../jena/sparql/exec/http/TestUpdateExecHTTP.java  | 43 ++++++++++++++++++++--
 3 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java 
b/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java
index cc68dfd302..c8460ae1c9 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java
@@ -64,18 +64,19 @@ public class HttpNames
     public static final String graphTargetDefault   = "default" ;
     public static final String graphTargetUnion     = "union" ;
 
-    public static final String paramUpdate          = "update" ;
-    public static final String paramRequest         = "request" ;
-    public static final String paramUsingGraphURI        = "using-graph-uri" ;
-    public static final String paramUsingNamedGraphURI   = 
"using-named-graph-uri" ;
-
-    // SPARQL parameter names
+    // SPARQL query parameter names
     public static final String paramQuery           = "query" ;
     public static final String paramQueryRef        = "query-ref" ;
     public static final String paramDefaultGraphURI = "default-graph-uri" ;
     public static final String paramNamedGraphURI   = "named-graph-uri" ;
     public static final String paramTarget          = "target" ;
 
+    // SPARQL Update parameter names
+    public static final String paramUpdate          = "update" ;
+    public static final String paramRequest         = "request" ;   // 
Alternative name.
+    public static final String paramUsingGraphURI        = "using-graph-uri" ;
+    public static final String paramUsingNamedGraphURI   = 
"using-named-graph-uri" ;
+
     // Jena parameter names (SPARQL protocol extensions)
     public static final String paramStyleSheet      = "stylesheet" ;
     public static final String paramLang            = "lang" ;
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
index 8c50cddfd5..17daa8072e 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
@@ -52,6 +52,7 @@ import org.apache.jena.irix.IRIxResolver;
 import org.apache.jena.query.QueryBuildException;
 import org.apache.jena.query.QueryParseException;
 import org.apache.jena.query.Syntax;
+import org.apache.jena.riot.WebContent;
 import org.apache.jena.riot.web.HttpNames;
 import org.apache.jena.shared.OperationDeniedException;
 import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
@@ -98,9 +99,7 @@ public class SPARQL_Update extends ActionService
 
     @Override
     public void execute(HttpAction action) {
-        ContentType ct = ActionLib.getContentType(action);
-        if ( ct == null )
-            ct = ctSPARQLUpdate;
+        ContentType ct = updateContentType(action);
 
         if ( matchContentType(ctSPARQLUpdate, ct) ) {
             executeBody(action);
@@ -127,9 +126,7 @@ public class SPARQL_Update extends ActionService
         if ( ! 
HttpNames.METHOD_POST.equalsIgnoreCase(action.getRequestMethod()) && ! 
HttpNames.METHOD_PATCH.equalsIgnoreCase(action.getRequestMethod()) )
             ServletOps.errorMethodNotAllowed("SPARQL Update : use POST or 
PATCH");
 
-        ContentType ct = ActionLib.getContentType(action);
-        if ( ct == null )
-            ct = ctSPARQLUpdate;
+        ContentType ct = updateContentType(action);
 
         if ( matchContentType(ctSPARQLUpdate, ct) ) {
             String charset = action.getRequestCharacterEncoding();
@@ -261,6 +258,24 @@ public class SPARQL_Update extends ActionService
         } finally { action.endWrite(); }
     }
 
+    /**
+     * Content type, with a default depending on whether it looks like a 
HTMLform
+     * using the query string.
+     */
+    private static ContentType updateContentType(HttpAction action) {
+        ContentType ct = ActionLib.getContentType(action);
+        if ( ct != null )
+            return ct;
+
+        // No content type header. Not covered by the spec which has MUST be
+        // HTML form application/x-www-form-urlencoded (query string) or 
application sparql-update.
+        // However, it is convenient to deal with the "no content header + 
queryString update=" case.
+        // If there is a query string, "request=" or "update=" treat as HTML 
form.
+        if ( action.getRequestParameter(paramUpdate) != null ||  
action.getRequestParameter(paramRequest) != null )
+            return WebContent.ctHTMLForm;
+        return ctSPARQLUpdate;
+    }
+
     /* [It is an error to supply the using-graph-uri or using-named-graph-uri 
parameters
      * when using this protocol to convey a SPARQL 1.1 Update request that 
contains an
      * operation that uses the USING, USING NAMED, or WITH clause.]
diff --git 
a/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestUpdateExecHTTP.java
 
b/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestUpdateExecHTTP.java
index 782d4d91a8..5d72bfdfd6 100644
--- 
a/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestUpdateExecHTTP.java
+++ 
b/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestUpdateExecHTTP.java
@@ -19,16 +19,21 @@
 package org.apache.jena.sparql.exec.http;
 
 import static org.apache.jena.sparql.sse.SSE.parseQuad;
-import static org.junit.Assert.assertTrue;
 
 import org.apache.jena.atlas.logging.LogCtl;
 import org.apache.jena.fuseki.Fuseki;
 import org.apache.jena.fuseki.main.FusekiServer;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.http.HttpLib;
+import org.apache.jena.http.HttpOp;
 import org.apache.jena.sparql.core.DatasetGraph;
 import org.apache.jena.sparql.core.DatasetGraphFactory;
 import org.apache.jena.sparql.core.Quad;
 import org.apache.jena.update.UpdateFactory;
 import org.apache.jena.update.UpdateRequest;
+
+import static org.junit.Assert.*;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -76,7 +81,7 @@ public class TestUpdateExecHTTP {
 
     private static String service() { return dsURL; }
     private static String serviceQuery() { return dsURL+"/query"; }
-
+    private static String serviceUpdate() { return dsURL+"/update"; }
 
     @Test public void update_1() {
         UpdateExecHTTP uExec = UpdateExecHTTP.service(service())
@@ -110,9 +115,41 @@ public class TestUpdateExecHTTP {
         }
     }
 
+    // Alternative to UpdateExecHTTP -- convenient update from other languages
+    // Fuseki treats:
+    //    POST ...?request=...
+    //    POST ...?update=...
+    // as an update.
+    @Test public void update_POST_queryString_1() {
+        String update1 = "INSERT DATA { <x:s> <x:p> 567 }";
+        String queryString1 = "update="+HttpLib.urlEncodeQueryString(update1);
+
+        String update2 = "CLEAR DEFAULT";
+        String queryString2 = "update="+HttpLib.urlEncodeQueryString(update2);
+
+        // Multiple operation endpoint.
+        HttpOp.httpPost(service()+"?"+queryString1);
+        Graph g1 = GSP.service(service()).defaultGraph().GET();
+        assertEquals(1, g1.size());
+
+        HttpOp.httpPost(service()+"?"+queryString2);
+        Graph g2 = GSP.service(service()).defaultGraph().GET();
+        assertEquals(0, g2.size());
+    }
+
+    @Test public void update_POST_queryString_2() {
+        String update = "INSERT DATA { <x:s> <x:p> 567 }";
+        String queryString = "request="+HttpLib.urlEncodeQueryString(update);
+
+        // Update endpoint.
+        HttpOp.httpPost(serviceUpdate()+"?"+queryString);
+
+        Graph g = GSP.service(service()).defaultGraph().GET();
+        assertEquals(1, g.size());
+    }
+
     // ?user-graph-uri= and ?using-named-graph-uri only apply to the WHERE 
clause of
     // an update.
-
     @Test public void update_using_1() {
         try {
             update_using_1_test();

Reply via email to