Repository: helidon-io/helidon (java)

Issue:
4.x: Different defaults for HTTP/1.1 limits
Limits in 3.x (in `io.helidon.webserver.SocketConfiguration.Builder`):
```
 private int maxHeaderSize = 16384;
private int maxInitialLineLength = 4096;
```

in 4.x, we have the limits set to (in `io.helidon.webserver.http1.Http1ConfigBlueprint`):
```
@Option.DefaultInt(16384) // correct
int maxHeadersSize(); 

@Option.DefaultInt(2048) // should be 4096
int maxPrologueLength();
```

Other defaults should be checked as well and aligned where the semantics is the same.

Pull request description:
Update max-prologue-length from 2048 to 4096 to align with 3.x
### Description

Before:
```yaml
server:
  protocols:
    http_1_1:
      max-prologue-length: 2048 # old default
```

After:
```yaml
server:
  protocols:
    http_1_1:
      max-prologue-length: 4096 # new default
```

Fixes #9002

### Documentation

None



Patch:
diff --git a/common/uri/src/main/java/io/helidon/common/uri/UriEncoding.java b/common/uri/src/main/java/io/helidon/common/uri/UriEncoding.java
index 70a5e1f213..f7abb5e1ce 100644
--- a/common/uri/src/main/java/io/helidon/common/uri/UriEncoding.java
+++ b/common/uri/src/main/java/io/helidon/common/uri/UriEncoding.java
@@ -43,19 +43,27 @@ public final class UriEncoding {
 
     /**
      * Decode a URI segment.
+     * <p>
+     * Percent characters {@code "%s"} found between brackets {@code "[]"} are not decoded to support IPv6 literal.
+     * E.g. {@code http://[fe80::1%lo0]:8080}.
+     * <p>
+     * See <a href="https://tools.ietf.org/html/rfc6874#section-2">RFC 6874, section 2.</a>
      *
      * @param uriSegment URI segment with percent encoding
      * @return decoded string
      */
     public static String decodeUri(String uriSegment) {
-        if (uriSegment.isEmpty()) {
-            return "";
-        }
-        if (uriSegment.indexOf('%') == -1 && uriSegment.indexOf('+') == -1) {
-            return uriSegment;
-        }
+        return decodeUri(uriSegment, true);
+    }
 
-        return decode(uriSegment);
+    /**
+     * Decode a URI query.
+     *
+     * @param uriQuery URI query with percent encoding
+     * @return decoded string
+     */
+    public static String decodeQuery(String uriQuery) {
+        return decodeUri(uriQuery, false);
     }
 
     /**
@@ -123,7 +131,18 @@ public final class UriEncoding {
         appender.append(HEX_DIGITS[b & 0x0F]);
     }
 
-    private static String decode(String string) {
+    private static String decodeUri(String uriSegment, boolean ignorePercentInBrackets) {
+        if (uriSegment.isEmpty()) {
+            return "";
+        }
+        if (uriSegment.indexOf('%') == -1 && uriSegment.indexOf('+') == -1) {
+            return uriSegment;
+        }
+        return decode(uriSegment, ignorePercentInBrackets);
+    }
+
+    // see java.net.URI.decode(String, boolean)
+    private static String decode(String string, boolean ignorePercentInBrackets) {
         int len = string.length();
 
         StringBuilder sb = new StringBuilder(len);
@@ -141,7 +160,7 @@ public final class UriEncoding {
             } else if (betweenBrackets && c == ']') {
                 betweenBrackets = false;
             }
-            if (c != '%' || betweenBrackets) {
+            if (c != '%' || (betweenBrackets && ignorePercentInBrackets)) {
                 sb.append(c == '+' && !betweenBrackets ? ' ' : c);      // handles '+' decoding
                 if (++i >= len) {
                     break;
diff --git a/common/uri/src/main/java/io/helidon/common/uri/UriQueryImpl.java b/common/uri/src/main/java/io/helidon/common/uri/UriQueryImpl.java
index dbe14f2265..fd6544cc80 100644
--- a/common/uri/src/main/java/io/helidon/common/uri/UriQueryImpl.java
+++ b/common/uri/src/main/java/io/helidon/common/uri/UriQueryImpl.java
@@ -31,7 +31,7 @@ import io.helidon.common.mapper.MapperManager;
 import io.helidon.common.mapper.OptionalValue;
 import io.helidon.common.mapper.Value;
 
-import static io.helidon.common.uri.UriEncoding.decodeUri;
+import static io.helidon.common.uri.UriEncoding.decodeQuery;
 
 // must be lazily populated to prevent perf overhead when queries are ignored
 final class UriQueryImpl implements UriQuery {
@@ -215,11 +215,11 @@ final class UriQueryImpl implements UriQuery {
     private void addDecoded(Map<String, List<String>> newQueryParams, String next) {
         int eq = next.indexOf('=');
         if (eq == -1) {
-            newQueryParams.putIfAbsent(decodeUri(next), new LinkedList<>());
+            newQueryParams.putIfAbsent(decodeQuery(next), new LinkedList<>());
         } else {
             String name = next.substring(0, eq);
             String value = next.substring(eq + 1);
-            newQueryParams.computeIfAbsent(decodeUri(name), it -> new LinkedList<>()).add(decodeUri(value));
+            newQueryParams.computeIfAbsent(decodeQuery(name), it -> new LinkedList<>()).add(decodeQuery(value));
         }
     }
 
diff --git a/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ConfigBlueprint.java b/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ConfigBlueprint.java
index f7673a98a2..2f35ecbe44 100644
--- a/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ConfigBlueprint.java
+++ b/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ConfigBlueprint.java
@@ -45,7 +45,7 @@ interface Http1ConfigBlueprint extends ProtocolConfig {
      * @return maximal size in bytes
      */
     @Option.Configured
-    @Option.DefaultInt(2048)
+    @Option.DefaultInt(4096)
     int maxPrologueLength();
 
     /**


Test patch:
diff --git a/common/uri/src/test/java/io/helidon/common/uri/UriEncodingTest.java b/common/uri/src/test/java/io/helidon/common/uri/UriEncodingTest.java
index 56d791e35d..e8c1214d97 100644
--- a/common/uri/src/test/java/io/helidon/common/uri/UriEncodingTest.java
+++ b/common/uri/src/test/java/io/helidon/common/uri/UriEncodingTest.java
@@ -30,4 +30,9 @@ class UriEncodingTest {
         assertThat(decodeUri("+hello+world+"), is(" hello world "));
         assertThat(decodeUri("[+]hello[+]world[+]"), is("[+]hello[+]world[+]"));
     }
+
+    @Test
+    void testIPv6Literal() {
+        assertThat(decodeUri("http://[fe80::1%lo0]:8080"), is("http://[fe80::1%lo0]:8080"));
+    }
 }
diff --git a/common/uri/src/test/java/io/helidon/common/uri/UriQueryTest.java b/common/uri/src/test/java/io/helidon/common/uri/UriQueryTest.java
index d9dc16fed2..cdbee2474a 100644
--- a/common/uri/src/test/java/io/helidon/common/uri/UriQueryTest.java
+++ b/common/uri/src/test/java/io/helidon/common/uri/UriQueryTest.java
@@ -16,7 +16,6 @@
 
 package io.helidon.common.uri;
 
-import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URLEncoder;
 
@@ -41,11 +40,17 @@ class UriQueryTest {
     }
 
     @Test
-    void testEncoded() throws UnsupportedEncodingException {
+    void testEncoded() {
         UriQuery uriQuery = UriQuery.create("a=" + URLEncoder.encode("1&b=2", US_ASCII));
         assertThat(uriQuery.get("a"), is("1&b=2"));
     }
 
+    @Test
+    void testEncodedWithinBrackets() {
+        UriQuery uriQuery = UriQuery.create("msg=[Hello%20World]");
+        assertThat(uriQuery.get("msg"), is("[Hello World]"));
+    }
+
     @Test
     void testEncodedOtherChars() {
         UriQuery uriQuery = UriQuery.create("a=b%26c=d&e=f&e=g&h=x%63%23e%3c");