Skip to content

Commit 03defaf

Browse files
committed
server: allow to configure maxHeaderSize
- fix #3721 - fix #3724
1 parent f0293b1 commit 03defaf

File tree

5 files changed

+102
-2
lines changed

5 files changed

+102
-2
lines changed

jooby/src/main/java/io/jooby/ServerOptions.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ public class ServerOptions {
106106
*/
107107
private int maxRequestSize = _10MB;
108108

109+
/** The maximum size in bytes of a http request header. Default is <code>8kb</code> */
110+
private int maxHeaderSize = _8KB;
111+
109112
private String host = LOCAL_HOST;
110113

111114
private SslOptions ssl;
@@ -447,6 +450,34 @@ public int getMaxRequestSize() {
447450
return this;
448451
}
449452

453+
/**
454+
* The maximum size in bytes of an http request header. Exceeding the size generates a different
455+
* response across server implementations.
456+
*
457+
* <ul>
458+
* <li>Jetty: generates a 431 error message
459+
* <li>Netty: the header is dropped/ignored, but don't fail
460+
* <li>Undertow: generates an empty 400 response, and the connection is closed.
461+
* </ul>
462+
*
463+
* @return The maximum size in bytes of an http request header.
464+
*/
465+
public int getMaxHeaderSize() {
466+
return maxHeaderSize;
467+
}
468+
469+
/**
470+
* Set the maximum size in bytes of an http request header.
471+
*
472+
* @param maxHeaderSize The maximum size in bytes of an http request header. Default is <code>8kb
473+
* </code>.
474+
* @return The maximum size in bytes of an http request header. Default is <code>8kb</code>.
475+
*/
476+
public @NonNull ServerOptions setMaxHeaderSize(int maxHeaderSize) {
477+
this.maxHeaderSize = maxHeaderSize;
478+
return this;
479+
}
480+
450481
/**
451482
* Server host, defaults is <code>0.0.0.0</code>.
452483
*

modules/jooby-jetty/src/main/java/io/jooby/jetty/JettyServer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public io.jooby.Server start(@NonNull Jooby... application) {
127127
httpConf.setSendXPoweredBy(false);
128128
httpConf.setSendDateHeader(options.getDefaultHeaders());
129129
httpConf.setSendServerVersion(false);
130+
httpConf.setRequestHeaderSize(options.getMaxHeaderSize());
130131

131132
if (httpConfigurer != null) {
132133
httpConfigurer.accept(httpConf);

modules/jooby-netty/src/main/java/io/jooby/netty/NettyServer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package io.jooby.netty;
77

88
import static io.jooby.ServerOptions._4KB;
9-
import static io.jooby.ServerOptions._8KB;
109
import static java.util.concurrent.Executors.newFixedThreadPool;
1110

1211
import java.net.BindException;
@@ -204,7 +203,7 @@ private NettyPipeline newPipeline(
204203
var decoderConfig =
205204
new HttpDecoderConfig()
206205
.setMaxInitialLineLength(_4KB)
207-
.setMaxHeaderSize(_8KB)
206+
.setMaxHeaderSize(options.getMaxHeaderSize())
208207
.setMaxChunkSize(bufferSize)
209208
.setHeadersFactory(headersFactory)
210209
.setTrailersFactory(headersFactory);

modules/jooby-undertow/src/main/java/io/jooby/undertow/UndertowServer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ public String getName() {
122122
/** Server: */
123123
// HTTP/1.1 is keep-alive by default, turn this option off
124124
.setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false)
125+
.setServerOption(UndertowOptions.MAX_HEADER_SIZE, options.getMaxHeaderSize())
125126
.setServerOption(UndertowOptions.ALLOW_EQUALS_IN_COOKIE_VALUE, true)
126127
.setServerOption(UndertowOptions.ALWAYS_SET_DATE, options.getDefaultHeaders())
127128
.setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3721;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
11+
import java.util.Set;
12+
13+
import io.jooby.ServerOptions;
14+
import io.jooby.junit.ServerTest;
15+
import io.jooby.junit.ServerTestRunner;
16+
17+
public class Issue3721 {
18+
19+
@ServerTest
20+
public void shouldAllowToSetMaxHeaderSize(ServerTestRunner runner) {
21+
runner
22+
.define(
23+
app -> {
24+
app.setServerOptions(new ServerOptions().setMaxHeaderSize(ServerOptions._16KB));
25+
app.get(
26+
"/3721",
27+
ctx -> {
28+
return ctx.header("large").value();
29+
});
30+
})
31+
.ready(
32+
http -> {
33+
var large = ".".repeat(ServerOptions._8KB + ServerOptions._4KB);
34+
http.header("large", large);
35+
http.get(
36+
"/3721",
37+
rsp -> {
38+
var result = rsp.body().string();
39+
assertEquals(large, result);
40+
assertEquals(ServerOptions._8KB + ServerOptions._4KB, result.length());
41+
});
42+
});
43+
}
44+
45+
@ServerTest
46+
public void shouldCheckErrorOnLargeHeaderSize(ServerTestRunner runner) {
47+
runner
48+
.define(
49+
app -> {
50+
app.setServerOptions(new ServerOptions().setMaxHeaderSize(ServerOptions._4KB));
51+
app.get(
52+
"/3721",
53+
ctx -> {
54+
return ctx.header("large").value();
55+
});
56+
})
57+
.ready(
58+
http -> {
59+
var large = ".".repeat(ServerOptions._8KB);
60+
http.header("large", large);
61+
http.get(
62+
"/3721",
63+
rsp -> {
64+
assertTrue(Set.of(400, 431).contains(rsp.code()));
65+
});
66+
});
67+
}
68+
}

0 commit comments

Comments
 (0)