diff --git a/common/uri/src/main/java/io/helidon/common/uri/UriPathNoParam.java b/common/uri/src/main/java/io/helidon/common/uri/UriPathNoParam.java index e284fc134b6..0d4b2d5a2ae 100644 --- a/common/uri/src/main/java/io/helidon/common/uri/UriPathNoParam.java +++ b/common/uri/src/main/java/io/helidon/common/uri/UriPathNoParam.java @@ -73,7 +73,7 @@ public String rawPathNoParams() { @Override public String path() { if (decodedPath == null) { - decodedPath = decode(rawPath); + decodedPath = decode(rawPath, false); } return decodedPath; } @@ -104,11 +104,11 @@ public String toString() { @Override public void validate() { if (decodedPath == null) { - this.decodedPath = URI.create(rawPath).normalize().getPath(); + this.decodedPath = decode(rawPath, true); } } - private static String decode(String rawPath) { + private static String decode(String rawPath, boolean validate) { /* Raw path may: - be encoded (%20) @@ -121,10 +121,18 @@ private static String decode(String rawPath) { int dot = rawPath.indexOf("."); int doubleSlash = rawPath.indexOf("//"); - if (percent == -1 && doubleSlash == -1 && dot == -1) { + if (!validate && percent == -1 && doubleSlash == -1 && dot == -1) { return rawPath; } + if (doubleSlash == 0) { + /* + RFC2396 - net_path starts with //, that would lead to loosing first path segment. + example: URI.create("//foo/bar").getPath() --> "/bar" + */ + rawPath = rawPath.substring(1); + } + return URI.create(rawPath).normalize().getPath(); } } diff --git a/common/uri/src/test/java/io/helidon/common/uri/UriPathTest.java b/common/uri/src/test/java/io/helidon/common/uri/UriPathTest.java index d230b964f1a..f94f70f1193 100644 --- a/common/uri/src/test/java/io/helidon/common/uri/UriPathTest.java +++ b/common/uri/src/test/java/io/helidon/common/uri/UriPathTest.java @@ -17,6 +17,8 @@ package io.helidon.common.uri; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -37,4 +39,16 @@ void testEncodeSpace() { assertThat(path.path(), is("/my path")); assertThat(path.rawPath(), is("/my%20path")); } + + @ParameterizedTest + @ValueSource(strings = { + "//foo/bar", + "//foo//bar", + "/foo//bar", + "/foo/bar", + }) + void testDoubleSlash(String rawPath) { + UriPath path = UriPath.create(rawPath); + assertThat(path.path(), is("/foo/bar")); + } } diff --git a/webclient/tests/webclient/src/test/java/io/helidon/webclient/tests/TracingPropagationTest.java b/webclient/tests/webclient/src/test/java/io/helidon/webclient/tests/TracingPropagationTest.java index 978fb0ba448..d9f6cb0f83e 100644 --- a/webclient/tests/webclient/src/test/java/io/helidon/webclient/tests/TracingPropagationTest.java +++ b/webclient/tests/webclient/src/test/java/io/helidon/webclient/tests/TracingPropagationTest.java @@ -59,6 +59,8 @@ class TracingPropagationTest { private static final Duration TIMEOUT = Duration.ofSeconds(15); private static final AtomicReference SPAN_COUNT_LATCH = new AtomicReference<>(); + // 2+1 after re-introduction of content-write span + private static final int EXPECTED_NUMBER_OF_SPANS = 3; private static MockTracer tracer; private final Http1Client client; private final URI uri; @@ -92,7 +94,7 @@ protected void onSpanFinished(MockSpan mockSpan) { @Test void testTracingSuccess() throws InterruptedException { - SPAN_COUNT_LATCH.set(new CountDownLatch(2)); + SPAN_COUNT_LATCH.set(new CountDownLatch(EXPECTED_NUMBER_OF_SPANS)); Context context = Context.builder().id("tracing-unit-test").build(); context.register(tracer); @@ -110,10 +112,7 @@ void testTracingSuccess() throws InterruptedException { List mockSpans = tracer.finishedSpans(); // the server traces asynchronously, some spans may be written after we receive the response. - // we need to try to wait for such spans - // re-introduced content-write span - assertThat("There should be 3 spans reported", tracer.finishedSpans(), hasSize(3)); - + assertThat("There should be 3 spans reported", tracer.finishedSpans(), hasSize(EXPECTED_NUMBER_OF_SPANS)); // we need the first span - parentId 0 MockSpan clientSpan = findSpanWithParentId(mockSpans, 0);