Skip to content

Commit 14d8cbb

Browse files
committed
netty: exceed file size are not detected #3790
- fix #3790
1 parent 002eb06 commit 14d8cbb

File tree

3 files changed

+58
-36
lines changed

3 files changed

+58
-36
lines changed

modules/jooby-netty/src/main/java/io/jooby/internal/netty/NettyHandler.java

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public class NettyHandler extends ChannelInboundHandlerAdapter {
3535
private final boolean defaultHeaders;
3636
private final long maxRequestSize;
3737
private final int maxFormFields;
38-
private long contentLength;
3938
private long chunkSize;
4039
private final boolean http2;
4140
private NettyContext context;
@@ -78,7 +77,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
7877
router.match(context).execute(context);
7978
} else {
8079
// possibly body:
81-
contentLength = contentLength(req);
80+
long contentLength = contentLength(req);
8281
if (contentLength > 0 || isTransferEncodingChunked(req)) {
8382
context.httpDataFactory = new DefaultHttpDataFactory(bufferSize);
8483
context.httpDataFactory.setBaseDir(app.getTmpdir().toString());
@@ -88,20 +87,6 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
8887
router.match(context).execute(context);
8988
}
9089
}
91-
} else if (isLastHttpContent(msg)) {
92-
var chunk = (HttpContent) msg;
93-
try {
94-
// when decoder == null, chunk is always a LastHttpContent.EMPTY, ignore it
95-
if (context.decoder != null) {
96-
if (offer(context, chunk)) {
97-
Router.Match route = router.match(context);
98-
resetDecoderState(context, !route.matches());
99-
route.execute(context);
100-
}
101-
}
102-
} finally {
103-
release(chunk);
104-
}
10590
} else if (isHttpContent(msg)) {
10691
var chunk = (HttpContent) msg;
10792
try {
@@ -113,10 +98,13 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
11398
router.match(context).execute(context, Route.REQUEST_ENTITY_TOO_LARGE);
11499
return;
115100
}
116-
offer(context, chunk);
101+
if (offer(context, chunk) && isLastHttpContent(msg)) {
102+
Router.Match route = router.match(context);
103+
resetDecoderState(context, !route.matches());
104+
route.execute(context);
105+
}
117106
}
118107
} finally {
119-
// must be released
120108
release(chunk);
121109
}
122110
} else if (isWebSocketFrame(msg)) {
@@ -191,7 +179,6 @@ private boolean offer(NettyContext context, HttpContent chunk) {
191179

192180
private void resetDecoderState(NettyContext context, boolean destroy) {
193181
chunkSize = 0;
194-
contentLength = -1;
195182
if (destroy && context.decoder != null) {
196183
var decoder = context.decoder;
197184
var httpDataFactory = context.httpDataFactory;

tests/src/test/java/io/jooby/i2806/Issue2806.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
*/
66
package io.jooby.i2806;
77

8+
import static io.jooby.test.TestUtil._19kb;
89
import static org.junit.jupiter.api.Assertions.assertEquals;
910

10-
import java.util.Arrays;
1111
import java.util.Map;
1212

1313
import com.google.common.collect.ImmutableMap;
@@ -22,9 +22,6 @@ public class Issue2806 {
2222

2323
@ServerTest
2424
public void renderShouldWorkFromErrorHandlerWhenLargeRequestAreSent(ServerTestRunner runner) {
25-
char[] chars = new char[19 * 1024];
26-
Arrays.fill(chars, 'S');
27-
String _19kb = new String(chars);
2825
runner
2926
.define(
3027
app -> {
@@ -43,20 +40,32 @@ public void renderShouldWorkFromErrorHandlerWhenLargeRequestAreSent(ServerTestRu
4340
ctx.render(map);
4441
});
4542

46-
app.post("/2806", ctx -> ctx.body().value(""));
43+
app.post(
44+
"/2806",
45+
ctx -> {
46+
return ctx.body().value("");
47+
});
4748

4849
app.get("/2806", ctx -> ctx.body().value(""));
4950
})
5051
.ready(
5152
client -> {
5253
// Exceeds
53-
client.post(
54-
"/2806",
55-
RequestBody.create(_19kb, MediaType.get("text/plain")),
56-
rsp -> {
57-
assertEquals(413, rsp.code());
58-
assertEquals("{\"router\":true,\"route\":true}", rsp.body().string());
59-
});
54+
client
55+
.post("/2806", RequestBody.create(_19kb, MediaType.get("text/plain")))
56+
.execute(
57+
rsp -> {
58+
assertEquals(413, rsp.code());
59+
assertEquals("{\"router\":true,\"route\":true}", rsp.body().string());
60+
});
61+
62+
client
63+
.get("/2806")
64+
.execute(
65+
rsp -> {
66+
assertEquals(200, rsp.code());
67+
assertEquals("", rsp.body().string());
68+
});
6069
});
6170
}
6271
}

tests/src/test/java/io/jooby/test/WebClient.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@
1414
import java.security.cert.X509Certificate;
1515
import java.util.ArrayList;
1616
import java.util.List;
17-
import java.util.concurrent.BlockingQueue;
18-
import java.util.concurrent.CountDownLatch;
19-
import java.util.concurrent.LinkedBlockingQueue;
20-
import java.util.concurrent.TimeUnit;
17+
import java.util.concurrent.*;
2118
import java.util.concurrent.atomic.AtomicBoolean;
2219
import java.util.function.BiConsumer;
2320
import java.util.function.Consumer;
@@ -142,17 +139,46 @@ public void close() {
142139

143140
public class Request {
144141
private final okhttp3.Request.Builder req;
142+
private SneakyThrows.Consumer<okhttp3.Request.Builder> configurer;
145143

146144
public Request(okhttp3.Request.Builder req) {
147145
this.req = req;
148146
}
149147

150148
public Request prepare(SneakyThrows.Consumer<okhttp3.Request.Builder> configurer) {
151-
configurer.accept(req);
149+
this.configurer = configurer;
152150
return this;
153151
}
154152

155153
public void execute(SneakyThrows.Consumer<Response> callback) {
154+
execute(1, callback);
155+
}
156+
157+
public void execute(int concurrency, SneakyThrows.Consumer<Response> callback) {
158+
if (configurer != null) {
159+
configurer.accept(req);
160+
}
161+
if (concurrency > 1) {
162+
var futures = new ArrayList<CompletableFuture<String>>();
163+
for (var i = 0; i < concurrency; i++) {
164+
futures.add(
165+
CompletableFuture.supplyAsync(
166+
() -> {
167+
executeCall(callback);
168+
return "success";
169+
}));
170+
try {
171+
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
172+
} catch (CompletionException x) {
173+
throw SneakyThrows.propagate(x.getCause());
174+
}
175+
}
176+
} else {
177+
executeCall(callback);
178+
}
179+
}
180+
181+
private void executeCall(SneakyThrows.Consumer<Response> callback) {
156182
okhttp3.Request r = req.build();
157183
try (Response rsp = client.newCall(r).execute()) {
158184
callback.accept(rsp);

0 commit comments

Comments
 (0)