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

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git


The following commit(s) were added to refs/heads/master by this push:
     new aea2671e3c Bound the JSON request body in every JSON builder
aea2671e3c is described below

commit aea2671e3c5ebd8638d37db30d69639223366d5d
Author: Robert Lazarski <[email protected]>
AuthorDate: Tue Sep 29 12:08:45 2026 -1000

    Bound the JSON request body in every JSON builder
    
    The request-body ceilings never reached axis2-json, so an application/json
    POST was read without limit. Add jsonMaxRequestSize (100 MB, -1 to opt out)
    and apply it in the legacy, Gson, Moshi and HTTP/2 JSON builders alike: a
    streaming reader still materialises a single string token whole.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 SECURITY.md                                        |   9 +-
 .../apache/axis2/json/AbstractJSONDataSource.java  |   4 +-
 .../apache/axis2/json/AbstractJSONOMBuilder.java   |  10 +-
 .../org/apache/axis2/json/gson/JsonBuilder.java    |   5 +
 .../axis2/json/gsonh2/EnhancedGsonJsonBuilder.java |   7 +
 .../org/apache/axis2/json/moshi/JsonBuilder.java   |   5 +
 .../json/moshih2/EnhancedMoshiJsonBuilder.java     |   7 +
 .../axis2/json/JsonRequestSizeLimitTest.java       | 163 +++++++++++++++++++++
 .../apache/axis2/builder/RequestSizeLimits.java    |  18 ++-
 src/site/markdown/release-notes/2.0.2.md           |   5 +-
 10 files changed, 224 insertions(+), 9 deletions(-)

diff --git a/SECURITY.md b/SECURITY.md
index bea9d04b79..4303c1d091 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -132,7 +132,7 @@ Axis2 exposes the following URL patterns from the servlet 
mapping:
 |-----------|---------|-------------|
 | **XML parsers** (AXIOM/StAX, DocumentBuilderFactory) | XXE, billion laughs, 
entity expansion DoS | DOCTYPE disallowed; external entities disabled; 
`DefaultEntityResolver` returns empty source |
 | **WSDL/XSD import resolution** (wsdl4j, xmlschema-core) | XXE in imported 
documents; SSRF via `file://`/`gopher://` schemes | `SecureWSDLLocator` 
pre-validates the client-side path with a hardened SAX parser (HTTP/HTTPS only, 
10MB default, connect/read timeouts, relative-path SSRF bypass blocked); 
`HardenedWSDLLocator` screens the file, archive, classpath and catalog paths, 
refusing a DOCTYPE without restricting where a document may be loaded from |
-| **JSON parser** (Gson) | Deep nesting stack exhaustion, large payload DoS | 
Fuzz-tested (1.7M+ iterations); Gson nesting limits |
+| **JSON parser** (Gson) | Deep nesting stack exhaustion, large payload DoS | 
Fuzz-tested (1.7M+ iterations); Gson nesting limits; `jsonMaxRequestSize` 
bounds the body for every JSON builder |
 | **JSON-RPC dispatch** | Method name injection; unexpected operation 
invocation | Method names validated against deployed operations; unknown 
methods return fault |
 | **Multipart/file upload** (commons-fileupload2) | Unbounded file count DoS 
(CVE-2023-24998 pattern); unbounded body size; temp-file accumulation | 
commons-fileupload2 enforces the file count limit; `multipartMaxRequestSize` / 
`multipartMaxFileSize` bound the body; temp files are deleted immediately for 
form fields and tracked to collection for file parts |
 | **Form-urlencoded builder** | Unbounded body read into an in-memory map | 
`formUrlEncodedMaxRequestSize` bounds the read; the stream fails rather than 
truncating |
@@ -404,9 +404,10 @@ migration from `commons-fileupload` 1.x to 
`commons-fileupload2` in
     stream directly, so a servlet container's post-size limit never sees the
     body. `multipartMaxRequestSize` and `multipartMaxFileSize` (100 MB),
     `formUrlEncodedMaxRequestSize` (2 MB), `mtomMaxRequestSize` (100 MB, the
-    whole `multipart/related` body, so MTOM and SwA) and `soapMaxRequestSize`
-    (100 MB, a plain SOAP or POX body) bound them; `-1` restores the previous
-    unbounded behaviour, and any may be set per service.
+    whole `multipart/related` body, so MTOM and SwA), `soapMaxRequestSize`
+    (100 MB, a plain SOAP or POX body) and `jsonMaxRequestSize` (100 MB, every
+    builder in `axis2-json`, streaming or not) bound them; `-1` restores the
+    previous unbounded behaviour, and any may be set per service.
 
     Every builder that reads the stream has to be bounded, not just the ones
     whose limits were reported: the caller picks which builder runs by choosing
diff --git a/modules/json/src/org/apache/axis2/json/AbstractJSONDataSource.java 
b/modules/json/src/org/apache/axis2/json/AbstractJSONDataSource.java
index 6d22c8236d..ccdeaf48d4 100755
--- a/modules/json/src/org/apache/axis2/json/AbstractJSONDataSource.java
+++ b/modules/json/src/org/apache/axis2/json/AbstractJSONDataSource.java
@@ -78,7 +78,9 @@ public abstract class AbstractJSONDataSource extends 
AbstractPullOMDataSource {
                 }
                 jsonString = sb.toString();
             } catch (IOException e) {
-                throw new OMException();
+                // Keep the cause: an over-sized body surfaces here, as the
+                // ceiling applied by AbstractJSONOMBuilder.
+                throw new OMException(e);
             }
             isRead = true;
             return jsonString;
diff --git a/modules/json/src/org/apache/axis2/json/AbstractJSONOMBuilder.java 
b/modules/json/src/org/apache/axis2/json/AbstractJSONOMBuilder.java
index 8ce2c1f867..89309c7210 100644
--- a/modules/json/src/org/apache/axis2/json/AbstractJSONOMBuilder.java
+++ b/modules/json/src/org/apache/axis2/json/AbstractJSONOMBuilder.java
@@ -25,7 +25,9 @@ import org.apache.axiom.om.OMFactory;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.Constants;
 import org.apache.axis2.addressing.EndpointReference;
+import org.apache.axis2.builder.BoundedInputStream;
 import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.kernel.http.util.URIEncoderDecoder;
 
@@ -111,8 +113,14 @@ public abstract class AbstractJSONOMBuilder implements 
Builder {
             if (charSetEncoding == null) {
                 charSetEncoding = MessageContext.DEFAULT_CHAR_SET_ENCODING;
             }
+            // The data source buffers the whole body into one String, so bound
+            // the transport stream as SOAPBuilder does.
+            long maxRequestSize = RequestSizeLimits.resolve(messageContext,
+                    RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                    RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE);
             try {
-                reader = new InputStreamReader(inputStream, charSetEncoding);
+                reader = new InputStreamReader(
+                        BoundedInputStream.wrap(inputStream, maxRequestSize), 
charSetEncoding);
             } catch (UnsupportedEncodingException ex) {
                 throw AxisFault.makeFault(ex);
             }
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonBuilder.java 
b/modules/json/src/org/apache/axis2/json/gson/JsonBuilder.java
index 022f5be970..7ce3215df6 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonBuilder.java
+++ b/modules/json/src/org/apache/axis2/json/gson/JsonBuilder.java
@@ -25,7 +25,9 @@ import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.SOAPFactory;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.Constants;
+import org.apache.axis2.builder.BoundedInputStream;
 import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.json.factory.JsonConstant;
 import org.apache.commons.logging.Log;
@@ -42,6 +44,9 @@ public class JsonBuilder implements Builder {
         JsonReader jsonReader;
         String charSetEncoding=null;
         if (inputStream != null) {
+            inputStream = BoundedInputStream.wrap(inputStream, 
RequestSizeLimits.resolve(messageContext,
+                    RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                    RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE));
             try {
                 charSetEncoding = (String) 
messageContext.getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
                 jsonReader = new JsonReader(new InputStreamReader(inputStream, 
charSetEncoding));
diff --git 
a/modules/json/src/org/apache/axis2/json/gsonh2/EnhancedGsonJsonBuilder.java 
b/modules/json/src/org/apache/axis2/json/gsonh2/EnhancedGsonJsonBuilder.java
index ebf7e6d7b1..3be985288a 100644
--- a/modules/json/src/org/apache/axis2/json/gsonh2/EnhancedGsonJsonBuilder.java
+++ b/modules/json/src/org/apache/axis2/json/gsonh2/EnhancedGsonJsonBuilder.java
@@ -24,7 +24,9 @@ import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.SOAPFactory;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.Constants;
+import org.apache.axis2.builder.BoundedInputStream;
 import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.description.Parameter;
 import org.apache.axis2.engine.AxisConfiguration;
@@ -161,6 +163,11 @@ public class EnhancedGsonJsonBuilder implements Builder {
                 return createDefaultEnvelope();
             }
 
+            // The payload-size strategy below only picks a code path; it 
bounds nothing.
+            inputStream = BoundedInputStream.wrap(inputStream, 
RequestSizeLimits.resolve(messageContext,
+                    RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                    RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE));
+
             // Determine processing strategy based on payload characteristics 
(from HTTP/2 analysis)
             ProcessingStrategy strategy = 
analyzeProcessingStrategy(messageContext, contentType);
 
diff --git a/modules/json/src/org/apache/axis2/json/moshi/JsonBuilder.java 
b/modules/json/src/org/apache/axis2/json/moshi/JsonBuilder.java
index 09976cf110..2aab6202f6 100644
--- a/modules/json/src/org/apache/axis2/json/moshi/JsonBuilder.java
+++ b/modules/json/src/org/apache/axis2/json/moshi/JsonBuilder.java
@@ -29,7 +29,9 @@ import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.SOAPFactory;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.Constants;
+import org.apache.axis2.builder.BoundedInputStream;
 import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.json.factory.JsonConstant;
 import org.apache.commons.logging.Log;
@@ -46,6 +48,9 @@ public class JsonBuilder implements Builder {
         JsonReader jsonReader;
         String charSetEncoding=null;
         if (inputStream != null) {
+            inputStream = BoundedInputStream.wrap(inputStream, 
RequestSizeLimits.resolve(messageContext,
+                    RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                    RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE));
             try {
                 charSetEncoding = (String) 
messageContext.getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
                 if (charSetEncoding != null && 
charSetEncoding.indexOf("UTF-8") == -1) {
diff --git 
a/modules/json/src/org/apache/axis2/json/moshih2/EnhancedMoshiJsonBuilder.java 
b/modules/json/src/org/apache/axis2/json/moshih2/EnhancedMoshiJsonBuilder.java
index 5db126ae50..59d90e80ab 100644
--- 
a/modules/json/src/org/apache/axis2/json/moshih2/EnhancedMoshiJsonBuilder.java
+++ 
b/modules/json/src/org/apache/axis2/json/moshih2/EnhancedMoshiJsonBuilder.java
@@ -26,7 +26,9 @@ import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.SOAPFactory;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.Constants;
+import org.apache.axis2.builder.BoundedInputStream;
 import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.description.Parameter;
 import org.apache.axis2.engine.AxisConfiguration;
@@ -161,6 +163,11 @@ public class EnhancedMoshiJsonBuilder implements Builder {
                 return createDefaultEnvelope();
             }
 
+            // The payload-size strategy below only picks a code path; it 
bounds nothing.
+            inputStream = BoundedInputStream.wrap(inputStream, 
RequestSizeLimits.resolve(messageContext,
+                    RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                    RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE));
+
             // Determine processing strategy based on payload characteristics 
(from HTTP/2 analysis)
             ProcessingStrategy strategy = 
analyzeProcessingStrategy(messageContext, contentType);
 
diff --git 
a/modules/json/test/org/apache/axis2/json/JsonRequestSizeLimitTest.java 
b/modules/json/test/org/apache/axis2/json/JsonRequestSizeLimitTest.java
new file mode 100644
index 0000000000..65ea648695
--- /dev/null
+++ b/modules/json/test/org/apache/axis2/json/JsonRequestSizeLimitTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.axis2.json;
+
+import junit.framework.TestCase;
+import org.apache.axiom.om.OMSourcedElement;
+import org.apache.axis2.builder.Builder;
+import org.apache.axis2.builder.RequestSizeLimits;
+import org.apache.axis2.context.ConfigurationContext;
+import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.description.Parameter;
+import org.apache.axis2.engine.AxisConfiguration;
+import org.apache.axis2.json.factory.JsonConstant;
+import org.apache.axis2.json.gson.GsonXMLStreamReader;
+import org.apache.axis2.json.gsonh2.EnhancedGsonJsonBuilder;
+import org.apache.axis2.json.moshi.MoshiXMLStreamReader;
+import org.apache.axis2.json.moshih2.EnhancedMoshiJsonBuilder;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * Every JSON builder must apply {@code jsonMaxRequestSize}. Streaming builders
+ * are no exception: one string token is still read into memory whole, which is
+ * what the body below is.
+ */
+public class JsonRequestSizeLimitTest extends TestCase {
+
+    private static final String LIMIT = "64";
+
+    private AxisConfiguration axisConfiguration;
+    private MessageContext messageContext;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        axisConfiguration = new AxisConfiguration();
+        ConfigurationContext configurationContext = new 
ConfigurationContext(axisConfiguration);
+        messageContext = configurationContext.createMessageContext();
+        
messageContext.setProperty(org.apache.axis2.Constants.Configuration.CHARACTER_SET_ENCODING,
 "UTF-8");
+    }
+
+    private void setLimit(String value) throws Exception {
+        axisConfiguration.addParameter(new 
Parameter(RequestSizeLimits.JSON_MAX_REQUEST_SIZE, value));
+    }
+
+    private static InputStream body(int stringLength) throws Exception {
+        StringBuilder sb = new StringBuilder("{\"a\":\"");
+        for (int i = 0; i < stringLength; i++) {
+            sb.append('A');
+        }
+        return new 
ByteArrayInputStream(sb.append("\"}").toString().getBytes("UTF-8"));
+    }
+
+    private static void assertExceedsCeiling(Throwable t) {
+        for (Throwable c = t; c != null; c = c.getCause()) {
+            if (c.getMessage() != null && c.getMessage().contains("exceeds the 
configured maximum")) {
+                return;
+            }
+        }
+        fail("Expected the request-size ceiling to be hit, got " + t);
+    }
+
+    public void testJsonCeilingHasADefault() {
+        assertEquals(RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE,
+                RequestSizeLimits.resolve(messageContext,
+                        RequestSizeLimits.JSON_MAX_REQUEST_SIZE,
+                        RequestSizeLimits.DEFAULT_JSON_MAX_REQUEST_SIZE));
+    }
+
+    public void testJsonOMBuilderIsBounded() throws Exception {
+        setLimit(LIMIT);
+        try {
+            readJsonString(1000);
+            fail("An over-sized body was read in full");
+        } catch (Exception e) {
+            assertExceedsCeiling(e);
+        }
+    }
+
+    public void testJsonOMBuilderAcceptsABodyUnderTheCeiling() throws 
Exception {
+        setLimit(LIMIT);
+        assertEquals("{\"a\":\"AAAAAAAA\"}", readJsonString(8));
+    }
+
+    public void testJsonOMBuilderCeilingCanBeOptedOut() throws Exception {
+        setLimit("-1");
+        assertEquals(1000 + 8, readJsonString(1000).length());
+    }
+
+    /** Builds with JSONOMBuilder, then reads the body the way its data source 
does. */
+    private String readJsonString(int stringLength) throws Exception {
+        OMSourcedElement element = (OMSourcedElement) new 
JSONOMBuilder().processDocument(
+                body(stringLength), JSONTestConstants.CONTENT_TYPE_MAPPED, 
messageContext);
+        return (String) ((AbstractJSONDataSource) 
element.getDataSource()).getObject();
+    }
+
+    public void testGsonJsonBuilderIsBounded() throws Exception {
+        setLimit(LIMIT);
+        assertGsonReaderBounded(new org.apache.axis2.json.gson.JsonBuilder());
+    }
+
+    public void testEnhancedGsonJsonBuilderIsBounded() throws Exception {
+        setLimit(LIMIT);
+        assertGsonReaderBounded(new EnhancedGsonJsonBuilder());
+    }
+
+    public void testMoshiJsonBuilderIsBounded() throws Exception {
+        setLimit(LIMIT);
+        assertMoshiReaderBounded(new 
org.apache.axis2.json.moshi.JsonBuilder());
+    }
+
+    public void testEnhancedMoshiJsonBuilderIsBounded() throws Exception {
+        setLimit(LIMIT);
+        assertMoshiReaderBounded(new EnhancedMoshiJsonBuilder());
+    }
+
+    private void assertGsonReaderBounded(Builder builder) throws Exception {
+        builder.processDocument(body(1000), "application/json", 
messageContext);
+        GsonXMLStreamReader reader = (GsonXMLStreamReader)
+                
messageContext.getProperty(JsonConstant.GSON_XML_STREAM_READER);
+        com.google.gson.stream.JsonReader jsonReader = reader.getJsonReader();
+        try {
+            jsonReader.beginObject();
+            jsonReader.nextName();
+            jsonReader.nextString();
+            fail("An over-sized body was read in full");
+        } catch (Exception e) {
+            assertExceedsCeiling(e);
+        }
+    }
+
+    private void assertMoshiReaderBounded(Builder builder) throws Exception {
+        builder.processDocument(body(1000), "application/json", 
messageContext);
+        MoshiXMLStreamReader reader = (MoshiXMLStreamReader)
+                
messageContext.getProperty(JsonConstant.MOSHI_XML_STREAM_READER);
+        com.squareup.moshi.JsonReader jsonReader = reader.getJsonReader();
+        try {
+            jsonReader.beginObject();
+            jsonReader.nextName();
+            jsonReader.nextString();
+            fail("An over-sized body was read in full");
+        } catch (Exception e) {
+            assertExceedsCeiling(e);
+        }
+    }
+}
diff --git a/modules/kernel/src/org/apache/axis2/builder/RequestSizeLimits.java 
b/modules/kernel/src/org/apache/axis2/builder/RequestSizeLimits.java
index ce9461b37d..8e69478383 100644
--- a/modules/kernel/src/org/apache/axis2/builder/RequestSizeLimits.java
+++ b/modules/kernel/src/org/apache/axis2/builder/RequestSizeLimits.java
@@ -61,7 +61,6 @@ public final class RequestSizeLimits {
     /** 2 MB: form encoding is for field data, not bulk transfer. */
     public static final long DEFAULT_FORM_URLENCODED_MAX_REQUEST_SIZE = 2L * 
1024 * 1024;
 
-    /** Sentinel for "no ceiling", matching the commons-fileupload2 
convention. */
     /**
      * Ceiling on a {@code multipart/related} body: MTOM and SwA.
      * <p>
@@ -82,6 +81,23 @@ public final class RequestSizeLimits {
     /** Default {@link #SOAP_MAX_REQUEST_SIZE}: 100 MB. */
     public static final long DEFAULT_SOAP_MAX_REQUEST_SIZE = 100L * 1024 * 
1024;
 
+    /**
+     * Ceiling on a JSON body, for every builder in the axis2-json module.
+     * <p>
+     * JSON is the primary protocol, so this is the ceiling most deployments
+     * actually rely on. Streaming does not make a JSON builder safe to leave
+     * unbounded: a single string token is still materialised whole.
+     */
+    public static final String JSON_MAX_REQUEST_SIZE = "jsonMaxRequestSize";
+
+    /**
+     * Default {@link #JSON_MAX_REQUEST_SIZE}: 100 MB, matching SOAP. The 
HTTP/2
+     * JSON builders are tuned for payloads of 50 MB and more, so a smaller
+     * default would break the deployments they were written for.
+     */
+    public static final long DEFAULT_JSON_MAX_REQUEST_SIZE = 100L * 1024 * 
1024;
+
+    /** Sentinel for "no ceiling", matching the commons-fileupload2 
convention. */
     public static final long UNLIMITED = -1L;
 
     private RequestSizeLimits() {
diff --git a/src/site/markdown/release-notes/2.0.2.md 
b/src/site/markdown/release-notes/2.0.2.md
index 3b789d4d61..e1628e8480 100644
--- a/src/site/markdown/release-notes/2.0.2.md
+++ b/src/site/markdown/release-notes/2.0.2.md
@@ -198,8 +198,9 @@ in `SECURITY.md`.
   so a servlet container's post-size limit never saw the body.
   `multipartMaxRequestSize` and `multipartMaxFileSize` (100 MB),
   `formUrlEncodedMaxRequestSize` (2 MB), `mtomMaxRequestSize` (100 MB, 
covering the
-  whole `multipart/related` body and so MTOM and SwA) and `soapMaxRequestSize`
-  (100 MB, a plain SOAP or POX body) now bound them; `-1` restores the previous
+  whole `multipart/related` body and so MTOM and SwA), `soapMaxRequestSize`
+  (100 MB, a plain SOAP or POX body) and `jsonMaxRequestSize` (100 MB, every 
JSON
+  builder including the Gson, Moshi and HTTP/2 variants) now bound them; `-1` 
restores the previous
   unbounded behaviour, and any may be set per service. All the stream-reading
   builders are covered, not only the form ones: the caller picks the builder by
   choosing the Content-Type, so bounding some of them bounds none. The 
ceilings are enforced

Reply via email to