mirror of
https://github.com/jetty/jetty.project.git
synced 2025-03-04 04:49:12 +00:00
Merge pull request #7873 from eclipse/jetty-10.0.x-4414-gzipInflationExclusion
Issue #4414 - add option to exclude paths from GzipHandler request inflation
This commit is contained in:
commit
7a5ea2bac0
@ -168,6 +168,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
// non-static, as other GzipHandler instances may have different configurations
|
||||
private final IncludeExclude<String> _methods = new IncludeExclude<>();
|
||||
private final IncludeExclude<String> _paths = new IncludeExclude<>(PathSpecSet.class);
|
||||
private final IncludeExclude<String> _inflatePaths = new IncludeExclude<>(PathSpecSet.class);
|
||||
private final IncludeExclude<String> _mimeTypes = new IncludeExclude<>(AsciiLowerCaseSet.class);
|
||||
private HttpField _vary = GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING;
|
||||
|
||||
@ -354,6 +355,41 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds excluded Path Specs for request filtering on request inflation.
|
||||
*
|
||||
* <p>
|
||||
* There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
|
||||
* Regex based. This means that the initial characters on the path spec
|
||||
* line are very strict, and determine the behavior of the path matching.
|
||||
* <ul>
|
||||
* <li>If the spec starts with <code>'^'</code> the spec is assumed to be
|
||||
* a regex based path spec and will match with normal Java regex rules.</li>
|
||||
* <li>If the spec starts with <code>'/'</code> then spec is assumed to be
|
||||
* a Servlet url-pattern rules path spec for either an exact match
|
||||
* or prefix based match.</li>
|
||||
* <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
|
||||
* a Servlet url-pattern rules path spec for a suffix based match.</li>
|
||||
* <li>All other syntaxes are unsupported</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Note: inclusion takes precedence over exclude.
|
||||
*
|
||||
* @param pathspecs Path specs (as per servlet spec) to exclude. If a
|
||||
* ServletContext is available, the paths are relative to the context path,
|
||||
* otherwise they are absolute.<br>
|
||||
* For backward compatibility the pathspecs may be comma separated strings, but this
|
||||
* will not be supported in future versions.
|
||||
* @see #addIncludedInflationPaths(String...)
|
||||
*/
|
||||
public void addExcludedInflationPaths(String... pathspecs)
|
||||
{
|
||||
for (String p : pathspecs)
|
||||
{
|
||||
_inflatePaths.exclude(StringUtil.csvSplit(p));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds included HTTP Methods (eg: POST, PATCH, DELETE) for filtering.
|
||||
*
|
||||
@ -440,6 +476,38 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add included Path Specs for filtering on request inflation.
|
||||
*
|
||||
* <p>
|
||||
* There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
|
||||
* Regex based. This means that the initial characters on the path spec
|
||||
* line are very strict, and determine the behavior of the path matching.
|
||||
* <ul>
|
||||
* <li>If the spec starts with <code>'^'</code> the spec is assumed to be
|
||||
* a regex based path spec and will match with normal Java regex rules.</li>
|
||||
* <li>If the spec starts with <code>'/'</code> then spec is assumed to be
|
||||
* a Servlet url-pattern rules path spec for either an exact match
|
||||
* or prefix based match.</li>
|
||||
* <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
|
||||
* a Servlet url-pattern rules path spec for a suffix based match.</li>
|
||||
* <li>All other syntaxes are unsupported</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Note: inclusion takes precedence over exclusion.
|
||||
*
|
||||
* @param pathspecs Path specs (as per servlet spec) to include. If a
|
||||
* ServletContext is available, the paths are relative to the context path,
|
||||
* otherwise they are absolute
|
||||
*/
|
||||
public void addIncludedInflationPaths(String... pathspecs)
|
||||
{
|
||||
for (String p : pathspecs)
|
||||
{
|
||||
_inflatePaths.include(StringUtil.csvSplit(p));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeflaterPool.Entry getDeflaterEntry(Request request, long contentLength)
|
||||
{
|
||||
@ -495,6 +563,18 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
return excluded.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current filter list of excluded Path Specs for request inflation.
|
||||
*
|
||||
* @return the filter list of excluded Path Specs
|
||||
* @see #getIncludedInflationPaths()
|
||||
*/
|
||||
public String[] getExcludedInflationPaths()
|
||||
{
|
||||
Set<String> excluded = _inflatePaths.getExcluded();
|
||||
return excluded.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current filter list of included HTTP Methods
|
||||
*
|
||||
@ -531,6 +611,18 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
return includes.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current filter list of included Path Specs for request inflation.
|
||||
*
|
||||
* @return the filter list of included Path Specs
|
||||
* @see #getExcludedInflationPaths()
|
||||
*/
|
||||
public String[] getIncludedInflationPaths()
|
||||
{
|
||||
Set<String> includes = _inflatePaths.getIncluded();
|
||||
return includes.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum size, in bytes, that a response {@code Content-Length} must be
|
||||
* before compression will trigger.
|
||||
@ -585,7 +677,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
|
||||
// Handle request inflation
|
||||
HttpFields httpFields = baseRequest.getHttpFields();
|
||||
boolean inflated = _inflateBufferSize > 0 && httpFields.contains(HttpHeader.CONTENT_ENCODING, "gzip");
|
||||
boolean inflated = _inflateBufferSize > 0 && httpFields.contains(HttpHeader.CONTENT_ENCODING, "gzip") && isPathInflatable(path);
|
||||
if (inflated)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
@ -750,6 +842,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
return _paths.test(requestURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the provided Request URI is allowed to be inflated based on the Path Specs filters.
|
||||
*
|
||||
* @param requestURI the request uri
|
||||
* @return whether decompressing is allowed for the given the path.
|
||||
*/
|
||||
protected boolean isPathInflatable(String requestURI)
|
||||
{
|
||||
if (requestURI == null)
|
||||
return true;
|
||||
|
||||
return _inflatePaths.test(requestURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the excluded filter list of HTTP methods (replacing any previously set)
|
||||
*
|
||||
@ -799,6 +905,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
_paths.exclude(pathspecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the excluded filter list of Path specs (replacing any previously set)
|
||||
*
|
||||
* @param pathspecs Path specs (as per servlet spec) to exclude from inflation. If a
|
||||
* ServletContext is available, the paths are relative to the context path,
|
||||
* otherwise they are absolute.
|
||||
* @see #setIncludedInflatePaths(String...)
|
||||
*/
|
||||
public void setExcludedInflatePaths(String... pathspecs)
|
||||
{
|
||||
_inflatePaths.getExcluded().clear();
|
||||
_inflatePaths.exclude(pathspecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of supported {@link DispatcherType} that this filter will operate on.
|
||||
*
|
||||
@ -861,6 +981,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
||||
_paths.include(pathspecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the included filter list of Path specs (replacing any previously set)
|
||||
*
|
||||
* @param pathspecs Path specs (as per servlet spec) to include for inflation. If a
|
||||
* ServletContext is available, the paths are relative to the context path,
|
||||
* otherwise they are absolute
|
||||
* @see #setExcludedInflatePaths(String...)
|
||||
*/
|
||||
public void setIncludedInflatePaths(String... pathspecs)
|
||||
{
|
||||
_inflatePaths.getIncluded().clear();
|
||||
_inflatePaths.include(pathspecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum response size to trigger dynamic compression.
|
||||
* <p>
|
||||
|
@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
@ -55,6 +56,7 @@ import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
@ -688,6 +690,49 @@ public class GzipHandlerTest
|
||||
assertEquals(__icontent, testOut.toString("UTF8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeExcludeGzipHandlerInflate() throws Exception
|
||||
{
|
||||
gzipHandler.addExcludedInflationPaths("/ctx/echo/exclude");
|
||||
gzipHandler.addIncludedInflationPaths("/ctx/echo/include");
|
||||
|
||||
String message = "hello world";
|
||||
byte[] gzippedMessage = gzipContent(message);
|
||||
|
||||
// The included path does deflate the content.
|
||||
HttpTester.Response response = sendGzipRequest("/ctx/echo/include", message);
|
||||
assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
|
||||
assertThat(response.getContent(), equalTo(message));
|
||||
|
||||
// The excluded path does not deflate the content.
|
||||
response = sendGzipRequest("/ctx/echo/exclude", message);
|
||||
assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
|
||||
assertThat(response.getContentBytes(), equalTo(gzippedMessage));
|
||||
}
|
||||
|
||||
private byte[] gzipContent(String content) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream output = new GZIPOutputStream(baos);
|
||||
output.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
output.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private HttpTester.Response sendGzipRequest(String uri, String data) throws Exception
|
||||
{
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
request.setMethod("GET");
|
||||
request.setURI(uri);
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host", "tester");
|
||||
request.setHeader("Content-Type", "text/plain");
|
||||
request.setHeader("Content-Encoding", "gzip");
|
||||
request.setContent(gzipContent(data));
|
||||
|
||||
return HttpTester.parseResponse(_connector.getResponse(request.generate()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddGetPaths()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user