/** * Look for a {@code PathResourceResolver} among the configured resource * resolvers and set its {@code allowedLocations} property (if empty) to * match the {@link #setLocations locations} configured on this class. */ protected void initAllowedLocations() { if (CollectionUtils.isEmpty(this.locations)) { return; } for (int i = getResourceResolvers().size() - 1; i >= 0; i--) { if (getResourceResolvers().get(i) instanceof PathResourceResolver) { PathResourceResolver pathResolver = (PathResourceResolver) getResourceResolvers().get(i); if (ObjectUtils.isEmpty(pathResolver.getAllowedLocations())) { pathResolver.setAllowedLocations(getLocations().toArray(new Resource[0])); } if (this.urlPathHelper != null) { pathResolver.setLocationCharsets(this.locationCharsets); pathResolver.setUrlPathHelper(this.urlPathHelper); } break; } } }
Resource resource = getResource(request); if (resource == null) { logger.debug("Resource not found"); response.setHeader("Allow", getAllowHeader()); return; checkRequest(request); prepareResponse(response); MediaType mediaType = getMediaType(request, resource); setHeaders(response, resource, mediaType); return; if (request.getHeader(HttpHeaders.RANGE) == null) { Assert.state(this.resourceHttpMessageConverter != null, "Not initialized"); setHeaders(response, resource, mediaType); this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
@Test // SPR-14368 public void getResourceWithMediaTypeResolvedThroughServletContext() throws Exception { MockServletContext servletContext = new MockServletContext() { @Override public String getMimeType(String filePath) { return "foo/bar"; } @Override public String getVirtualServerName() { return ""; } }; List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass())); ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); handler.setServletContext(servletContext); handler.setLocations(paths); handler.afterPropertiesSet(); this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css"); handler.handleRequest(this.request, this.response); assertEquals("foo/bar", this.response.getContentType()); assertEquals("h1 { color:red; }", this.response.getContentAsString()); }
/** * Return a {@link ResourceHttpRequestHandler} instance. */ protected ResourceHttpRequestHandler getRequestHandler() { ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); if (this.resourceChainRegistration != null) { handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers()); handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers()); } handler.setLocationValues(this.locationValues); if (this.cacheControl != null) { handler.setCacheControl(this.cacheControl); } else if (this.cachePeriod != null) { handler.setCacheSeconds(this.cachePeriod); } return handler; }
/** * Check whether the given path contains invalid escape sequences. * @param path the path to validate * @return {@code true} if the path is invalid, {@code false} otherwise */ private boolean isInvalidEncodedPath(String path) { if (path.contains("%")) { try { // Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8 chars String decodedPath = URLDecoder.decode(path, "UTF-8"); if (isInvalidPath(decodedPath)) { return true; } decodedPath = processPath(decodedPath); if (isInvalidPath(decodedPath)) { return true; } } catch (IllegalArgumentException | UnsupportedEncodingException ex) { // Should never happen... } } return false; }
@Nullable protected Resource getResource(HttpServletRequest request) throws IOException { String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); if (path == null) { throw new IllegalStateException("Required request attribute '" + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); } path = processPath(path); if (!StringUtils.hasText(path) || isInvalidPath(path)) { return null; } if (isInvalidEncodedPath(path)) { return null; } Assert.notNull(this.resolverChain, "ResourceResolverChain not initialized."); Assert.notNull(this.transformerChain, "ResourceTransformerChain not initialized."); Resource resource = this.resolverChain.resolveResource(request, path, getLocations()); if (resource != null) { resource = this.transformerChain.transform(request, resource); } return resource; }
ResourceHttpRequestHandler handler = registration.getRequestHandler(); if (this.pathHelper != null) { handler.setUrlPathHelper(this.pathHelper); handler.setContentNegotiationManager(this.contentNegotiationManager); handler.setServletContext(this.servletContext); handler.setApplicationContext(this.applicationContext); try { handler.afterPropertiesSet();
@Test(expected = IllegalStateException.class) public void noPathWithinHandlerMappingAttribute() throws Exception { this.handler.handleRequest(this.request, this.response); }
@Test public void initAllowedLocationsWithExplicitConfiguration() throws Exception { ClassPathResource location1 = new ClassPathResource("test/", getClass()); ClassPathResource location2 = new ClassPathResource("testalternatepath/", getClass()); PathResourceResolver pathResolver = new PathResourceResolver(); pathResolver.setAllowedLocations(location1); ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); handler.setResourceResolvers(Collections.singletonList(pathResolver)); handler.setServletContext(new MockServletContext()); handler.setLocations(Arrays.asList(location1, location2)); handler.afterPropertiesSet(); Resource[] locations = pathResolver.getAllowedLocations(); assertEquals(1, locations.length); assertEquals("test/", ((ClassPathResource) locations[0]).getPath()); }
@Before public void setup() throws Exception { List<Resource> paths = new ArrayList<>(2); paths.add(new ClassPathResource("test/", getClass())); paths.add(new ClassPathResource("testalternatepath/", getClass())); paths.add(new ClassPathResource("META-INF/resources/webjars/")); this.handler = new ResourceHttpRequestHandler(); this.handler.setLocations(paths); this.handler.setCacheSeconds(3600); this.handler.setServletContext(new TestServletContext()); this.handler.afterPropertiesSet(); this.request = new MockHttpServletRequest("GET", ""); this.response = new MockHttpServletResponse(); }
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) { ResourceHttpRequestHandler resourceHandler = new ResourceHttpRequestHandler(); resourceHandler.setResourceResolvers(resolvers); resourceHandler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass()))); ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider(); resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler)); return resourceUrlProvider; }
@Test public void getVersionedResource() throws Exception { VersionResourceResolver versionResolver = new VersionResourceResolver() .addFixedVersionStrategy("versionString", "/**"); this.handler.setResourceResolvers(Arrays.asList(versionResolver, new PathResourceResolver())); this.handler.afterPropertiesSet(); this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "versionString/foo.css"); this.handler.handleRequest(this.request, this.response); assertEquals("\"versionString\"", this.response.getHeader("ETag")); assertEquals("bytes", this.response.getHeader("Accept-Ranges")); assertEquals(1, this.response.getHeaders("Accept-Ranges").size()); }
@Test @SuppressWarnings("deprecation") public void getResourceHttp10BehaviorCache() throws Exception { this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css"); this.handler.setCacheSeconds(3600); this.handler.setUseExpiresHeader(true); this.handler.setUseCacheControlHeader(true); this.handler.setAlwaysMustRevalidate(true); this.handler.handleRequest(this.request, this.response); assertEquals("max-age=3600, must-revalidate", this.response.getHeader("Cache-Control")); assertTrue(this.response.getDateHeader("Expires") >= System.currentTimeMillis() - 1000 + (3600 * 1000)); assertTrue(this.response.containsHeader("Last-Modified")); assertEquals(resourceLastModified("test/foo.css") / 1000, this.response.getDateHeader("Last-Modified") / 1000); assertEquals("bytes", this.response.getHeader("Accept-Ranges")); assertEquals(1, this.response.getHeaders("Accept-Ranges").size()); }
@Test @SuppressWarnings("deprecation") public void getResourceHttp10BehaviorNoCache() throws Exception { this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css"); this.handler.setCacheSeconds(0); this.handler.setUseExpiresHeader(true); this.handler.setUseCacheControlNoStore(false); this.handler.setUseCacheControlHeader(true); this.handler.handleRequest(this.request, this.response); assertEquals("no-cache", this.response.getHeader("Pragma")); assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.iterableWithSize(1)); assertEquals("no-cache", this.response.getHeader("Cache-Control")); assertTrue(this.response.getDateHeader("Expires") <= System.currentTimeMillis()); assertTrue(this.response.containsHeader("Last-Modified")); assertEquals(resourceLastModified("test/foo.css") / 1000, this.response.getDateHeader("Last-Modified") / 1000); assertEquals("bytes", this.response.getHeader("Accept-Ranges")); assertEquals(1, this.response.getHeaders("Accept-Ranges").size()); }
@Test public void urlResourceWithCharset() throws Exception { this.registration.addResourceLocations("[charset=ISO-8859-1]file:///tmp"); this.registration.resourceChain(true); ResourceHttpRequestHandler handler = getHandler("/resources/**"); UrlResource resource = (UrlResource) handler.getLocations().get(1); assertEquals("file:/tmp", resource.getURL().toString()); assertNotNull(handler.getUrlPathHelper()); List<ResourceResolver> resolvers = handler.getResourceResolvers(); PathResourceResolver resolver = (PathResourceResolver) resolvers.get(resolvers.size()-1); Map<Resource, Charset> locationCharsets = resolver.getLocationCharsets(); assertEquals(1, locationCharsets.size()); assertEquals(StandardCharsets.ISO_8859_1, locationCharsets.values().iterator().next()); }
@Before public void setUp() throws Exception { this.locations.add(new ClassPathResource("test/", getClass())); this.locations.add(new ClassPathResource("testalternatepath/", getClass())); this.handler.setServletContext(new MockServletContext()); this.handler.setLocations(locations); this.handler.afterPropertiesSet(); this.handlerMap.put("/resources/**", this.handler); this.urlProvider.setHandlerMap(this.handlerMap); }
@Test public void resourceChainWithoutCaching() throws Exception { this.registration.resourceChain(false); ResourceHttpRequestHandler handler = getHandler("/resources/**"); List<ResourceResolver> resolvers = handler.getResourceResolvers(); assertThat(resolvers, Matchers.hasSize(2)); assertThat(resolvers.get(0), Matchers.instanceOf(WebJarsResourceResolver.class)); assertThat(resolvers.get(1), Matchers.instanceOf(PathResourceResolver.class)); List<ResourceTransformer> transformers = handler.getResourceTransformers(); assertThat(transformers, Matchers.hasSize(0)); }
@Test // SPR-16296 public void getForLookupPathShouldNotFailIfPathContainsDoubleSlashes() { // given ResourceResolver mockResourceResolver = mock(ResourceResolver.class); when(mockResourceResolver.resolveUrlPath(any(), any(), any())).thenReturn("some-path"); ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); handler.getResourceResolvers().add(mockResourceResolver); ResourceUrlProvider provider = new ResourceUrlProvider(); provider.getHandlerMap().put("/some-pattern/**", handler); // when String lookupForPath = provider.getForLookupPath("/some-pattern/some-lib//some-resource"); // then assertEquals("/some-pattern/some-path", lookupForPath); }
@Test public void getResourceNoCache() throws Exception { this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css"); this.handler.setCacheSeconds(0); this.handler.handleRequest(this.request, this.response); assertEquals("no-store", this.response.getHeader("Cache-Control")); assertTrue(this.response.containsHeader("Last-Modified")); assertEquals(resourceLastModified("test/foo.css") / 1000, this.response.getDateHeader("Last-Modified") / 1000); assertEquals("bytes", this.response.getHeader("Accept-Ranges")); assertEquals(1, this.response.getHeaders("Accept-Ranges").size()); }
/** * {@inheritDoc} * * Overriding to handle case where media type was unknown to default to Text */ @Override protected MediaType getMediaType(final HttpServletRequest request, final Resource resource) { final MediaType mediaType = super.getMediaType(request, resource); return mediaType == null ? MediaType.TEXT_PLAIN : mediaType; } }