diff --git a/modules/web/web-api/src/main/java/com/enonic/xp/web/servlet/ServletRequestUrlHelper.java b/modules/web/web-api/src/main/java/com/enonic/xp/web/servlet/ServletRequestUrlHelper.java index 0da334dcc12..1c9b0e474cc 100644 --- a/modules/web/web-api/src/main/java/com/enonic/xp/web/servlet/ServletRequestUrlHelper.java +++ b/modules/web/web-api/src/main/java/com/enonic/xp/web/servlet/ServletRequestUrlHelper.java @@ -3,6 +3,8 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; import com.google.common.base.Splitter; @@ -12,8 +14,6 @@ import com.enonic.xp.web.vhost.VirtualHost; import com.enonic.xp.web.vhost.VirtualHostHelper; -import static com.google.common.base.Strings.isNullOrEmpty; - @PublicApi public final class ServletRequestUrlHelper { @@ -22,10 +22,15 @@ public final class ServletRequestUrlHelper public static String createUri( final HttpServletRequest req, final String path ) { - return rewriteUri( req, path ).getRewrittenUri(); + return Objects.requireNonNullElse( rewriteUri( VirtualHostHelper.getVirtualHost( req ), path ), path ); } public static String getServerUrl( final HttpServletRequest req ) + { + return getOrigin( req ).toString(); + } + + private static StringBuilder getOrigin( final HttpServletRequest req ) { final StringBuilder str = new StringBuilder(); @@ -43,18 +48,14 @@ public static String getServerUrl( final HttpServletRequest req ) str.append( ":" ).append( port ); } - return str.toString(); + return str; } public static String getFullUrl( final HttpServletRequest req ) { - //Appends the server part - StringBuilder fullUrl = new StringBuilder( getServerUrl( req ) ); - - //Appends the path part - fullUrl.append( rewriteUri( req, req.getRequestURI() ).getRewrittenUri() ); + final StringBuilder fullUrl = getOrigin( req ); + fullUrl.append( createUri( req, req.getRequestURI() ) ); - //Appends the query string part final String queryString = req.getQueryString(); if ( queryString != null ) { @@ -66,75 +67,74 @@ public static String getFullUrl( final HttpServletRequest req ) private static boolean needPortNumber( final String scheme, final int port ) { - final boolean isUndefined = port < 0; - final boolean isHttpOrWs = ( "http".equals( scheme ) || "ws".equals( scheme ) ) && 80 == port; - final boolean isHttpsOrWss = ( "https".equals( scheme ) || "wss".equals( scheme ) ) && 443 == port; - return !( isUndefined || isHttpOrWs || isHttpsOrWss ); + return switch ( port ) + { + case 80 -> !"http".equals( scheme ) && !"ws".equals( scheme ); + case 443 -> !"https".equals( scheme ) && !"wss".equals( scheme ); + default -> port > 0; + }; } public static UriRewritingResult rewriteUri( final HttpServletRequest req, final String uri ) { - UriRewritingResult.Builder resultBuilder = UriRewritingResult.create(); + final UriRewritingResult.Builder resultBuilder = UriRewritingResult.create(); + final VirtualHost vhost = VirtualHostHelper.getVirtualHost( req ); if ( vhost == null ) { return resultBuilder.rewrittenUri( uri ).build(); } - final String targetPath = vhost.getTarget(); - if ( needRewrite( uri, targetPath ) ) - { - final String result = uri.substring( targetPath.length() ); - final String newUri = normalizePath( vhost.getSource() + ( "/".equals( targetPath ) ? "/" : "" ) + result ); - return resultBuilder.rewrittenUri( newUri ) - .deletedUriPrefix( targetPath ) - .newUriPrefix( normalizePath( vhost.getSource() ) ) - .build(); - } + final String rewrittenUri = rewriteUri( vhost, uri ); - return resultBuilder.rewrittenUri( normalizePath( uri ) ).outOfScope( true ).build(); + final String source = vhost.getSource(); + final String target = vhost.getTarget(); + + return resultBuilder.deletedUriPrefix( target ) + .newUriPrefix( source ) + .rewrittenUri( Objects.requireNonNullElse( rewrittenUri, uri ) ) + .outOfScope( rewrittenUri == null ) + .build(); } - private static boolean needRewrite( final String uri, final String targetPath ) + private static String rewriteUri( final VirtualHost vhost, final String uri ) { - if ( targetPath.equals( "/" ) ) + if ( vhost == null || !uri.startsWith( "/" ) ) { - return uri.startsWith( "/" ); + return uri; } - if ( uri.equals( targetPath ) ) + + final String source = vhost.getSource(); + final String target = vhost.getTarget(); + + if ( target.equals( "/" ) ) { - return true; + return normalizePath( "/".equals( source ) ? uri : source + uri ); } final int queryPos = uri.indexOf( '?' ); + final int pathLength = queryPos == -1 ? uri.length() : queryPos; - if ( queryPos == -1 ) - { - return uri.startsWith( targetPath + "/" ); - } - else + final int targetLength = target.length(); + + if ( uri.startsWith( target ) && + ( pathLength == targetLength || ( pathLength > targetLength && uri.charAt( targetLength ) == '/' ) ) ) { - final String uriWithoutQuery = uri.substring( 0, queryPos ); - if ( uriWithoutQuery.equals( targetPath ) ) + final StringBuilder sb = new StringBuilder(); + if ( !"/".equals( source ) ) { - return true; - } - else - { - return uriWithoutQuery.startsWith( targetPath + "/" ); + sb.append( source ); } + sb.append( uri, targetLength, uri.length() ); + return normalizePath( sb.toString() ); } + + return null; } - private static String normalizePath( final String value ) + private static String normalizePath( final String path ) { - if ( isNullOrEmpty( value ) ) - { - return "/"; - } - - final Iterable parts = Splitter.on( '/' ).trimResults().omitEmptyStrings().split( value ); - return "/" + String.join( "/", parts ); + return Splitter.on( '/' ).omitEmptyStrings().trimResults().splitToStream( path ).collect( Collectors.joining( "/", "/", "" ) ); } public static String contentDispositionAttachment( final String fileName ) @@ -149,7 +149,7 @@ public static String contentDispositionAttachment( final String fileName ) private static void appendQuoted( final StringBuilder builder, final String input ) { - builder.append( "\"" ); + builder.append( '"' ); input.codePoints().forEachOrdered( value -> { if ( value == '"' ) { @@ -160,7 +160,7 @@ private static void appendQuoted( final StringBuilder builder, final String inpu builder.appendCodePoint( value ); } } ); - builder.append( "\"" ); + builder.append( '"' ); } private static void appendRfc8187Encoded( final StringBuilder builder, final String input, final Charset charset ) diff --git a/modules/web/web-api/src/test/java/com/enonic/xp/web/servlet/ServletRequestUrlHelperTest.java b/modules/web/web-api/src/test/java/com/enonic/xp/web/servlet/ServletRequestUrlHelperTest.java index dc3f536787b..064e702319d 100644 --- a/modules/web/web-api/src/test/java/com/enonic/xp/web/servlet/ServletRequestUrlHelperTest.java +++ b/modules/web/web-api/src/test/java/com/enonic/xp/web/servlet/ServletRequestUrlHelperTest.java @@ -95,6 +95,30 @@ void rewriteUri_vhost() assertFalse( rewritingResult3.isOutOfScope() ); } + @Test + void rewriteUri_vhost_trivial() + { + final VirtualHost vhost = mock( VirtualHost.class ); + when( req.getAttribute( VirtualHost.class.getName() ) ).thenReturn( vhost ); + + when( vhost.getTarget() ).thenReturn( "/" ); + when( vhost.getSource() ).thenReturn( "/" ); + + final UriRewritingResult rewritingResult = ServletRequestUrlHelper.rewriteUri( req, "/path/to/page" ); + assertEquals( "/path/to/page", rewritingResult.getRewrittenUri() ); + assertFalse( rewritingResult.isOutOfScope() ); + + when( vhost.getTarget() ).thenReturn( "/root/to/site" ); + final UriRewritingResult rewritingResult2 = ServletRequestUrlHelper.rewriteUri( req, "/path/to/page" ); + assertEquals( "/path/to/page", rewritingResult2.getRewrittenUri() ); + assertTrue( rewritingResult2.isOutOfScope() ); + + when( vhost.getTarget() ).thenReturn( "/path/to" ); + final UriRewritingResult rewritingResult3 = ServletRequestUrlHelper.rewriteUri( req, "/path/to/page" ); + assertEquals( "/page", rewritingResult3.getRewrittenUri() ); + assertFalse( rewritingResult3.isOutOfScope() ); + } + @Test void contentDispositionAttachment_filename_with_comma() { @@ -166,6 +190,20 @@ void rewriteUri_vhost_outOfScope() assertFalse( rewritingResult.isOutOfScope() ); } + @Test + void rewriteUri_vhost_outOfScope_short() + { + final VirtualHost vhost = mock( VirtualHost.class ); + when( req.getAttribute( VirtualHost.class.getName() ) ).thenReturn( vhost ); + + when( vhost.getTarget() ).thenReturn( "/site/default/draft/enonic" ); + when( vhost.getSource() ).thenReturn( "/no" ); + + UriRewritingResult rewritingResult = ServletRequestUrlHelper.rewriteUri( req, "/site/default" ); + assertEquals( "/site/default", rewritingResult.getRewrittenUri() ); + assertTrue( rewritingResult.isOutOfScope() ); + } + @Test void createUri_admin_queryString() { diff --git a/modules/web/web-vhost/src/main/java/com/enonic/xp/web/vhost/impl/mapping/VirtualHostIdProvidersMapping.java b/modules/web/web-vhost/src/main/java/com/enonic/xp/web/vhost/impl/mapping/VirtualHostIdProvidersMapping.java index 7249a4b4d7b..22cec37a5ad 100644 --- a/modules/web/web-vhost/src/main/java/com/enonic/xp/web/vhost/impl/mapping/VirtualHostIdProvidersMapping.java +++ b/modules/web/web-vhost/src/main/java/com/enonic/xp/web/vhost/impl/mapping/VirtualHostIdProvidersMapping.java @@ -1,21 +1,18 @@ package com.enonic.xp.web.vhost.impl.mapping; -import java.util.ArrayList; -import java.util.List; +import com.google.common.collect.ImmutableSet; import com.enonic.xp.security.IdProviderKey; import com.enonic.xp.security.IdProviderKeys; public class VirtualHostIdProvidersMapping { - private final IdProviderKey defaultIdProvider; - private final IdProviderKeys idProviderKeys; public VirtualHostIdProvidersMapping( final Builder builder ) { - this.defaultIdProvider = builder.defaultIdProvider; - this.idProviderKeys = IdProviderKeys.from( builder.idProviderKeys ); + this.idProviderKeys = IdProviderKeys.from( + ImmutableSet.builder().add( builder.defaultIdProvider ).addAll( builder.idProviderKeys.build() ).build() ); } public static Builder create() @@ -25,7 +22,7 @@ public static Builder create() public IdProviderKey getDefaultIdProvider() { - return defaultIdProvider; + return idProviderKeys.first(); } public IdProviderKeys getIdProviderKeys() @@ -37,28 +34,21 @@ public static class Builder { private IdProviderKey defaultIdProvider; - private final List idProviderKeys; + private final ImmutableSet.Builder idProviderKeys = ImmutableSet.builder(); private Builder() { - this.idProviderKeys = new ArrayList<>(); } public Builder setDefaultIdProvider( final IdProviderKey defaultIdProvider ) { this.defaultIdProvider = defaultIdProvider; - addIdProviderKey( defaultIdProvider ); - return this; } public Builder addIdProviderKey( final IdProviderKey idProviderKey ) { - if ( !this.idProviderKeys.contains( idProviderKey ) ) - { - this.idProviderKeys.add( idProviderKey ); - } - + this.idProviderKeys.add( idProviderKey ); return this; }