From 90aa803f7e5d58a74320550b8232f869c4822706 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 20 Aug 2021 00:24:22 +0200 Subject: [PATCH] Additional work on path normalization --- .../deployment/util/UriNormalizationUtil.java | 8 +++- .../ResteasyDeploymentBuildItem.java | 4 +- .../ResteasyServerConfigBuildItem.java | 2 +- .../deployment/ResteasyServletProcessor.java | 5 +-- .../undertow/deployment/ServletConfig.java | 37 +++++++++++++++++++ .../deployment/UndertowBuildStep.java | 10 ++--- .../runtime/UndertowDeploymentRecorder.java | 13 +------ 7 files changed, 54 insertions(+), 25 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java index 3a629bf968b16..77ef04d84404f 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java @@ -91,14 +91,18 @@ public static URI toURI(String path, boolean trailingSlash) { * * * @param base URI to resolve relative paths. Use {@link #toURI(String, boolean)} to construct this parameter. - * + * * @param segment Relative or absolute path * @param trailingSlash true if resulting URI must end with a '/' * @throws IllegalArgumentException if the path contains invalid characters or path segments. */ public static URI normalizeWithBase(URI base, String segment, boolean trailingSlash) { if (segment == null || segment.trim().isEmpty()) { - return base; + if ("/".equals(base.getPath())) { + return base; + } + // otherwise, make sure trailingSlash is honored + return toURI(base.getPath(), trailingSlash); } URI segmentUri = toURI(segment, trailingSlash); URI resolvedUri = base.resolve(segmentUri); diff --git a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyDeploymentBuildItem.java b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyDeploymentBuildItem.java index ad88ad4e84596..86b7141d67d4c 100644 --- a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyDeploymentBuildItem.java +++ b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyDeploymentBuildItem.java @@ -5,12 +5,12 @@ import io.quarkus.builder.item.SimpleBuildItem; public final class ResteasyDeploymentBuildItem extends SimpleBuildItem { - private ResteasyDeployment deployment; private String rootPath; + private ResteasyDeployment deployment; public ResteasyDeploymentBuildItem(String rootPath, ResteasyDeployment deployment) { + this.rootPath = rootPath.startsWith("/") ? rootPath : "/" + rootPath; this.deployment = deployment; - this.rootPath = rootPath; } public ResteasyDeployment getDeployment() { diff --git a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerConfigBuildItem.java b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerConfigBuildItem.java index 7705fd62b6b53..a092917849ee6 100644 --- a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerConfigBuildItem.java +++ b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerConfigBuildItem.java @@ -21,7 +21,7 @@ public final class ResteasyServerConfigBuildItem extends SimpleBuildItem { */ public ResteasyServerConfigBuildItem(String rootPath, String path, Map initParameters) { this.rootPath = rootPath; - this.path = path; + this.path = path.startsWith("/") ? path : "/" + path; this.initParameters = initParameters; } diff --git a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java index 8a2f3435ef55e..1bac198489765 100644 --- a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java +++ b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java @@ -53,9 +53,8 @@ public void jaxrsConfig( BuildProducer resteasyJaxrsConfig, HttpRootPathBuildItem httpRootPathBuildItem) { if (resteasyServerConfig.isPresent()) { - String rp = resteasyServerConfig.get().getRootPath(); - String rootPath = httpRootPathBuildItem.resolvePath(rp.startsWith("/") ? rp.substring(1) : rp); - String defaultPath = httpRootPathBuildItem.resolvePath(resteasyServerConfig.get().getPath()); + String rootPath = httpRootPathBuildItem.relativePath(resteasyServerConfig.get().getRootPath()); + String defaultPath = resteasyServerConfig.get().getPath(); deprecatedResteasyJaxrsConfig.produce(new ResteasyJaxrsConfigBuildItem(defaultPath)); resteasyJaxrsConfig diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/ServletConfig.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/ServletConfig.java index b14400aaff5a7..3a702c2d9ec34 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/ServletConfig.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/ServletConfig.java @@ -1,10 +1,17 @@ package io.quarkus.undertow.deployment; +import static io.quarkus.runtime.configuration.ConverterSupport.DEFAULT_QUARKUS_CONVERTER_PRIORITY; + import java.util.Optional; +import javax.annotation.Priority; + +import org.eclipse.microprofile.config.spi.Converter; + import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.quarkus.runtime.annotations.ConvertWith; @ConfigRoot(phase = ConfigPhase.BUILD_TIME) public class ServletConfig { @@ -17,6 +24,7 @@ public class ServletConfig { * is /bar and the http root is /foo then the actual Servlet path will be /foo/bar. */ @ConfigItem + @ConvertWith(ContextPathConverter.class) Optional contextPath; /** @@ -25,4 +33,33 @@ public class ServletConfig { @ConfigItem(defaultValue = "UTF-8") public String defaultCharset; + /** + * This converter adds a / at the beginning of the context path but does not add one at the end, given we want to support + * it. + *

+ * See ContextPathTestCase for an example. + */ + @Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY) + public static class ContextPathConverter implements Converter { + + private static final String SLASH = "/"; + + @Override + public String convert(String value) throws IllegalArgumentException, NullPointerException { + if (value == null) { + return SLASH; + } + + value = value.trim(); + if (SLASH.equals(value)) { + return value; + } + if (!value.startsWith(SLASH)) { + value = SLASH + value; + } + + return value; + } + } + } diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java index 633596dc8b88a..fa8f71c8f185f 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java @@ -116,6 +116,7 @@ import io.quarkus.undertow.runtime.UndertowDeploymentRecorder; import io.quarkus.undertow.runtime.UndertowHandlersConfServletExtension; import io.quarkus.vertx.http.deployment.DefaultRouteBuildItem; +import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem; import io.quarkus.vertx.http.deployment.RouteBuildItem; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; import io.quarkus.vertx.http.runtime.HttpConfiguration; @@ -319,11 +320,7 @@ public ServletContextPathBuildItem contextPath( WebMetadataBuildItem webMetadataBuildItem) { String contextPath; if (servletConfig.contextPath.isPresent()) { - if (!servletConfig.contextPath.get().startsWith("/")) { - contextPath = "/" + servletConfig.contextPath; - } else { - contextPath = servletConfig.contextPath.get(); - } + contextPath = servletConfig.contextPath.get(); } else if (webMetadataBuildItem.getWebMetaData().getDefaultContextPath() != null) { contextPath = webMetadataBuildItem.getWebMetaData().getDefaultContextPath(); } else { @@ -351,6 +348,7 @@ public ServletDeploymentManagerBuildItem build(List servlets, ShutdownContextBuildItem shutdownContext, KnownPathsBuildItem knownPaths, HttpBuildTimeConfig httpBuildTimeConfig, + HttpRootPathBuildItem httpRootPath, ServletConfig servletConfig) throws Exception { ObjectSubstitutionBuildItem.Holder holder = new ObjectSubstitutionBuildItem.Holder(ServletSecurityInfo.class, @@ -365,7 +363,7 @@ public ServletDeploymentManagerBuildItem build(List servlets, String contextPath = servletContextPathBuildItem.getServletContextPath(); RuntimeValue deployment = recorder.createDeployment("test", knownPaths.knownFiles, knownPaths.knownDirectories, - launchMode.getLaunchMode(), shutdownContext, contextPath, httpBuildTimeConfig.rootPath, + launchMode.getLaunchMode(), shutdownContext, httpRootPath.relativePath(contextPath), servletConfig.defaultCharset, webMetaData.getRequestCharacterEncoding(), webMetaData.getResponseCharacterEncoding(), httpBuildTimeConfig.auth.proactive, webMetaData.getWelcomeFileList() != null ? webMetaData.getWelcomeFileList().getWelcomeFiles() : null); diff --git a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java index aa6532a2f53f3..730b858eea093 100644 --- a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java +++ b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java @@ -156,18 +156,9 @@ public static void setHotDeploymentResources(List resources) { } public RuntimeValue createDeployment(String name, Set knownFile, Set knownDirectories, - LaunchMode launchMode, ShutdownContext context, String contextPath, String httpRootPath, String defaultCharset, + LaunchMode launchMode, ShutdownContext context, String mountPoint, String defaultCharset, String requestCharacterEncoding, String responseCharacterEncoding, boolean proactiveAuth, List welcomeFiles) { - String realMountPoint; - if (contextPath.equals("/")) { - realMountPoint = httpRootPath; - } else if (httpRootPath.equals("/")) { - realMountPoint = contextPath; - } else { - realMountPoint = httpRootPath + contextPath; - } - DeploymentInfo d = new DeploymentInfo(); d.setDefaultRequestEncoding(requestCharacterEncoding); d.setDefaultResponseEncoding(responseCharacterEncoding); @@ -175,7 +166,7 @@ public RuntimeValue createDeployment(String name, Set kn d.setSessionIdGenerator(new QuarkusSessionIdGenerator()); d.setClassLoader(getClass().getClassLoader()); d.setDeploymentName(name); - d.setContextPath(realMountPoint); + d.setContextPath(mountPoint); d.setEagerFilterInit(true); ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) {