mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Improve handling of reserved characters in MetaInfResourceManager
Previously, MetaInfResourceManager that we use with Undertow to serve static resources from jar's META-INF/resources did not correctly handle characters in the path that should be percent-encoded when used in a URL. This commit updates MetaInfResourceManager to encode the path before it is used to create a URL. Prior to this encoding, encoded slashes (%2F) are decoded as, unlike other encoded characters in the request's URL, encoded slashes are not decoded prior to calling the ResourceManager. Fixes gh-17853
This commit is contained in:
parent
674f2f5a6c
commit
9961647c7f
@ -18,8 +18,8 @@ package org.springframework.boot.web.embedded.undertow;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -32,6 +32,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
@ -94,6 +95,8 @@ import org.springframework.util.Assert;
|
||||
public class UndertowServletWebServerFactory extends AbstractServletWebServerFactory
|
||||
implements ConfigurableUndertowWebServerFactory, ResourceLoaderAware {
|
||||
|
||||
private static final Pattern ENCODED_SLASH = Pattern.compile("%2F", Pattern.LITERAL);
|
||||
|
||||
private static final Set<Class<?>> NO_CLASSES = Collections.emptySet();
|
||||
|
||||
private List<UndertowBuilderCustomizer> builderCustomizers = new ArrayList<>();
|
||||
@ -578,14 +581,15 @@ public class UndertowServletWebServerFactory extends AbstractServletWebServerFac
|
||||
|
||||
private URLResource getMetaInfResource(URL resourceJar, String path) {
|
||||
try {
|
||||
URL resourceUrl = new URL(resourceJar + "META-INF/resources" + path);
|
||||
String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), "UTF-8");
|
||||
URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath);
|
||||
URLResource resource = new URLResource(resourceUrl, path);
|
||||
if (resource.getContentLength() < 0) {
|
||||
return null;
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,10 @@ class ApplicationBuilder {
|
||||
resourcesJarStream.putNextEntry(new ZipEntry("META-INF/resources/nested-meta-inf-resource.txt"));
|
||||
resourcesJarStream.write("nested".getBytes());
|
||||
resourcesJarStream.closeEntry();
|
||||
resourcesJarStream.putNextEntry(
|
||||
new ZipEntry("META-INF/resources/nested-reserved-!#$%&()*+,:=?@[]-meta-inf-resource.txt"));
|
||||
resourcesJarStream.write("encoded-name".getBytes());
|
||||
resourcesJarStream.closeEntry();
|
||||
return resourcesJar;
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,15 @@ public class EmbeddedServletContainerJarDevelopmentIntegrationTests
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyWithNameThatContainsReservedCharactersIsAvailableViaHttp() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("encoded-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaServletContext() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/servletContext?/nested-meta-inf-resource.txt",
|
||||
|
@ -54,6 +54,15 @@ public class EmbeddedServletContainerJarPackagingIntegrationTests
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceWithNameThatContainsReservedCharactersIsAvailableViaHttp() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("encoded-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaServletContext() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/servletContext?/nested-meta-inf-resource.txt",
|
||||
|
@ -60,6 +60,15 @@ public class EmbeddedServletContainerWarDevelopmentIntegrationTests
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyWithNameThatContainsReservedCharactersIsAvailableViaHttp() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("encoded-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaServletContext() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/servletContext?/nested-meta-inf-resource.txt",
|
||||
|
@ -60,6 +60,15 @@ public class EmbeddedServletContainerWarPackagingIntegrationTests
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceWithNameThatContainsReservedCharactersIsAvailableViaHttp() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("encoded-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaServletContext() {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/servletContext?/nested-meta-inf-resource.txt",
|
||||
|
Loading…
Reference in New Issue
Block a user