Skip to content

Commit dbbebde

Browse files
authored
[exceptions] Add eof/timeout handling in main exception handler path (javalin#1845)
1 parent 6473347 commit dbbebde

File tree

3 files changed

+23
-6
lines changed

3 files changed

+23
-6
lines changed

javalin/src/main/java/io/javalin/http/servlet/ExceptionMapper.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ExceptionMapper(val cfg: JavalinConfig) {
2727
return handle(ctx, t.cause as Exception)
2828
}
2929
when {
30+
JettyUtil.isSomewhatExpectedException(t) -> JettyUtil.logDebugAndSetError(t, ctx.res())
3031
t is Exception && HttpResponseExceptionMapper.canHandle(t) && noUserHandler(t) -> HttpResponseExceptionMapper.handle(t as HttpResponseException, ctx)
3132
t is Exception -> Util.findByClass(handlers, t.javaClass)?.handle(t, ctx) ?: uncaughtException(ctx, t)
3233
else -> handleUnexpectedThrowable(ctx.res(), t)
@@ -39,13 +40,11 @@ class ExceptionMapper(val cfg: JavalinConfig) {
3940
}
4041

4142
internal fun handleUnexpectedThrowable(res: HttpServletResponse, throwable: Throwable): Nothing? {
42-
val unwrapped = (throwable as? CompletionException)?.cause ?: throwable
43-
if (JettyUtil.isClientAbortException(unwrapped) || JettyUtil.isJettyTimeoutException(unwrapped)) {
44-
JavalinLogger.debug("Client aborted or timed out", throwable)
45-
return null // jetty aborts and timeouts happen when clients disconnect, they are not actually unexpected
46-
}
4743
res.status = HttpStatus.INTERNAL_SERVER_ERROR.code
48-
JavalinLogger.error("Exception occurred while servicing http-request", throwable)
44+
when (JettyUtil.isSomewhatExpectedException(throwable)) {
45+
true -> JettyUtil.logDebugAndSetError(throwable, res)
46+
false -> JavalinLogger.error("Exception occurred while servicing http-request", throwable)
47+
}
4948
return null
5049
}
5150

javalin/src/main/java/io/javalin/jetty/JettyUtil.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package io.javalin.jetty
22

3+
import io.javalin.http.HttpStatus
34
import io.javalin.util.ConcurrencyUtil
45
import io.javalin.util.JavalinLogger
6+
import jakarta.servlet.http.HttpServletResponse
57
import org.eclipse.jetty.server.LowResourceMonitor
68
import org.eclipse.jetty.server.Server
79
import org.eclipse.jetty.server.handler.StatisticsHandler
810
import java.io.IOException
11+
import java.util.concurrent.CompletionException
912
import java.util.concurrent.TimeoutException
1013

1114
object JettyUtil {
@@ -36,4 +39,13 @@ object JettyUtil {
3639
// This is rare, but intended (see issues #163 and #1277)
3740
fun isJettyTimeoutException(t: Throwable) = t is IOException && t.cause is TimeoutException
3841

42+
fun isSomewhatExpectedException(t: Throwable): Boolean {
43+
val unwrapped = (t as? CompletionException)?.cause ?: t
44+
return isClientAbortException(unwrapped) || isJettyTimeoutException(unwrapped)
45+
}
46+
fun logDebugAndSetError(t: Throwable, res: HttpServletResponse) {
47+
JavalinLogger.debug("Client aborted or timed out", t)
48+
res.status = HttpStatus.INTERNAL_SERVER_ERROR.code
49+
}
50+
3951
}

javalin/src/test/java/io/javalin/TestExceptionMapper.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import io.javalin.testing.TestUtil
1818
import io.javalin.testing.TypedException
1919
import io.javalin.testing.httpCode
2020
import org.assertj.core.api.Assertions.assertThat
21+
import org.eclipse.jetty.io.EofException
2122
import org.junit.jupiter.api.Test
2223
import kotlin.reflect.full.allSuperclasses
2324

@@ -103,4 +104,9 @@ class TestExceptionMapper {
103104
assertThat(http.jsonGet("/").body).contains("""MY MESSAGE WITH \nNEWLINES\n""")
104105
}
105106

107+
@Test
108+
fun `jetty eof exceptions are caught and handled as errors`() = TestUtil.test { app, http ->
109+
app.get("/") { throw EofException() }
110+
assertThat(http.get("/").httpCode()).isEqualTo(INTERNAL_SERVER_ERROR)
111+
}
106112
}

0 commit comments

Comments
 (0)