diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java index b250915db6..8b9b6fb042 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java @@ -83,7 +83,7 @@ public void filter(final ClientRequestContext context) throws IOException { printRequestLine(b, "Sending client request", id, context.getMethod(), context.getUri()); printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getStringHeaders()); - if (context.hasEntity() && printEntity(verbosity, context.getMediaType())) { + if (printEntity(verbosity, context.getMediaType()) && context.hasEntity()) { final OutputStream stream = new LoggingStream(b, context.getEntityStream()); context.setEntityStream(stream); context.setProperty(ENTITY_LOGGER_PROPERTY, stream); @@ -107,7 +107,7 @@ public void filter(final ClientRequestContext requestContext, final ClientRespon printResponseLine(b, "Client response received", id, responseContext.getStatus()); printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getHeaders()); - if (responseContext.hasEntity() && printEntity(verbosity, responseContext.getMediaType())) { + if (printEntity(verbosity, responseContext.getMediaType()) && responseContext.hasEntity()) { responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(), MessageUtils.getCharset(responseContext.getMediaType()))); } diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java index 87cac240c1..b0f8523b7c 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java @@ -83,7 +83,7 @@ public void filter(final ContainerRequestContext context) throws IOException { printRequestLine(b, "Server has received a request", id, context.getMethod(), context.getUriInfo().getRequestUri()); printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getHeaders()); - if (context.hasEntity() && printEntity(verbosity, context.getMediaType())) { + if (printEntity(verbosity, context.getMediaType()) && context.hasEntity()) { context.setEntityStream( logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType()))); } @@ -105,7 +105,7 @@ public void filter(final ContainerRequestContext requestContext, final Container printResponseLine(b, "Server responded with a response", id, responseContext.getStatus()); printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getStringHeaders()); - if (responseContext.hasEntity() && printEntity(verbosity, responseContext.getMediaType())) { + if (printEntity(verbosity, responseContext.getMediaType()) && responseContext.hasEntity()) { final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream()); responseContext.setEntityStream(stream); requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream); diff --git a/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java b/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java new file mode 100644 index 0000000000..35459f9422 --- /dev/null +++ b/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.logging; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.UriInfo; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + + +public class HasEntityTimeoutTest { + + private enum DirectionType { + INBOUND, + OUTBOUND + } + + private static class UriInfoHandler implements InvocationHandler { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "getRequestUri": + return URI.create("http://localhost:8080/get"); + } + return null; + } + } + + private static class RequestResponseHandler implements InvocationHandler { + private final DirectionType type; + + private RequestResponseHandler(DirectionType type) { + this.type = type; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "hasEntity": + throw new ProcessingException(new SocketTimeoutException("Read timed out")); + case "getUri": + return URI.create("http://localhost:8080"); + case "getStringHeaders": + case "getHeaders": + return new MultivaluedHashMap(); + case "getMethod": + return "GET"; + case "getMediaType": + return MediaType.SERVER_SENT_EVENTS_TYPE; + case "getEntityStream": + return type == DirectionType.OUTBOUND + ? new ByteArrayOutputStream() + : new ByteArrayInputStream("entity".getBytes()); + case "getStatus": + return 200; + case "getUriInfo": + return Proxy.newProxyInstance( + UriInfo.class.getClassLoader(), + new Class[]{UriInfo.class}, + new UriInfoHandler()); + } + return null; + } + } + + @Test + public void testClientFilterTimedOut() throws IOException { + ClientLoggingFilter loggingFilter = new ClientLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY) + .maxEntitySize(10) + ); + + ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance( + ClientRequestContext.class.getClassLoader(), + new Class[]{ClientRequestContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + loggingFilter.filter(clientRequestContext); + } + + @Test + public void testClientFilterTimedOutException() throws IOException { + ClientLoggingFilter loggingFilter = new ClientLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY) + .maxEntitySize(10) + ); + + ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance( + ClientRequestContext.class.getClassLoader(), + new Class[]{ClientRequestContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + try { + loggingFilter.filter(clientRequestContext); + throw new RuntimeException("The expected exception has not been thrown"); + } catch (ProcessingException pe) { + // expected + } + } + + @Test + public void testClientFilterResponseTimedOut() throws IOException { + ClientLoggingFilter loggingFilter = new ClientLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY) + .maxEntitySize(10) + ); + + ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance( + ClientRequestContext.class.getClassLoader(), + new Class[]{ClientRequestContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + + ClientResponseContext clientResponseContext = (ClientResponseContext) Proxy.newProxyInstance( + ClientResponseContext.class.getClassLoader(), + new Class[]{ClientResponseContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + loggingFilter.filter(clientRequestContext, clientResponseContext); + } + + @Test + public void testClientFilterResponseTimedOutException() throws IOException { + ClientLoggingFilter loggingFilter = new ClientLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY) + .maxEntitySize(10) + ); + + ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance( + ClientRequestContext.class.getClassLoader(), + new Class[]{ClientRequestContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + + ClientResponseContext clientResponseContext = (ClientResponseContext) Proxy.newProxyInstance( + ClientResponseContext.class.getClassLoader(), + new Class[]{ClientResponseContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + + try { + loggingFilter.filter(clientRequestContext, clientResponseContext); + throw new RuntimeException("The expected exception has not been thrown"); + } catch (ProcessingException pe) { + // expected + } + } + + @Test + public void testServerFilterTimedOut() throws IOException { + ServerLoggingFilter loggingFilter = new ServerLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY) + .maxEntitySize(10) + ); + + ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance( + ContainerRequestContext.class.getClassLoader(), + new Class[]{ContainerRequestContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + loggingFilter.filter(containerRequestContext); + } + + @Test + public void testServerFilterTimedOutException() throws IOException { + ServerLoggingFilter loggingFilter = new ServerLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY) + .maxEntitySize(10) + ); + + ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance( + ContainerRequestContext.class.getClassLoader(), + new Class[]{ContainerRequestContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + + try { + loggingFilter.filter(containerRequestContext); + throw new RuntimeException("The expected exception has not been thrown"); + } catch (ProcessingException pe) { + // expected + } + } + + @Test + public void testServerFilterResponseTimedOut() throws IOException { + ServerLoggingFilter loggingFilter = new ServerLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY) + .maxEntitySize(10) + ); + + ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance( + ContainerRequestContext.class.getClassLoader(), + new Class[]{ContainerRequestContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + + ContainerResponseContext containerResponseContext = (ContainerResponseContext) Proxy.newProxyInstance( + ContainerResponseContext.class.getClassLoader(), + new Class[]{ContainerResponseContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + + loggingFilter.filter(containerRequestContext, containerResponseContext); + } + + @Test + public void testServerFilterResponseTimedOutException() throws IOException { + ServerLoggingFilter loggingFilter = new ServerLoggingFilter( + LoggingFeature.builder() + .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME)) + .level(Level.INFO) + .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY) + .maxEntitySize(10) + ); + + ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance( + ContainerRequestContext.class.getClassLoader(), + new Class[]{ContainerRequestContext.class}, + new RequestResponseHandler(DirectionType.INBOUND)); + + ContainerResponseContext containerResponseContext = (ContainerResponseContext) Proxy.newProxyInstance( + ContainerResponseContext.class.getClassLoader(), + new Class[]{ContainerResponseContext.class}, + new RequestResponseHandler(DirectionType.OUTBOUND)); + + try { + loggingFilter.filter(containerRequestContext, containerResponseContext); + throw new RuntimeException("The expected exception has not been thrown"); + } catch (ProcessingException pe) { + // expected + } + } + +}