Skip to content

Commit

Permalink
Prevent LoggingFeature timeout on context#hasEntity for HEADERS_ONLY
Browse files Browse the repository at this point in the history
Signed-off-by: jansupol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed May 27, 2022
1 parent 31f6557 commit f40c630
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())));
}
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, String>();
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
}
}

}

0 comments on commit f40c630

Please sign in to comment.