diff --git a/logbook-api/src/main/java/org/zalando/logbook/BaseHttpRequest.java b/logbook-api/src/main/java/org/zalando/logbook/BaseHttpRequest.java index 805e9eb0f..d22c045ff 100644 --- a/logbook-api/src/main/java/org/zalando/logbook/BaseHttpRequest.java +++ b/logbook-api/src/main/java/org/zalando/logbook/BaseHttpRequest.java @@ -22,6 +22,10 @@ import com.google.common.collect.ListMultimap; +import javax.annotation.Nullable; + +import static java.util.Arrays.asList; + public interface BaseHttpRequest extends BaseHttpMessage { String getRemote(); @@ -29,14 +33,46 @@ public interface BaseHttpRequest extends BaseHttpMessage { String getMethod(); /** - * Request URI without the query string. + * Absolute Request URI including scheme, host, port (unless http/80 or https/443), path and query string. * *

Note that the URI may be invalid if the client issued an HTTP request using a malformed URL.

* - * @return the requested URI + * @return the requested URI */ - String getRequestUri(); - + default String getRequestUri() { + final String scheme = getScheme(); + final String host = getHost(); + final int port = getPort(); + final String path = getPath(); + final String query = getQuery(); + + final StringBuilder url = new StringBuilder() + .append(scheme).append("://").append(host); + + if ("http".equals(scheme) && port != 80 || + "https".equals(scheme) && port != 443) { + url.append(':').append(port); + } + + url.append(path); + + if (!query.isEmpty()) { + url.append('?').append(query); + } + + return url.toString(); + } + + String getScheme(); + + String getHost(); + + int getPort(); + + String getPath(); + + String getQuery(); + ListMultimap getQueryParameters(); } diff --git a/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogFormatter.java b/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogFormatter.java index d8a17e985..c6d43c966 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogFormatter.java +++ b/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogFormatter.java @@ -45,7 +45,7 @@ private String formatRequestLine(final HttpRequest request) { return String.format("%s %s %s", request.getMethod(), renderRequestUri(request), request.getProtocolVersion()); } - private String renderRequestUri(HttpRequest request) { + private String renderRequestUri(final HttpRequest request) { final String query = QueryParameters.render(request.getQueryParameters()); return request.getRequestUri() + (query.isEmpty() ? "" : "?" + query); } diff --git a/logbook-core/src/main/java/org/zalando/logbook/DefaultLogbookFactory.java b/logbook-core/src/main/java/org/zalando/logbook/DefaultLogbookFactory.java index 39d9c55f1..d8d92c9ce 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/DefaultLogbookFactory.java +++ b/logbook-core/src/main/java/org/zalando/logbook/DefaultLogbookFactory.java @@ -29,15 +29,15 @@ public final class DefaultLogbookFactory implements LogbookFactory { @Override public Logbook create( - @Nullable Predicate predicate, - @Nullable Obfuscator headerObfuscator, - @Nullable Obfuscator parameterObfuscator, - @Nullable BodyObfuscator bodyObfuscator, - @Nullable HttpLogFormatter formatter, - @Nullable HttpLogWriter writer) { + @Nullable final Predicate predicate, + @Nullable final Obfuscator headerObfuscator, + @Nullable final Obfuscator parameterObfuscator, + @Nullable final BodyObfuscator bodyObfuscator, + @Nullable final HttpLogFormatter formatter, + @Nullable final HttpLogWriter writer) { return new DefaultLogbook( - firstNonNull(predicate, request -> true), + firstNonNull(predicate, $ -> true), new Obfuscation( firstNonNull(headerObfuscator, Obfuscator.authorization()), firstNonNull(parameterObfuscator, Obfuscator.none()), diff --git a/logbook-core/src/main/java/org/zalando/logbook/ForwardingHttpRequest.java b/logbook-core/src/main/java/org/zalando/logbook/ForwardingHttpRequest.java index 6ac889ed3..836260704 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/ForwardingHttpRequest.java +++ b/logbook-core/src/main/java/org/zalando/logbook/ForwardingHttpRequest.java @@ -42,6 +42,31 @@ public String getRequestUri() { return delegate().getRequestUri(); } + @Override + public String getHost() { + return delegate().getHost(); + } + + @Override + public String getScheme() { + return delegate().getScheme(); + } + + @Override + public int getPort() { + return delegate().getPort(); + } + + @Override + public String getPath() { + return delegate().getPath(); + } + + @Override + public String getQuery() { + return delegate().getQuery(); + } + @Override public ListMultimap getQueryParameters() { return delegate().getQueryParameters(); diff --git a/logbook-core/src/main/java/org/zalando/logbook/ForwardingRawHttpRequest.java b/logbook-core/src/main/java/org/zalando/logbook/ForwardingRawHttpRequest.java index ba193cd7f..82d9dc109 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/ForwardingRawHttpRequest.java +++ b/logbook-core/src/main/java/org/zalando/logbook/ForwardingRawHttpRequest.java @@ -66,6 +66,31 @@ public String getRequestUri() { return delegate().getRequestUri(); } + @Override + public String getScheme() { + return delegate().getScheme(); + } + + @Override + public String getHost() { + return delegate().getHost(); + } + + @Override + public int getPort() { + return delegate().getPort(); + } + + @Override + public String getPath() { + return delegate().getPath(); + } + + @Override + public String getQuery() { + return delegate().getQuery(); + } + @Override public ListMultimap getQueryParameters() { return delegate().getQueryParameters(); diff --git a/logbook-core/src/main/java/org/zalando/logbook/Glob.java b/logbook-core/src/main/java/org/zalando/logbook/Glob.java new file mode 100644 index 000000000..d9e8ab5aa --- /dev/null +++ b/logbook-core/src/main/java/org/zalando/logbook/Glob.java @@ -0,0 +1,222 @@ +package org.zalando.logbook; + +/* + * #%L + * Logbook: Core + * %% + * Copyright (C) 2015 - 2016 Zalando SE + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.google.common.base.Splitter; + +import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.google.common.base.Splitter.on; + +final class Glob { + + public static Predicate compile(final String pattern) { + if (pattern.equals("/**") || pattern.equals("**")) { + return $ -> true; + } else if (isSuffix(pattern)) { + return new SuffixGlob(pattern.substring(0, pattern.length() - 3)); + } else { + return new DefaultGlob(pattern); + } + } + + private static boolean isSuffix(final String pattern) { + return pattern.endsWith("/**") + && pattern.indexOf('?') == -1 + && pattern.indexOf("*") == pattern.length() - 2; + } + + private static class SuffixGlob implements Predicate { + private final String subPath; + + private SuffixGlob(final String subPath) { + this.subPath = subPath; + } + + @Override + public boolean test(final String path) { + return path.startsWith(subPath) + && (path.length() == subPath.length() || path.charAt(subPath.length()) == '/'); + } + } + + private static final class DefaultGlob implements Predicate { + + private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*"); + private static final String DEFAULT_VARIABLE_PATTERN = "(.*)"; + private static final Splitter SLASH = on('/').trimResults().omitEmptyStrings(); + + private final String pattern; + + DefaultGlob(final String pattern) { + this.pattern = pattern; + } + + @Override + public boolean test(final String path) { + if (path.startsWith("/") != pattern.startsWith("/")) { + return false; + } + + final String[] patternSegments = tokenizePath(pattern); + final String[] pathSegments = tokenizePath(path); + + int patternSegmentIndex = 0; + int patternSegmentEnd = patternSegments.length - 1; + int pathSegmentIndex = 0; + int pathIndexEnd = pathSegments.length - 1; + + while (patternSegmentIndex <= patternSegmentEnd && pathSegmentIndex <= pathIndexEnd) { + final String patternSegment = patternSegments[patternSegmentIndex]; + if ("**".equals(patternSegment)) { + break; + } + if (!match(patternSegment, pathSegments[pathSegmentIndex])) { + return false; + } + patternSegmentIndex++; + pathSegmentIndex++; + } + + if (pathSegmentIndex > pathIndexEnd) { + if (patternSegmentIndex > patternSegmentEnd) { + return pattern.endsWith("/") == path.endsWith("/"); + } + if (patternSegmentIndex == patternSegmentEnd && patternSegments[patternSegmentIndex].equals("*") && path.endsWith("/")) { + return true; + } + for (int i = patternSegmentIndex; i <= patternSegmentEnd; i++) { + if (!patternSegments[i].equals("**")) { + return false; + } + } + return true; + } else if (patternSegmentIndex > patternSegmentEnd) { + return false; + } + + while (patternSegmentIndex <= patternSegmentEnd && pathSegmentIndex <= pathIndexEnd) { + final String patternSegment = patternSegments[patternSegmentEnd]; + if (patternSegment.equals("**")) { + break; + } + if (!match(patternSegment, pathSegments[pathIndexEnd])) { + return false; + } + patternSegmentEnd--; + pathIndexEnd--; + } + if (pathSegmentIndex > pathIndexEnd) { + for (int i = patternSegmentIndex; i <= patternSegmentEnd; i++) { + if (!patternSegments[i].equals("**")) { + return false; + } + } + return true; + } + + while (patternSegmentIndex != patternSegmentEnd && pathSegmentIndex <= pathIndexEnd) { + int temporaryPatternIndex = -1; + for (int i = patternSegmentIndex + 1; i <= patternSegmentEnd; i++) { + if (patternSegments[i].equals("**")) { + temporaryPatternIndex = i; + break; + } + } + if (temporaryPatternIndex == patternSegmentIndex + 1) { + patternSegmentIndex++; + continue; + } + final int patternLength = (temporaryPatternIndex - patternSegmentIndex - 1); + final int strLength = (pathIndexEnd - pathSegmentIndex + 1); + int foundSegment = -1; + + loop: + for (int i = 0; i <= strLength - patternLength; i++) { + for (int j = 0; j < patternLength; j++) { + final String subPat = patternSegments[patternSegmentIndex + j + 1]; + final String subStr = pathSegments[pathSegmentIndex + i + j]; + if (!match(subPat, subStr)) { + continue loop; + } + } + foundSegment = pathSegmentIndex + i; + break; + } + + if (foundSegment == -1) { + return false; + } + + patternSegmentIndex = temporaryPatternIndex; + pathSegmentIndex = foundSegment + patternLength; + } + + for (int i = patternSegmentIndex; i <= patternSegmentEnd; i++) { + if (!patternSegments[i].equals("**")) { + return false; + } + } + + return true; + } + + private String[] tokenizePath(final String path) { + final List tokens = SLASH.splitToList(path); + return tokens.toArray(new String[tokens.size()]); + } + + private boolean match(final String pattern, final String str) { + return toPattern(pattern).matcher(str).matches(); + } + + private Pattern toPattern(final String pattern) { + final StringBuilder result = new StringBuilder(); + final Matcher matcher = GLOB_PATTERN.matcher(pattern); + int end = 0; + while (matcher.find()) { + result.append(quote(pattern, end, matcher.start())); + final String match = matcher.group(); + if ("?".equals(match)) { + result.append('.'); + } else if ("*".equals(match)) { + result.append(".*"); + } else { + result.append(DEFAULT_VARIABLE_PATTERN); + } + end = matcher.end(); + } + result.append(quote(pattern, end, pattern.length())); + return Pattern.compile(result.toString()); + } + + private String quote(final String s, final int start, final int end) { + if (start == end) { + return ""; + } + return Pattern.quote(s.substring(start, end)); + } + + } +} diff --git a/logbook-core/src/main/java/org/zalando/logbook/JsonHttpLogFormatter.java b/logbook-core/src/main/java/org/zalando/logbook/JsonHttpLogFormatter.java index a725cfda7..133a74fed 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/JsonHttpLogFormatter.java +++ b/logbook-core/src/main/java/org/zalando/logbook/JsonHttpLogFormatter.java @@ -77,7 +77,7 @@ public String format(final Precorrelation precorrelation) throws IO return mapper.writeValueAsString(content); } - private String renderRequestUri(HttpRequest request) { + private String renderRequestUri(final HttpRequest request) { final String query = QueryParameters.render(request.getQueryParameters()); return request.getRequestUri() + (query.isEmpty() ? "" : "?" + query); } diff --git a/logbook-core/src/main/java/org/zalando/logbook/RequestPredicates.java b/logbook-core/src/main/java/org/zalando/logbook/RequestPredicates.java index 2d32736bd..c323113aa 100644 --- a/logbook-core/src/main/java/org/zalando/logbook/RequestPredicates.java +++ b/logbook-core/src/main/java/org/zalando/logbook/RequestPredicates.java @@ -23,8 +23,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.function.BiPredicate; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.regex.Pattern; public final class RequestPredicates { @@ -41,23 +41,24 @@ public static Predicate exclude(final Collection true); + .orElse($ -> true); } - public static Predicate requestTo(final String url) { - return requestTo(url::equals); - } + public static Predicate requestTo(final String pattern) { + final Predicate predicate = Glob.compile(pattern); - public static Predicate requestTo(final Pattern pattern) { - return requestTo(url -> - pattern.matcher(url).matches()); + return pattern.startsWith("/") ? + requestTo(RawHttpRequest::getPath, predicate) : + requestTo(RawHttpRequest::getRequestUri, // TODO without query parameters!!! + predicate); } - - public static Predicate requestTo(final Predicate predicate) { - return request -> - predicate.test(request.getRequestUri()); + + private static Predicate requestTo(final Function extractor, + final Predicate predicate) { + return request -> predicate.test(extractor.apply(request)); } + // TODO(whiskeysierra): This should probably be more sophisticated, i.e. contains/compatibleWith public static Predicate contentType(final String contentType) { return request -> contentType.equals(request.getContentType()); diff --git a/logbook-core/src/test/java/org/zalando/logbook/DefaultHttpLogFormatterTest.java b/logbook-core/src/test/java/org/zalando/logbook/DefaultHttpLogFormatterTest.java index e7022b92b..2f943d1e5 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/DefaultHttpLogFormatterTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/DefaultHttpLogFormatterTest.java @@ -40,7 +40,7 @@ public void shouldLogRequest() throws IOException { final HttpRequest request = MockHttpRequest.builder() .protocolVersion("HTTP/1.0") .origin(Origin.REMOTE) - .requestUri("/test") + .path("/test") .queryParameters(ImmutableListMultimap.of( "limit", "1" )) @@ -53,7 +53,7 @@ public void shouldLogRequest() throws IOException { final String http = unit.format(new SimplePrecorrelation<>(correlationId, request)); assertThat(http, equalTo("Incoming Request: c9408eaa-677d-11e5-9457-10ddb1ee7671\n" + - "GET /test?limit=1 HTTP/1.0\n" + + "GET http://localhost/test?limit=1 HTTP/1.0\n" + "Accept: application/json\n" + "Content-Type: text/plain\n" + "\n" + @@ -65,7 +65,7 @@ public void shouldLogRequestWithoutQueryParameters() throws IOException { final String correlationId = "2bd05240-6827-11e5-bbee-10ddb1ee7671"; final HttpRequest request = MockHttpRequest.builder() .origin(Origin.LOCAL) - .requestUri("/test") + .path("/test") .headers(ImmutableListMultimap.of( "Accept", "application/json", "Content-Type", "text/plain")) @@ -75,7 +75,7 @@ public void shouldLogRequestWithoutQueryParameters() throws IOException { final String http = unit.format(new SimplePrecorrelation<>(correlationId, request)); assertThat(http, equalTo("Outgoing Request: 2bd05240-6827-11e5-bbee-10ddb1ee7671\n" + - "GET /test HTTP/1.1\n" + + "GET http://localhost/test HTTP/1.1\n" + "Accept: application/json\n" + "Content-Type: text/plain\n" + "\n" + @@ -86,14 +86,14 @@ public void shouldLogRequestWithoutQueryParameters() throws IOException { public void shouldLogRequestWithoutBody() throws IOException { final String correlationId = "0eae9f6c-6824-11e5-8b0a-10ddb1ee7671"; final HttpRequest request = MockHttpRequest.builder() - .requestUri("/test") + .path("/test") .headers(ImmutableListMultimap.of("Accept", "application/json")) .build(); final String http = unit.format(new SimplePrecorrelation<>(correlationId, request)); assertThat(http, equalTo("Incoming Request: 0eae9f6c-6824-11e5-8b0a-10ddb1ee7671\n" + - "GET /test HTTP/1.1\n" + + "GET http://localhost/test HTTP/1.1\n" + "Accept: application/json")); } diff --git a/logbook-core/src/test/java/org/zalando/logbook/ForwardingHttpRequestTest.java b/logbook-core/src/test/java/org/zalando/logbook/ForwardingHttpRequestTest.java index 82026ff96..48cbf6d65 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/ForwardingHttpRequestTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/ForwardingHttpRequestTest.java @@ -46,6 +46,11 @@ public void shouldDelegate() throws IOException { assertThat(unit.getRemote(), is("127.0.0.1")); assertThat(unit.getMethod(), is("GET")); assertThat(unit.getRequestUri(), is("http://localhost/")); + assertThat(unit.getScheme(), is("http")); + assertThat(unit.getHost(), is("localhost")); + assertThat(unit.getPort(), is(80)); + assertThat(unit.getPath(), is("/")); + assertThat(unit.getQuery(), is(emptyString())); assertThat(unit.getQueryParameters().values(), is(empty())); assertThat(unit.getProtocolVersion(), is("HTTP/1.1")); assertThat(unit.getHeaders().values(), is(empty())); diff --git a/logbook-core/src/test/java/org/zalando/logbook/ForwardingRawHttpRequestTest.java b/logbook-core/src/test/java/org/zalando/logbook/ForwardingRawHttpRequestTest.java index dadc45074..6a2361d20 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/ForwardingRawHttpRequestTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/ForwardingRawHttpRequestTest.java @@ -49,6 +49,11 @@ public void shouldDelegate() throws IOException { assertThat(unit.getRemote(), is("127.0.0.1")); assertThat(unit.getMethod(), is("GET")); assertThat(unit.getRequestUri(), is("http://localhost/")); + assertThat(unit.getScheme(), is("http")); + assertThat(unit.getHost(), is("localhost")); + assertThat(unit.getPort(), is(80)); + assertThat(unit.getPath(), is("/")); + assertThat(unit.getQuery(), is(emptyString())); assertThat(unit.getQueryParameters().values(), is(empty())); assertThat(unit.getProtocolVersion(), is("HTTP/1.1")); assertThat(unit.getHeaders(), is(ImmutableMultimap.of())); @@ -64,6 +69,11 @@ public void shouldDelegateWithBody() throws IOException { assertThat(request.getRemote(), is("127.0.0.1")); assertThat(request.getMethod(), is("GET")); assertThat(request.getRequestUri(), is("http://localhost/")); + assertThat(request.getScheme(), is("http")); + assertThat(request.getHost(), is("localhost")); + assertThat(request.getPort(), is(80)); + assertThat(request.getPath(), is("/")); + assertThat(request.getQuery(), is(emptyString())); assertThat(request.getQueryParameters().values(), is(empty())); assertThat(request.getProtocolVersion(), is("HTTP/1.1")); assertThat(request.getHeaders().values(), is(empty())); diff --git a/logbook-core/src/test/java/org/zalando/logbook/JsonHttpLogFormatterTest.java b/logbook-core/src/test/java/org/zalando/logbook/JsonHttpLogFormatterTest.java index 1eb00a6b4..c9bd2dc88 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/JsonHttpLogFormatterTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/JsonHttpLogFormatterTest.java @@ -49,7 +49,7 @@ public void shouldLogRequest() throws IOException { final HttpRequest request = MockHttpRequest.builder() .protocolVersion("HTTP/1.0") .origin(REMOTE) - .requestUri("/test") + .path("/test") .queryParameters(ImmutableListMultimap.of( "limit", "1" )) @@ -69,7 +69,7 @@ public void shouldLogRequest() throws IOException { .assertThat("$.protocol", is("HTTP/1.0")) .assertThat("$.remote", is("127.0.0.1")) .assertThat("$.method", is("GET")) - .assertThat("$.uri", is("/test?limit=1")) + .assertThat("$.uri", is("http://localhost/test?limit=1")) .assertThat("$.headers.*", hasSize(2)) .assertThat("$.headers['Accept']", is(singletonList("application/json"))) .assertThat("$.headers['Date']", is(singletonList("Tue, 15 Nov 1994 08:12:31 GMT"))) @@ -80,7 +80,7 @@ public void shouldLogRequest() throws IOException { public void shouldLogRequestWithoutHeaders() throws IOException { final String correlationId = "b7e7a488-682a-11e5-b527-10ddb1ee7671\n"; final HttpRequest request = MockHttpRequest.builder() - .requestUri("/test") + .path("/test") .body("Hello, world!") .build(); diff --git a/logbook-core/src/test/java/org/zalando/logbook/ObfuscatedHttpRequestTest.java b/logbook-core/src/test/java/org/zalando/logbook/ObfuscatedHttpRequestTest.java index b11fe161f..5889f1edc 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/ObfuscatedHttpRequestTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/ObfuscatedHttpRequestTest.java @@ -27,6 +27,7 @@ import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; @@ -35,7 +36,6 @@ public final class ObfuscatedHttpRequestTest { private final HttpRequest unit = new ObfuscatedHttpRequest(MockHttpRequest.builder() - .requestUri("/") .queryParameters(ImmutableListMultimap.of( "password", "1234", "limit", "1" @@ -54,13 +54,14 @@ public void shouldNotFailOnInvalidUri() { final String invalidUri = "/af.cgi?_browser_out=.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2Fetc%2Fpasswd"; final ObfuscatedHttpRequest invalidRequest = new ObfuscatedHttpRequest( MockHttpRequest.builder() - .requestUri(invalidUri) + .path("/af.cgi") + .query("_browser_out=.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2F.|.%2Fetc%2Fpasswd") .build(), Obfuscator.none(), Obfuscator.obfuscate("_browser_out"::equalsIgnoreCase, "unknown"), BodyObfuscator.none()); - assertThat(invalidRequest.getRequestUri(), is(invalidUri)); + assertThat(invalidRequest.getRequestUri(), endsWith(invalidUri)); } @Test @@ -77,7 +78,7 @@ public void shouldNotObfuscateAcceptHeader() { public void shouldNotObfuscateEmptyQueryString() { final ObfuscatedHttpRequest request = new ObfuscatedHttpRequest(MockHttpRequest.create(), Obfuscator.none(), - Obfuscator.obfuscate(x -> true, "*"), + Obfuscator.obfuscate($ -> true, "*"), BodyObfuscator.none()); assertThat(request.getRequestUri(), is("http://localhost/")); diff --git a/logbook-core/src/test/java/org/zalando/logbook/RequestPredicatesTest.java b/logbook-core/src/test/java/org/zalando/logbook/RequestPredicatesTest.java index 551e26781..c9aff1427 100644 --- a/logbook-core/src/test/java/org/zalando/logbook/RequestPredicatesTest.java +++ b/logbook-core/src/test/java/org/zalando/logbook/RequestPredicatesTest.java @@ -26,7 +26,6 @@ import java.util.function.Predicate; import static com.google.common.collect.Sets.newHashSet; -import static java.util.regex.Pattern.compile; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.zalando.logbook.RequestPredicates.contentType; @@ -43,21 +42,21 @@ public final class RequestPredicatesTest { @Test public void excludeShouldMatchIfNoneMatches() { - final Predicate unit = exclude(requestTo("/"), contentType("application/json")); + final Predicate unit = exclude(requestTo("/admin"), contentType("application/json")); assertThat(unit.test(request), is(true)); } @Test public void excludeNotShouldMatchIfAnyMatches() { - final Predicate unit = exclude(requestTo("/"), contentType("text/plain")); + final Predicate unit = exclude(requestTo("/admin"), contentType("text/plain")); assertThat(unit.test(request), is(false)); } @Test public void excludeNotShouldMatchIfAllMatches() { - final Predicate unit = exclude(requestTo("http://localhost/"), contentType("text/plain")); + final Predicate unit = exclude(requestTo("/"), contentType("text/plain")); assertThat(unit.test(request), is(false)); } @@ -70,47 +69,19 @@ public void excludeShouldDefaultToAlwaysTrue() { } @Test - public void requestToShouldMatchString() { + public void requestToShouldMatchURI() { final Predicate unit = requestTo("http://localhost/"); - - assertThat(unit.test(request), is(true)); - } - - @Test - public void requestToShouldNotMatchString() { - final Predicate unit = requestTo("/"); - - assertThat(unit.test(request), is(false)); - } - - @Test - public void requestToShouldMatchPattern() { - final Predicate unit = requestTo(compile("https?://localhost/?.*")); assertThat(unit.test(request), is(true)); } @Test - public void requestToShouldNotPatternString() { - final Predicate unit = requestTo(compile("https://localhost/?.*")); - - assertThat(unit.test(request), is(false)); - } - - @Test - public void requestToShouldMatchPredicate() { - final Predicate unit = requestTo(url -> url.startsWith("http")); + public void requestToShouldMatchPath() { + final Predicate unit = requestTo("/"); assertThat(unit.test(request), is(true)); } - @Test - public void requestToShoulNotdMatchPredicate() { - final Predicate unit = requestTo(url -> url.startsWith("https")); - - assertThat(unit.test(request), is(false)); - } - @Test public void contentTypeShouldMatch() { final Predicate unit = contentType("text/plain"); diff --git a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LocalRequest.java b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LocalRequest.java index 2aed96aff..34221b95f 100644 --- a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LocalRequest.java +++ b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LocalRequest.java @@ -21,6 +21,7 @@ */ import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; @@ -46,6 +47,7 @@ import java.nio.charset.Charset; import java.util.Optional; +import static com.google.common.base.MoreObjects.firstNonNull; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.http.client.utils.URLEncodedUtils.parse; @@ -64,13 +66,16 @@ final class LocalRequest implements RawHttpRequest, org.zalando.logbook.HttpRequ } private static URI getOriginalRequestUri(final HttpRequest request) { - final HttpRequest original = request instanceof HttpRequestWrapper ? - HttpRequestWrapper.class.cast(request).getOriginal() : - request; + return request instanceof HttpRequestWrapper ? + getUri(HttpRequestWrapper.class.cast(request)): + request instanceof HttpUriRequest ? + HttpUriRequest.class.cast(request).getURI() : + URI.create(request.getRequestLine().getUri()); // TODO dumb fallback + } + + private static URI getUri(final HttpRequestWrapper request) { - return original instanceof HttpUriRequest ? - HttpUriRequest.class.cast(original).getURI() : - URI.create(request.getRequestLine().getUri()); + return URI.create(request.getOriginal().getRequestLine().getUri()); } @Override @@ -97,15 +102,31 @@ public String getMethod() { return request.getRequestLine().getMethod(); } + + @Override + public String getScheme() { + return originalRequestUri.getScheme(); + } + + @Override + public String getHost() { + return originalRequestUri.getHost(); + } + + @Override + public int getPort() { + final int port = originalRequestUri.getPort(); + return port == -1 ? 80 : port; // TODO(wschoenborn): is that safe to do? + } + + @Override + public String getPath() { + return originalRequestUri.getPath(); + } + @Override - public String getRequestUri() { - return stripQueryString( - originalRequestUri.getScheme(), - originalRequestUri.getUserInfo(), - originalRequestUri.getHost(), - originalRequestUri.getPort(), - originalRequestUri.getPath(), - originalRequestUri.getFragment()); + public String getQuery() { + return firstNonNull(originalRequestUri.getQuery(), ""); } @SneakyThrows @@ -125,7 +146,7 @@ public ListMultimap getQueryParameters() { return ImmutableListMultimap.of(); } - for (NameValuePair pair : parse(query, UTF_8)) { + for (final NameValuePair pair : parse(query, UTF_8)) { parameters.put(pair.getName(), pair.getValue()); } @@ -136,7 +157,7 @@ public ListMultimap getQueryParameters() { public ListMultimap getHeaders() { final ListMultimap headers = Headers.create(); - for (Header header : request.getAllHeaders()) { + for (final Header header : request.getAllHeaders()) { headers.put(header.getName(), header.getValue()); } diff --git a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpRequestInterceptor.java b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpRequestInterceptor.java index 7668f4709..6c76d4331 100644 --- a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpRequestInterceptor.java +++ b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpRequestInterceptor.java @@ -37,12 +37,12 @@ public final class LogbookHttpRequestInterceptor implements HttpRequestIntercept private final Logbook logbook; private final Localhost localhost; - public LogbookHttpRequestInterceptor(Logbook logbook) { + public LogbookHttpRequestInterceptor(final Logbook logbook) { this(logbook, Localhost.resolve()); } @VisibleForTesting - LogbookHttpRequestInterceptor(Logbook logbook, Localhost localhost) { + LogbookHttpRequestInterceptor(final Logbook logbook, final Localhost localhost) { this.logbook = logbook; this.localhost = localhost; } diff --git a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpResponseInterceptor.java b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpResponseInterceptor.java index 891df1bec..2cc9de351 100644 --- a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpResponseInterceptor.java +++ b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/LogbookHttpResponseInterceptor.java @@ -40,7 +40,7 @@ public void process(final HttpResponse original, final HttpContext context) thro } } - private Optional getCorrelator(HttpContext context) { + private Optional getCorrelator(final HttpContext context) { return Optional.ofNullable(context.getAttribute(Attributes.CORRELATOR)) .map(Correlator.class::cast); } diff --git a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/RemoteResponse.java b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/RemoteResponse.java index 4d42fcd8c..4ece252e2 100644 --- a/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/RemoteResponse.java +++ b/logbook-httpclient/src/main/java/org/zalando/logbook/httpclient/RemoteResponse.java @@ -65,7 +65,7 @@ public int getStatus() { public ListMultimap getHeaders() { final ListMultimap headers = Headers.create(); - for (Header header : response.getAllHeaders()) { + for (final Header header : response.getAllHeaders()) { headers.put(header.getName(), header.getValue()); } diff --git a/logbook-httpclient/src/test/java/org/zalando/logbook/httpclient/LocalRequestTest.java b/logbook-httpclient/src/test/java/org/zalando/logbook/httpclient/LocalRequestTest.java index 0148d36e4..1a9267de2 100644 --- a/logbook-httpclient/src/test/java/org/zalando/logbook/httpclient/LocalRequestTest.java +++ b/logbook-httpclient/src/test/java/org/zalando/logbook/httpclient/LocalRequestTest.java @@ -63,7 +63,7 @@ public final class LocalRequestTest { private final Localhost localhost = mock(Localhost.class); - private HttpRequest get(String uri) { + private HttpRequest get(final String uri) { return new HttpGet(uri); } @@ -103,7 +103,7 @@ public void shouldTrimQueryStringFromRequestUri() { final LocalRequest unit = unit(get("http://localhost/?limit=1")); assertThat(unit, hasFeature("request uri", BaseHttpRequest::getRequestUri, - hasToString("http://localhost/"))); + hasToString("http://localhost/?limit=1"))); } @Test @@ -125,10 +125,10 @@ public void shouldRetrieveAbsoluteRequestUriForWrappedRequests() throws URISynta public void shouldRetrieveRelativeUriForNonHttpUriRequests() throws URISyntaxException { final LocalRequest unit = unit(wrap(new BasicHttpRequest("GET", "http://localhost/"))); - assertThat(unit, hasFeature("request uri", BaseHttpRequest::getRequestUri, hasToString("/"))); + assertThat(unit, hasFeature("request uri", BaseHttpRequest::getRequestUri, hasToString("http://localhost/"))); } - private HttpRequestWrapper wrap(HttpRequest delegate) throws URISyntaxException { + private HttpRequestWrapper wrap(final HttpRequest delegate) throws URISyntaxException { final HttpHost target = HttpHost.create("localhost"); final HttpRequestWrapper wrap = HttpRequestWrapper.wrap(delegate, target); wrap.setURI(URIUtils.rewriteURIForRoute(URI.create("http://localhost/"), new HttpRoute(target))); diff --git a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/HttpFilter.java b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/HttpFilter.java index 93fdea826..b8bd433ab 100644 --- a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/HttpFilter.java +++ b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/HttpFilter.java @@ -35,7 +35,7 @@ interface HttpFilter extends Filter { @Override - default void init(FilterConfig filterConfig) throws ServletException { + default void init(final FilterConfig filterConfig) throws ServletException { } diff --git a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/RemoteRequest.java b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/RemoteRequest.java index 5470fc307..036c2c390 100644 --- a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/RemoteRequest.java +++ b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/RemoteRequest.java @@ -79,8 +79,23 @@ public String getRemote() { } @Override - public String getRequestUri() { - return getRequestURL().toString(); + public String getHost() { + return getServerName(); + } + + @Override + public int getPort() { + return getServerPort(); + } + + @Override + public String getPath() { + return getRequestURI(); + } + + @Override + public String getQuery() { + return firstNonNull(getQueryString(), ""); } @Override diff --git a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedHttpRequest.java b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedHttpRequest.java index 8d2532bf5..4163d6271 100644 --- a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedHttpRequest.java +++ b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedHttpRequest.java @@ -29,7 +29,7 @@ final class UnauthorizedHttpRequest extends ForwardingHttpRequest { private final RemoteRequest request; - public UnauthorizedHttpRequest(RemoteRequest request) { + public UnauthorizedHttpRequest(final RemoteRequest request) { this.request = request; } diff --git a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedRawHttpRequest.java b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedRawHttpRequest.java index b4e648c57..09171d4b4 100644 --- a/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedRawHttpRequest.java +++ b/logbook-servlet/src/main/java/org/zalando/logbook/servlet/UnauthorizedRawHttpRequest.java @@ -29,7 +29,7 @@ final class UnauthorizedRawHttpRequest extends ForwardingRawHttpRequest { private final RemoteRequest request; - UnauthorizedRawHttpRequest(RemoteRequest request) { + UnauthorizedRawHttpRequest(final RemoteRequest request) { this.request = request; } diff --git a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/FormattingTest.java b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/FormattingTest.java index 1b913ee1c..7b38bc91f 100644 --- a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/FormattingTest.java +++ b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/FormattingTest.java @@ -91,7 +91,7 @@ public void shouldFormatRequest() throws Exception { assertThat(request, hasFeature("remote address", HttpRequest::getRemote, is("127.0.0.1"))); assertThat(request, hasFeature("method", HttpRequest::getMethod, is("GET"))); assertThat(request, hasFeature("url", HttpRequest::getRequestUri, - hasToString("http://localhost/api/sync"))); + hasToString("http://localhost/api/sync?limit=1"))); assertThat(request, hasFeature("parameters", HttpRequest::getQueryParameters, is(of("limit", "1")))); assertThat(request, hasFeature("headers", HttpRequest::getHeaders, is(of("Accept", "text/plain")))); diff --git a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/SecurityFilter.java b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/SecurityFilter.java index 0db12eab4..51d7c8aa3 100644 --- a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/SecurityFilter.java +++ b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/SecurityFilter.java @@ -33,7 +33,7 @@ class SecurityFilter implements HttpFilter { private Integer status; @Override - public void doFilter(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) + public void doFilter(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse, final FilterChain chain) throws ServletException, IOException { if (status == null) { @@ -43,7 +43,7 @@ public void doFilter(HttpServletRequest httpRequest, HttpServletResponse httpRes } } - public void setStatus(Integer status) { + public void setStatus(final Integer status) { this.status = status; } } diff --git a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/WritingTest.java b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/WritingTest.java index 9c0eb48b5..f4ee393b5 100644 --- a/logbook-servlet/src/test/java/org/zalando/logbook/servlet/WritingTest.java +++ b/logbook-servlet/src/test/java/org/zalando/logbook/servlet/WritingTest.java @@ -113,7 +113,7 @@ public void shouldLogResponse() throws Exception { "{\"value\":\"Hello, world!\"}")); } - private RequestPostProcessor protocol(String protocol) { + private RequestPostProcessor protocol(final String protocol) { return request -> { request.setProtocol(protocol); return request; diff --git a/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookAutoConfiguration.java b/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookAutoConfiguration.java index c41eea298..3298d91fe 100644 --- a/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookAutoConfiguration.java +++ b/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookAutoConfiguration.java @@ -38,7 +38,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; -import org.springframework.util.AntPathMatcher; import org.zalando.logbook.BodyObfuscator; import org.zalando.logbook.DefaultHttpLogFormatter; import org.zalando.logbook.DefaultHttpLogWriter; @@ -49,6 +48,7 @@ import org.zalando.logbook.Logbook; import org.zalando.logbook.Obfuscator; import org.zalando.logbook.RawHttpRequest; +import org.zalando.logbook.RequestPredicates; import org.zalando.logbook.servlet.LogbookFilter; import javax.servlet.Filter; @@ -121,21 +121,15 @@ private Predicate mergeWithExcludes(final Predicate matcher(String pattern) { - final AntPathMatcher matcher = new AntPathMatcher(); - return request -> - matcher.match(pattern, request.getRequestUri()); - } - @Bean @ConditionalOnMissingBean(name = "requestPredicate") public Predicate requestPredicate() { - return request -> true; + return $ -> true; } @Bean diff --git a/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookProperties.java b/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookProperties.java index 7dffd5d57..ebd813df8 100644 --- a/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookProperties.java +++ b/logbook-spring-boot-starter/src/main/java/org/zalando/logbook/spring/LogbookProperties.java @@ -71,7 +71,7 @@ public String getCategory() { return category; } - public void setCategory(String category) { + public void setCategory(final String category) { this.category = category; } @@ -80,7 +80,7 @@ public Level getLevel() { return level; } - public void setLevel(Level level) { + public void setLevel(final Level level) { this.level = level; } diff --git a/logbook-spring-boot-starter/src/test/java/org/zalando/logbook/spring/ExcludeTest.java b/logbook-spring-boot-starter/src/test/java/org/zalando/logbook/spring/ExcludeTest.java index 27e8f6307..0a9ad969a 100644 --- a/logbook-spring-boot-starter/src/test/java/org/zalando/logbook/spring/ExcludeTest.java +++ b/logbook-spring-boot-starter/src/test/java/org/zalando/logbook/spring/ExcludeTest.java @@ -27,21 +27,23 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.zalando.logbook.Correlator; import org.zalando.logbook.Logbook; import org.zalando.logbook.MockRawHttpRequest; import org.zalando.logbook.RawHttpRequest; import java.io.IOException; -import java.util.Optional; import java.util.function.Predicate; import static java.util.Optional.empty; +import static java.util.regex.Pattern.compile; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.zalando.logbook.MockRawHttpRequest.builder; +import static org.zalando.logbook.RequestPredicates.exclude; +import static org.zalando.logbook.RequestPredicates.requestTo; @ContextConfiguration @TestPropertySource(properties = "spring.config.name = exclude") @@ -59,8 +61,7 @@ public Logger httpLogger() { @Bean public Predicate requestPredicate() { - return request -> - !"/health".equals(request.getRequestUri()); + return exclude(requestTo("/health")); } } @@ -70,27 +71,35 @@ public Predicate requestPredicate() { @Test public void shouldExcludeHealth() throws IOException { - assertThat(logbook.write(requestTo("/health")), is(empty())); + assertThat(logbook.write(request("/health")), is(empty())); } @Test public void shouldExcludeAdmin() throws IOException { - assertThat(logbook.write(requestTo("/admin")), is(empty())); + assertThat(logbook.write(request("/admin")), is(empty())); } @Test public void shouldExcludeAdminWithPath() throws IOException { - assertThat(logbook.write(requestTo("/admin/users")), is(empty())); + assertThat(logbook.write(request("/admin/users")), is(empty())); + } + + @Test + public void shouldNotExcludeAdminWithQueryParameters() throws IOException { + assertThat(logbook.write(builder() + .path("/admin") + .query("debug=true") + .build()), is(empty())); } @Test public void shouldNotExcludeApi() throws IOException { - assertThat(logbook.write(requestTo("/api")), is(not(empty()))); + assertThat(logbook.write(request("/api")), is(not(empty()))); } - private MockRawHttpRequest requestTo(String requestUri) { - return MockRawHttpRequest.builder() - .requestUri(requestUri) + private MockRawHttpRequest request(final String path) { + return builder() + .path(path) .build(); } diff --git a/logbook-test/src/main/java/org/zalando/logbook/MockHttpRequest.java b/logbook-test/src/main/java/org/zalando/logbook/MockHttpRequest.java index ece157a79..f43d59e78 100644 --- a/logbook-test/src/main/java/org/zalando/logbook/MockHttpRequest.java +++ b/logbook-test/src/main/java/org/zalando/logbook/MockHttpRequest.java @@ -25,19 +25,25 @@ import lombok.Builder; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import static com.google.common.base.MoreObjects.firstNonNull; import static org.zalando.logbook.BaseHttpMessage.Headers.copy; +@Immutable public final class MockHttpRequest implements MockHttpMessage, HttpRequest { private final String protocolVersion; private final Origin origin; private final String remote; private final String method; - private final String requestUri; + private final String scheme; + private final String host; + private final int port; + private final String path; + private final String query; private final ListMultimap queryParameters; private final ListMultimap headers; private final String contentType; @@ -50,7 +56,11 @@ public MockHttpRequest( @Nullable final Origin origin, @Nullable final String remote, @Nullable final String method, - @Nullable final String requestUri, + @Nullable final String scheme, + @Nullable final String host, + final int port, + @Nullable final String path, + @Nullable final String query, @Nullable final ListMultimap queryParameters, @Nullable final ListMultimap headers, @Nullable final String contentType, @@ -60,7 +70,11 @@ public MockHttpRequest( this.origin = firstNonNull(origin, Origin.REMOTE); this.remote = firstNonNull(remote, "127.0.0.1"); this.method = firstNonNull(method, "GET"); - this.requestUri = firstNonNull(requestUri, "http://localhost/"); + this.scheme = firstNonNull(scheme, "http"); + this.host = firstNonNull(host, "localhost"); + this.port = port == 0 ? 80 : port; + this.path = firstNonNull(path, "/"); + this.query = firstNonNull(query, ""); this.queryParameters = firstNonNullNorEmpty(queryParameters, ImmutableListMultimap.of()); this.headers = copy(firstNonNullNorEmpty(headers, ImmutableListMultimap.of())); this.contentType = firstNonNull(contentType, ""); @@ -89,8 +103,28 @@ public String getMethod() { } @Override - public String getRequestUri() { - return requestUri; + public String getScheme() { + return scheme; + } + + @Override + public String getHost() { + return host; + } + + @Override + public int getPort() { + return port; + } + + @Override + public String getPath() { + return path; + } + + @Override + public String getQuery() { + return query; } @Override diff --git a/logbook-test/src/main/java/org/zalando/logbook/MockHttpResponse.java b/logbook-test/src/main/java/org/zalando/logbook/MockHttpResponse.java index ca005b0dc..865ce5ebc 100644 --- a/logbook-test/src/main/java/org/zalando/logbook/MockHttpResponse.java +++ b/logbook-test/src/main/java/org/zalando/logbook/MockHttpResponse.java @@ -25,12 +25,14 @@ import lombok.Builder; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import static com.google.common.base.MoreObjects.firstNonNull; import static org.zalando.logbook.BaseHttpMessage.Headers.copy; +@Immutable public final class MockHttpResponse implements MockHttpMessage, HttpResponse { private final String protocolVersion; diff --git a/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpRequest.java b/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpRequest.java index 33ee3086d..e84cb5ae8 100644 --- a/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpRequest.java +++ b/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpRequest.java @@ -25,6 +25,7 @@ import lombok.Builder; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -32,13 +33,18 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static org.zalando.logbook.BaseHttpMessage.Headers.copy; +@Immutable public final class MockRawHttpRequest implements MockHttpMessage, RawHttpRequest { private final String protocolVersion; private final Origin origin; private final String remote; private final String method; - private final String requestUri; + private final String scheme; + private final String host; + private final int port; + private final String path; + private final String query; private final ListMultimap queryParameters; private final ListMultimap headers; private final String contentType; @@ -50,7 +56,11 @@ public MockRawHttpRequest( @Nullable final Origin origin, @Nullable final String remote, @Nullable final String method, - @Nullable final String requestUri, + @Nullable final String scheme, + @Nullable final String host, + final int port, + @Nullable final String path, + @Nullable final String query, @Nullable final ListMultimap queryParameters, @Nullable final ListMultimap headers, @Nullable final String contentType, @@ -59,7 +69,11 @@ public MockRawHttpRequest( this.origin = firstNonNull(origin, Origin.REMOTE); this.remote = firstNonNull(remote, "127.0.0.1"); this.method = firstNonNull(method, "GET"); - this.requestUri = firstNonNull(requestUri, "http://localhost/"); + this.scheme = firstNonNull(scheme, "http"); + this.host = firstNonNull(host, "localhost"); + this.port = port == 0 ? 80 : port; + this.path = firstNonNull(path, "/"); + this.query = firstNonNull(query, ""); this.queryParameters = firstNonNullNorEmpty(queryParameters, ImmutableListMultimap.of()); this.headers = copy(firstNonNullNorEmpty(headers, ImmutableListMultimap.of())); this.contentType = firstNonNull(contentType, ""); @@ -82,8 +96,28 @@ public String getMethod() { } @Override - public String getRequestUri() { - return requestUri; + public String getHost() { + return host; + } + + @Override + public String getScheme() { + return scheme; + } + + @Override + public int getPort() { + return port; + } + + @Override + public String getPath() { + return path; + } + + @Override + public String getQuery() { + return query; } @Override @@ -120,7 +154,11 @@ public HttpRequest withBody() throws IOException { .origin(origin) .remote(remote) .method(method) - .requestUri(requestUri) + .scheme(scheme) + .host(host) + .port(port) + .path(path) + .query(query) .build(); } diff --git a/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpResponse.java b/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpResponse.java index 5442080ea..3cca66e68 100644 --- a/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpResponse.java +++ b/logbook-test/src/main/java/org/zalando/logbook/MockRawHttpResponse.java @@ -25,6 +25,7 @@ import lombok.Builder; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -32,6 +33,7 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static org.zalando.logbook.BaseHttpMessage.Headers.copy; +@Immutable public final class MockRawHttpResponse implements MockHttpMessage, RawHttpResponse { private final String protocolVersion;