Skip to content

Commit

Permalink
[exceptions] Include eof/timeout handling in main exception handler path
Browse files Browse the repository at this point in the history
  • Loading branch information
tipsy committed Apr 2, 2023
1 parent 97ff3ba commit afb30d5
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 4 deletions.
Expand Up @@ -27,6 +27,7 @@ class ExceptionMapper(val cfg: JavalinConfig) {
return handle(ctx, t.cause as Exception)
}
when {
JettyUtil.isExpectedException(t) -> JettyUtil.logExpectedException(t)
t is Exception && HttpResponseExceptionMapper.canHandle(t) && noUserHandler(t) -> HttpResponseExceptionMapper.handle(t as HttpResponseException, ctx)
t is Exception -> Util.findByClass(handlers, t.javaClass)?.handle(t, ctx) ?: uncaughtException(ctx, t)
else -> handleUnexpectedThrowable(ctx.res(), t)
Expand All @@ -40,11 +41,10 @@ class ExceptionMapper(val cfg: JavalinConfig) {

internal fun handleUnexpectedThrowable(res: HttpServletResponse, throwable: Throwable): Nothing? {
val unwrapped = (throwable as? CompletionException)?.cause ?: throwable
if (JettyUtil.isClientAbortException(unwrapped) || JettyUtil.isJettyTimeoutException(unwrapped)) {
JavalinLogger.debug("Client aborted or timed out", throwable)
return null // jetty aborts and timeouts happen when clients disconnect, they are not actually unexpected
}
res.status = HttpStatus.INTERNAL_SERVER_ERROR.code
if (JettyUtil.isExpectedException(unwrapped)) {
return null.also { JettyUtil.logExpectedException(unwrapped) }
}
JavalinLogger.error("Exception occurred while servicing http-request", throwable)
return null
}
Expand Down
3 changes: 3 additions & 0 deletions javalin/src/main/java/io/javalin/jetty/JettyUtil.kt
Expand Up @@ -36,4 +36,7 @@ object JettyUtil {
// This is rare, but intended (see issues #163 and #1277)
fun isJettyTimeoutException(t: Throwable) = t is IOException && t.cause is TimeoutException

fun isExpectedException(t: Throwable) = isClientAbortException(t) || isJettyTimeoutException(t)
fun logExpectedException(t: Throwable) = JavalinLogger.debug("Client aborted or timed out", t)

}
6 changes: 6 additions & 0 deletions javalin/src/test/java/io/javalin/TestExceptionMapper.kt
Expand Up @@ -18,6 +18,7 @@ import io.javalin.testing.TestUtil
import io.javalin.testing.TypedException
import io.javalin.testing.httpCode
import org.assertj.core.api.Assertions.assertThat
import org.eclipse.jetty.io.EofException
import org.junit.jupiter.api.Test
import kotlin.reflect.full.allSuperclasses

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

@Test
fun `jetty eof exceptions are ignored and logged as debug`() = TestUtil.test { app, http ->
app.get("/") { throw EofException() }
assertThat(http.get("/").httpCode()).isEqualTo(OK)
}
}

0 comments on commit afb30d5

Please sign in to comment.