Skip to content

Commit 91bee8a

Browse files
author
Bo Zhang
committed
Add fallback bodyHandler
We found that if http request is read first then forest handler is called, it may complain "body already read". Workaround this by installing a fallback bodyHandler.
1 parent e61ecac commit 91bee8a

4 files changed

Lines changed: 73 additions & 38 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ val configureGroovy: Project.() -> Unit by rootProject.ext
1515
val configureKotlin: Project.() -> Unit by rootProject.ext
1616

1717
rootProject.group = "io.forestframework"
18-
rootProject.version = "0.3.5-SNAPSHOT"
18+
rootProject.version = "0.3.6-SNAPSHOT"
1919

2020
allprojects {
2121
repositories {

core/src/main/java/io/forestframework/core/http/DefaultHttpRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,20 @@ public class DefaultHttpRequest implements HttpRequest {
3030
private final HttpServerRequestInternal delegate;
3131
private final HttpResponse response;
3232
private final RoutingMatchResult routingMatchResult;
33+
/**
34+
* This allows a body to be read multiple times, in multiple handlers.
35+
*/
3336
private Future<Buffer> bodyCache;
3437

3538
public DefaultHttpRequest(HttpServerRequestInternal delegate, RoutingMatchResult routingMatchResult) {
3639
this.delegate = delegate;
3740
this.routingMatchResult = routingMatchResult;
3841
this.response = new DefaultHttpResponse(delegate.response());
42+
// TODO this is unsafe
43+
// However, we need this to handle the situation in which HTTP request is read to the end
44+
// before `body()` is called.
45+
// Also, as said in `bodyHandler` documentation, it's unsafe to call it on a huge input
46+
bodyHandler(buffer -> bodyCache = Future.succeededFuture(buffer));
3947
}
4048

4149
@SuppressWarnings("unchecked")
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
@file:Suppress("UNUSED_PARAMETER")
2+
3+
package io.forestframework.core.http
4+
5+
import io.forestframework.core.ForestApplication
6+
import io.forestframework.core.http.param.JsonRequestBody
7+
import io.forestframework.core.http.result.PlainText
8+
import io.forestframework.core.http.routing.Post
9+
import io.forestframework.core.http.routing.PreHandler
10+
import io.forestframework.testfixtures.AbstractForestIntegrationTest
11+
import io.forestframework.testfixtures.DisableAutoScan
12+
import io.forestframework.testsupport.ForestIntegrationTest
13+
import kotlinx.coroutines.delay
14+
import org.junit.jupiter.api.Test
15+
16+
@ForestApplication
17+
class ReadBodyMultipleTimesIntegrationTestApp {
18+
@PreHandler("/readMultipleTimes")
19+
fun readCookie(
20+
@JsonRequestBody body: String
21+
) {
22+
}
23+
24+
@Post("/readMultipleTimes")
25+
@PlainText
26+
fun getText(@JsonRequestBody body: String) = body
27+
28+
@PreHandler("/delayInPreHandler")
29+
suspend fun delayInPreHandler() {
30+
delay(1000)
31+
}
32+
33+
@Post("/delayInPreHandler")
34+
@PlainText
35+
fun delayInPreHandler(
36+
@JsonRequestBody body: String
37+
) = body
38+
}
39+
40+
@ForestIntegrationTest(appClass = ReadBodyMultipleTimesIntegrationTestApp::class)
41+
@DisableAutoScan
42+
class ReadBodyMultipleTimesIntegrationTest : AbstractForestIntegrationTest() {
43+
@Test
44+
fun canReadRequestMultipleTimes() {
45+
post("/readMultipleTimes",
46+
headers = mapOf("Content-Type" to "application/json"),
47+
body = "{}")
48+
.assertBody("{}")
49+
}
50+
51+
/*
52+
java.lang.IllegalStateException: Request has already been read
53+
at io.vertx.core.http.impl.Http1xServerRequest.checkEnded(Http1xServerRequest.java:628) ~[vertx-core-4.0.3.jar:4.0.3]
54+
at io.vertx.core.http.impl.Http1xServerRequest.body(Http1xServerRequest.java:506) ~[vertx-core-4.0.3.jar:4.0.3]
55+
at io.forestframework.core.http.DefaultHttpRequest.body(DefaultHttpRequest.java:203)
56+
*/
57+
@Test
58+
fun canHaveDelayInPreHandler() {
59+
post("/delayInPreHandler",
60+
headers = mapOf("Content-Type" to "application/json"),
61+
body = "{}")
62+
.assertBody("{}")
63+
}
64+
}

core/src/test/kotlin/io/forestframework/core/http/ReadBodyMultipleTimesIntegrationTest.kt

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)