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


The following commit(s) were added to refs/heads/main by this push:
     new 66d75cf2b2 GH-3110: Set the maximum HTML form size
66d75cf2b2 is described below

commit 66d75cf2b22b1e96a6964465c8665e5619f077c6
Author: Andy Seaborne <[email protected]>
AuthorDate: Thu Apr 3 12:09:20 2025 +0100

    GH-3110: Set the maximum HTML form size
---
 .../org/apache/jena/fuseki/server/Dispatcher.java  | 23 +++----
 .../org/apache/jena/fuseki/servlets/ActionLib.java | 22 ++++++
 .../org/apache/jena/fuseki/main/FusekiServer.java  |  8 +--
 .../org/apache/jena/fuseki/main/JettyServer.java   | 16 +++--
 .../fuseki/main/sys/FusekiSystemConstants.java     | 78 ++++++++++++++++++++++
 .../org/apache/jena/fuseki/main/sys/JettyLib.java  | 22 +++---
 6 files changed, 133 insertions(+), 36 deletions(-)

diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java
index 8ceac84ea1..7bab11025e 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java
@@ -35,7 +35,6 @@ import org.apache.jena.fuseki.Fuseki;
 import org.apache.jena.fuseki.auth.Auth;
 import org.apache.jena.fuseki.servlets.*;
 import org.apache.jena.fuseki.system.ActionCategory;
-import org.apache.jena.riot.WebContent;
 import org.apache.jena.riot.web.HttpNames;
 import org.apache.jena.web.HttpSC;
 import org.slf4j.Logger;
@@ -414,9 +413,16 @@ public class Dispatcher {
      * nor that access control will allow it to be performed.
      */
     private static Operation chooseOperation(HttpAction action, EndpointSet 
epSet) {
-        // which is a DispatchFunction.
         HttpServletRequest request = action.getRequest();
 
+        // Forces query string / HTML form processing for better error 
handling.
+        try {
+            request.getParameterMap();
+        } catch (Throwable th) {
+            ServletOps.errorBadRequest(th.getMessage());
+            return null;
+        }
+
         // ---- Dispatch based on HttpParams : Query, Update, GSP.
         // -- Query
         boolean isQuery = request.getParameter(HttpNames.paramQuery) != null;
@@ -431,14 +437,8 @@ public class Dispatcher {
             return Update;
 
         // ---- Content-type
-        String ct = request.getContentType();
-        // Without ";charset="
-        if ( ct != null ) {
-            int idx = ct.indexOf(';');
-            if ( idx > 0 )
-                ct = ct.substring(0, idx);
-        }
         // -- Any registration?
+        String ct = ActionLib.getContentMediaType(action);
         if ( ct != null ) {
             Operation operation = 
action.getOperationRegistry().findByContentType(ct);
             if ( operation != null )
@@ -459,10 +459,7 @@ public class Dispatcher {
         // Place for an extension point.
         boolean hasParams = request.getParameterMap().size() > 0;
         if ( hasParams ) {
-            // One nasty case:
-            // Bad HTML form (content-type  
application/x-www-form-urlencoded), but body is not an HTML form.
-            //  map is one entry, and the key is all of the body,
-            if ( 
WebContent.contentTypeHTMLForm.equals(request.getContentType()) ) {
+            if ( ActionLib.isHTMLForm(action) ) {
                 ServletOps.errorBadRequest("Malformed request: unrecognized 
HTML form request");
                 return null;
             }
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
index 9cdf3f2d1c..c274db9422 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
@@ -19,6 +19,7 @@
 package org.apache.jena.fuseki.servlets;
 
 import static java.lang.String.format;
+import static org.apache.jena.riot.web.HttpNames.METHOD_POST;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -396,6 +397,27 @@ public class ActionLib {
         return FusekiNetLib.getContentType(action.getRequest());
     }
 
+    public static boolean isHTMLForm(HttpAction action) {
+        String method = action.getRequestMethod();
+        if ( ! method.equals(METHOD_POST) )
+            return false;
+
+        String ct = getContentMediaType(action);
+        return WebContent.contentTypeHTMLForm.equalsIgnoreCase(ct);
+    }
+
+    /** Get the content type without any HTTP header field parameters such as 
"charset=" */
+    public static String getContentMediaType(HttpAction action) {
+        String ct = action.getRequestContentType();
+        // Without ";charset="
+        if ( ct != null ) {
+            int idx = ct.indexOf(';');
+            if ( idx > 0 )
+                ct = ct.substring(0, idx).trim();
+        }
+        return ct;
+    }
+
     public static void setCommonHeadersForOptions(HttpAction action) {
         setCommonHeadersForOptions(action.getResponse());
     }
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
index ac7905a216..b7787b6de1 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
@@ -1715,8 +1715,8 @@ public class FusekiServer {
             // Also set on the server which handles requests that don't 
Fuseki-dispatch.
             context.setErrorHandler(errorHandler);
             context.setContextPath(contextPath);
-            // SPARQL Update by HTML - not the best way but.
-            context.setMaxFormContentSize(1024*1024);
+            // SPARQL Update by HTML form POST (not great, but does get used)
+            
context.setMaxFormContentSize(FusekiSystemConstants.jettyMaxFormContentSize);
             // securityHandler done in buildAccessControl
             return context;
         }
@@ -1825,8 +1825,8 @@ public class FusekiServer {
             if ( Fuseki.outputJettyServerHeader )
                 httpConfig.setSendServerVersion(true);
 
-            HttpConnectionFactory f1 = new HttpConnectionFactory(httpConfig);
-            ServerConnector connector = new ServerConnector(server, f1);
+            HttpConnectionFactory httpConnectionFactory = new 
HttpConnectionFactory(httpConfig);
+            ServerConnector connector = new ServerConnector(server, 
httpConnectionFactory);
             connector.setPort(port);
             server.addConnector(connector);
             server.setHandler(handler);
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java
index fb65a1044f..d8d66adfd9 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java
@@ -36,6 +36,7 @@ import org.apache.jena.atlas.lib.FileOps;
 import org.apache.jena.atlas.lib.Pair;
 import org.apache.jena.fuseki.Fuseki;
 import org.apache.jena.fuseki.FusekiConfigException;
+import org.apache.jena.fuseki.main.sys.FusekiSystemConstants;
 import org.apache.jena.fuseki.main.sys.JettyLib;
 import org.apache.jena.fuseki.server.DataAccessPointRegistry;
 import org.apache.jena.fuseki.server.OperationRegistry;
@@ -64,7 +65,10 @@ import org.slf4j.LoggerFactory;
 public class JettyServer {
     // Possibility: Use this for the super class of FusekiServer or within 
FusekiServer.jettyServer
     // as implementation inheritance.
-    // Caution : there are small differences e.g. in building where order 
matters.
+    // Caution :
+    //   there are small differences e.g. in building where order matters.
+    //   Setting default (look for FusekiServerConstants)
+    //
 
     private static Logger LOG = LoggerFactory.getLogger("HTTP");
 
@@ -410,6 +414,8 @@ public class JettyServer {
             context.setDisplayName(servletContextName);
             context.setErrorHandler(errorHandler);
             context.setContextPath(contextPath);
+            // Large - for SPARQL Update by HTML forms
+            
context.setMaxFormContentSize(FusekiSystemConstants.jettyMaxFormContentSize);
             if ( securityHandler != null )
                 context.setSecurityHandler(securityHandler);
             return context;
@@ -469,16 +475,12 @@ public class JettyServer {
     }
 
     private static void serverAddConnectors(Server server, int port,  boolean 
loopback) {
-        HttpConnectionFactory f1 = new HttpConnectionFactory();
-
-        //f1.getHttpConfiguration().setRequestHeaderSize(512 * 1024);
-        //f1.getHttpConfiguration().setOutputBufferSize(1024 * 1024);
-        f1.getHttpConfiguration().setSendServerVersion(false);
+        HttpConfiguration httpConnectionFactory = JettyLib.httpConfiguration();
+        HttpConnectionFactory f1 = new 
HttpConnectionFactory(httpConnectionFactory);
         ServerConnector connector = new ServerConnector(server, f1);
         connector.setPort(port);
         server.addConnector(connector);
         if ( loopback )
             connector.setHost("localhost");
     }
-
 }
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiSystemConstants.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiSystemConstants.java
new file mode 100644
index 0000000000..647a8ee22d
--- /dev/null
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiSystemConstants.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.jena.fuseki.main.sys;
+
+import org.apache.jena.atlas.lib.PropertyUtils;
+import org.apache.jena.fuseki.Fuseki;
+import org.eclipse.jetty.server.FormFields;
+
+public class FusekiSystemConstants {
+
+    private static final int jettyMaxFormContentSizeDefault = 25 * 1024 * 1024;
+
+    /**
+     * Jetty: ServletContextHandler.setMaxFormContentSize (set in
+     * {@link 
org.apache.jena.fuseki.main.FusekiServer.Builder#buildServletContext})
+     * (Jetty 12 default is 200k.)
+     */
+    public static final int jettyMaxFormContentSize = 
getValueInt(FormFields.MAX_LENGTH_ATTRIBUTE, jettyMaxFormContentSizeDefault);
+
+    /** Get an integer-valued property */
+    private static int getValueInt(String propertyKey, int defaultValue) {
+        // Respect jetty constant:
+        // "org.eclipse.jetty.server.Request.maxFormContentSize";
+        // When set by API, that takes precedence over system property setting.
+        try {
+            return PropertyUtils.getPropertyAsInteger(System.getProperties(), 
propertyKey, defaultValue);
+        } catch (NumberFormatException ex) {
+            Fuseki.configLog.warn("Bad number format for " + propertyKey);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Jetty output buffer size.
+     * <p>
+     * Setting for HttpConfiguration.setOutputBufferSize (set in
+     * {@link JettyLib#httpConfiguration}).
+     */
+    public static final int jettyOutputBufferSize = 5 * 1024 * 1024;
+
+    /**
+     * JettyrRequest header size.
+     * <p>
+     * Setting for HttpConfiguration.setRequestHeaderSize (set in
+     * {@link JettyLib#httpConfiguration}). Space is used "on demand" while 
reading
+     * the HTTP header. (Jetty 12 default is 8k.)
+     */
+    public static final int jettyRequestHeaderSize = 512 * 1024;
+
+    /**
+     * Jetty response header size.
+     * <p>
+     * Setting for HttpConfiguration.setResponseHeaderSize (set in
+     * {@link JettyLib#httpConfiguration}). This is not an "upper bound maximum
+     * limit" - the buffer is always allocated at full size pre-allocated, not
+     * on-demand.
+     * <p>
+     * Fuseki does not generate large headers. 16k is the general level of 
proxy
+     * support. (Jetty 12 default is 8k.)
+     */
+    public static final int jettyResponseHeaderSize = 16 * 1024;
+}
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/JettyLib.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/JettyLib.java
index 7c5db7a016..64b2bafbf3 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/JettyLib.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/JettyLib.java
@@ -27,7 +27,6 @@ import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceFactory;
 
 /** Helpers for working with Jetty.
@@ -86,19 +85,18 @@ public class JettyLib {
         mimeTypes.addMimeMapping("tsv",     WebContent.contentTypeTextTSV);
     }
 
-    /** HTTP configuration with setting for Fuseki workload. No "secure" 
settings. */
+    /** HTTP configuration with setting for Fuseki workload. */
     public static HttpConfiguration httpConfiguration() {
-        HttpConfiguration http_config = new HttpConfiguration();
-        // Some people do try very large operations ... really, should use 
POST.
-        http_config.setRequestHeaderSize(512 * 1024);
-        http_config.setOutputBufferSize(1024 * 1024);
-//      http_config.setResponseHeaderSize(8192);
-        http_config.setSendServerVersion(false);
-        return http_config;
+        HttpConfiguration httpConfig = new HttpConfiguration();
+        
httpConfig.setRequestHeaderSize(FusekiSystemConstants.jettyRequestHeaderSize);
+        
httpConfig.setResponseHeaderSize(FusekiSystemConstants.jettyResponseHeaderSize);
+        
httpConfig.setOutputBufferSize(FusekiSystemConstants.jettyOutputBufferSize);
+        httpConfig.setSendServerVersion(false);
+        return httpConfig;
     }
 
-    /** Create a resource for a filename */
-    public static Resource newResource(String filename) {
+    /** Create a Jetty resource for a filename */
+    public static org.eclipse.jetty.util.resource.Resource newResource(String 
filename) {
         return ResourceFactory.root().newResource(filename);
     }
-}
\ No newline at end of file
+}

Reply via email to