Polish resource handling tests
This commit is contained in:
parent
f121aa5e31
commit
9274de390a
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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,25 +18,20 @@ package org.springframework.web.reactive.resource;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
|
||||||
import static org.mockito.BDDMockito.mock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link AppCacheManifestTransformer}.
|
* Unit tests for {@link AppCacheManifestTransformer}.
|
||||||
|
@ -45,6 +40,9 @@ import static org.mockito.BDDMockito.mock;
|
||||||
*/
|
*/
|
||||||
public class AppCacheManifestTransformerTests {
|
public class AppCacheManifestTransformerTests {
|
||||||
|
|
||||||
|
private static final Duration TIMEOUT = Duration.ofSeconds(5);
|
||||||
|
|
||||||
|
|
||||||
private AppCacheManifestTransformer transformer;
|
private AppCacheManifestTransformer transformer;
|
||||||
|
|
||||||
private ResourceTransformerChain chain;
|
private ResourceTransformerChain chain;
|
||||||
|
@ -52,92 +50,76 @@ public class AppCacheManifestTransformerTests {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
|
|
||||||
ResourceWebHandler resourceHandler = new ResourceWebHandler();
|
|
||||||
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
|
|
||||||
resourceUrlProvider.registerHandlers(Collections.singletonMap("/static/**", resourceHandler));
|
|
||||||
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
pathResolver.setAllowedLocations(allowedLocation);
|
resolvers.add(versionResolver);
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
resolvers.add(new PathResourceResolver());
|
||||||
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
||||||
|
|
||||||
CssLinkResourceTransformer cssLinkResourceTransformer = new CssLinkResourceTransformer();
|
this.chain = new DefaultResourceTransformerChain(resolverChain, Collections.emptyList());
|
||||||
cssLinkResourceTransformer.setResourceUrlProvider(resourceUrlProvider);
|
|
||||||
List<ResourceTransformer> transformers = Collections.singletonList(cssLinkResourceTransformer);
|
|
||||||
this.chain = new DefaultResourceTransformerChain(resolverChain, transformers);
|
|
||||||
this.transformer = new AppCacheManifestTransformer();
|
this.transformer = new AppCacheManifestTransformer();
|
||||||
this.transformer.setResourceUrlProvider(resourceUrlProvider);
|
this.transformer.setResourceUrlProvider(createUrlProvider(resolvers));
|
||||||
|
}
|
||||||
|
|
||||||
resourceHandler.setResourceResolvers(resolvers);
|
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
resourceHandler.setResourceTransformers(transformers);
|
ResourceWebHandler handler = new ResourceWebHandler();
|
||||||
resourceHandler.setLocations(Collections.singletonList(allowedLocation));
|
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
||||||
|
handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
|
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
|
urlProvider.registerHandlers(Collections.singletonMap("/static/**", handler));
|
||||||
|
return urlProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noTransformIfExtensionNoMatch() throws Exception {
|
public void noTransformIfExtensionDoesNotMatch() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("/static/foobar.file").build();
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/foo.css"));
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
Resource expected = getResource("foo.css");
|
||||||
this.chain = mock(ResourceTransformerChain.class);
|
Resource actual = this.transformer.transform(exchange, expected, this.chain).block(TIMEOUT);
|
||||||
Resource resource = mock(Resource.class);
|
|
||||||
given(resource.getFilename()).willReturn("foobar.file");
|
|
||||||
given(this.chain.transform(exchange, resource)).willReturn(Mono.just(resource));
|
|
||||||
|
|
||||||
Resource result = this.transformer.transform(exchange, resource, this.chain).block(Duration.ofMillis(5000));
|
assertSame(expected, actual);
|
||||||
assertEquals(resource, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void syntaxErrorInManifest() throws Exception {
|
public void syntaxErrorInManifest() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("/static/error.appcache").build();
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/error.appcache"));
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
Resource expected = getResource("error.appcache");
|
||||||
this.chain = mock(ResourceTransformerChain.class);
|
Resource actual = this.transformer.transform(exchange, expected, this.chain).block(TIMEOUT);
|
||||||
Resource resource = new ClassPathResource("test/error.appcache", getClass());
|
|
||||||
given(this.chain.transform(exchange, resource)).willReturn(Mono.just(resource));
|
|
||||||
|
|
||||||
Resource result = this.transformer.transform(exchange, resource, this.chain).block(Duration.ofMillis(5000));
|
assertEquals(expected, actual);
|
||||||
assertEquals(resource, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformManifest() throws Exception {
|
public void transformManifest() throws Exception {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("/static/test.appcache").build();
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/test.appcache"));
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
Resource resource = getResource("test.appcache");
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
Resource actual = this.transformer.transform(exchange, resource, this.chain).block(TIMEOUT);
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
|
||||||
|
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
assertNotNull(actual);
|
||||||
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
byte[] bytes = FileCopyUtils.copyToByteArray(actual.getInputStream());
|
||||||
|
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
|
||||||
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
|
||||||
|
|
||||||
List<ResourceTransformer> transformers = new ArrayList<>();
|
|
||||||
transformers.add(new CssLinkResourceTransformer());
|
|
||||||
this.chain = new DefaultResourceTransformerChain(resolverChain, transformers);
|
|
||||||
|
|
||||||
Resource resource = new ClassPathResource("test/test.appcache", getClass());
|
|
||||||
Resource result = this.transformer.transform(exchange, resource, this.chain).block(Duration.ofMillis(5000));
|
|
||||||
byte[] bytes = FileCopyUtils.copyToByteArray(result.getInputStream());
|
|
||||||
String content = new String(bytes, "UTF-8");
|
String content = new String(bytes, "UTF-8");
|
||||||
|
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css"));
|
containsString("/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css"));
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/bar-11e16cf79faee7ac698c805cf28248d2.css"));
|
containsString("/static/bar-11e16cf79faee7ac698c805cf28248d2.css"));
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/js/bar-bd508c62235b832d960298ca6c0b7645.js"));
|
containsString("/static/js/bar-bd508c62235b832d960298ca6c0b7645.js"));
|
||||||
|
|
||||||
assertThat("should not rewrite external resources", content,
|
assertThat("should not rewrite external resources", content, containsString("//example.org/style.css"));
|
||||||
Matchers.containsString("//example.org/style.css"));
|
assertThat("should not rewrite external resources", content, containsString("http://example.org/image.png"));
|
||||||
assertThat("should not rewrite external resources", content,
|
|
||||||
Matchers.containsString("http://example.org/image.png"));
|
// Not the same hash as Spring MVC
|
||||||
|
// Hash is computed from links, and not from the linked content
|
||||||
|
|
||||||
assertThat("should generate fingerprint", content,
|
assertThat("should generate fingerprint", content,
|
||||||
Matchers.containsString("# Hash: 8eefc904df3bd46537fa7bdbbc5ab9fb"));
|
containsString("# Hash: 8eefc904df3bd46537fa7bdbbc5ab9fb"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -31,9 +31,7 @@ import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link CachingResourceResolver}.
|
* Unit tests for {@link CachingResourceResolver}.
|
||||||
|
@ -69,23 +67,21 @@ public class CachingResourceResolverTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceInternal() {
|
public void resolveResourceInternal() {
|
||||||
String file = "bar.css";
|
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
||||||
Resource expected = new ClassPathResource("test/" + file, getClass());
|
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
Resource actual = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
Resource actual = this.chain.resolveResource(exchange, "bar.css", this.locations).block(TIMEOUT);
|
||||||
|
|
||||||
|
assertNotSame(expected, actual);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceInternalFromCache() {
|
public void resolveResourceInternalFromCache() {
|
||||||
|
|
||||||
Resource expected = Mockito.mock(Resource.class);
|
Resource expected = Mockito.mock(Resource.class);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", expected);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", expected);
|
||||||
|
|
||||||
String file = "bar.css";
|
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
Resource actual = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
Resource actual = this.chain.resolveResource(exchange, "bar.css", this.locations).block(TIMEOUT);
|
||||||
|
|
||||||
assertSame(expected, actual);
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
@ -121,39 +117,41 @@ public class CachingResourceResolverTests {
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceAcceptEncodingInCacheKey() {
|
public void resolveResourceAcceptEncodingInCacheKey() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file)
|
MockServerHttpRequest request = MockServerHttpRequest.get(file).header("Accept-Encoding", "gzip").build();
|
||||||
.header("Accept-Encoding", "gzip"));
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
|
|
||||||
Resource expected = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
Resource expected = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
||||||
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file + "+encoding=gzip";
|
|
||||||
|
|
||||||
assertEquals(expected, this.cache.get(cacheKey).get());
|
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file + "+encoding=gzip";
|
||||||
|
Object actual = this.cache.get(cacheKey).get();
|
||||||
|
|
||||||
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceNoAcceptEncodingInCacheKey() {
|
public void resolveResourceNoAcceptEncoding() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file));
|
||||||
|
|
||||||
Resource expected = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
Resource expected = this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT);
|
||||||
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file;
|
|
||||||
|
|
||||||
assertEquals(expected, this.cache.get(cacheKey).get());
|
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file;
|
||||||
|
Object actual = this.cache.get(cacheKey).get();
|
||||||
|
|
||||||
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceMatchingEncoding() {
|
public void resolveResourceMatchingEncoding() {
|
||||||
Resource resource = Mockito.mock(Resource.class);
|
Resource resource = Mockito.mock(Resource.class);
|
||||||
Resource gzResource = Mockito.mock(Resource.class);
|
Resource gzipped = Mockito.mock(Resource.class);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", resource);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", resource);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css+encoding=gzip", gzResource);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css+encoding=gzip", gzipped);
|
||||||
|
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file));
|
||||||
assertSame(resource, this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT));
|
assertSame(resource, this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT));
|
||||||
|
|
||||||
exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file).header("Accept-Encoding", "gzip"));
|
exchange = MockServerWebExchange.from(MockServerHttpRequest.get(file).header("Accept-Encoding", "gzip"));
|
||||||
assertSame(gzResource, this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT));
|
assertSame(gzipped, this.chain.resolveResource(exchange, file, this.locations).block(TIMEOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -45,7 +45,7 @@ public class ContentBasedVersionStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extractVersion() throws Exception {
|
public void extractVersion() {
|
||||||
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
||||||
String path = "font-awesome/css/font-awesome.min-" + hash + ".css";
|
String path = "font-awesome/css/font-awesome.min-" + hash + ".css";
|
||||||
|
|
||||||
|
@ -54,26 +54,25 @@ public class ContentBasedVersionStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeVersion() throws Exception {
|
public void removeVersion() {
|
||||||
String file = "font-awesome/css/font-awesome.min%s%s.css";
|
|
||||||
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
||||||
|
String path = "font-awesome/css/font-awesome.min%s%s.css";
|
||||||
|
|
||||||
assertEquals(String.format(file, "", ""), this.strategy.removeVersion(String.format(file, "-", hash), hash));
|
assertEquals(String.format(path, "", ""),
|
||||||
assertNull(this.strategy.extractVersion("foo/bar.css"));
|
this.strategy.removeVersion(String.format(path, "-", hash), hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResourceVersion() throws Exception {
|
public void getResourceVersion() throws Exception {
|
||||||
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
||||||
String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream()));
|
String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream()));
|
||||||
|
|
||||||
assertEquals(hash, this.strategy.getResourceVersion(expected).block());
|
assertEquals(hash, this.strategy.getResourceVersion(expected).block());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addVersionToUrl() throws Exception {
|
public void addVersionToUrl() {
|
||||||
String requestPath = "test/bar.css";
|
assertEquals("test/bar-123.css", this.strategy.addVersion("test/bar.css", "123"));
|
||||||
String version = "123";
|
|
||||||
assertEquals("test/bar-123.css", this.strategy.addVersion(requestPath, version));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -16,12 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.web.reactive.resource;
|
package org.springframework.web.reactive.resource;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.util.ArrayList;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -32,12 +28,12 @@ import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.reactive.resource.EncodedResourceResolver.EncodedResource;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link CssLinkResourceTransformer}.
|
* Unit tests for {@link CssLinkResourceTransformer}.
|
||||||
|
@ -50,35 +46,35 @@ public class CssLinkResourceTransformerTests {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
|
|
||||||
ResourceWebHandler resourceHandler = new ResourceWebHandler();
|
|
||||||
|
|
||||||
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
|
|
||||||
resourceUrlProvider.registerHandlers(Collections.singletonMap("/static/**", resourceHandler));
|
|
||||||
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
pathResolver.setAllowedLocations(allowedLocation);
|
resolvers.add(versionResolver);
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
resolvers.add(new PathResourceResolver());
|
||||||
|
|
||||||
CssLinkResourceTransformer cssLinkResourceTransformer = new CssLinkResourceTransformer();
|
CssLinkResourceTransformer cssLinkTransformer = new CssLinkResourceTransformer();
|
||||||
cssLinkResourceTransformer.setResourceUrlProvider(resourceUrlProvider);
|
cssLinkTransformer.setResourceUrlProvider(createUrlProvider(resolvers));
|
||||||
List<ResourceTransformer> transformers = Collections.singletonList(cssLinkResourceTransformer);
|
|
||||||
|
|
||||||
resourceHandler.setResourceResolvers(resolvers);
|
this.transformerChain = new DefaultResourceTransformerChain(
|
||||||
resourceHandler.setResourceTransformers(transformers);
|
new DefaultResourceResolverChain(resolvers), Collections.singletonList(cssLinkTransformer));
|
||||||
resourceHandler.setLocations(Collections.singletonList(allowedLocation));
|
}
|
||||||
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
|
||||||
this.transformerChain = new DefaultResourceTransformerChain(resolverChain, transformers);
|
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
|
ResourceWebHandler handler = new ResourceWebHandler();
|
||||||
|
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
||||||
|
handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
|
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
|
urlProvider.registerHandlers(Collections.singletonMap("/static/**", handler));
|
||||||
|
return urlProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transform() throws Exception {
|
public void transform() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/main.css"));
|
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
|
||||||
|
|
||||||
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/main.css"));
|
||||||
|
Resource css = getResource("main.css");
|
||||||
String expected = "\n" +
|
String expected = "\n" +
|
||||||
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
|
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
|
||||||
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" +
|
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" +
|
||||||
|
@ -87,78 +83,84 @@ public class CssLinkResourceTransformerTests {
|
||||||
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
|
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
|
||||||
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n";
|
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n";
|
||||||
|
|
||||||
StepVerifier.create(this.transformerChain.transform(exchange, css).cast(TransformedResource.class))
|
StepVerifier.create(this.transformerChain.transform(exchange, css)
|
||||||
.consumeNextWith(resource -> {
|
.cast(TransformedResource.class))
|
||||||
String result = new String(resource.getByteArray(), StandardCharsets.UTF_8);
|
.consumeNextWith(transformedResource -> {
|
||||||
|
String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8);
|
||||||
result = StringUtils.deleteAny(result, "\r");
|
result = StringUtils.deleteAny(result, "\r");
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
})
|
})
|
||||||
.expectComplete().verify();
|
.expectComplete()
|
||||||
|
.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformNoLinks() throws Exception {
|
public void transformNoLinks() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/foo.css"));
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/foo.css"));
|
||||||
Resource expected = new ClassPathResource("test/foo.css", getClass());
|
Resource expected = getResource("foo.css");
|
||||||
|
|
||||||
StepVerifier.create(this.transformerChain.transform(exchange, expected))
|
StepVerifier.create(this.transformerChain.transform(exchange, expected))
|
||||||
.consumeNextWith(resource -> assertSame(expected, resource))
|
.consumeNextWith(resource -> assertSame(expected, resource))
|
||||||
.expectComplete().verify();
|
.expectComplete().verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformExtLinksNotAllowed() throws Exception {
|
public void transformExtLinksNotAllowed() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/external.css"));
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/external.css"));
|
||||||
ResourceResolverChain resolverChain = Mockito.mock(DefaultResourceResolverChain.class);
|
|
||||||
ResourceTransformerChain transformerChain = new DefaultResourceTransformerChain(resolverChain,
|
|
||||||
Collections.singletonList(new CssLinkResourceTransformer()));
|
|
||||||
|
|
||||||
Resource externalCss = new ClassPathResource("test/external.css", getClass());
|
List<ResourceTransformer> transformers = Collections.singletonList(new CssLinkResourceTransformer());
|
||||||
StepVerifier.create(transformerChain.transform(exchange, externalCss).cast(TransformedResource.class))
|
ResourceResolverChain mockChain = Mockito.mock(DefaultResourceResolverChain.class);
|
||||||
.consumeNextWith(resource -> {
|
ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers);
|
||||||
String expected = "@import url(\"http://example.org/fonts/css\");\n" +
|
|
||||||
"body { background: url(\"file:///home/spring/image.png\") }\n" +
|
Resource resource = getResource("external.css");
|
||||||
"figure { background: url(\"//example.org/style.css\")}";
|
String expected = "@import url(\"http://example.org/fonts/css\");\n" +
|
||||||
String result = new String(resource.getByteArray(), StandardCharsets.UTF_8);
|
"body { background: url(\"file:///home/spring/image.png\") }\n" +
|
||||||
|
"figure { background: url(\"//example.org/style.css\")}";
|
||||||
|
|
||||||
|
StepVerifier.create(chain.transform(exchange, resource)
|
||||||
|
.cast(TransformedResource.class))
|
||||||
|
.consumeNextWith(transformedResource -> {
|
||||||
|
String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8);
|
||||||
result = StringUtils.deleteAny(result, "\r");
|
result = StringUtils.deleteAny(result, "\r");
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}).expectComplete().verify();
|
})
|
||||||
|
.expectComplete()
|
||||||
|
.verify();
|
||||||
|
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
List<Resource> locations = Collections.singletonList(resource);
|
||||||
.resolveUrlPath("http://example.org/fonts/css", Collections.singletonList(externalCss));
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("http://example.org/fonts/css", locations);
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("file:///home/spring/image.png", locations);
|
||||||
.resolveUrlPath("file:///home/spring/image.png", Collections.singletonList(externalCss));
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("//example.org/style.css", locations);
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
|
||||||
.resolveUrlPath("//example.org/style.css", Collections.singletonList(externalCss));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformWithNonCssResource() throws Exception {
|
public void transformSkippedForNonCssResource() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/images/image.png"));
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/images/image.png"));
|
||||||
Resource expected = new ClassPathResource("test/images/image.png", getClass());
|
Resource expected = getResource("images/image.png");
|
||||||
|
|
||||||
StepVerifier.create(this.transformerChain.transform(exchange, expected))
|
StepVerifier.create(this.transformerChain.transform(exchange, expected))
|
||||||
.expectNext(expected)
|
.expectNext(expected)
|
||||||
.expectComplete().verify();
|
.expectComplete()
|
||||||
|
.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformWithGzippedResource() throws Exception {
|
public void transformSkippedForGzippedResource() throws Exception {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/main.css"));
|
|
||||||
Resource original = new ClassPathResource("test/main.css", getClass());
|
EncodedResourceResolverTests.createGzippedFile("main.css");
|
||||||
createTempCopy("main.css", "main.css.gz");
|
|
||||||
EncodedResourceResolver.EncodedResource expected =
|
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/main.css"));
|
||||||
new EncodedResourceResolver.EncodedResource(original, "gzip", ".gz");
|
Resource resource = getResource("main.css");
|
||||||
StepVerifier.create(this.transformerChain.transform(exchange, expected))
|
EncodedResource gzipped = new EncodedResource(resource, "gzip", ".gz");
|
||||||
.expectNext(expected)
|
|
||||||
.expectComplete().verify();
|
StepVerifier.create(this.transformerChain.transform(exchange, gzipped))
|
||||||
|
.expectNext(gzipped)
|
||||||
|
.expectComplete()
|
||||||
|
.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTempCopy(String filePath, String copyFilePath) throws IOException {
|
private Resource getResource(String filePath) {
|
||||||
Resource location = new ClassPathResource("test/", CssLinkResourceTransformerTests.class);
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
Path original = Paths.get(location.getFile().getAbsolutePath(), filePath);
|
|
||||||
Path copy = Paths.get(location.getFile().getAbsolutePath(), copyFilePath);
|
|
||||||
Files.deleteIfExists(copy);
|
|
||||||
Files.copy(original, copy);
|
|
||||||
copy.toFile().deleteOnExit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,11 @@ import java.nio.file.Paths;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
|
@ -63,11 +60,11 @@ public class EncodedResourceResolverTests {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void createGzippedResources() throws IOException {
|
public static void createGzippedResources() throws IOException {
|
||||||
createGzFile("/js/foo.js");
|
createGzippedFile("/js/foo.js");
|
||||||
createGzFile("foo.css");
|
createGzippedFile("foo.css");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createGzFile(String filePath) throws IOException {
|
static void createGzippedFile(String filePath) throws IOException {
|
||||||
Resource location = new ClassPathResource("test/", EncodedResourceResolverTests.class);
|
Resource location = new ClassPathResource("test/", EncodedResourceResolverTests.class);
|
||||||
Resource resource = new FileSystemResource(location.createRelative(filePath).getFile());
|
Resource resource = new FileSystemResource(location.createRelative(filePath).getFile());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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,8 +19,7 @@ package org.springframework.web.reactive.resource;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link FixedVersionStrategy}.
|
* Unit tests for {@link FixedVersionStrategy}.
|
||||||
|
@ -29,44 +28,45 @@ import static org.junit.Assert.assertNull;
|
||||||
*/
|
*/
|
||||||
public class FixedVersionStrategyTests {
|
public class FixedVersionStrategyTests {
|
||||||
|
|
||||||
private final String version = "1df341f";
|
private static final String VERSION = "1df341f";
|
||||||
|
|
||||||
|
private static final String PATH = "js/foo.js";
|
||||||
|
|
||||||
private final String path = "js/foo.js";
|
|
||||||
|
|
||||||
private FixedVersionStrategy strategy;
|
private FixedVersionStrategy strategy;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.strategy = new FixedVersionStrategy(this.version);
|
this.strategy = new FixedVersionStrategy(VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void emptyPrefixVersion() throws Exception {
|
public void emptyPrefixVersion() {
|
||||||
new FixedVersionStrategy(" ");
|
new FixedVersionStrategy(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extractVersion() throws Exception {
|
public void extractVersion() {
|
||||||
assertEquals(this.version, this.strategy.extractVersion(this.version + "/" + this.path));
|
assertEquals(VERSION, this.strategy.extractVersion(VERSION + "/" + PATH));
|
||||||
assertNull(this.strategy.extractVersion(this.path));
|
assertNull(this.strategy.extractVersion(PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeVersion() throws Exception {
|
public void removeVersion() {
|
||||||
assertEquals("/" + this.path, this.strategy.removeVersion(this.version + "/" + this.path, this.version));
|
assertEquals("/" + PATH, this.strategy.removeVersion(VERSION + "/" + PATH, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addVersion() throws Exception {
|
public void addVersion() {
|
||||||
assertEquals(this.version + "/" + this.path, this.strategy.addVersion("/" + this.path, this.version));
|
assertEquals(VERSION + "/" + PATH, this.strategy.addVersion("/" + PATH, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13727
|
@Test // SPR-13727
|
||||||
public void addVersionRelativePath() throws Exception {
|
public void addVersionRelativePath() {
|
||||||
String relativePath = "../" + this.path;
|
String relativePath = "../" + PATH;
|
||||||
assertEquals(relativePath, this.strategy.addVersion(relativePath, this.version));
|
assertEquals(relativePath, this.strategy.addVersion(relativePath, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -38,6 +38,9 @@ import static org.junit.Assert.fail;
|
||||||
*/
|
*/
|
||||||
public class PathResourceResolverTests {
|
public class PathResourceResolverTests {
|
||||||
|
|
||||||
|
private static final Duration TIMEOUT = Duration.ofSeconds(5);
|
||||||
|
|
||||||
|
|
||||||
private final PathResourceResolver resolver = new PathResourceResolver();
|
private final PathResourceResolver resolver = new PathResourceResolver();
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,16 +49,18 @@ public class PathResourceResolverTests {
|
||||||
Resource location = new ClassPathResource("test/", PathResourceResolver.class);
|
Resource location = new ClassPathResource("test/", PathResourceResolver.class);
|
||||||
String path = "bar.css";
|
String path = "bar.css";
|
||||||
List<Resource> locations = singletonList(location);
|
List<Resource> locations = singletonList(location);
|
||||||
Resource actual = this.resolver.resolveResource(null, path, locations, null).block(Duration.ofMillis(5000));
|
Resource actual = this.resolver.resolveResource(null, path, locations, null).block(TIMEOUT);
|
||||||
|
|
||||||
assertEquals(location.createRelative(path), actual);
|
assertEquals(location.createRelative(path), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveFromClasspathRoot() throws IOException {
|
public void resolveFromClasspathRoot() {
|
||||||
Resource location = new ClassPathResource("/");
|
Resource location = new ClassPathResource("/");
|
||||||
String path = "org/springframework/web/reactive/resource/test/bar.css";
|
String path = "org/springframework/web/reactive/resource/test/bar.css";
|
||||||
List<Resource> locations = singletonList(location);
|
List<Resource> locations = singletonList(location);
|
||||||
Resource actual = this.resolver.resolveResource(null, path, locations, null).block(Duration.ofMillis(5000));
|
Resource actual = this.resolver.resolveResource(null, path, locations, null).block(TIMEOUT);
|
||||||
|
|
||||||
assertNotNull(actual);
|
assertNotNull(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +85,7 @@ public class PathResourceResolverTests {
|
||||||
|
|
||||||
private void testCheckResource(Resource location, String requestPath) throws IOException {
|
private void testCheckResource(Resource location, String requestPath) throws IOException {
|
||||||
List<Resource> locations = singletonList(location);
|
List<Resource> locations = singletonList(location);
|
||||||
Resource actual = this.resolver.resolveResource(null, requestPath, locations, null).block(Duration.ofMillis(5000));
|
Resource actual = this.resolver.resolveResource(null, requestPath, locations, null).block(TIMEOUT);
|
||||||
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
||||||
fail(requestPath + " doesn't actually exist as a relative path");
|
fail(requestPath + " doesn't actually exist as a relative path");
|
||||||
}
|
}
|
||||||
|
@ -94,9 +99,9 @@ public class PathResourceResolverTests {
|
||||||
new ClassPathResource("testalternatepath/", PathResourceResolver.class)
|
new ClassPathResource("testalternatepath/", PathResourceResolver.class)
|
||||||
);
|
);
|
||||||
|
|
||||||
Resource location = new ClassPathResource("test/main.css", PathResourceResolver.class);
|
Resource location = getResource("main.css");
|
||||||
String actual = this.resolver.resolveUrlPath("../testalternatepath/bar.css",
|
String actual = this.resolver.resolveUrlPath("../testalternatepath/bar.css",
|
||||||
singletonList(location), null).block(Duration.ofMillis(5000));
|
singletonList(location), null).block(TIMEOUT);
|
||||||
|
|
||||||
assertEquals("../testalternatepath/bar.css", actual);
|
assertEquals("../testalternatepath/bar.css", actual);
|
||||||
}
|
}
|
||||||
|
@ -106,21 +111,26 @@ public class PathResourceResolverTests {
|
||||||
String locationUrl= new UrlResource(getClass().getResource("./test/")).getURL().toExternalForm();
|
String locationUrl= new UrlResource(getClass().getResource("./test/")).getURL().toExternalForm();
|
||||||
Resource location = new UrlResource(locationUrl.replace("/springframework","/../org/springframework"));
|
Resource location = new UrlResource(locationUrl.replace("/springframework","/../org/springframework"));
|
||||||
List<Resource> locations = singletonList(location);
|
List<Resource> locations = singletonList(location);
|
||||||
assertNotNull(this.resolver.resolveResource(null, "main.css", locations, null).block(Duration.ofMillis(5000)));
|
assertNotNull(this.resolver.resolveResource(null, "main.css", locations, null).block(TIMEOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-12747
|
@Test // SPR-12747
|
||||||
public void checkFileLocation() throws Exception {
|
public void checkFileLocation() throws Exception {
|
||||||
Resource resource = new ClassPathResource("test/main.css", PathResourceResolver.class);
|
Resource resource = getResource("main.css");
|
||||||
assertTrue(this.resolver.checkResource(resource, resource));
|
assertTrue(this.resolver.checkResource(resource, resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13241
|
@Test // SPR-13241
|
||||||
public void resolvePathRootResource() throws Exception {
|
public void resolvePathRootResource() {
|
||||||
Resource webjarsLocation = new ClassPathResource("/META-INF/resources/webjars/", PathResourceResolver.class);
|
Resource webjarsLocation = new ClassPathResource("/META-INF/resources/webjars/", PathResourceResolver.class);
|
||||||
String path = this.resolver.resolveUrlPathInternal(
|
String path = this.resolver.resolveUrlPathInternal(
|
||||||
"", singletonList(webjarsLocation), null).block(Duration.ofMillis(5000));
|
"", singletonList(webjarsLocation), null).block(TIMEOUT);
|
||||||
|
|
||||||
assertNull(path);
|
assertNull(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
package org.springframework.web.reactive.resource;
|
package org.springframework.web.reactive.resource;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@code ResourceTransformerSupport}.
|
* Unit tests for {@code ResourceTransformerSupport}.
|
||||||
|
@ -41,7 +41,10 @@ import static org.junit.Assert.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class ResourceTransformerSupportTests {
|
public class ResourceTransformerSupportTests {
|
||||||
|
|
||||||
private ResourceTransformerChain transformerChain;
|
private static final Duration TIMEOUT = Duration.ofSeconds(5);
|
||||||
|
|
||||||
|
|
||||||
|
private ResourceTransformerChain chain;
|
||||||
|
|
||||||
private TestResourceTransformerSupport transformer;
|
private TestResourceTransformerSupport transformer;
|
||||||
|
|
||||||
|
@ -52,17 +55,22 @@ public class ResourceTransformerSupportTests {
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
PathResourceResolver pathResolver = new PathResourceResolver();
|
||||||
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
|
||||||
this.transformerChain = new DefaultResourceTransformerChain(new DefaultResourceResolverChain(resolvers), null);
|
|
||||||
|
|
||||||
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
|
resolvers.add(versionResolver);
|
||||||
|
resolvers.add(pathResolver);
|
||||||
|
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
||||||
|
|
||||||
|
this.chain = new DefaultResourceTransformerChain(resolverChain, Collections.emptyList());
|
||||||
this.transformer = new TestResourceTransformerSupport();
|
this.transformer = new TestResourceTransformerSupport();
|
||||||
this.transformer.setResourceUrlProvider(createResourceUrlProvider(resolvers));
|
this.transformer.setResourceUrlProvider(createUrlProvider(resolvers));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceUrlProvider createResourceUrlProvider(List<ResourceResolver> resolvers) {
|
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
ResourceWebHandler handler = new ResourceWebHandler();
|
ResourceWebHandler handler = new ResourceWebHandler();
|
||||||
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
||||||
handler.setResourceResolvers(resolvers);
|
handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
urlProvider.registerHandlers(Collections.singletonMap("/resources/**", handler));
|
urlProvider.registerHandlers(Collections.singletonMap("/resources/**", handler));
|
||||||
return urlProvider;
|
return urlProvider;
|
||||||
|
@ -70,44 +78,43 @@ public class ResourceTransformerSupportTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPath() throws Exception {
|
public void resolveUrlPath() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/resources/main.css"));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/resources/main.css"));
|
||||||
String resourcePath = "/resources/bar.css";
|
String resourcePath = "/resources/bar.css";
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
Resource resource = getResource("main.css");
|
||||||
String actual = this.transformer.resolveUrlPath(
|
String actual = this.transformer.resolveUrlPath(resourcePath, exchange, resource, this.chain).block(TIMEOUT);
|
||||||
resourcePath, exchange, css, this.transformerChain).block(Duration.ofSeconds(5));
|
|
||||||
|
|
||||||
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPathWithRelativePath() throws Exception {
|
public void resolveUrlPathWithRelativePath() {
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
Resource resource = getResource("main.css");
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
String actual = this.transformer.resolveUrlPath(
|
String actual = this.transformer.resolveUrlPath("bar.css", exchange, resource, this.chain).block(TIMEOUT);
|
||||||
"bar.css", exchange, css, this.transformerChain).block(Duration.ofSeconds(5));
|
|
||||||
|
|
||||||
assertEquals("bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPathWithRelativePathInParentDirectory() throws Exception {
|
public void resolveUrlPathWithRelativePathInParentDirectory() {
|
||||||
Resource imagePng = new ClassPathResource("test/images/image.png", getClass());
|
Resource resource = getResource("images/image.png");
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
String actual = this.transformer.resolveUrlPath(
|
String actual = this.transformer.resolveUrlPath("../bar.css", exchange, resource, this.chain).block(TIMEOUT);
|
||||||
"../bar.css", exchange, imagePng, this.transformerChain).block(Duration.ofSeconds(5));
|
|
||||||
|
|
||||||
assertEquals("../bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("../bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class TestResourceTransformerSupport extends ResourceTransformerSupport {
|
private static class TestResourceTransformerSupport extends ResourceTransformerSupport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Resource> transform(ServerWebExchange exchange, Resource resource,
|
public Mono<Resource> transform(ServerWebExchange ex, Resource res, ResourceTransformerChain chain) {
|
||||||
ResourceTransformerChain chain) {
|
|
||||||
|
|
||||||
return Mono.error(new IllegalStateException("Should never be called"));
|
return Mono.error(new IllegalStateException("Should never be called"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.web.reactive.resource;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -32,15 +33,14 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
|
||||||
import org.springframework.mock.web.test.MockServletContext;
|
import org.springframework.mock.web.test.MockServletContext;
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
||||||
import org.springframework.web.util.pattern.PathPattern;
|
import org.springframework.web.util.pattern.PathPattern;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link ResourceUrlProvider}.
|
* Unit tests for {@link ResourceUrlProvider}.
|
||||||
|
@ -49,6 +49,9 @@ import static org.junit.Assert.assertThat;
|
||||||
*/
|
*/
|
||||||
public class ResourceUrlProviderTests {
|
public class ResourceUrlProviderTests {
|
||||||
|
|
||||||
|
private static final Duration TIMEOUT = Duration.ofSeconds(5);
|
||||||
|
|
||||||
|
|
||||||
private final List<Resource> locations = new ArrayList<>();
|
private final List<Resource> locations = new ArrayList<>();
|
||||||
|
|
||||||
private final ResourceWebHandler handler = new ResourceWebHandler();
|
private final ResourceWebHandler handler = new ResourceWebHandler();
|
||||||
|
@ -57,12 +60,14 @@ public class ResourceUrlProviderTests {
|
||||||
|
|
||||||
private final ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
private final ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
|
|
||||||
|
private final MockServerWebExchange exchange = MockServerWebExchange.from(get("/"));
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
this.locations.add(new ClassPathResource("test/", getClass()));
|
this.locations.add(new ClassPathResource("test/", getClass()));
|
||||||
this.locations.add(new ClassPathResource("testalternatepath/", getClass()));
|
this.locations.add(new ClassPathResource("testalternatepath/", getClass()));
|
||||||
this.handler.setLocations(locations);
|
this.handler.setLocations(this.locations);
|
||||||
this.handler.afterPropertiesSet();
|
this.handler.afterPropertiesSet();
|
||||||
this.handlerMap.put("/resources/**", this.handler);
|
this.handlerMap.put("/resources/**", this.handler);
|
||||||
this.urlProvider.registerHandlers(this.handlerMap);
|
this.urlProvider.registerHandlers(this.handlerMap);
|
||||||
|
@ -71,52 +76,46 @@ public class ResourceUrlProviderTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getStaticResourceUrl() {
|
public void getStaticResourceUrl() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
String expected = "/resources/foo.css";
|
||||||
String uriString = "/resources/foo.css";
|
String actual = this.urlProvider.getForUriString(expected, this.exchange).block(TIMEOUT);
|
||||||
String actual = this.urlProvider.getForUriString(uriString, exchange).block(Duration.ofSeconds(5));
|
|
||||||
assertEquals(uriString, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13374
|
@Test // SPR-13374
|
||||||
public void getStaticResourceUrlRequestWithQueryOrHash() {
|
public void getStaticResourceUrlRequestWithQueryOrHash() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
|
||||||
|
|
||||||
String url = "/resources/foo.css?foo=bar&url=http://example.org";
|
String url = "/resources/foo.css?foo=bar&url=http://example.org";
|
||||||
String resolvedUrl = this.urlProvider.getForUriString(url, exchange).block(Duration.ofSeconds(5));
|
String resolvedUrl = this.urlProvider.getForUriString(url, this.exchange).block(TIMEOUT);
|
||||||
assertEquals(url, resolvedUrl);
|
assertEquals(url, resolvedUrl);
|
||||||
|
|
||||||
url = "/resources/foo.css#hash";
|
url = "/resources/foo.css#hash";
|
||||||
resolvedUrl = this.urlProvider.getForUriString(url, exchange).block(Duration.ofSeconds(5));
|
resolvedUrl = this.urlProvider.getForUriString(url, this.exchange).block(TIMEOUT);
|
||||||
assertEquals(url, resolvedUrl);
|
assertEquals(url, resolvedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFingerprintedResourceUrl() {
|
public void getVerionedResourceUrl() {
|
||||||
Map<String, VersionStrategy> versionStrategyMap = new HashMap<>();
|
|
||||||
versionStrategyMap.put("/**", new ContentVersionStrategy());
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(versionStrategyMap);
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
|
|
||||||
List<ResourceResolver> resolvers = new ArrayList<>();
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
resolvers.add(versionResolver);
|
resolvers.add(versionResolver);
|
||||||
resolvers.add(new PathResourceResolver());
|
resolvers.add(new PathResourceResolver());
|
||||||
this.handler.setResourceResolvers(resolvers);
|
this.handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
|
||||||
String path = "/resources/foo.css";
|
String path = "/resources/foo.css";
|
||||||
String url = this.urlProvider.getForUriString(path, exchange).block(Duration.ofSeconds(5));
|
String url = this.urlProvider.getForUriString(path, this.exchange).block(TIMEOUT);
|
||||||
|
|
||||||
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-12647
|
@Test // SPR-12647
|
||||||
public void bestPatternMatch() throws Exception {
|
public void bestPatternMatch() {
|
||||||
ResourceWebHandler otherHandler = new ResourceWebHandler();
|
ResourceWebHandler otherHandler = new ResourceWebHandler();
|
||||||
otherHandler.setLocations(this.locations);
|
otherHandler.setLocations(this.locations);
|
||||||
Map<String, VersionStrategy> versionStrategyMap = new HashMap<>();
|
|
||||||
versionStrategyMap.put("/**", new ContentVersionStrategy());
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
|
||||||
versionResolver.setStrategyMap(versionStrategyMap);
|
|
||||||
|
|
||||||
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
List<ResourceResolver> resolvers = new ArrayList<>();
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
resolvers.add(versionResolver);
|
resolvers.add(versionResolver);
|
||||||
resolvers.add(new PathResourceResolver());
|
resolvers.add(new PathResourceResolver());
|
||||||
|
@ -125,22 +124,21 @@ public class ResourceUrlProviderTests {
|
||||||
this.handlerMap.put("/resources/*.css", otherHandler);
|
this.handlerMap.put("/resources/*.css", otherHandler);
|
||||||
this.urlProvider.registerHandlers(this.handlerMap);
|
this.urlProvider.registerHandlers(this.handlerMap);
|
||||||
|
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
|
||||||
String path = "/resources/foo.css";
|
String path = "/resources/foo.css";
|
||||||
String url = this.urlProvider.getForUriString(path, exchange).block(Duration.ofSeconds(5));
|
String url = this.urlProvider.getForUriString(path, this.exchange).block(TIMEOUT);
|
||||||
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-12592
|
@Test // SPR-12592
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
public void initializeOnce() throws Exception {
|
public void initializeOnce() {
|
||||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||||
context.setServletContext(new MockServletContext());
|
context.setServletContext(new MockServletContext());
|
||||||
context.register(HandlerMappingConfiguration.class);
|
context.register(HandlerMappingConfiguration.class);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
||||||
ResourceUrlProvider urlProviderBean = context.getBean(ResourceUrlProvider.class);
|
assertThat(context.getBean(ResourceUrlProvider.class).getHandlerMap(),
|
||||||
assertThat(urlProviderBean.getHandlerMap(), Matchers.hasKey(pattern("/resources/**")));
|
Matchers.hasKey(pattern("/resources/**")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -76,13 +76,13 @@ public class ResourceWebHandlerTests {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
List<Resource> paths = new ArrayList<>(2);
|
List<Resource> locations = new ArrayList<>(2);
|
||||||
paths.add(new ClassPathResource("test/", getClass()));
|
locations.add(new ClassPathResource("test/", getClass()));
|
||||||
paths.add(new ClassPathResource("testalternatepath/", getClass()));
|
locations.add(new ClassPathResource("testalternatepath/", getClass()));
|
||||||
paths.add(new ClassPathResource("META-INF/resources/webjars/"));
|
locations.add(new ClassPathResource("META-INF/resources/webjars/"));
|
||||||
|
|
||||||
this.handler = new ResourceWebHandler();
|
this.handler = new ResourceWebHandler();
|
||||||
this.handler.setLocations(paths);
|
this.handler.setLocations(locations);
|
||||||
this.handler.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS));
|
this.handler.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS));
|
||||||
this.handler.afterPropertiesSet();
|
this.handler.afterPropertiesSet();
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResourceHttpOptions() throws Exception {
|
public void getResourceHttpOptions() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options(""));
|
||||||
setPathWithinHandlerMapping(exchange, "foo.css");
|
setPathWithinHandlerMapping(exchange, "foo.css");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
|
@ -200,7 +200,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResourceFromSubDirectory() throws Exception {
|
public void getResourceFromSubDirectory() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
setPathWithinHandlerMapping(exchange, "js/foo.js");
|
setPathWithinHandlerMapping(exchange, "js/foo.js");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
|
@ -211,7 +211,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResourceFromSubDirectoryOfAlternatePath() throws Exception {
|
public void getResourceFromSubDirectoryOfAlternatePath() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
setPathWithinHandlerMapping(exchange, "js/baz.js");
|
setPathWithinHandlerMapping(exchange, "js/baz.js");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
|
@ -315,21 +315,24 @@ public class ResourceWebHandlerTests {
|
||||||
// testResolvePathWithTraversal(location, "/ " + secretPath);
|
// testResolvePathWithTraversal(location, "/ " + secretPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testResolvePathWithTraversal(HttpMethod httpMethod, String requestPath, Resource location) throws Exception {
|
private void testResolvePathWithTraversal(HttpMethod httpMethod, String requestPath, Resource location)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.method(httpMethod, ""));
|
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.method(httpMethod, ""));
|
||||||
setPathWithinHandlerMapping(exchange, requestPath);
|
setPathWithinHandlerMapping(exchange, requestPath);
|
||||||
StepVerifier.create(this.handler.handle(exchange))
|
StepVerifier.create(this.handler.handle(exchange))
|
||||||
.expectErrorSatisfies(err -> {
|
.expectErrorSatisfies(err -> {
|
||||||
assertThat(err, instanceOf(ResponseStatusException.class));
|
assertThat(err, instanceOf(ResponseStatusException.class));
|
||||||
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
|
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
|
||||||
}).verify(TIMEOUT);
|
})
|
||||||
|
.verify(TIMEOUT);
|
||||||
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
||||||
fail(requestPath + " doesn't actually exist as a relative path");
|
fail(requestPath + " doesn't actually exist as a relative path");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void processPath() throws Exception {
|
public void processPath() {
|
||||||
assertSame("/foo/bar", this.handler.processPath("/foo/bar"));
|
assertSame("/foo/bar", this.handler.processPath("/foo/bar"));
|
||||||
assertSame("foo/bar", this.handler.processPath("foo/bar"));
|
assertSame("foo/bar", this.handler.processPath("foo/bar"));
|
||||||
|
|
||||||
|
@ -358,7 +361,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initAllowedLocations() throws Exception {
|
public void initAllowedLocations() {
|
||||||
PathResourceResolver resolver = (PathResourceResolver) this.handler.getResourceResolvers().get(0);
|
PathResourceResolver resolver = (PathResourceResolver) this.handler.getResourceResolvers().get(0);
|
||||||
Resource[] locations = resolver.getAllowedLocations();
|
Resource[] locations = resolver.getAllowedLocations();
|
||||||
|
|
||||||
|
@ -388,8 +391,9 @@ public class ResourceWebHandlerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notModified() throws Exception {
|
public void notModified() throws Exception {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("")
|
MockServerWebExchange exchange = MockServerWebExchange.from(
|
||||||
.ifModifiedSince(resourceLastModified("test/foo.css")));
|
MockServerHttpRequest.get("").ifModifiedSince(resourceLastModified("test/foo.css")));
|
||||||
|
|
||||||
setPathWithinHandlerMapping(exchange, "foo.css");
|
setPathWithinHandlerMapping(exchange, "foo.css");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
assertEquals(HttpStatus.NOT_MODIFIED, exchange.getResponse().getStatusCode());
|
assertEquals(HttpStatus.NOT_MODIFIED, exchange.getResponse().getStatusCode());
|
||||||
|
@ -408,7 +412,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void directory() throws Exception {
|
public void directory() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
setPathWithinHandlerMapping(exchange, "js/");
|
setPathWithinHandlerMapping(exchange, "js/");
|
||||||
StepVerifier.create(this.handler.handle(exchange))
|
StepVerifier.create(this.handler.handle(exchange))
|
||||||
|
@ -419,7 +423,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void directoryInJarFile() throws Exception {
|
public void directoryInJarFile() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
setPathWithinHandlerMapping(exchange, "underscorejs/");
|
setPathWithinHandlerMapping(exchange, "underscorejs/");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
|
@ -429,7 +433,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void missingResourcePath() throws Exception {
|
public void missingResourcePath() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
setPathWithinHandlerMapping(exchange, "");
|
setPathWithinHandlerMapping(exchange, "");
|
||||||
StepVerifier.create(this.handler.handle(exchange))
|
StepVerifier.create(this.handler.handle(exchange))
|
||||||
|
@ -440,13 +444,13 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void noPathWithinHandlerMappingAttribute() throws Exception {
|
public void noPathWithinHandlerMappingAttribute() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = MethodNotAllowedException.class)
|
@Test(expected = MethodNotAllowedException.class)
|
||||||
public void unsupportedHttpMethod() throws Exception {
|
public void unsupportedHttpMethod() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post(""));
|
||||||
setPathWithinHandlerMapping(exchange, "foo.css");
|
setPathWithinHandlerMapping(exchange, "foo.css");
|
||||||
this.handler.handle(exchange).block(TIMEOUT);
|
this.handler.handle(exchange).block(TIMEOUT);
|
||||||
|
@ -459,7 +463,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resourceNotFound(HttpMethod httpMethod) throws Exception {
|
private void resourceNotFound(HttpMethod httpMethod) {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();
|
MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "not-there.css");
|
setPathWithinHandlerMapping(exchange, "not-there.css");
|
||||||
|
@ -471,7 +475,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentByteRange() throws Exception {
|
public void partialContentByteRange() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -487,7 +491,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentByteRangeNoEnd() throws Exception {
|
public void partialContentByteRangeNoEnd() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -503,7 +507,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentByteRangeLargeEnd() throws Exception {
|
public void partialContentByteRangeLargeEnd() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-10000").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-10000").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -519,7 +523,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentSuffixRange() throws Exception {
|
public void partialContentSuffixRange() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-1").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-1").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -535,7 +539,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentSuffixRangeLargeSuffix() throws Exception {
|
public void partialContentSuffixRangeLargeSuffix() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-11").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-11").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -551,7 +555,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentInvalidRangeHeader() throws Exception {
|
public void partialContentInvalidRangeHeader() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=foo bar").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=foo bar").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -566,7 +570,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partialContentMultipleByteRanges() throws Exception {
|
public void partialContentMultipleByteRanges() {
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1, 4-5, 8-9").build();
|
MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1, 4-5, 8-9").build();
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
MockServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||||
setPathWithinHandlerMapping(exchange, "foo.txt");
|
setPathWithinHandlerMapping(exchange, "foo.txt");
|
||||||
|
@ -610,7 +614,7 @@ public class ResourceWebHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-14005
|
@Test // SPR-14005
|
||||||
public void doOverwriteExistingCacheControlHeaders() throws Exception {
|
public void doOverwriteExistingCacheControlHeaders() {
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
|
||||||
exchange.getResponse().getHeaders().setCacheControl(CacheControl.noStore().getHeaderValue());
|
exchange.getResponse().getHeaders().setCacheControl(CacheControl.noStore().getHeaderValue());
|
||||||
setPathWithinHandlerMapping(exchange, "foo.css");
|
setPathWithinHandlerMapping(exchange, "foo.css");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -33,16 +33,9 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.mockito.BDDMockito.*;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.BDDMockito.mock;
|
|
||||||
import static org.mockito.BDDMockito.never;
|
|
||||||
import static org.mockito.BDDMockito.times;
|
|
||||||
import static org.mockito.BDDMockito.verify;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link VersionResourceResolver}.
|
* Unit tests for {@link VersionResourceResolver}.
|
||||||
|
@ -72,7 +65,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceExisting() throws Exception {
|
public void resolveResourceExisting() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
Resource expected = new ClassPathResource("test/" + file, getClass());
|
Resource expected = new ClassPathResource("test/" + file, getClass());
|
||||||
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.just(expected));
|
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.just(expected));
|
||||||
|
@ -88,7 +81,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceNoVersionStrategy() throws Exception {
|
public void resolveResourceNoVersionStrategy() {
|
||||||
String file = "missing.css";
|
String file = "missing.css";
|
||||||
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty());
|
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty());
|
||||||
|
|
||||||
|
@ -102,7 +95,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceNoVersionInPath() throws Exception {
|
public void resolveResourceNoVersionInPath() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty());
|
given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty());
|
||||||
given(this.versionStrategy.extractVersion(file)).willReturn("");
|
given(this.versionStrategy.extractVersion(file)).willReturn("");
|
||||||
|
@ -118,7 +111,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceNoResourceAfterVersionRemoved() throws Exception {
|
public void resolveResourceNoResourceAfterVersionRemoved() {
|
||||||
String versionFile = "bar-version.css";
|
String versionFile = "bar-version.css";
|
||||||
String version = "version";
|
String version = "version";
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
|
@ -137,7 +130,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceVersionDoesNotMatch() throws Exception {
|
public void resolveResourceVersionDoesNotMatch() {
|
||||||
String versionFile = "bar-version.css";
|
String versionFile = "bar-version.css";
|
||||||
String version = "version";
|
String version = "version";
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
|
@ -158,7 +151,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceSuccess() throws Exception {
|
public void resolveResourceSuccess() {
|
||||||
String versionFile = "bar-version.css";
|
String versionFile = "bar-version.css";
|
||||||
String version = "version";
|
String version = "version";
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
|
@ -183,7 +176,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getStrategyForPath() throws Exception {
|
public void getStrategyForPath() {
|
||||||
Map<String, VersionStrategy> strategies = new HashMap<>();
|
Map<String, VersionStrategy> strategies = new HashMap<>();
|
||||||
VersionStrategy jsStrategy = mock(VersionStrategy.class);
|
VersionStrategy jsStrategy = mock(VersionStrategy.class);
|
||||||
VersionStrategy catchAllStrategy = mock(VersionStrategy.class);
|
VersionStrategy catchAllStrategy = mock(VersionStrategy.class);
|
||||||
|
@ -198,7 +191,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13883
|
@Test // SPR-13883
|
||||||
public void shouldConfigureFixedPrefixAutomatically() throws Exception {
|
public void shouldConfigureFixedPrefixAutomatically() {
|
||||||
|
|
||||||
this.resolver.addFixedVersionStrategy("fixedversion", "/js/**", "/css/**", "/fixedversion/css/**");
|
this.resolver.addFixedVersionStrategy("fixedversion", "/js/**", "/css/**", "/fixedversion/css/**");
|
||||||
|
|
||||||
|
@ -218,7 +211,7 @@ public class VersionResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-15372
|
@Test // SPR-15372
|
||||||
public void resolveUrlPathNoVersionStrategy() throws Exception {
|
public void resolveUrlPathNoVersionStrategy() {
|
||||||
given(this.chain.resolveUrlPath("/foo.css", this.locations)).willReturn(Mono.just("/foo.css"));
|
given(this.chain.resolveUrlPath("/foo.css", this.locations)).willReturn(Mono.just("/foo.css"));
|
||||||
String resolved = this.resolver.resolveUrlPathInternal("/foo.css", this.locations, this.chain)
|
String resolved = this.resolver.resolveUrlPathInternal("/foo.css", this.locations, this.chain)
|
||||||
.block(Duration.ofMillis(1000));
|
.block(Duration.ofMillis(1000));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -16,12 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -30,13 +29,14 @@ import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.BDDMockito.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link AppCacheManifestTransformer}.
|
* Unit tests for {@link AppCacheManifestTransformer}.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class AppCacheManifestTransformerTests {
|
public class AppCacheManifestTransformerTests {
|
||||||
|
|
||||||
|
@ -46,77 +46,79 @@ public class AppCacheManifestTransformerTests {
|
||||||
|
|
||||||
private HttpServletRequest request;
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
|
|
||||||
ResourceHttpRequestHandler resourceHandler = new ResourceHttpRequestHandler();
|
|
||||||
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
|
|
||||||
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
|
|
||||||
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
PathResourceResolver pathResolver = new PathResourceResolver();
|
||||||
pathResolver.setAllowedLocations(allowedLocation);
|
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
|
resolvers.add(versionResolver);
|
||||||
|
resolvers.add(pathResolver);
|
||||||
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
||||||
|
|
||||||
CssLinkResourceTransformer cssLinkResourceTransformer = new CssLinkResourceTransformer();
|
this.chain = new DefaultResourceTransformerChain(resolverChain, Collections.emptyList());
|
||||||
cssLinkResourceTransformer.setResourceUrlProvider(resourceUrlProvider);
|
|
||||||
List<ResourceTransformer> transformers = Arrays.asList(cssLinkResourceTransformer);
|
|
||||||
this.chain = new DefaultResourceTransformerChain(resolverChain, transformers);
|
|
||||||
this.transformer = new AppCacheManifestTransformer();
|
this.transformer = new AppCacheManifestTransformer();
|
||||||
this.transformer.setResourceUrlProvider(resourceUrlProvider);
|
this.transformer.setResourceUrlProvider(createUrlProvider(resolvers));
|
||||||
|
|
||||||
resourceHandler.setResourceResolvers(resolvers);
|
|
||||||
resourceHandler.setResourceTransformers(transformers);
|
|
||||||
resourceHandler.setLocations(Collections.singletonList(allowedLocation));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
public void noTransformIfExtensionNoMatch() throws Exception {
|
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
|
||||||
this.chain = mock(ResourceTransformerChain.class);
|
ResourceHttpRequestHandler resourceHandler = new ResourceHttpRequestHandler();
|
||||||
this.request = mock(HttpServletRequest.class);
|
|
||||||
Resource resource = mock(Resource.class);
|
|
||||||
given(resource.getFilename()).willReturn("foobar.file");
|
|
||||||
given(this.chain.transform(this.request, resource)).willReturn(resource);
|
|
||||||
|
|
||||||
|
resourceHandler.setResourceResolvers(resolvers);
|
||||||
|
resourceHandler.setLocations(Collections.singletonList(allowedLocation));
|
||||||
|
|
||||||
|
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
|
||||||
|
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
|
||||||
|
return resourceUrlProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noTransformIfExtensionDoesNotMatch() throws Exception {
|
||||||
|
this.request = new MockHttpServletRequest("GET", "/static/foo.css");
|
||||||
|
Resource resource = getResource("foo.css");
|
||||||
Resource result = this.transformer.transform(this.request, resource, this.chain);
|
Resource result = this.transformer.transform(this.request, resource, this.chain);
|
||||||
|
|
||||||
assertEquals(resource, result);
|
assertEquals(resource, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void syntaxErrorInManifest() throws Exception {
|
public void syntaxErrorInManifest() throws Exception {
|
||||||
this.chain = mock(ResourceTransformerChain.class);
|
this.request = new MockHttpServletRequest("GET", "/static/error.appcache");
|
||||||
this.request = mock(HttpServletRequest.class);
|
Resource resource = getResource("error.appcache");
|
||||||
Resource resource = new ClassPathResource("test/error.appcache", getClass());
|
|
||||||
given(this.chain.transform(this.request, resource)).willReturn(resource);
|
|
||||||
|
|
||||||
Resource result = this.transformer.transform(this.request, resource, this.chain);
|
Resource result = this.transformer.transform(this.request, resource, this.chain);
|
||||||
|
|
||||||
assertEquals(resource, result);
|
assertEquals(resource, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformManifest() throws Exception {
|
public void transformManifest() throws Exception {
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/test.appcache");
|
this.request = new MockHttpServletRequest("GET", "/static/test.appcache");
|
||||||
Resource resource = new ClassPathResource("test/test.appcache", getClass());
|
Resource resource = getResource("test.appcache");
|
||||||
Resource result = this.transformer.transform(this.request, resource, this.chain);
|
Resource actual = this.transformer.transform(this.request, resource, this.chain);
|
||||||
byte[] bytes = FileCopyUtils.copyToByteArray(result.getInputStream());
|
|
||||||
|
byte[] bytes = FileCopyUtils.copyToByteArray(actual.getInputStream());
|
||||||
String content = new String(bytes, "UTF-8");
|
String content = new String(bytes, "UTF-8");
|
||||||
|
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css"));
|
containsString("/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css"));
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/bar-11e16cf79faee7ac698c805cf28248d2.css"));
|
containsString("/static/bar-11e16cf79faee7ac698c805cf28248d2.css"));
|
||||||
assertThat("should rewrite resource links", content,
|
assertThat("should rewrite resource links", content,
|
||||||
Matchers.containsString("/static/js/bar-bd508c62235b832d960298ca6c0b7645.js"));
|
containsString("/static/js/bar-bd508c62235b832d960298ca6c0b7645.js"));
|
||||||
|
|
||||||
assertThat("should not rewrite external resources", content,
|
assertThat("should not rewrite external resources", content, containsString("//example.org/style.css"));
|
||||||
Matchers.containsString("//example.org/style.css"));
|
assertThat("should not rewrite external resources", content, containsString("http://example.org/image.png"));
|
||||||
assertThat("should not rewrite external resources", content,
|
|
||||||
Matchers.containsString("http://example.org/image.png"));
|
|
||||||
|
|
||||||
assertThat("should generate fingerprint", content,
|
assertThat("should generate fingerprint", content,
|
||||||
Matchers.containsString("# Hash: 4bf0338bcbeb0a5b3a4ec9ed8864107d"));
|
containsString("# Hash: 4bf0338bcbeb0a5b3a4ec9ed8864107d"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -63,21 +63,18 @@ public class CachingResourceResolverTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceInternal() {
|
public void resolveResourceInternal() {
|
||||||
String file = "bar.css";
|
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
||||||
Resource expected = new ClassPathResource("test/" + file, getClass());
|
Resource actual = this.chain.resolveResource(null, "bar.css", this.locations);
|
||||||
Resource actual = this.chain.resolveResource(null, file, this.locations);
|
|
||||||
|
|
||||||
|
assertNotSame(expected, actual);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceInternalFromCache() {
|
public void resolveResourceInternalFromCache() {
|
||||||
|
|
||||||
Resource expected = Mockito.mock(Resource.class);
|
Resource expected = Mockito.mock(Resource.class);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", expected);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", expected);
|
||||||
|
Resource actual = this.chain.resolveResource(null, "bar.css", this.locations);
|
||||||
String file = "bar.css";
|
|
||||||
Resource actual = this.chain.resolveResource(null, file, this.locations);
|
|
||||||
|
|
||||||
assertSame(expected, actual);
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
@ -112,39 +109,41 @@ public class CachingResourceResolverTests {
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceAcceptEncodingInCacheKey() {
|
public void resolveResourceAcceptEncodingInCacheKey() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", file);
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", file);
|
||||||
request.addHeader("Accept-Encoding", "gzip");
|
request.addHeader("Accept-Encoding", "gzip");
|
||||||
Resource expected = this.chain.resolveResource(request, file, this.locations);
|
Resource expected = this.chain.resolveResource(request, file, this.locations);
|
||||||
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file + "+encoding=gzip";
|
|
||||||
|
|
||||||
assertEquals(expected, this.cache.get(cacheKey).get());
|
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file + "+encoding=gzip";
|
||||||
|
Object actual = this.cache.get(cacheKey).get();
|
||||||
|
|
||||||
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceNoAcceptEncodingInCacheKey() {
|
public void resolveResourceNoAcceptEncoding() {
|
||||||
String file = "bar.css";
|
String file = "bar.css";
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", file);
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", file);
|
||||||
Resource expected = this.chain.resolveResource(request, file, this.locations);
|
Resource expected = this.chain.resolveResource(request, file, this.locations);
|
||||||
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file;
|
|
||||||
|
|
||||||
assertEquals(expected, this.cache.get(cacheKey).get());
|
String cacheKey = CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + file;
|
||||||
|
Object actual = this.cache.get(cacheKey).get();
|
||||||
|
|
||||||
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveResourceMatchingEncoding() {
|
public void resolveResourceMatchingEncoding() {
|
||||||
Resource resource = Mockito.mock(Resource.class);
|
Resource resource = Mockito.mock(Resource.class);
|
||||||
Resource gzResource = Mockito.mock(Resource.class);
|
Resource gzipped = Mockito.mock(Resource.class);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", resource);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css", resource);
|
||||||
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css+encoding=gzip", gzResource);
|
this.cache.put(CachingResourceResolver.RESOLVED_RESOURCE_CACHE_KEY_PREFIX + "bar.css+encoding=gzip", gzipped);
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "bar.css");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "bar.css");
|
||||||
assertSame(resource, this.chain.resolveResource(request,"bar.css", this.locations));
|
assertSame(resource, this.chain.resolveResource(request,"bar.css", this.locations));
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "bar.css");
|
request = new MockHttpServletRequest("GET", "bar.css");
|
||||||
request.addHeader("Accept-Encoding", "gzip");
|
request.addHeader("Accept-Encoding", "gzip");
|
||||||
assertSame(gzResource, this.chain.resolveResource(request, "bar.css", this.locations));
|
assertSame(gzipped, this.chain.resolveResource(request, "bar.css", this.locations));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -28,8 +29,10 @@ import org.springframework.util.FileCopyUtils;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link ContentVersionStrategy}
|
* Unit tests for {@link ContentVersionStrategy}.
|
||||||
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class ContentBasedVersionStrategyTests {
|
public class ContentBasedVersionStrategyTests {
|
||||||
|
|
||||||
|
@ -43,7 +46,7 @@ public class ContentBasedVersionStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extractVersion() throws Exception {
|
public void extractVersion() {
|
||||||
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
||||||
String path = "font-awesome/css/font-awesome.min-" + hash + ".css";
|
String path = "font-awesome/css/font-awesome.min-" + hash + ".css";
|
||||||
|
|
||||||
|
@ -52,26 +55,25 @@ public class ContentBasedVersionStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeVersion() throws Exception {
|
public void removeVersion() {
|
||||||
String file = "font-awesome/css/font-awesome.min%s%s.css";
|
|
||||||
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
String hash = "7fbe76cdac6093784895bb4989203e5a";
|
||||||
|
String file = "font-awesome/css/font-awesome.min%s%s.css";
|
||||||
|
|
||||||
assertEquals(String.format(file, "", ""), this.versionStrategy.removeVersion(String.format(file, "-", hash), hash));
|
assertEquals(String.format(file, "", ""),
|
||||||
assertNull(this.versionStrategy.extractVersion("foo/bar.css"));
|
this.versionStrategy.removeVersion(String.format(file, "-", hash), hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResourceVersion() throws Exception {
|
public void getResourceVersion() throws IOException {
|
||||||
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
Resource expected = new ClassPathResource("test/bar.css", getClass());
|
||||||
String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream()));
|
String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream()));
|
||||||
|
|
||||||
assertEquals(hash, this.versionStrategy.getResourceVersion(expected));
|
assertEquals(hash, this.versionStrategy.getResourceVersion(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addVersionToUrl() throws Exception {
|
public void addVersionToUrl() {
|
||||||
String requestPath = "test/bar.css";
|
assertEquals("test/bar-123.css", this.versionStrategy.addVersion("test/bar.css", "123"));
|
||||||
String version = "123";
|
|
||||||
assertEquals("test/bar-123.css", this.versionStrategy.addVersion(requestPath, version));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -16,12 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.util.ArrayList;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -33,6 +29,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.servlet.resource.EncodedResourceResolver.EncodedResource;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -53,37 +50,37 @@ public class CssLinkResourceTransformerTests {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
|
|
||||||
ResourceHttpRequestHandler resourceHandler = new ResourceHttpRequestHandler();
|
|
||||||
|
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
PathResourceResolver pathResolver = new PathResourceResolver();
|
||||||
pathResolver.setAllowedLocations(allowedLocation);
|
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
|
resolvers.add(versionResolver);
|
||||||
|
resolvers.add(new PathResourceResolver());
|
||||||
|
ResourceUrlProvider resourceUrlProvider = createUrlProvider(resolvers);
|
||||||
|
|
||||||
|
CssLinkResourceTransformer cssLinkTransformer = new CssLinkResourceTransformer();
|
||||||
|
cssLinkTransformer.setResourceUrlProvider(resourceUrlProvider);
|
||||||
|
|
||||||
|
this.transformerChain = new DefaultResourceTransformerChain(
|
||||||
|
new DefaultResourceResolverChain(resolvers), Collections.singletonList(cssLinkTransformer));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 resourceUrlProvider = new ResourceUrlProvider();
|
||||||
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
|
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
|
||||||
|
return resourceUrlProvider;
|
||||||
CssLinkResourceTransformer cssLinkResourceTransformer = new CssLinkResourceTransformer();
|
|
||||||
cssLinkResourceTransformer.setResourceUrlProvider(resourceUrlProvider);
|
|
||||||
List<ResourceTransformer> transformers = Arrays.asList(cssLinkResourceTransformer);
|
|
||||||
|
|
||||||
resourceHandler.setResourceResolvers(resolvers);
|
|
||||||
resourceHandler.setResourceTransformers(transformers);
|
|
||||||
resourceHandler.setLocations(Collections.singletonList(allowedLocation));
|
|
||||||
|
|
||||||
ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers);
|
|
||||||
this.transformerChain = new DefaultResourceTransformerChain(resolverChain, transformers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transform() throws Exception {
|
public void transform() throws Exception {
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/main.css");
|
this.request = new MockHttpServletRequest("GET", "/static/main.css");
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
Resource css = getResource("main.css");
|
||||||
TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css);
|
|
||||||
|
|
||||||
String expected = "\n" +
|
String expected = "\n" +
|
||||||
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
|
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
|
||||||
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" +
|
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" +
|
||||||
|
@ -92,6 +89,7 @@ public class CssLinkResourceTransformerTests {
|
||||||
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
|
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
|
||||||
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n";
|
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n";
|
||||||
|
|
||||||
|
TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css);
|
||||||
String result = new String(actual.getByteArray(), StandardCharsets.UTF_8);
|
String result = new String(actual.getByteArray(), StandardCharsets.UTF_8);
|
||||||
result = StringUtils.deleteAny(result, "\r");
|
result = StringUtils.deleteAny(result, "\r");
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
@ -100,7 +98,7 @@ public class CssLinkResourceTransformerTests {
|
||||||
@Test
|
@Test
|
||||||
public void transformNoLinks() throws Exception {
|
public void transformNoLinks() throws Exception {
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/foo.css");
|
this.request = new MockHttpServletRequest("GET", "/static/foo.css");
|
||||||
Resource expected = new ClassPathResource("test/foo.css", getClass());
|
Resource expected = getResource("foo.css");
|
||||||
Resource actual = this.transformerChain.transform(this.request, expected);
|
Resource actual = this.transformerChain.transform(this.request, expected);
|
||||||
assertSame(expected, actual);
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
@ -108,55 +106,51 @@ public class CssLinkResourceTransformerTests {
|
||||||
@Test
|
@Test
|
||||||
public void transformExtLinksNotAllowed() throws Exception {
|
public void transformExtLinksNotAllowed() throws Exception {
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/external.css");
|
this.request = new MockHttpServletRequest("GET", "/static/external.css");
|
||||||
ResourceResolverChain resolverChain = Mockito.mock(DefaultResourceResolverChain.class);
|
|
||||||
ResourceTransformerChain transformerChain = new DefaultResourceTransformerChain(resolverChain,
|
|
||||||
Arrays.asList(new CssLinkResourceTransformer()));
|
|
||||||
|
|
||||||
Resource externalCss = new ClassPathResource("test/external.css", getClass());
|
List<ResourceTransformer> transformers = Collections.singletonList(new CssLinkResourceTransformer());
|
||||||
Resource resource = transformerChain.transform(this.request, externalCss);
|
ResourceResolverChain mockChain = Mockito.mock(DefaultResourceResolverChain.class);
|
||||||
TransformedResource transformedResource = (TransformedResource) resource;
|
ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers);
|
||||||
|
|
||||||
|
Resource resource = getResource("external.css");
|
||||||
String expected = "@import url(\"http://example.org/fonts/css\");\n" +
|
String expected = "@import url(\"http://example.org/fonts/css\");\n" +
|
||||||
"body { background: url(\"file:///home/spring/image.png\") }\n" +
|
"body { background: url(\"file:///home/spring/image.png\") }\n" +
|
||||||
"figure { background: url(\"//example.org/style.css\")}";
|
"figure { background: url(\"//example.org/style.css\")}";
|
||||||
|
|
||||||
|
TransformedResource transformedResource = (TransformedResource) chain.transform(this.request, resource);
|
||||||
String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8);
|
String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8);
|
||||||
result = StringUtils.deleteAny(result, "\r");
|
result = StringUtils.deleteAny(result, "\r");
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
List<Resource> locations = Collections.singletonList(resource);
|
||||||
.resolveUrlPath("http://example.org/fonts/css", Arrays.asList(externalCss));
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("http://example.org/fonts/css", locations);
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("file:///home/spring/image.png", locations);
|
||||||
.resolveUrlPath("file:///home/spring/image.png", Arrays.asList(externalCss));
|
Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("//example.org/style.css", locations);
|
||||||
Mockito.verify(resolverChain, Mockito.never())
|
|
||||||
.resolveUrlPath("//example.org/style.css", Arrays.asList(externalCss));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformWithNonCssResource() throws Exception {
|
public void transformSkippedForNonCssResource() throws Exception {
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/images/image.png");
|
this.request = new MockHttpServletRequest("GET", "/static/images/image.png");
|
||||||
Resource expected = new ClassPathResource("test/images/image.png", getClass());
|
Resource expected = getResource("images/image.png");
|
||||||
Resource actual = this.transformerChain.transform(this.request, expected);
|
Resource actual = this.transformerChain.transform(this.request, expected);
|
||||||
|
|
||||||
assertSame(expected, actual);
|
assertSame(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformWithGzippedResource() throws Exception {
|
public void transformSkippedForGzippedResource() throws Exception {
|
||||||
|
|
||||||
|
EncodedResourceResolverTests.createGzippedFile("main.css");
|
||||||
|
|
||||||
this.request = new MockHttpServletRequest("GET", "/static/main.css");
|
this.request = new MockHttpServletRequest("GET", "/static/main.css");
|
||||||
Resource original = new ClassPathResource("test/main.css", getClass());
|
Resource original = new ClassPathResource("test/main.css", getClass());
|
||||||
createTempCopy("main.css", "main.css.gz");
|
EncodedResource gzipped = new EncodedResource(original, "gzip", ".gz");
|
||||||
EncodedResourceResolver.EncodedResource expected =
|
Resource actual = this.transformerChain.transform(this.request, gzipped);
|
||||||
new EncodedResourceResolver.EncodedResource(original, "gzip", ".gz");
|
|
||||||
Resource actual = this.transformerChain.transform(this.request, expected);
|
assertSame(gzipped, actual);
|
||||||
assertSame(expected, actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTempCopy(String filePath, String copyFilePath) throws IOException {
|
private Resource getResource(String filePath) {
|
||||||
Resource location = new ClassPathResource("test/", CssLinkResourceTransformerTests.class);
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
Path original = Paths.get(location.getFile().getAbsolutePath(), filePath);
|
|
||||||
Path copy = Paths.get(location.getFile().getAbsolutePath(), copyFilePath);
|
|
||||||
Files.deleteIfExists(copy);
|
|
||||||
Files.copy(original, copy);
|
|
||||||
copy.toFile().deleteOnExit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,11 @@ public class EncodedResourceResolverTests {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void createGzippedResources() throws IOException {
|
public static void createGzippedResources() throws IOException {
|
||||||
createGzipFile("/js/foo.js");
|
createGzippedFile("/js/foo.js");
|
||||||
createGzipFile("foo.css");
|
createGzippedFile("foo.css");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createGzipFile(String filePath) throws IOException {
|
static void createGzippedFile(String filePath) throws IOException {
|
||||||
Resource location = new ClassPathResource("test/", EncodedResourceResolverTests.class);
|
Resource location = new ClassPathResource("test/", EncodedResourceResolverTests.class);
|
||||||
Resource resource = new FileSystemResource(location.createRelative(filePath).getFile());
|
Resource resource = new FileSystemResource(location.createRelative(filePath).getFile());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -22,50 +22,52 @@ import org.junit.Test;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link org.springframework.web.servlet.resource.FixedVersionStrategy}.
|
* Unit tests for {@link FixedVersionStrategy}.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class FixedVersionStrategyTests {
|
public class FixedVersionStrategyTests {
|
||||||
|
|
||||||
private final String version = "1df341f";
|
private static final String VERSION = "1df341f";
|
||||||
|
|
||||||
|
private static final String PATH = "js/foo.js";
|
||||||
|
|
||||||
private final String path = "js/foo.js";
|
|
||||||
|
|
||||||
private FixedVersionStrategy strategy;
|
private FixedVersionStrategy strategy;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.strategy = new FixedVersionStrategy(this.version);
|
this.strategy = new FixedVersionStrategy(VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void emptyPrefixVersion() throws Exception {
|
public void emptyPrefixVersion() {
|
||||||
new FixedVersionStrategy(" ");
|
new FixedVersionStrategy(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extractVersion() throws Exception {
|
public void extractVersion() {
|
||||||
assertEquals(this.version, this.strategy.extractVersion(this.version + "/" + this.path));
|
assertEquals(VERSION, this.strategy.extractVersion(VERSION + "/" + PATH));
|
||||||
assertNull(this.strategy.extractVersion(this.path));
|
assertNull(this.strategy.extractVersion(PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeVersion() throws Exception {
|
public void removeVersion() {
|
||||||
assertEquals("/" + this.path, this.strategy.removeVersion(this.version + "/" + this.path, this.version));
|
assertEquals("/" + PATH, this.strategy.removeVersion(VERSION + "/" + PATH, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addVersion() throws Exception {
|
public void addVersion() {
|
||||||
assertEquals(this.version + "/" + this.path, this.strategy.addVersion("/" + this.path, this.version));
|
assertEquals(VERSION + "/" + PATH, this.strategy.addVersion("/" + PATH, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13727
|
@Test // SPR-13727
|
||||||
public void addVersionRelativePath() throws Exception {
|
public void addVersionRelativePath() {
|
||||||
String relativePath = "../" + this.path;
|
String relativePath = "../" + PATH;
|
||||||
assertEquals(relativePath, this.strategy.addVersion(relativePath, this.version));
|
assertEquals(relativePath, this.strategy.addVersion(relativePath, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2018 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,7 +18,6 @@ package org.springframework.web.servlet.resource;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -32,16 +31,10 @@ import org.springframework.mock.web.test.MockServletContext;
|
||||||
import org.springframework.web.context.support.ServletContextResource;
|
import org.springframework.web.context.support.ServletContextResource;
|
||||||
import org.springframework.web.util.UrlPathHelper;
|
import org.springframework.web.util.UrlPathHelper;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for
|
* Unit tests for {@link PathResourceResolver}.
|
||||||
* {@link org.springframework.web.servlet.resource.PathResourceResolver}.
|
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
@ -55,15 +48,17 @@ public class PathResourceResolverTests {
|
||||||
public void resolveFromClasspath() throws IOException {
|
public void resolveFromClasspath() throws IOException {
|
||||||
Resource location = new ClassPathResource("test/", PathResourceResolver.class);
|
Resource location = new ClassPathResource("test/", PathResourceResolver.class);
|
||||||
String requestPath = "bar.css";
|
String requestPath = "bar.css";
|
||||||
Resource actual = this.resolver.resolveResource(null, requestPath, Arrays.asList(location), null);
|
Resource actual = this.resolver.resolveResource(null, requestPath, Collections.singletonList(location), null);
|
||||||
|
|
||||||
assertEquals(location.createRelative(requestPath), actual);
|
assertEquals(location.createRelative(requestPath), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveFromClasspathRoot() throws IOException {
|
public void resolveFromClasspathRoot() {
|
||||||
Resource location = new ClassPathResource("/");
|
Resource location = new ClassPathResource("/");
|
||||||
String requestPath = "org/springframework/web/servlet/resource/test/bar.css";
|
String requestPath = "org/springframework/web/servlet/resource/test/bar.css";
|
||||||
Resource actual = this.resolver.resolveResource(null, requestPath, Arrays.asList(location), null);
|
Resource actual = this.resolver.resolveResource(null, requestPath, Collections.singletonList(location), null);
|
||||||
|
|
||||||
assertNotNull(actual);
|
assertNotNull(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +82,8 @@ public class PathResourceResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testCheckResource(Resource location, String requestPath) throws IOException {
|
private void testCheckResource(Resource location, String requestPath) throws IOException {
|
||||||
Resource actual = this.resolver.resolveResource(null, requestPath, Arrays.asList(location), null);
|
List<Resource> locations = Collections.singletonList(location);
|
||||||
|
Resource actual = this.resolver.resolveResource(null, requestPath, locations, null);
|
||||||
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
|
||||||
fail(requestPath + " doesn't actually exist as a relative path");
|
fail(requestPath + " doesn't actually exist as a relative path");
|
||||||
}
|
}
|
||||||
|
@ -101,8 +97,9 @@ public class PathResourceResolverTests {
|
||||||
new ClassPathResource("testalternatepath/", PathResourceResolver.class)
|
new ClassPathResource("testalternatepath/", PathResourceResolver.class)
|
||||||
);
|
);
|
||||||
|
|
||||||
Resource location = new ClassPathResource("test/main.css", PathResourceResolver.class);
|
Resource location = getResource("main.css");
|
||||||
String actual = this.resolver.resolveUrlPath("../testalternatepath/bar.css", Arrays.asList(location), null);
|
List<Resource> locations = Collections.singletonList(location);
|
||||||
|
String actual = this.resolver.resolveUrlPath("../testalternatepath/bar.css", locations, null);
|
||||||
assertEquals("../testalternatepath/bar.css", actual);
|
assertEquals("../testalternatepath/bar.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,21 +122,21 @@ public class PathResourceResolverTests {
|
||||||
String locationUrl= new UrlResource(getClass().getResource("./test/")).getURL().toExternalForm();
|
String locationUrl= new UrlResource(getClass().getResource("./test/")).getURL().toExternalForm();
|
||||||
Resource location = new UrlResource(locationUrl.replace("/springframework","/../org/springframework"));
|
Resource location = new UrlResource(locationUrl.replace("/springframework","/../org/springframework"));
|
||||||
|
|
||||||
assertNotNull(this.resolver.resolveResource(null, "main.css", Arrays.asList(location), null));
|
assertNotNull(this.resolver.resolveResource(null, "main.css", Collections.singletonList(location), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-12747
|
// SPR-12747
|
||||||
@Test
|
@Test
|
||||||
public void checkFileLocation() throws Exception {
|
public void checkFileLocation() throws Exception {
|
||||||
Resource resource = new ClassPathResource("test/main.css", PathResourceResolver.class);
|
Resource resource = getResource("main.css");
|
||||||
assertTrue(this.resolver.checkResource(resource, resource));
|
assertTrue(this.resolver.checkResource(resource, resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-13241
|
// SPR-13241
|
||||||
@Test
|
@Test
|
||||||
public void resolvePathRootResource() throws Exception {
|
public void resolvePathRootResource() {
|
||||||
Resource webjarsLocation = new ClassPathResource("/META-INF/resources/webjars/", PathResourceResolver.class);
|
Resource webjarsLocation = new ClassPathResource("/META-INF/resources/webjars/", PathResourceResolver.class);
|
||||||
String path = this.resolver.resolveUrlPathInternal("", Arrays.asList(webjarsLocation), null);
|
String path = this.resolver.resolveUrlPathInternal("", Collections.singletonList(webjarsLocation), null);
|
||||||
|
|
||||||
assertNull(path);
|
assertNull(path);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +166,10 @@ public class PathResourceResolverTests {
|
||||||
assertEquals("%C3%84%20%3B%C3%A4.txt", location.getSavedRelativePath());
|
assertEquals("%C3%84%20%3B%C3%A4.txt", location.getSavedRelativePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class TestUrlResource extends UrlResource {
|
private static class TestUrlResource extends UrlResource {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -27,7 +27,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@code ResourceTransformerSupport}.
|
* Unit tests for {@code ResourceTransformerSupport}.
|
||||||
|
@ -41,7 +41,7 @@ public class ResourceTransformerSupportTests {
|
||||||
|
|
||||||
private TestResourceTransformerSupport transformer;
|
private TestResourceTransformerSupport transformer;
|
||||||
|
|
||||||
private MockHttpServletRequest request;
|
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -50,19 +50,20 @@ public class ResourceTransformerSupportTests {
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
PathResourceResolver pathResolver = new PathResourceResolver();
|
||||||
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
|
resolvers.add(versionResolver);
|
||||||
|
resolvers.add(pathResolver);
|
||||||
this.transformerChain = new DefaultResourceTransformerChain(new DefaultResourceResolverChain(resolvers), null);
|
this.transformerChain = new DefaultResourceTransformerChain(new DefaultResourceResolverChain(resolvers), null);
|
||||||
|
|
||||||
this.transformer = new TestResourceTransformerSupport();
|
this.transformer = new TestResourceTransformerSupport();
|
||||||
this.transformer.setResourceUrlProvider(createResourceUrlProvider(resolvers));
|
this.transformer.setResourceUrlProvider(createUrlProvider(resolvers));
|
||||||
|
|
||||||
this.request = new MockHttpServletRequest("GET", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceUrlProvider createResourceUrlProvider(List<ResourceResolver> resolvers) {
|
private ResourceUrlProvider createUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
||||||
handler.setResourceResolvers(resolvers);
|
handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
urlProvider.setHandlerMap(Collections.singletonMap("/resources/**", handler));
|
urlProvider.setHandlerMap(Collections.singletonMap("/resources/**", handler));
|
||||||
return urlProvider;
|
return urlProvider;
|
||||||
|
@ -70,30 +71,37 @@ public class ResourceTransformerSupportTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPath() throws Exception {
|
public void resolveUrlPath() {
|
||||||
this.request.setRequestURI("/context/servlet/resources/main.css");
|
this.request.setRequestURI("/context/servlet/resources/main.css");
|
||||||
this.request.setContextPath("/context");
|
this.request.setContextPath("/context");
|
||||||
this.request.setServletPath("/servlet");
|
this.request.setServletPath("/servlet");
|
||||||
String resourcePath = "/context/servlet/resources/bar.css";
|
String resourcePath = "/context/servlet/resources/bar.css";
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
Resource resource = getResource("main.css");
|
||||||
String actual = this.transformer.resolveUrlPath(resourcePath, this.request, css, this.transformerChain);
|
String actual = this.transformer.resolveUrlPath(resourcePath, this.request, resource, this.transformerChain);
|
||||||
|
|
||||||
assertEquals("/context/servlet/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("/context/servlet/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPathWithRelativePath() throws Exception {
|
public void resolveUrlPathWithRelativePath() {
|
||||||
Resource css = new ClassPathResource("test/main.css", getClass());
|
Resource resource = getResource("main.css");
|
||||||
String actual = this.transformer.resolveUrlPath("bar.css", this.request, css, this.transformerChain);
|
String actual = this.transformer.resolveUrlPath("bar.css", this.request, resource, this.transformerChain);
|
||||||
|
|
||||||
assertEquals("bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveUrlPathWithRelativePathInParentDirectory() throws Exception {
|
public void resolveUrlPathWithRelativePathInParentDirectory() {
|
||||||
Resource imagePng = new ClassPathResource("test/images/image.png", getClass());
|
Resource resource = getResource("images/image.png");
|
||||||
String actual = this.transformer.resolveUrlPath("../bar.css", this.request, imagePng, this.transformerChain);
|
String actual = this.transformer.resolveUrlPath("../bar.css", this.request, resource, this.transformerChain);
|
||||||
|
|
||||||
assertEquals("../bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
assertEquals("../bar-11e16cf79faee7ac698c805cf28248d2.css", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Resource getResource(String filePath) {
|
||||||
|
return new ClassPathResource("test/" + filePath, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class TestResourceTransformerSupport extends ResourceTransformerSupport {
|
private static class TestResourceTransformerSupport extends ResourceTransformerSupport {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 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.
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -27,7 +27,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@code ResourceUrlEncodingFilter}.
|
* Unit tests for {@code ResourceUrlEncodingFilter}.
|
||||||
|
@ -38,24 +38,38 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
|
|
||||||
private ResourceUrlEncodingFilter filter;
|
private ResourceUrlEncodingFilter filter;
|
||||||
|
|
||||||
private ResourceUrlProvider resourceUrlProvider;
|
private ResourceUrlProvider urlProvider;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void createFilter() throws Exception {
|
public void createFilter() {
|
||||||
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
VersionResourceResolver versionResolver = new VersionResourceResolver();
|
||||||
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
|
||||||
PathResourceResolver pathResolver = new PathResourceResolver();
|
PathResourceResolver pathResolver = new PathResourceResolver();
|
||||||
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass()));
|
||||||
List<ResourceResolver> resolvers = Arrays.asList(versionResolver, pathResolver);
|
List<ResourceResolver> resolvers = new ArrayList<>();
|
||||||
|
resolvers.add(versionResolver);
|
||||||
|
resolvers.add(pathResolver);
|
||||||
|
|
||||||
this.filter = new ResourceUrlEncodingFilter();
|
this.filter = new ResourceUrlEncodingFilter();
|
||||||
this.resourceUrlProvider = createResourceUrlProvider(resolvers);
|
this.urlProvider = createResourceUrlProvider(resolvers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceUrlProvider createResourceUrlProvider(List<ResourceResolver> resolvers) {
|
||||||
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
|
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
|
||||||
|
handler.setResourceResolvers(resolvers);
|
||||||
|
|
||||||
|
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
||||||
|
urlProvider.setHandlerMap(Collections.singletonMap("/resources/**", handler));
|
||||||
|
return urlProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encodeURL() throws Exception {
|
public void encodeURL() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -68,7 +82,7 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
public void encodeURLWithContext() throws Exception {
|
public void encodeURLWithContext() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/foo");
|
||||||
request.setContextPath("/context");
|
request.setContextPath("/context");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -77,12 +91,11 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-13757
|
@Test // SPR-13757
|
||||||
@Test
|
|
||||||
public void encodeContextPathUrlWithoutSuffix() throws Exception {
|
public void encodeContextPathUrlWithoutSuffix() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context");
|
||||||
request.setContextPath("/context");
|
request.setContextPath("/context");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -95,7 +108,7 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
public void encodeContextPathUrlWithSuffix() throws Exception {
|
public void encodeContextPathUrlWithSuffix() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/");
|
||||||
request.setContextPath("/context");
|
request.setContextPath("/context");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -104,12 +117,11 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-13018
|
@Test // SPR-13018
|
||||||
@Test
|
|
||||||
public void encodeEmptyURLWithContext() throws Exception {
|
public void encodeEmptyURLWithContext() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context/foo");
|
||||||
request.setContextPath("/context");
|
request.setContextPath("/context");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -118,12 +130,11 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-13374
|
@Test // SPR-13374
|
||||||
@Test
|
|
||||||
public void encodeURLWithRequestParams() throws Exception {
|
public void encodeURLWithRequestParams() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
request.setContextPath("/");
|
request.setContextPath("/");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -132,13 +143,12 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPR-13847
|
@Test // SPR-13847
|
||||||
@Test
|
|
||||||
public void encodeUrlPreventStringOutOfBounds() throws Exception {
|
public void encodeUrlPreventStringOutOfBounds() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context-path/index");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context-path/index");
|
||||||
request.setContextPath("/context-path");
|
request.setContextPath("/context-path");
|
||||||
request.setServletPath("");
|
request.setServletPath("");
|
||||||
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
|
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.urlProvider);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
this.filter.doFilter(request, response, (req, res) -> {
|
this.filter.doFilter(request, response, (req, res) -> {
|
||||||
|
@ -147,14 +157,4 @@ public class ResourceUrlEncodingFilterTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected ResourceUrlProvider createResourceUrlProvider(List<ResourceResolver> resolvers) {
|
|
||||||
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
|
||||||
handler.setLocations(Arrays.asList(new ClassPathResource("test/", getClass())));
|
|
||||||
handler.setResourceResolvers(resolvers);
|
|
||||||
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
|
|
||||||
urlProvider.setHandlerMap(Collections.singletonMap("/resources/**", handler));
|
|
||||||
return urlProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue