From c05e45271f88dd5e2b60997c0142d676e01a2874 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 29 Aug 2018 09:56:33 +0200 Subject: [PATCH] fix timeout for 404 proxy resources --- .../sonia/scm/ProxyPushStateDispatcher.java | 36 +++++++-------- .../scm/ProxyPushStateDispatcherTest.java | 45 ++++++++++++++++--- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/ProxyPushStateDispatcher.java b/scm-webapp/src/main/java/sonia/scm/ProxyPushStateDispatcher.java index ce0aadf246..092ac02f88 100644 --- a/scm-webapp/src/main/java/sonia/scm/ProxyPushStateDispatcher.java +++ b/scm-webapp/src/main/java/sonia/scm/ProxyPushStateDispatcher.java @@ -2,10 +2,11 @@ package sonia.scm; import com.google.common.annotations.VisibleForTesting; import com.google.common.io.ByteStreams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -24,6 +25,8 @@ import java.util.Map; */ public final class ProxyPushStateDispatcher implements PushStateDispatcher { + private static final Logger LOG = LoggerFactory.getLogger(ProxyPushStateDispatcher.class); + @FunctionalInterface interface ConnectionFactory { @@ -57,43 +60,38 @@ public final class ProxyPushStateDispatcher implements PushStateDispatcher { @Override public void dispatch(HttpServletRequest request, HttpServletResponse response, String uri) throws IOException { - try { - proxy(request, response, uri); - } catch (FileNotFoundException ex) { - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - } - } - - private void proxy(HttpServletRequest request, HttpServletResponse response, String uri) throws IOException { URL url = createProxyUrl(uri); HttpURLConnection connection = connectionFactory.open(url); connection.setRequestMethod(request.getMethod()); - copyRequestHeaders(request, connection); + copyRequestHeaders(request, connection); if (request.getContentLength() > 0) { copyRequestBody(request, connection); } int responseCode = connection.getResponseCode(); response.setStatus(responseCode); + copyResponseHeaders(response, connection); - - appendProxyHeader(response, url); - - copyResponseBody(response, connection); - } - - private void appendProxyHeader(HttpServletResponse response, URL url) { - response.addHeader("X-Forwarded-Port", String.valueOf(url.getPort())); + if (connection.getContentLength() > 0) { + copyResponseBody(response, connection); + } } private void copyResponseBody(HttpServletResponse response, HttpURLConnection connection) throws IOException { - try (InputStream input = connection.getInputStream(); OutputStream output = response.getOutputStream()) { + try (InputStream input = getConnectionInput(connection); OutputStream output = response.getOutputStream()) { ByteStreams.copy(input, output); } } + private InputStream getConnectionInput(HttpURLConnection connection) throws IOException { + if (connection.getErrorStream() != null) { + return connection.getErrorStream(); + } + return connection.getInputStream(); + } + private void copyResponseHeaders(HttpServletResponse response, HttpURLConnection connection) { Map> headerFields = connection.getHeaderFields(); for (Map.Entry> entry : headerFields.entrySet()) { diff --git a/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java b/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java index 52c13a4d54..f9798fb431 100644 --- a/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java +++ b/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java @@ -51,11 +51,15 @@ public class ProxyPushStateDispatcherTest { when(request.getHeaders("Content-Type")).thenReturn(toEnum("application/json")); // configure proxy url connection mock - when(connection.getInputStream()).thenReturn(new ByteArrayInputStream("hitchhicker".getBytes(Charsets.UTF_8))); + byte[] data = "hitchhicker".getBytes(Charsets.UTF_8); + when(connection.getErrorStream()).thenReturn(null); + when(connection.getInputStream()).thenReturn(new ByteArrayInputStream(data)); + Map> headerFields = new HashMap<>(); headerFields.put("Content-Type", Lists.newArrayList("application/yaml")); when(connection.getHeaderFields()).thenReturn(headerFields); when(connection.getResponseCode()).thenReturn(200); + when(connection.getContentLength()).thenReturn(data.length); // configure response mock DevServletOutputStream output = new DevServletOutputStream(); @@ -70,6 +74,41 @@ public class ProxyPushStateDispatcherTest { // verify response verify(response).setStatus(200); verify(response).addHeader("Content-Type", "application/yaml"); + + assertEquals("hitchhicker", output.stream.toString()); + } + + @Test + public void testGetNotFound() throws IOException { + // configure request mock + when(request.getMethod()).thenReturn("GET"); + when(request.getHeaderNames()).thenReturn(toEnum("Content-Type")); + when(request.getHeaders("Content-Type")).thenReturn(toEnum("application/json")); + + // configure proxy url connection mock + byte[] data = "hitchhicker".getBytes(Charsets.UTF_8); + when(connection.getErrorStream()).thenReturn(new ByteArrayInputStream(data)); + + Map> headerFields = new HashMap<>(); + headerFields.put("Content-Type", Lists.newArrayList("application/yaml")); + when(connection.getHeaderFields()).thenReturn(headerFields); + when(connection.getResponseCode()).thenReturn(404); + when(connection.getContentLength()).thenReturn(data.length); + + // configure response mock + DevServletOutputStream output = new DevServletOutputStream(); + when(response.getOutputStream()).thenReturn(output); + + dispatcher.dispatch(request, response, "/people/trillian"); + + // verify connection + verify(connection).setRequestMethod("GET"); + verify(connection).setRequestProperty("Content-Type", "application/json"); + + // verify response + verify(response).setStatus(404); + verify(response).addHeader("Content-Type", "application/yaml"); + assertEquals("hitchhicker", output.stream.toString()); } @@ -82,14 +121,10 @@ public class ProxyPushStateDispatcherTest { when(request.getContentLength()).thenReturn(1); // configure proxy url connection mock - when(connection.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[0])); Map> headerFields = new HashMap<>(); when(connection.getHeaderFields()).thenReturn(headerFields); when(connection.getResponseCode()).thenReturn(204); - // configure response mock - when(response.getOutputStream()).thenReturn(new DevServletOutputStream()); - ByteArrayOutputStream output = new ByteArrayOutputStream(); when(connection.getOutputStream()).thenReturn(output);