jodd.servlet.filter.GzipFilter Maven / Gradle / Ivy
Show all versions of jodd-all Show documentation
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.servlet.filter;
import jodd.io.FileNameUtil;
import jodd.servlet.ServletUtil;
import jodd.typeconverter.Convert;
import jodd.typeconverter.TypeConversionException;
import jodd.util.StringPool;
import jodd.util.StringUtil;
import jodd.util.Wildcard;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Compresses output with GZIP, for browsers that supports it.
*
* Configuration is based on the following initialization parameters:
*
*
* threshold
- min number of bytes for compressing
* or 0 for no compression at all. By defaults is 0. Good value is 128.
*
* match
- comma separated string patterns to be found
* in the uri for using gzip. Only uris that match these patterns will be gzipped.
* Use '*' to enable default matching using just extensions.
* extensions (ignoring the wildcards value)
*
* extensions
- when match is set to all resources,
* this parameter defines list of URI extensions that should be gzipped.
* By default set to: html, htm, css, js
. Use '*' to
* match all extensions.
*
*
* exclude
- comma separated string patterns to be excluded
* if found in uri for using gzip. It is applied only if all urls are matched.
*
* wildcards
- boolean that specifies wildcard matching for string patterns.
* by default false
. URL is matched as {@link Wildcard#matchPathOne(String, String[]) paths}.
*
* requestParameterName
- name of request parameter that can override GZipping.
* Default value is gzip
. Set it to an empty string to turn this feature off.
*
*
*
*
* All matching is done in lowercase. You can override this class for finer control.
*/
public class GzipFilter implements Filter {
/**
* If browser supports gzip, sets the Content-Encoding response header and
* invoke resource with a wrapped response that collects all the output.
* Extracts the output and write it into a gzipped byte array. Finally, write
* that array to the client's output stream.
*
* If browser does not support gzip, invokes resource normally.
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (
(threshold == 0) ||
(!ServletUtil.isGzipSupported(req)) ||
(!isGzipEligible(req))
) {
chain.doFilter(request, response);
return;
}
GzipResponseWrapper wrappedResponse = new GzipResponseWrapper(res);
wrappedResponse.setCompressionThreshold(threshold);
try {
chain.doFilter(request, wrappedResponse);
} finally {
wrappedResponse.finishResponse();
}
}
protected int threshold; // the threshold number to compress, (0 == no compression).
protected String[] matches;
protected String[] excludes;
protected boolean wildcards;
protected String requestParameterName;
protected String[] extensions;
/**
* Filter initialization.
*/
public void init(FilterConfig config) throws ServletException {
try {
wildcards = Convert.toBooleanValue(config.getInitParameter("wildcards"), false);
} catch (TypeConversionException ignore) {
wildcards = false;
}
// min size
try {
threshold = Convert.toIntValue(config.getInitParameter("threshold"), 0);
} catch (TypeConversionException ignore) {
threshold = 0;
}
// match string
String uriMatch = config.getInitParameter("match");
if ((uriMatch != null) && (!uriMatch.equals(StringPool.STAR))) {
matches = StringUtil.splitc(uriMatch, ',');
for (int i = 0; i < matches.length; i++) {
matches[i] = matches[i].trim();
}
}
// exclude string
String uriExclude = config.getInitParameter("exclude");
if (uriExclude != null) {
excludes = StringUtil.splitc(uriExclude, ',');
for (int i = 0; i < excludes.length; i++) {
excludes[i] = excludes[i].trim();
}
}
// request parameter name
requestParameterName = config.getInitParameter("requestParameterName");
if (requestParameterName == null) {
requestParameterName = "gzip";
}
requestParameterName = requestParameterName.trim();
// allowed extensions
String urlExtensions = config.getInitParameter("extensions");
if (urlExtensions != null) {
if (urlExtensions.equals(StringPool.STAR)) {
extensions = null;
} else {
extensions = StringUtil.splitc(urlExtensions, ", ");
}
} else {
extensions = new String[] {"html", "htm", "js", "css"};
}
}
public void destroy() {
}
/**
* Determine if request is eligible for GZipping.
*/
protected boolean isGzipEligible(HttpServletRequest request) {
// request parameter name
if (requestParameterName.length() != 0) {
String forceGzipString = request.getParameter(requestParameterName);
if (forceGzipString != null) {
return Convert.toBooleanValue(forceGzipString, false);
}
}
// extract uri
String uri = request.getRequestURI();
if (uri == null) {
return false;
}
uri = uri.toLowerCase();
boolean result = false;
// check uri
if (matches == null) { // match == *
if (extensions == null) { // extensions == *
return true;
}
// extension
String extension = FileNameUtil.getExtension(uri);
if (extension.length() > 0) {
extension = extension.toLowerCase();
if (StringUtil.equalsOne(extension, extensions) != -1) {
result = true;
}
}
} else {
if (wildcards) {
result = Wildcard.matchPathOne(uri, matches) != -1;
} else {
for (String match : matches) {
if (uri.contains(match)) {
result = true;
break;
}
}
}
}
if ((result) && (excludes != null)) {
if (wildcards) {
if (Wildcard.matchPathOne(uri, excludes) != -1) {
result = false;
}
} else {
for (String exclude : excludes) {
if (uri.contains(exclude)) {
result = false; // excludes founded
break;
}
}
}
}
return result;
}
}