@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException { Resource transformed = this.cache.get(resource, Resource.class); if (transformed != null) { if (logger.isTraceEnabled()) { logger.trace("Resource resolved from cache"); } return transformed; } transformed = transformerChain.transform(request, resource); this.cache.put(resource, transformed); return transformed; }
/** * A transformer can use this method when a resource being transformed * contains links to other resources. Such links need to be replaced with the * public facing link as determined by the resource resolver chain (e.g. the * public URL may have a version inserted). * @param resourcePath the path to a resource that needs to be re-written * @param request the current request * @param resource the resource being transformed * @param transformerChain the transformer chain * @return the resolved URL, or {@code} if not resolvable */ @Nullable protected String resolveUrlPath(String resourcePath, HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) { if (resourcePath.startsWith("/")) { // full resource path ResourceUrlProvider urlProvider = findResourceUrlProvider(request); return (urlProvider != null ? urlProvider.getForRequestUrl(request, resourcePath) : null); } else { // try resolving as relative path return transformerChain.getResolverChain().resolveUrlPath( resourcePath, Collections.singletonList(resource)); } }
@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException { Resource transformed = transformerChain.transform(request, resource); return minifyService.minify(transformed); }
/** * A transformer can use this method when a resource being transformed * contains links to other resources. Such links need to be replaced with the * public facing link as determined by the resource resolver chain (e.g. the * public URL may have a version inserted). * @param resourcePath the path to a resource that needs to be re-written * @param request the current request * @param resource the resource being transformed * @param transformerChain the transformer chain * @return the resolved URL, or {@code} if not resolvable */ @Nullable protected String resolveUrlPath(String resourcePath, HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) { if (resourcePath.startsWith("/")) { // full resource path ResourceUrlProvider urlProvider = findResourceUrlProvider(request); return (urlProvider != null ? urlProvider.getForRequestUrl(request, resourcePath) : null); } else { // try resolving as relative path return transformerChain.getResolverChain().resolveUrlPath( resourcePath, Collections.singletonList(resource)); } }
@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException { if (resourceTransformerCachingEnabled) { return super.transform(request, resource, transformerChain); } else { return transformerChain.transform(request, resource); } }
private LineOutput processLine(LineInfo info, HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) { if (!info.isLink()) { return new LineOutput(info.getLine(), null); } Resource appCacheResource = transformerChain.getResolverChain() .resolveResource(null, info.getLine(), Collections.singletonList(resource)); String path = info.getLine(); String absolutePath = toAbsolutePath(path, request); String newPath = resolveUrlPath(absolutePath, request, resource, transformerChain); return new LineOutput((newPath != null ? newPath : path), appCacheResource); }
@Nullable protected Resource getResource(HttpServletRequest request) throws IOException { String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); if (path == null) { throw new IllegalStateException("Required request attribute '" + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); } path = processPath(path); if (!StringUtils.hasText(path) || isInvalidPath(path)) { return null; } if (isInvalidEncodedPath(path)) { return null; } Assert.notNull(this.resolverChain, "ResourceResolverChain not initialized."); Assert.notNull(this.transformerChain, "ResourceTransformerChain not initialized."); Resource resource = this.resolverChain.resolveResource(request, path, getLocations()); if (resource != null) { resource = this.transformerChain.transform(request, resource); } return resource; }
private LineOutput processLine(LineInfo info, HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) { if (!info.isLink()) { return new LineOutput(info.getLine(), null); } Resource appCacheResource = transformerChain.getResolverChain() .resolveResource(null, info.getLine(), Collections.singletonList(resource)); String path = info.getLine(); String absolutePath = toAbsolutePath(path, request); String newPath = resolveUrlPath(absolutePath, request, resource, transformerChain); return new LineOutput((newPath != null ? newPath : path), appCacheResource); }
@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException { Resource transformed = this.cache.get(resource, Resource.class); if (transformed != null) { if (logger.isTraceEnabled()) { logger.trace("Resource resolved from cache"); } return transformed; } transformed = transformerChain.transform(request, resource); this.cache.put(resource, transformed); return transformed; }
/** * A transformer can use this method when a resource being transformed * contains links to other resources. Such links need to be replaced with the * public facing link as determined by the resource resolver chain (e.g. the * public URL may have a version inserted). * @param resourcePath the path to a resource that needs to be re-written * @param request the current request * @param resource the resource being transformed * @param transformerChain the transformer chain * @return the resolved URL, or {@code} if not resolvable */ protected String resolveUrlPath(String resourcePath, HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) { if (resourcePath.startsWith("/")) { // full resource path ResourceUrlProvider urlProvider = findResourceUrlProvider(request); return (urlProvider != null ? urlProvider.getForRequestUrl(request, resourcePath) : null); } else { // try resolving as relative path return transformerChain.getResolverChain().resolveUrlPath( resourcePath, Collections.singletonList(resource)); } }
@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain chain) throws IOException { resource = chain.transform(request, resource); if (!this.fileExtension.equals(StringUtils.getFilenameExtension(resource.getFilename()))) { return resource; } byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream()); String content = new String(bytes, DEFAULT_CHARSET); if (!content.startsWith(MANIFEST_HEADER)) { if (logger.isTraceEnabled()) { logger.trace("Skipping " + resource + ": Manifest does not start with 'CACHE MANIFEST'"); } return resource; } @SuppressWarnings("resource") Scanner scanner = new Scanner(content); LineInfo previous = null; LineAggregator aggregator = new LineAggregator(resource, content); while (scanner.hasNext()) { String line = scanner.nextLine(); LineInfo current = new LineInfo(line, previous); LineOutput lineOutput = processLine(current, request, resource, chain); aggregator.add(lineOutput); previous = current; } return aggregator.createResource(); }
throws IOException { resource = transformerChain.transform(request, resource);
@Nullable protected Resource getResource(HttpServletRequest request) throws IOException { String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); if (path == null) { throw new IllegalStateException("Required request attribute '" + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); } path = processPath(path); if (!StringUtils.hasText(path) || isInvalidPath(path)) { return null; } if (isInvalidEncodedPath(path)) { return null; } Assert.notNull(this.resolverChain, "ResourceResolverChain not initialized."); Assert.notNull(this.transformerChain, "ResourceTransformerChain not initialized."); Resource resource = this.resolverChain.resolveResource(request, path, getLocations()); if (resource != null) { resource = this.transformerChain.transform(request, resource); } return resource; }
@Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain chain) throws IOException { resource = chain.transform(request, resource); if (!this.fileExtension.equals(StringUtils.getFilenameExtension(resource.getFilename()))) { return resource; } byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream()); String content = new String(bytes, DEFAULT_CHARSET); if (!content.startsWith(MANIFEST_HEADER)) { if (logger.isTraceEnabled()) { logger.trace("Skipping " + resource + ": Manifest does not start with 'CACHE MANIFEST'"); } return resource; } @SuppressWarnings("resource") Scanner scanner = new Scanner(content); LineInfo previous = null; LineAggregator aggregator = new LineAggregator(resource, content); while (scanner.hasNext()) { String line = scanner.nextLine(); LineInfo current = new LineInfo(line, previous); LineOutput lineOutput = processLine(current, request, resource, chain); aggregator.add(lineOutput); previous = current; } return aggregator.createResource(); }
throws IOException { resource = transformerChain.transform(request, resource);
@Test public void transformSkippedForGzippedResource() throws Exception { EncodedResourceResolverTests.createGzippedFile("main.css"); this.request = new MockHttpServletRequest("GET", "/static/main.css"); Resource original = new ClassPathResource("test/main.css", getClass()); EncodedResource gzipped = new EncodedResource(original, "gzip", ".gz"); Resource actual = this.transformerChain.transform(this.request, gzipped); assertSame(gzipped, actual); }
@Test public void transformExtLinksNotAllowed() throws Exception { this.request = new MockHttpServletRequest("GET", "/static/external.css"); List<ResourceTransformer> transformers = Collections.singletonList(new CssLinkResourceTransformer()); ResourceResolverChain mockChain = Mockito.mock(DefaultResourceResolverChain.class); ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers); Resource resource = getResource("external.css"); String expected = "@import url(\"http://example.org/fonts/css\");\n" + "body { background: url(\"file:///home/spring/image.png\") }\n" + "figure { background: url(\"//example.org/style.css\")}"; TransformedResource transformedResource = (TransformedResource) chain.transform(this.request, resource); String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8); result = StringUtils.deleteAny(result, "\r"); assertEquals(expected, result); List<Resource> locations = Collections.singletonList(resource); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("http://example.org/fonts/css", locations); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("file:///home/spring/image.png", locations); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("//example.org/style.css", locations); }
@Test public void transformSkippedForNonCssResource() throws Exception { this.request = new MockHttpServletRequest("GET", "/static/images/image.png"); Resource expected = getResource("images/image.png"); Resource actual = this.transformerChain.transform(this.request, expected); assertSame(expected, actual); }
@Test public void transformNoLinks() throws Exception { this.request = new MockHttpServletRequest("GET", "/static/foo.css"); Resource expected = getResource("foo.css"); Resource actual = this.transformerChain.transform(this.request, expected); assertSame(expected, actual); }
@Test public void transform() throws Exception { this.request = new MockHttpServletRequest("GET", "/static/main.css"); Resource css = getResource("main.css"); String expected = "\n" + "@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" + "@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" + "@import url(/static/bar-11e16cf79faee7ac698c805cf28248d2.css);\n\n" + "@import \"/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css\";\n" + "@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\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); result = StringUtils.deleteAny(result, "\r"); assertEquals(expected, result); }