Skip to content

Commit 75a23bb

Browse files
hqbhonkerColinMarkAias00
authored
fix(netty): support configurable httpRequestDecoder properties (#6378)
Add HTTP request decoder configuration support including: - maxInitialLineLength (default 4096) - maxHeaderSize (default 8192) - maxChunkSize (default 8192) Users can now configure these properties via application.yml: shenyu.netty.http.httpDecoder.maxInitialLineLength=8192 This resolves the issue where HTTP requests with URLs exceeding 4096 bytes are rejected by the gateway. Closes #5856 Co-authored-by: ColinMark <pagedev@163.com> Co-authored-by: aias00 <liuhongyu@apache.org>
1 parent 1ecc77c commit 75a23bb

4 files changed

Lines changed: 147 additions & 0 deletions

File tree

shenyu-bootstrap/src/main/resources/application.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ shenyu:
139139
# - domain: 'example.com'
140140
# keyCertChainFile: '/Users/zhukunshuai/Desktop/cert/example.com+1.pem'
141141
# keyFile: '/Users/zhukunshuai/Desktop/cert/example.com+1-key.pem'
142+
httpDecoder:
143+
maxInitialLineLength: 4096
144+
maxHeaderSize: 8192
145+
maxChunkSize: 8192
142146
# httpclient:
143147
# strategy: netty # webClient
144148
# connectTimeout: 45000

shenyu-common/src/main/java/org/apache/shenyu/common/config/NettyHttpProperties.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public class NettyHttpProperties {
4040

4141
private SniProperties sni = new SniProperties();
4242

43+
private HttpDecoderProperties httpDecoder = new HttpDecoderProperties();
44+
4345
/**
4446
* get webServerFactoryEnabled.
4547
*
@@ -167,6 +169,24 @@ public void setAccessLog(final Boolean accessLog) {
167169
this.accessLog = accessLog;
168170
}
169171

172+
/**
173+
* get httpDecoder properties.
174+
*
175+
* @return httpDecoder properties
176+
*/
177+
public HttpDecoderProperties getHttpDecoder() {
178+
return httpDecoder;
179+
}
180+
181+
/**
182+
* set httpDecoder properties.
183+
*
184+
* @param httpDecoder http decoder properties
185+
*/
186+
public void setHttpDecoder(final HttpDecoderProperties httpDecoder) {
187+
this.httpDecoder = httpDecoder;
188+
}
189+
170190
public static class ServerSocketChannelProperties extends NettyChannelProperties {
171191

172192
private Integer soBacklog = 128;
@@ -292,6 +312,84 @@ public void setAllowHalfClosure(final Boolean allowHalfClosure) {
292312
}
293313
}
294314

315+
/**
316+
* Properties for HTTP request decoder configuration.
317+
*/
318+
public static class HttpDecoderProperties {
319+
320+
/**
321+
* The maximum length of the initial line (e.g. "GET / HTTP/1.1").
322+
* Default is 4096.
323+
*/
324+
private int maxInitialLineLength = 4096;
325+
326+
/**
327+
* The maximum size of all headers.
328+
* Default is 8192.
329+
*/
330+
private int maxHeaderSize = 8192;
331+
332+
/**
333+
* The maximum size of the content of each chunk.
334+
* Default is 8192.
335+
*/
336+
private int maxChunkSize = 8192;
337+
338+
/**
339+
* get maxInitialLineLength.
340+
*
341+
* @return maxInitialLineLength
342+
*/
343+
public int getMaxInitialLineLength() {
344+
return maxInitialLineLength;
345+
}
346+
347+
/**
348+
* set maxInitialLineLength.
349+
*
350+
* @param maxInitialLineLength max initial line length
351+
*/
352+
public void setMaxInitialLineLength(final int maxInitialLineLength) {
353+
this.maxInitialLineLength = maxInitialLineLength;
354+
}
355+
356+
/**
357+
* get maxHeaderSize.
358+
*
359+
* @return maxHeaderSize
360+
*/
361+
public int getMaxHeaderSize() {
362+
return maxHeaderSize;
363+
}
364+
365+
/**
366+
* set maxHeaderSize.
367+
*
368+
* @param maxHeaderSize max header size
369+
*/
370+
public void setMaxHeaderSize(final int maxHeaderSize) {
371+
this.maxHeaderSize = maxHeaderSize;
372+
}
373+
374+
/**
375+
* get maxChunkSize.
376+
*
377+
* @return maxChunkSize
378+
*/
379+
public int getMaxChunkSize() {
380+
return maxChunkSize;
381+
}
382+
383+
/**
384+
* set maxChunkSize.
385+
*
386+
* @param maxChunkSize max chunk size
387+
*/
388+
public void setMaxChunkSize(final int maxChunkSize) {
389+
this.maxChunkSize = maxChunkSize;
390+
}
391+
}
392+
295393
public static class SniProperties {
296394

297395
private Boolean enabled = false;

shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/netty/ShenyuNettyWebServerConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@ public HttpServer apply(final HttpServer httpServer) {
156156
return sniProcessor.apply(httpServer)
157157
.runOn(LoopResources.create("shenyu-netty", nettyHttpProperties.getSelectCount(), nettyHttpProperties.getWorkerCount(), true))
158158
.accessLog(nettyHttpProperties.getAccessLog())
159+
// configure http request decoder
160+
.httpRequestDecoder(spec -> {
161+
NettyHttpProperties.HttpDecoderProperties decoder = nettyHttpProperties.getHttpDecoder();
162+
if (Objects.nonNull(decoder)) {
163+
spec.maxInitialLineLength(decoder.getMaxInitialLineLength());
164+
spec.maxHeaderSize(decoder.getMaxHeaderSize());
165+
spec.maxChunkSize(decoder.getMaxChunkSize());
166+
}
167+
return spec;
168+
})
159169
// server socket channel parameters
160170
.option(ChannelOption.SO_BACKLOG, nettyHttpProperties.getServerSocketChannel().getSoBacklog())
161171
.option(ChannelOption.SO_REUSEADDR, nettyHttpProperties.getServerSocketChannel().isSoReuseAddr())

shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/test/java/org/apache/shenyu/springboot/starter/netty/ShenyuNettyWebServerConfigurationTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,39 @@ public void testNettyProperties() {
9797
assertThat(properties.getSocketChannel().getSingleEventExecutorPerGroup(), is(false));
9898
});
9999
}
100+
101+
@Test
102+
public void testHttpDecoderProperties() {
103+
applicationContextRunner
104+
.withPropertyValues(
105+
"shenyu.netty.http.web-server-factory-enabled=false",
106+
"shenyu.netty.http.httpDecoder.maxInitialLineLength=8192",
107+
"shenyu.netty.http.httpDecoder.maxHeaderSize=16384",
108+
"shenyu.netty.http.httpDecoder.maxChunkSize=16384"
109+
)
110+
.run(context -> {
111+
NettyHttpProperties properties = context.getBean("nettyTcpProperties", NettyHttpProperties.class);
112+
assertNotNull(properties);
113+
assertNotNull(properties.getHttpDecoder());
114+
assertThat(properties.getHttpDecoder().getMaxInitialLineLength(), is(8192));
115+
assertThat(properties.getHttpDecoder().getMaxHeaderSize(), is(16384));
116+
assertThat(properties.getHttpDecoder().getMaxChunkSize(), is(16384));
117+
});
118+
}
119+
120+
@Test
121+
public void testHttpDecoderDefaultProperties() {
122+
applicationContextRunner
123+
.withPropertyValues(
124+
"shenyu.netty.http.web-server-factory-enabled=false"
125+
)
126+
.run(context -> {
127+
NettyHttpProperties properties = context.getBean("nettyTcpProperties", NettyHttpProperties.class);
128+
assertNotNull(properties);
129+
assertNotNull(properties.getHttpDecoder());
130+
assertThat(properties.getHttpDecoder().getMaxInitialLineLength(), is(4096));
131+
assertThat(properties.getHttpDecoder().getMaxHeaderSize(), is(8192));
132+
assertThat(properties.getHttpDecoder().getMaxChunkSize(), is(8192));
133+
});
134+
}
100135
}

0 commit comments

Comments
 (0)