Merge pull request #1613 from xz64/header_filters

Add general purpose HeaderFilter
This commit is contained in:
Joakim Erdfelt 2017-06-15 10:40:21 -07:00 committed by GitHub
commit 10da4fce1d
6 changed files with 965 additions and 0 deletions

View File

@ -30,6 +30,7 @@ include::balancer-servlet.adoc[]
include::cgi-servlet.adoc[]
include::qos-filter.adoc[]
include::dos-filter.adoc[]
include::header-filter.adoc[]
include::gzip-filter.adoc[]
include::cross-origin-filter.adoc[]
include::resource-handler.adoc[]

View File

@ -0,0 +1,115 @@
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ========================================================================
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
[[header-filter]]
=== Header Filter
[[header-filter-metadata]]
==== Info
* Classname: `org.eclipse.jetty.servlets.HeaderFilter`
* Maven Artifact: org.eclipse.jetty:jetty-servlets
* Javadoc: {JDURL}/org/eclipse/jetty/servlets/HeaderFilter.html
* Xref: {JXURL}/org/eclipse/jetty/servlets/HeaderFilter.html
[[header-filter-usage]]
==== Usage
The header filter sets or adds headers to each response based on an optionally included/excluded list of path specs, mime types, and/or HTTP methods.
===== Required JARs
To use the Header Filter, these JAR files must be available in WEB-INF/lib:
* $JETTY_HOME/lib/jetty-http.jar
* $JETTY_HOME/lib/jetty-servlets.jar
* $JETTY_HOME/lib/jetty-util.jar
===== Sample Configuration
Place the configuration in a webapp's `web.xml` or `jetty-web.xml`.
This filter will perform the following actions on each response:
* Set the X-Frame-Options header to DENY.
* Add a Cache-Control header containing no-cache, no-store, must-revalidate
* Set the Expires header to approximately one year in the future.
* Add a Date header with the current system time.
____
[NOTE]
Each action must be separated by a comma.
____
[source, xml, subs="{sub-order}"]
----
<filter>
<filter-name>HeaderFilter</filter-name>
<filter-class>org.eclipse.jetty.servlets.HeaderFilter</filter-class>
<init-param>
<param-name>headerConfig</param-name>
<param-value>
set X-Frame-Options: DENY,
"add Cache-Control: no-cache, no-store, must-revalidate",
setDate Expires: 31540000000,
addDate Date: 0
</param-value>
</init-param>
</filter>
----
[[header-filter-init]]
===== Configuring Header Filter Parameters
The following `init` parameters control the behavior of the filter:
includedPaths::
Optional. CSV of included path specs.
excludedPaths::
Optional. CSV of excluded path specs.
includedMimeTypes::
Optional. CSV of included mime types.
excludedMimeTypes::
Optional. CSV of excluded mime types.
includedHttpMethods::
Optional. CSV of included http methods.
excludedHttpMethods::
Optional. CSV of excluded http methods.
headerConfig::
CSV of actions to perform on headers. The syntax for each action is `action headerName: headerValue`.
Supported header actions:
* `set` - causes set `setHeader` to be called on the response
* `add` - causes set `addHeader` to be called on the response
* `setDate` - causes `setDateHeader` to be called on the response.
* `addDate` - causes `addDateHeader` to be called on the response.
If `setDate` or `addDate` is used, `headerValue` should be the number of milliseconds to add to the current system time before writing the header value.
If a property is both included and excluded by the filter configuration, then it will be considered excluded.
Path spec rules:
* If the spec starts with `^`, the spec is assumed to be a regex based path spec and will match with normal Java regex rules.
* If the spec starts with `/`, the spec is assumed to be a Servlet url-pattern rules path spec for either an exact match or prefix based match.
* If the spec starts with `*.`, the spec is assumed to be a Servlet url-pattern rules path spec for a suffix based match.
* All other syntaxes are unsupported.

View File

@ -0,0 +1,197 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlets;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Header Filter
* <p>
* This filter sets or adds a header to the response.
* <p>
* The {@code headerConfig} init param is a CSV of actions to perform on headers, with the following syntax: <br>
* [action] [header name]: [header value] <br>
* [action] can be one of <code>set</code>, <code>add</code>, <code>setDate</code>, or <code>addDate</code> <br>
* The date actions will add the header value in milliseconds to the current system time before setting a date header.
* <p>
* Below is an example value for <code>headerConfig</code>:<br>
*
* <pre>
* set X-Frame-Options: DENY,
* "add Cache-Control: no-cache, no-store, must-revalidate",
* setDate Expires: 31540000000,
* addDate Date: 0
* </pre>
*
* @see IncludeExcludeBasedFilter
*/
public class HeaderFilter extends IncludeExcludeBasedFilter
{
private List<ConfiguredHeader> _configuredHeaders = new ArrayList<>();
private static final Logger LOG = Log.getLogger(HeaderFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
super.init(filterConfig);
String header_config = filterConfig.getInitParameter("headerConfig");
if (header_config != null)
{
String[] configs = StringUtil.csvSplit(header_config);
for (String config : configs)
_configuredHeaders.add(parseHeaderConfiguration(config));
}
if (LOG.isDebugEnabled())
LOG.debug(this.toString());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
chain.doFilter(request,response);
HttpServletRequest http_request = (HttpServletRequest)request;
HttpServletResponse http_response = (HttpServletResponse)response;
if (!super.shouldFilter(http_request,http_response))
{
return;
}
for (ConfiguredHeader header : _configuredHeaders)
{
if (header.isDate())
{
long header_value = System.currentTimeMillis() + header.getMsOffset();
if (header.isAdd())
{
http_response.addDateHeader(header.getName(),header_value);
}
else
{
http_response.setDateHeader(header.getName(),header_value);
}
}
else // constant header value
{
if (header.isAdd())
{
http_response.addHeader(header.getName(),header.getValue());
}
else
{
http_response.setHeader(header.getName(),header.getValue());
}
}
}
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(super.toString()).append("\n");
sb.append("configured headers:\n");
for (ConfiguredHeader c : _configuredHeaders)
sb.append(c).append("\n");
return sb.toString();
}
private ConfiguredHeader parseHeaderConfiguration(String config)
{
String[] config_tokens = config.trim().split(" ",2);
String method = config_tokens[0].trim();
String header = config_tokens[1];
String[] header_tokens = header.trim().split(":",2);
String header_name = header_tokens[0].trim();
String header_value = header_tokens[1].trim();
ConfiguredHeader configured_header = new ConfiguredHeader(header_name,header_value,method.startsWith("add"),method.endsWith("Date"));
return configured_header;
}
private static class ConfiguredHeader
{
private String _name;
private String _value;
private long _msOffset;
private boolean _add;
private boolean _date;
public ConfiguredHeader(String name, String value, boolean add, boolean date)
{
_name = name;
_value = value;
_add = add;
_date = date;
if (_date)
{
_msOffset = Long.parseLong(_value);
}
}
public String getName()
{
return _name;
}
public String getValue()
{
return _value;
}
public boolean isAdd()
{
return _add;
}
public boolean isDate()
{
return _date;
}
public long getMsOffset()
{
return _msOffset;
}
@Override
public String toString()
{
return (_add?"add":"set") + (_date?"Date":"") + " " + _name + ": " + _value;
}
}
}

View File

@ -0,0 +1,162 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlets;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.pathmap.PathSpecSet;
import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.IncludeExcludeSet;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Include Exclude Based Filter
* <p>
* This is an abstract filter which helps with filtering based on include/exclude of paths, mime types, and/or http methods.
* <p>
* Use the {@link #shouldFilter(HttpServletRequest, HttpServletResponse)} method to determine if a request/response should be filtered. If mime types are used,
* it should be called after {@link javax.servlet.FilterChain#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} since the mime type may not
* be written until then.
*
* Supported init params:
* <ul>
* <li><code>includedPaths</code> - CSV of path specs to include</li>
* <li><code>excludedPaths</code> - CSV of path specs to exclude</li>
* <li><code>includedMimeTypes</code> - CSV of mime types to include</li>
* <li><code>excludedMimeTypes</code> - CSV of mime types to exclude</li>
* <li><code>includedHttpMethods</code> - CSV of http methods to include</li>
* <li><code>excludedHttpMethods</code> - CSV of http methods to exclude</li>
* </ul>
* <p>
* Path spec rules:
* <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> the 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> the 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>
* CSVs are parsed with {@link StringUtil#csvSplit(String)}
*
* @see PathSpecSet
* @see IncludeExcludeSet
*/
public abstract class IncludeExcludeBasedFilter implements Filter
{
private final IncludeExclude<String> _mimeTypes = new IncludeExclude<>();
private final IncludeExclude<String> _httpMethods = new IncludeExclude<>();
private final IncludeExclude<String> _paths = new IncludeExclude<>(PathSpecSet.class);
private static final Logger LOG = Log.getLogger(IncludeExcludeBasedFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String included_paths = filterConfig.getInitParameter("includedPaths");
String excluded_paths = filterConfig.getInitParameter("excludedPaths");
String included_mime_types = filterConfig.getInitParameter("includedMimeTypes");
String excluded_mime_types = filterConfig.getInitParameter("excludedMimeTypes");
String included_http_methods = filterConfig.getInitParameter("includedHttpMethods");
String excluded_http_methods = filterConfig.getInitParameter("excludedHttpMethods");
if (included_paths != null)
{
_paths.include(StringUtil.csvSplit(included_paths));
}
if (excluded_paths != null)
{
_paths.exclude(StringUtil.csvSplit(excluded_paths));
}
if (included_mime_types != null)
{
_mimeTypes.include(StringUtil.csvSplit(included_mime_types));
}
if (excluded_mime_types != null)
{
_mimeTypes.exclude(StringUtil.csvSplit(excluded_mime_types));
}
if (included_http_methods != null)
{
_httpMethods.include(StringUtil.csvSplit(included_http_methods));
}
if (excluded_http_methods != null)
{
_httpMethods.exclude(StringUtil.csvSplit(excluded_http_methods));
}
}
protected boolean shouldFilter(HttpServletRequest http_request, HttpServletResponse http_response)
{
String http_method = http_request.getMethod();
LOG.debug("HTTP method is: {}",http_method);
if (!_httpMethods.test(http_method))
{
LOG.debug("should not apply filter because HTTP method does not match");
return false;
}
String content_type = http_response.getContentType();
LOG.debug("Content Type is: {}",content_type);
content_type = (content_type == null)?"":content_type;
String mime_type = MimeTypes.getContentTypeWithoutCharset(content_type);
LOG.debug("Mime Type is: {}",content_type);
if (!_mimeTypes.test(mime_type))
{
LOG.debug("should not apply filter because mime type does not match");
return false;
}
ServletContext context = http_request.getServletContext();
String path = context == null?http_request.getRequestURI():URIUtil.addPaths(http_request.getServletPath(),http_request.getPathInfo());
LOG.debug("Path is: {}",path);
if (!_paths.test(path))
{
LOG.debug("should not apply filter because path does not match");
return false;
}
return true;
}
@Override
public void destroy()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("filter configuration:\n");
sb.append("paths:\n").append(_paths).append("\n");
sb.append("mime types:\n").append(_mimeTypes).append("\n");
sb.append("http methods:\n").append(_httpMethods);
return sb.toString();
}
}

View File

@ -0,0 +1,137 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlets;
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletTester;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class HeaderFilterTest
{
private ServletTester _tester;
@Before
public void setUp() throws Exception
{
_tester = new ServletTester();
_tester.setContextPath("/context");
_tester.addServlet(NullServlet.class,"/test/*");
_tester.start();
}
@After
public void tearDown() throws Exception
{
_tester.stop();
}
@Test
public void testHeaderFilterSet() throws Exception
{
FilterHolder holder = new FilterHolder(HeaderFilter.class);
holder.setInitParameter("headerConfig","set X-Frame-Options: DENY");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Frame-Options","DENY"));
}
@Test
public void testHeaderFilterAdd() throws Exception
{
FilterHolder holder = new FilterHolder(HeaderFilter.class);
holder.setInitParameter("headerConfig","add X-Frame-Options: DENY");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Frame-Options","DENY"));
}
@Test
public void testHeaderFilterSetDate() throws Exception
{
FilterHolder holder = new FilterHolder(HeaderFilter.class);
holder.setInitParameter("headerConfig","setDate Expires: 100");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains(HttpHeader.EXPIRES));
}
@Test
public void testHeaderFilterAddDate() throws Exception
{
FilterHolder holder = new FilterHolder(HeaderFilter.class);
holder.setInitParameter("headerConfig","addDate Expires: 100");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains(HttpHeader.EXPIRES));
}
public static class NullServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setStatus(HttpStatus.NO_CONTENT_204);
}
}
}

View File

@ -0,0 +1,353 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlets;
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletTester;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class IncludeExcludeBasedFilterTest
{
private ServletTester _tester;
@Before
public void setUp() throws Exception
{
_tester = new ServletTester();
_tester.setContextPath("/context");
_tester.addServlet(NullServlet.class,"/test/*");
_tester.start();
}
@After
public void tearDown() throws Exception
{
_tester.stop();
}
@Test
public void testIncludeExcludeFilterIncludedPathMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedPaths","^/test/0$");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludedPathNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedPaths","^/nomatchtest$");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludedPathMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedPaths","^/test/0$");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludedPathNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedPaths","^/nomatchtest$");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludeOverridesInclude() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedPaths","^/test/0$");
holder.setInitParameter("excludedPaths","^/test/0$");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMethodMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedHttpMethods","GET");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMethodNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedHttpMethods","POST,PUT");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludeMethodMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedHttpMethods","GET");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludeMethodNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedHttpMethods","POST,PUT");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/0");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMimeTypeMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedMimeTypes","application/json");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMimeTypeNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedMimeTypes","application/xml");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludeMimeTypeMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedMimeTypes","application/json");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterExcludeMimeTypeNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("excludedMimeTypes","application/xml");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMimeTypeSemicolonMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedMimeTypes","application/json");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json-utf8");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertTrue(response.contains("X-Custom-Value","1"));
}
@Test
public void testIncludeExcludeFilterIncludeMimeTypeSemicolonNoMatch() throws Exception
{
FilterHolder holder = new FilterHolder(MockIncludeExcludeFilter.class);
holder.setInitParameter("includedMimeTypes","application/xml");
_tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST));
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setVersion("HTTP/1.1");
request.setHeader("Host","localhost");
request.setURI("/context/test/json-utf8");
HttpTester.Response response = HttpTester.parseResponse(_tester.getResponses(request.generate()));
Assert.assertFalse(response.contains("X-Custom-Value","1"));
}
public static class MockIncludeExcludeFilter extends IncludeExcludeBasedFilter
{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
chain.doFilter(request,response);
HttpServletRequest http_request = (HttpServletRequest)request;
HttpServletResponse http_response = (HttpServletResponse)response;
if (!super.shouldFilter(http_request,http_response))
{
return;
}
http_response.setHeader("X-Custom-Value","1");
}
}
public static class NullServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
if (req.getPathInfo().equals("/json"))
{
resp.setContentType("application/json");
}
else if (req.getPathInfo().equals("/json-utf8"))
{
resp.setContentType("application/json; charset=utf-8");
}
resp.setStatus(HttpStatus.NO_CONTENT_204);
}
}
}