001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.resource; 018 019import java.io.File; 020import java.io.IOException; 021import java.io.InputStream; 022import java.net.URI; 023import java.net.URL; 024import java.util.List; 025 026import javax.servlet.http.HttpServletRequest; 027 028import org.springframework.core.io.AbstractResource; 029import org.springframework.core.io.Resource; 030import org.springframework.http.HttpHeaders; 031import org.springframework.lang.Nullable; 032 033/** 034 * A {@code ResourceResolver} that delegates to the chain to locate a resource 035 * and then attempts to find a variation with the ".gz" extension. 036 * 037 * <p>The resolver gets involved only if the "Accept-Encoding" request header 038 * contains the value "gzip" indicating the client accepts gzipped responses. 039 * 040 * @author Jeremy Grelle 041 * @author Rossen Stoyanchev 042 * @author Sam Brannen 043 * @since 4.1 044 * @deprecated as of 5.1, in favor of using {@link EncodedResourceResolver} 045 */ 046@Deprecated 047public class GzipResourceResolver extends AbstractResourceResolver { 048 049 @Override 050 protected Resource resolveResourceInternal(@Nullable HttpServletRequest request, String requestPath, 051 List<? extends Resource> locations, ResourceResolverChain chain) { 052 053 Resource resource = chain.resolveResource(request, requestPath, locations); 054 if (resource == null || (request != null && !isGzipAccepted(request))) { 055 return resource; 056 } 057 058 try { 059 Resource gzipped = new GzippedResource(resource); 060 if (gzipped.exists()) { 061 return gzipped; 062 } 063 } 064 catch (IOException ex) { 065 logger.trace("No gzip resource for [" + resource.getFilename() + "]", ex); 066 } 067 068 return resource; 069 } 070 071 private boolean isGzipAccepted(HttpServletRequest request) { 072 String value = request.getHeader("Accept-Encoding"); 073 return (value != null && value.toLowerCase().contains("gzip")); 074 } 075 076 @Override 077 protected String resolveUrlPathInternal(String resourceUrlPath, 078 List<? extends Resource> locations, ResourceResolverChain chain) { 079 080 return chain.resolveUrlPath(resourceUrlPath, locations); 081 } 082 083 084 /** 085 * A gzipped {@link HttpResource}. 086 */ 087 static final class GzippedResource extends AbstractResource implements HttpResource { 088 089 private final Resource original; 090 091 private final Resource gzipped; 092 093 public GzippedResource(Resource original) throws IOException { 094 this.original = original; 095 this.gzipped = original.createRelative(original.getFilename() + ".gz"); 096 } 097 098 @Override 099 public InputStream getInputStream() throws IOException { 100 return this.gzipped.getInputStream(); 101 } 102 103 @Override 104 public boolean exists() { 105 return this.gzipped.exists(); 106 } 107 108 @Override 109 public boolean isReadable() { 110 return this.gzipped.isReadable(); 111 } 112 113 @Override 114 public boolean isOpen() { 115 return this.gzipped.isOpen(); 116 } 117 118 @Override 119 public boolean isFile() { 120 return this.gzipped.isFile(); 121 } 122 123 @Override 124 public URL getURL() throws IOException { 125 return this.gzipped.getURL(); 126 } 127 128 @Override 129 public URI getURI() throws IOException { 130 return this.gzipped.getURI(); 131 } 132 133 @Override 134 public File getFile() throws IOException { 135 return this.gzipped.getFile(); 136 } 137 138 @Override 139 public long contentLength() throws IOException { 140 return this.gzipped.contentLength(); 141 } 142 143 @Override 144 public long lastModified() throws IOException { 145 return this.gzipped.lastModified(); 146 } 147 148 @Override 149 public Resource createRelative(String relativePath) throws IOException { 150 return this.gzipped.createRelative(relativePath); 151 } 152 153 @Override 154 @Nullable 155 public String getFilename() { 156 return this.original.getFilename(); 157 } 158 159 @Override 160 public String getDescription() { 161 return this.gzipped.getDescription(); 162 } 163 164 @Override 165 public HttpHeaders getResponseHeaders() { 166 HttpHeaders headers = (this.original instanceof HttpResource ? 167 ((HttpResource) this.original).getResponseHeaders() : new HttpHeaders()); 168 headers.add(HttpHeaders.CONTENT_ENCODING, "gzip"); 169 headers.add(HttpHeaders.VARY, HttpHeaders.ACCEPT_ENCODING); 170 return headers; 171 } 172 } 173 174}