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
+}