Include HTTP/2 stream idle timeouts in IOExceptionMapper

This commit is contained in:
Chris Eager 2024-03-05 17:51:14 -06:00 committed by Chris Eager
parent 3cc740cda3
commit 9f6a6d7f5b
2 changed files with 54 additions and 2 deletions

View File

@ -21,8 +21,19 @@ public class IOExceptionMapper implements ExceptionMapper<IOException> {
public Response toResponse(IOException e) {
if (!(e.getCause() instanceof java.util.concurrent.TimeoutException)) {
logger.warn("IOExceptionMapper", e);
} else if (e.getCause().getMessage().startsWith("Idle timeout expired")) {
return Response.status(Response.Status.REQUEST_TIMEOUT).build();
} else {
// Some TimeoutExceptions are because the connection is idle, but are only distinguishable using the exception
// message
final String message = e.getCause().getMessage();
final boolean idleTimeout =
message != null &&
// org.eclipse.jetty.io.IdleTimeout
(message.startsWith("Idle timeout expired")
// org.eclipse.jetty.http2.HTTP2Session
|| (message.startsWith("Idle timeout") && message.endsWith("elapsed")));
if (idleTimeout) {
return Response.status(Response.Status.REQUEST_TIMEOUT).build();
}
}
return Response.status(503).build();

View File

@ -0,0 +1,41 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.mappers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import javax.ws.rs.core.Response;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class IOExceptionMapperTest {
@ParameterizedTest
@MethodSource
void testExceptionParsing(final IOException exception, final int expectedStatus) {
try (Response response = new IOExceptionMapper().toResponse(exception)) {
assertEquals(expectedStatus, response.getStatus());
}
}
static Stream<Arguments> testExceptionParsing() {
return Stream.of(
Arguments.of(new IOException(), 503),
Arguments.of(new IOException(new TimeoutException("A timeout")), 503),
Arguments.of(new IOException(new TimeoutException()), 503),
Arguments.of(new IOException(new TimeoutException("Idle timeout 30000 ms elapsed")), 408),
Arguments.of(new IOException(new TimeoutException("Idle timeout expired")), 408),
Arguments.of(new IOException(new RuntimeException(new TimeoutException("Idle timeout expired"))), 503),
Arguments.of(new IOException(new TimeoutException("Idle timeout of another kind expired")), 503)
);
}
}