Merge branch '5.3.x'
This commit is contained in:
		
						commit
						5e979af95a
					
				|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2002-2021 the original author or authors. | ||||
|  * Copyright 2002-2022 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. | ||||
|  | @ -259,10 +259,15 @@ public class PathResourceResolver extends AbstractResourceResolver { | |||
| 	} | ||||
| 
 | ||||
| 	private String encodeOrDecodeIfNecessary(String path, @Nullable HttpServletRequest request, Resource location) { | ||||
| 		if (shouldDecodeRelativePath(location, request)) { | ||||
| 		if (request != null) { | ||||
| 			boolean usesPathPattern = ( | ||||
| 					ServletRequestPathUtils.hasCachedPath(request) && | ||||
| 					ServletRequestPathUtils.getCachedPath(request) instanceof PathContainer); | ||||
| 
 | ||||
| 			if (shouldDecodeRelativePath(location, usesPathPattern)) { | ||||
| 				return UriUtils.decode(path, StandardCharsets.UTF_8); | ||||
| 			} | ||||
| 		else if (shouldEncodeRelativePath(location) && request != null) { | ||||
| 			else if (shouldEncodeRelativePath(location, usesPathPattern)) { | ||||
| 				Charset charset = this.locationCharsets.getOrDefault(location, StandardCharsets.UTF_8); | ||||
| 				StringBuilder sb = new StringBuilder(); | ||||
| 				StringTokenizer tokenizer = new StringTokenizer(path, "/"); | ||||
|  | @ -276,19 +281,25 @@ public class PathResourceResolver extends AbstractResourceResolver { | |||
| 				} | ||||
| 				return sb.toString(); | ||||
| 			} | ||||
| 		else { | ||||
| 		} | ||||
| 		return path; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * When the {@code HandlerMapping} is set to not decode the URL path, the | ||||
| 	 * path needs to be decoded for non-{@code UrlResource} locations. | ||||
| 	 */ | ||||
| 	private boolean shouldDecodeRelativePath(Resource location, boolean usesPathPattern) { | ||||
| 		return (!(location instanceof UrlResource) && | ||||
| 				(usesPathPattern || (this.urlPathHelper != null && !this.urlPathHelper.isUrlDecode()))); | ||||
| 	} | ||||
| 
 | ||||
| 	private boolean shouldDecodeRelativePath(Resource location, @Nullable HttpServletRequest request) { | ||||
| 		return  (!(location instanceof UrlResource) && request != null && | ||||
| 				ServletRequestPathUtils.hasCachedPath(request) && | ||||
| 				ServletRequestPathUtils.getCachedPath(request) instanceof PathContainer); | ||||
| 	} | ||||
| 
 | ||||
| 	private boolean shouldEncodeRelativePath(Resource location) { | ||||
| 		return (location instanceof UrlResource && | ||||
| 	/** | ||||
| 	 * When the {@code HandlerMapping} is set to decode the URL path, the path | ||||
| 	 * needs to be encoded for {@code UrlResource} locations. | ||||
| 	 */ | ||||
| 	private boolean shouldEncodeRelativePath(Resource location, boolean usesPathPattern) { | ||||
| 		return (location instanceof UrlResource && !usesPathPattern && | ||||
| 				this.urlPathHelper != null && this.urlPathHelper.isUrlDecode()); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2002-2021 the original author or authors. | ||||
|  * Copyright 2002-2022 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. | ||||
|  | @ -40,6 +40,7 @@ import org.springframework.web.testfixture.servlet.MockHttpServletResponse; | |||
| import org.springframework.web.testfixture.servlet.MockServletConfig; | ||||
| import org.springframework.web.testfixture.servlet.MockServletContext; | ||||
| import org.springframework.web.util.UriUtils; | ||||
| import org.springframework.web.util.UrlPathHelper; | ||||
| import org.springframework.web.util.pattern.PathPatternParser; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
|  | @ -59,23 +60,35 @@ public class ResourceHttpRequestHandlerIntegrationTests { | |||
| 
 | ||||
| 	public static Stream<Arguments> argumentSource() { | ||||
| 		return Stream.of( | ||||
| 				arguments(true, "/cp"), | ||||
| 				arguments(true, "/fs"), | ||||
| 				arguments(true, "/url"), | ||||
| 				arguments(false, "/cp"), | ||||
| 				arguments(false, "/fs"), | ||||
| 				arguments(false, "/url") | ||||
| 				// PathPattern | ||||
| 				arguments(true, true, "/cp"), | ||||
| 				arguments(true, true, "/fs"), | ||||
| 				arguments(true, true, "/url"), | ||||
| 
 | ||||
| 				arguments(true, false, "/cp"), | ||||
| 				arguments(true, false, "/fs"), | ||||
| 				arguments(true, false, "/url"), | ||||
| 
 | ||||
| 				// PathMatcher | ||||
| 				arguments(false, true, "/cp"), | ||||
| 				arguments(false, true, "/fs"), | ||||
| 				arguments(false, true, "/url"), | ||||
| 
 | ||||
| 				arguments(false, false, "/cp"), | ||||
| 				arguments(false, false, "/fs"), | ||||
| 				arguments(false, false, "/url") | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	@ParameterizedTest | ||||
| 	@MethodSource("argumentSource") | ||||
| 	void cssFile(boolean usePathPatterns, String pathPrefix) throws Exception { | ||||
| 	void cssFile(boolean usePathPatterns, boolean decodingUrlPathHelper, String pathPrefix) throws Exception { | ||||
| 
 | ||||
| 		MockHttpServletRequest request = initRequest(pathPrefix + "/test/foo.css"); | ||||
| 		MockHttpServletResponse response = new MockHttpServletResponse(); | ||||
| 
 | ||||
| 		DispatcherServlet servlet = initDispatcherServlet(usePathPatterns, WebConfig.class); | ||||
| 		DispatcherServlet servlet = initDispatcherServlet(usePathPatterns, decodingUrlPathHelper, WebConfig.class); | ||||
| 		servlet.service(request, response); | ||||
| 
 | ||||
| 		String description = "usePathPattern=" + usePathPatterns + ", prefix=" + pathPrefix; | ||||
|  | @ -85,12 +98,14 @@ public class ResourceHttpRequestHandlerIntegrationTests { | |||
| 	} | ||||
| 
 | ||||
| 	@ParameterizedTest | ||||
| 	@MethodSource("argumentSource") | ||||
| 	void classpathLocationWithEncodedPath(boolean usePathPatterns, String pathPrefix) throws Exception { | ||||
| 	@MethodSource("argumentSource") // gh-26775 | ||||
| 	void classpathLocationWithEncodedPath( | ||||
| 			boolean usePathPatterns, boolean decodingUrlPathHelper, String pathPrefix) throws Exception { | ||||
| 
 | ||||
| 		MockHttpServletRequest request = initRequest(pathPrefix + "/test/foo with spaces.css"); | ||||
| 		MockHttpServletResponse response = new MockHttpServletResponse(); | ||||
| 
 | ||||
| 		DispatcherServlet servlet = initDispatcherServlet(usePathPatterns, WebConfig.class); | ||||
| 		DispatcherServlet servlet = initDispatcherServlet(usePathPatterns, decodingUrlPathHelper, WebConfig.class); | ||||
| 		servlet.service(request, response); | ||||
| 
 | ||||
| 		String description = "usePathPattern=" + usePathPatterns + ", prefix=" + pathPrefix; | ||||
|  | @ -99,14 +114,16 @@ public class ResourceHttpRequestHandlerIntegrationTests { | |||
| 		assertThat(response.getContentAsString()).as(description).isEqualTo("h1 { color:red; }"); | ||||
| 	} | ||||
| 
 | ||||
| 	private DispatcherServlet initDispatcherServlet(boolean usePathPatterns, Class<?>... configClasses) | ||||
| 			throws ServletException { | ||||
| 	private DispatcherServlet initDispatcherServlet( | ||||
| 			boolean usePathPatterns, boolean decodingUrlPathHelper, Class<?>... configClasses) throws ServletException { | ||||
| 
 | ||||
| 		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); | ||||
| 		context.register(configClasses); | ||||
| 		if (usePathPatterns) { | ||||
| 			context.register(PathPatternParserConfig.class); | ||||
| 		} | ||||
| 		context.register(decodingUrlPathHelper ? | ||||
| 				DecodingUrlPathHelperConfig.class : NonDecodingUrlPathHelperConfig.class); | ||||
| 		context.setServletConfig(this.servletConfig); | ||||
| 		context.refresh(); | ||||
| 
 | ||||
|  | @ -129,41 +146,36 @@ public class ResourceHttpRequestHandlerIntegrationTests { | |||
| 
 | ||||
| 		@Override | ||||
| 		public void addResourceHandlers(ResourceHandlerRegistry registry) { | ||||
| 
 | ||||
| 			ClassPathResource classPathLocation = new ClassPathResource("", getClass()); | ||||
| 			String path = getPath(classPathLocation); | ||||
| 
 | ||||
| 			registerClasspathLocation("/cp/**", classPathLocation, registry); | ||||
| 			registerFileSystemLocation("/fs/**", path, registry); | ||||
| 			registerUrlLocation("/url/**", "file:" + path, registry); | ||||
| 		} | ||||
| 
 | ||||
| 		protected void registerClasspathLocation(String pattern, ClassPathResource resource, ResourceHandlerRegistry registry) { | ||||
| 			registry.addResourceHandler(pattern).addResourceLocations(resource); | ||||
| 		} | ||||
| 
 | ||||
| 		protected void registerFileSystemLocation(String pattern, String path, ResourceHandlerRegistry registry) { | ||||
| 			FileSystemResource fileSystemLocation = new FileSystemResource(path); | ||||
| 			registry.addResourceHandler(pattern).addResourceLocations(fileSystemLocation); | ||||
| 		} | ||||
| 
 | ||||
| 		protected void registerUrlLocation(String pattern, String path, ResourceHandlerRegistry registry) { | ||||
| 			try { | ||||
| 				UrlResource urlLocation = new UrlResource(path); | ||||
| 				registry.addResourceHandler(pattern).addResourceLocations(urlLocation); | ||||
| 			} | ||||
| 			catch (MalformedURLException ex) { | ||||
| 				throw new IllegalStateException(ex); | ||||
| 			} | ||||
| 			registry.addResourceHandler("/cp/**").addResourceLocations(classPathLocation); | ||||
| 			registry.addResourceHandler("/fs/**").addResourceLocations(new FileSystemResource(path)); | ||||
| 			registry.addResourceHandler("/url/**").addResourceLocations(urlResource(path)); | ||||
| 		} | ||||
| 
 | ||||
| 		private String getPath(ClassPathResource resource) { | ||||
| 			try { | ||||
| 				return resource.getFile().getCanonicalPath().replace('\\', '/').replace("classes/java", "resources") + "/"; | ||||
| 				return resource.getFile().getCanonicalPath() | ||||
| 						.replace('\\', '/') | ||||
| 						.replace("classes/java", "resources") + "/"; | ||||
| 			} | ||||
| 			catch (IOException ex) { | ||||
| 				throw new IllegalStateException(ex); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private UrlResource urlResource(String path) { | ||||
| 			UrlResource urlResource; | ||||
| 			try { | ||||
| 				urlResource = new UrlResource("file:" + path); | ||||
| 			} | ||||
| 			catch (MalformedURLException ex) { | ||||
| 				throw new IllegalStateException(ex); | ||||
| 			} | ||||
| 			return urlResource; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|  | @ -175,4 +187,26 @@ public class ResourceHttpRequestHandlerIntegrationTests { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	static class DecodingUrlPathHelperConfig implements WebMvcConfigurer { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void configurePathMatch(PathMatchConfigurer configurer) { | ||||
| 			UrlPathHelper helper = new UrlPathHelper(); | ||||
| 			helper.setUrlDecode(true); | ||||
| 			configurer.setUrlPathHelper(helper); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	static class NonDecodingUrlPathHelperConfig implements WebMvcConfigurer { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void configurePathMatch(PathMatchConfigurer configurer) { | ||||
| 			UrlPathHelper helper = new UrlPathHelper(); | ||||
| 			helper.setUrlDecode(false); | ||||
| 			configurer.setUrlPathHelper(helper); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue