diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedLocation.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedLocation.java index 589ef597283..94e513b6403 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedLocation.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedLocation.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,6 +48,7 @@ import org.springframework.boot.loader.net.util.UrlDecoder; * @param path the path to the zip that contains the nested entry * @param nestedEntryName the nested entry name * @author Phillip Webb + * @author Andy Wilkinson * @since 3.2.0 */ public record NestedLocation(Path path, String nestedEntryName) { @@ -72,7 +73,7 @@ public record NestedLocation(Path path, String nestedEntryName) { if (url == null || !"nested".equalsIgnoreCase(url.getProtocol())) { throw new IllegalArgumentException("'url' must not be null and must use 'nested' protocol"); } - return parse(UrlDecoder.decode(url.getPath())); + return parse(UrlDecoder.decode(url.toString().substring(7))); } /** @@ -98,7 +99,7 @@ public record NestedLocation(Path path, String nestedEntryName) { private static NestedLocation create(int index, String location) { String locationPath = (index != -1) ? location.substring(0, index) : location; - if (isWindows()) { + if (isWindows() && !isUncPath(location)) { while (locationPath.startsWith("/")) { locationPath = locationPath.substring(1, locationPath.length()); } @@ -111,6 +112,10 @@ public record NestedLocation(Path path, String nestedEntryName) { return File.separatorChar == '\\'; } + private static boolean isUncPath(String input) { + return !input.contains(":"); + } + static void clearCache() { cache.clear(); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedLocationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedLocationTests.java index c1a13b21b0c..40449813b83 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedLocationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedLocationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.boot.loader.net.protocol.nested; import java.io.File; +import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.file.Path; @@ -24,6 +25,8 @@ import java.nio.file.Path; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.springframework.boot.loader.net.protocol.Handlers; @@ -35,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * Tests for {@link NestedLocation}. * * @author Phillip Webb + * @author Andy Wilkinson */ class NestedLocationTests { @@ -130,4 +134,13 @@ class NestedLocationTests { assertThat(location.nestedEntryName()).isEqualTo("lib/nested.jar"); } + @Test + @EnabledOnOs(OS.WINDOWS) + void windowsUncPathIsHandledCorrectly() throws MalformedURLException { + NestedLocation location = NestedLocation.fromUrl( + new URL("nested://localhost/c$/dev/temp/demo/build/libs/demo-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/")); + assertThat(location.path()).asString() + .isEqualTo("\\\\localhost\\c$\\dev\\temp\\demo\\build\\libs\\demo-0.0.1-SNAPSHOT.jar"); + } + }