Fix Undertow's resource loading when filename contains reserved chars

Fixes gh-9283
pull/28061/head
Andy Wilkinson 3 years ago
parent 7f15a37909
commit 1900a11f8a

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.boot.web.embedded.undertow;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import io.undertow.UndertowMessages; import io.undertow.UndertowMessages;
@ -39,16 +40,17 @@ class JarResourceManager implements ResourceManager {
private final String jarPath; private final String jarPath;
JarResourceManager(File jarFile) { JarResourceManager(File jarFile) {
this(jarFile.getAbsolutePath()); try {
} this.jarPath = jarFile.getAbsoluteFile().toURI().toURL().toString();
}
JarResourceManager(String jarPath) { catch (MalformedURLException ex) {
this.jarPath = jarPath; throw new IllegalArgumentException(ex);
}
} }
@Override @Override
public Resource getResource(String path) throws IOException { public Resource getResource(String path) throws IOException {
URL url = new URL("jar:file:" + this.jarPath + "!" + (path.startsWith("/") ? path : "/" + path)); URL url = new URL("jar:" + this.jarPath + "!" + (path.startsWith("/") ? path : "/" + path));
URLResource resource = new URLResource(url, path); URLResource resource = new URLResource(url, path);
if (StringUtils.hasText(path) && !"/".equals(path) && resource.getContentLength() < 0) { if (StringUtils.hasText(path) && !"/".equals(path) && resource.getContentLength() < 0) {
return null; return null;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,14 +19,23 @@ package org.springframework.boot.web.embedded.undertow;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarOutputStream; import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import io.undertow.server.handlers.resource.Resource; import io.undertow.server.handlers.resource.Resource;
import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.ResourceManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -37,46 +46,58 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class JarResourceManagerTests { class JarResourceManagerTests {
private ResourceManager resourceManager; @TempDir
static File tempDir;
@BeforeEach @ResourceManagersTest
void createJar(@TempDir File tempDir) throws IOException { void emptyPathIsHandledCorrectly(String filename, ResourceManager resourceManager) throws IOException {
File jar = new File(tempDir, "test.jar"); Resource resource = resourceManager.getResource("");
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar))) {
out.putNextEntry(new ZipEntry("hello.txt"));
out.write("hello".getBytes());
}
this.resourceManager = new JarResourceManager(jar);
}
@Test
void emptyPathIsHandledCorrectly() throws IOException {
Resource resource = this.resourceManager.getResource("");
assertThat(resource).isNotNull(); assertThat(resource).isNotNull();
assertThat(resource.isDirectory()).isTrue(); assertThat(resource.isDirectory()).isTrue();
} }
@Test @ResourceManagersTest
void rootPathIsHandledCorrectly() throws IOException { void rootPathIsHandledCorrectly(String filename, ResourceManager resourceManager) throws IOException {
Resource resource = this.resourceManager.getResource("/"); Resource resource = resourceManager.getResource("/");
assertThat(resource).isNotNull(); assertThat(resource).isNotNull();
assertThat(resource.isDirectory()).isTrue(); assertThat(resource.isDirectory()).isTrue();
} }
@Test @ResourceManagersTest
void resourceIsFoundInJarFile() throws IOException { void resourceIsFoundInJarFile(String filename, ResourceManager resourceManager) throws IOException {
Resource resource = this.resourceManager.getResource("/hello.txt"); Resource resource = resourceManager.getResource("/hello.txt");
assertThat(resource).isNotNull(); assertThat(resource).isNotNull();
assertThat(resource.isDirectory()).isFalse(); assertThat(resource.isDirectory()).isFalse();
assertThat(resource.getContentLength()).isEqualTo(5); assertThat(resource.getContentLength()).isEqualTo(5);
} }
@Test @ResourceManagersTest
void resourceIsFoundInJarFileWithoutLeadingSlash() throws IOException { void resourceIsFoundInJarFileWithoutLeadingSlash(String filename, ResourceManager resourceManager)
Resource resource = this.resourceManager.getResource("hello.txt"); throws IOException {
Resource resource = resourceManager.getResource("hello.txt");
assertThat(resource).isNotNull(); assertThat(resource).isNotNull();
assertThat(resource.isDirectory()).isFalse(); assertThat(resource.isDirectory()).isFalse();
assertThat(resource.getContentLength()).isEqualTo(5); assertThat(resource.getContentLength()).isEqualTo(5);
} }
static List<Arguments> resourceManagers() throws IOException {
File jar = new File(tempDir, "test.jar");
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar))) {
out.putNextEntry(new ZipEntry("hello.txt"));
out.write("hello".getBytes());
}
File troublesomeNameJar = new File(tempDir, "test##1.0.jar");
FileCopyUtils.copy(jar, troublesomeNameJar);
return Arrays.asList(Arguments.of(jar.getName(), new JarResourceManager(jar)),
Arguments.of(troublesomeNameJar.getName(), new JarResourceManager(troublesomeNameJar)));
}
@ParameterizedTest(name = "[{index}] {0}")
@MethodSource("resourceManagers")
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
private @interface ResourceManagersTest {
}
} }

Loading…
Cancel
Save