From c1ed50df6fe63e9e86c7e525ca519c14a8fd77a7 Mon Sep 17 00:00:00 2001 From: Mikhael Sokolov Date: Mon, 3 May 2021 12:51:07 +0300 Subject: [PATCH] netty more extractions are implemented (#997) Co-authored-by: sokomishalov --- .../logbook/CommonsLogFormatSinkTest.java | 8 +++ .../org/zalando/logbook/netty/Request.java | 43 ++++++++++--- .../org/zalando/logbook/netty/Response.java | 5 +- .../logbook/netty/RequestUnitTest.java | 64 +++++++++++++++++++ 4 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 logbook-netty/src/test/java/org/zalando/logbook/netty/RequestUnitTest.java diff --git a/logbook-core/src/test/java/org/zalando/logbook/CommonsLogFormatSinkTest.java b/logbook-core/src/test/java/org/zalando/logbook/CommonsLogFormatSinkTest.java index c3329289d..70ec72864 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/CommonsLogFormatSinkTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/CommonsLogFormatSinkTest.java @@ -1,5 +1,6 @@ package org.zalando.logbook; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.zalando.logbook.DefaultLogbook.SimpleCorrelation; @@ -9,9 +10,11 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; +import java.util.Locale; import static java.time.Clock.fixed; import static java.time.ZoneOffset.UTC; +import static java.util.Locale.US; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -26,6 +29,11 @@ final class CommonsLogFormatSinkTest { private final HttpLogWriter writer = mock(HttpLogWriter.class); + @BeforeEach + void setUp() { + Locale.setDefault(US); + } + @Test void shouldDelegateActive() { final Sink unit = new CommonsLogFormatSink(writer); diff --git a/logbook-netty/src/main/java/org/zalando/logbook/netty/Request.java b/logbook-netty/src/main/java/org/zalando/logbook/netty/Request.java index bce69f370..5dfcf3309 100644 --- a/logbook-netty/src/main/java/org/zalando/logbook/netty/Request.java +++ b/logbook-netty/src/main/java/org/zalando/logbook/netty/Request.java @@ -1,20 +1,29 @@ package org.zalando.logbook.netty; import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpUtil; +import io.netty.handler.ssl.SslHandler; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.URI; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Nullable; + import lombok.AllArgsConstructor; import org.zalando.logbook.HttpHeaders; import org.zalando.logbook.Origin; -import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; + import static io.netty.handler.codec.http.HttpHeaderNames.HOST; +import static java.nio.charset.StandardCharsets.UTF_8; import static lombok.AccessLevel.PRIVATE; +import static org.zalando.logbook.Origin.LOCAL; @AllArgsConstructor(access = PRIVATE) final class Request implements org.zalando.logbook.HttpRequest, HeaderSupport { @@ -56,19 +65,34 @@ public String getMethod() { @Override public String getScheme() { - // TODO pick the real one - return "http"; + final SslHandler handler = context.channel().pipeline().get(SslHandler.class); + return handler == null ? "http" : "https"; } @Override public String getHost() { - return request.headers().get(HOST, "unknown"); + final String host = request.headers().get(HOST); + if (host == null) { + return extractAddress().map(InetSocketAddress::getHostString).orElse("unknown"); + } else { + return stripPortIfNecessary(host); + } } @Override public Optional getPort() { - // TODO implement - return Optional.empty(); + return extractAddress().map(InetSocketAddress::getPort); + } + + private String stripPortIfNecessary(String host) { + final int separator = host.indexOf(":"); + return separator == -1 ? host : host.substring(0, separator); + } + + private Optional extractAddress() { + final Channel channel = context.channel(); + final SocketAddress address = origin == LOCAL ? channel.remoteAddress() : channel.localAddress(); + return address instanceof InetSocketAddress ? Optional.of((InetSocketAddress) address) : Optional.empty(); } @Override @@ -89,13 +113,12 @@ public HttpHeaders getHeaders() { @Nullable @Override public String getContentType() { - return request.headers().get(CONTENT_TYPE); + return Objects.toString(HttpUtil.getMimeType(request), null); } @Override public Charset getCharset() { - // TODO pick the real one - return StandardCharsets.UTF_8; + return HttpUtil.getCharset(request, UTF_8); } @Override diff --git a/logbook-netty/src/main/java/org/zalando/logbook/netty/Response.java b/logbook-netty/src/main/java/org/zalando/logbook/netty/Response.java index c4af6cdd0..3fa19fe1f 100644 --- a/logbook-netty/src/main/java/org/zalando/logbook/netty/Response.java +++ b/logbook-netty/src/main/java/org/zalando/logbook/netty/Response.java @@ -6,6 +6,8 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Nullable; + +import io.netty.handler.codec.http.HttpUtil; import lombok.AllArgsConstructor; import org.zalando.logbook.HttpHeaders; import org.zalando.logbook.Origin; @@ -49,8 +51,7 @@ public String getContentType() { @Override public Charset getCharset() { - // TODO pick the real one - return StandardCharsets.UTF_8; + return HttpUtil.getCharset(response, StandardCharsets.UTF_8); } @Override diff --git a/logbook-netty/src/test/java/org/zalando/logbook/netty/RequestUnitTest.java b/logbook-netty/src/test/java/org/zalando/logbook/netty/RequestUnitTest.java new file mode 100644 index 000000000..aacdb16d1 --- /dev/null +++ b/logbook-netty/src/test/java/org/zalando/logbook/netty/RequestUnitTest.java @@ -0,0 +1,64 @@ +package org.zalando.logbook.netty; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.local.LocalAddress; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.ssl.SslHandler; +import org.junit.jupiter.api.Test; + +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; +import static io.netty.handler.codec.http.HttpHeaderNames.HOST; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.zalando.logbook.Origin.LOCAL; +import static org.zalando.logbook.Origin.REMOTE; + +/** + * @author sokomishalov + */ +public class RequestUnitTest { + + @Test + void shouldBeDefaultRequest() { + HttpRequest req = mock(HttpRequest.class); + when(req.uri()).thenReturn("/test"); + when(req.headers()).thenReturn(new DefaultHttpHeaders().add(CONTENT_TYPE, "text/plain")); + when(req.method()).thenReturn(HttpMethod.GET); + when(req.protocolVersion()).thenReturn(HttpVersion.HTTP_1_1); + + ChannelHandlerContext context = mock(ChannelHandlerContext.class); + + when(context.channel()).thenReturn(mock(Channel.class)); + when(context.channel().pipeline()).thenReturn(mock(ChannelPipeline.class)); + when(context.channel().pipeline().get(SslHandler.class)).thenReturn(mock(SslHandler.class)); + + when(context.channel().remoteAddress()).thenReturn(LocalAddress.ANY); + + Request remoteRequest = new Request(context, REMOTE, req); + + assertThat(remoteRequest.getScheme()).isEqualTo("https"); + assertThat(remoteRequest.getHost()).isEqualTo("unknown"); + assertThat(remoteRequest.getPort()).isEmpty(); + assertThat(remoteRequest.getContentType()).isEqualTo("text/plain"); + assertThat(remoteRequest.getCharset()).isEqualTo(UTF_8); + assertThat(remoteRequest.getRemote()).isEqualTo("local:any"); + assertThat(remoteRequest.getRequestUri()).isEqualTo("https://unknown/test"); + assertThat(remoteRequest.getOrigin()).isEqualTo(REMOTE); + assertThat(remoteRequest.getMethod()).isEqualTo("GET"); + assertThat(remoteRequest.getPath()).isEqualTo("/test"); + assertThat(remoteRequest.getProtocolVersion()).isEqualTo("HTTP/1.1"); + + + when(req.headers()).thenReturn(new DefaultHttpHeaders().add(HOST, "localhost")); + Request localRequest = new Request(context, LOCAL, req); + + assertThat(localRequest.getHost()).isEqualTo("localhost"); + } +}