Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
5638f7b25b
|
@ -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[]
|
||||
|
|
|
@ -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.
|
|
@ -71,6 +71,12 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-annotations</artifactId>
|
||||
<version>${pluginToolsVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
|
|
|
@ -341,7 +341,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
{
|
||||
try
|
||||
{
|
||||
List<URL> provided = new ArrayList<URL>();
|
||||
List<URL> provided = new ArrayList<>();
|
||||
URL[] urls = null;
|
||||
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
|
|
|
@ -18,24 +18,29 @@
|
|||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.eclipse.jetty.util.PathWatcher;
|
||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.eclipse.jetty.util.PathWatcher;
|
||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* This goal is used in-situ on a Maven project without first requiring that the project
|
||||
* is assembled into a war, saving time during the development cycle.
|
||||
|
@ -154,18 +159,20 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* List of deps that are wars
|
||||
*/
|
||||
protected List<Artifact> warArtifacts;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true)
|
||||
private List<MavenProject> reactorProjects;
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
if ( !"war".equals( project.getPackaging() ) || skip )
|
||||
{
|
||||
return;
|
||||
}
|
||||
warPluginInfo = new WarPluginInfo(project);
|
||||
super.execute();
|
||||
}
|
||||
|
@ -273,7 +280,8 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
webApp.setClasses (classesDirectory);
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
webApp.setTestClasses (testClassesDirectory);
|
||||
|
||||
|
||||
webApp.getClassPathFiles().addAll( getDependencyProjects() );
|
||||
webApp.setWebInfLib (getDependencyFiles());
|
||||
|
||||
//get copy of a list of war artifacts
|
||||
|
@ -556,18 +564,22 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
/**
|
||||
* @return
|
||||
*/
|
||||
private List<File> getDependencyFiles ()
|
||||
private List<File> getDependencyFiles()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
Artifact artifact = iter.next();
|
||||
|
||||
// Include runtime and compile time libraries, and possibly test libs too
|
||||
if(artifact.getType().equals("war"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (getProjectReferences( artifact, project )!=null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
|
||||
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
|
||||
|
@ -581,6 +593,57 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
private List<File> getDependencyProjects()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = iter.next();
|
||||
|
||||
// Include runtime and compile time libraries, and possibly test libs too
|
||||
if(artifact.getType().equals("war"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
|
||||
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
|
||||
|
||||
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
|
||||
continue; //only add dependencies of scope=test if explicitly required
|
||||
|
||||
MavenProject mavenProject = getProjectReferences( artifact, project );
|
||||
if (mavenProject != null)
|
||||
{
|
||||
dependencyFiles.add( Paths.get(mavenProject.getBuild().getOutputDirectory()).toFile() );
|
||||
getLog().debug( "Adding project reference " + mavenProject.getBuild().getOutputDirectory()
|
||||
+ " for WEB-INF/classes " );
|
||||
}
|
||||
}
|
||||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
|
||||
private MavenProject getProjectReferences( Artifact artifact, MavenProject project )
|
||||
{
|
||||
if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Collection<MavenProject> mavenProjects = project.getProjectReferences().values();
|
||||
for ( MavenProject mavenProject : mavenProjects )
|
||||
{
|
||||
if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) )
|
||||
{
|
||||
return mavenProject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -69,10 +69,10 @@ public class JettyWebAppContext extends WebAppContext
|
|||
|
||||
private File _classes = null;
|
||||
private File _testClasses = null;
|
||||
private final List<File> _webInfClasses = new ArrayList<File>();
|
||||
private final List<File> _webInfJars = new ArrayList<File>();
|
||||
private final List<File> _webInfClasses = new ArrayList<>();
|
||||
private final List<File> _webInfJars = new ArrayList<>();
|
||||
private final Map<String, File> _webInfJarMap = new HashMap<String, File>();
|
||||
private List<File> _classpathFiles; //webInfClasses+testClasses+webInfJars
|
||||
private List<File> _classpathFiles = new ArrayList<>(); //webInfClasses+testClasses+webInfJars
|
||||
private String _jettyEnvXml;
|
||||
private List<Overlay> _overlays;
|
||||
|
||||
|
@ -352,7 +352,6 @@ public class JettyWebAppContext extends WebAppContext
|
|||
_webInfClasses.add(_classes);
|
||||
|
||||
// Set up the classpath
|
||||
_classpathFiles = new ArrayList<File>();
|
||||
_classpathFiles.addAll(_webInfClasses);
|
||||
_classpathFiles.addAll(_webInfJars);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ package org.eclipse.jetty.websocket.api;
|
|||
* The <a href="https://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455 specified status codes</a> and <a
|
||||
* href="https://www.iana.org/assignments/websocket/websocket.xml#close-code-number-rules">IANA: WebSocket Close Code Number Registry</a>
|
||||
*/
|
||||
public class StatusCode
|
||||
public final class StatusCode
|
||||
{
|
||||
/**
|
||||
* 1000 indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
|
||||
|
@ -137,6 +137,13 @@ public class StatusCode
|
|||
*/
|
||||
public final static int TRY_AGAIN_LATER = 1013;
|
||||
|
||||
/**
|
||||
* 1014 indicates that a gateway or proxy received and invalid upstream response.
|
||||
* <p>
|
||||
* See <a href="https://www.ietf.org/mail-archive/web/hybi/current/msg10748.html">[hybi] WebSocket Subprotocol Close Code: Bad Gateway</a>
|
||||
*/
|
||||
public final static int INVALID_UPSTREAM_RESPONSE = 1014;
|
||||
|
||||
/**
|
||||
* 1015 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting
|
||||
* a status code to indicate that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).
|
||||
|
@ -144,4 +151,28 @@ public class StatusCode
|
|||
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
|
||||
*/
|
||||
public final static int FAILED_TLS_HANDSHAKE = 1015;
|
||||
|
||||
/**
|
||||
* Test if provided status code can be sent/received on a WebSocket close.
|
||||
* <p>
|
||||
* This honors the RFC6455 rules and IANA rules.
|
||||
* </p>
|
||||
* @param statusCode the statusCode to test
|
||||
* @return true if transmittable
|
||||
*/
|
||||
public static boolean isTransmittable(int statusCode)
|
||||
{
|
||||
return (statusCode == NORMAL) ||
|
||||
(statusCode == SHUTDOWN) ||
|
||||
(statusCode == PROTOCOL) ||
|
||||
(statusCode == BAD_DATA) ||
|
||||
(statusCode == BAD_PAYLOAD) ||
|
||||
(statusCode == POLICY_VIOLATION) ||
|
||||
(statusCode == MESSAGE_TOO_LARGE) ||
|
||||
(statusCode == REQUIRED_EXTENSION) ||
|
||||
(statusCode == SERVER_ERROR) ||
|
||||
(statusCode == SERVICE_RESTART) ||
|
||||
(statusCode == TRY_AGAIN_LATER) ||
|
||||
(statusCode == INVALID_UPSTREAM_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.eclipse.jetty.websocket.common.frames.CloseFrame;
|
|||
|
||||
public class CloseInfo
|
||||
{
|
||||
private int statusCode;
|
||||
private int statusCode = 0;
|
||||
private String reason;
|
||||
|
||||
public CloseInfo()
|
||||
|
@ -71,11 +71,7 @@ public class CloseInfo
|
|||
|
||||
if (validate)
|
||||
{
|
||||
if ((statusCode < StatusCode.NORMAL) || (statusCode == StatusCode.UNDEFINED) || (statusCode == StatusCode.NO_CLOSE)
|
||||
|| (statusCode == StatusCode.NO_CODE) || ((statusCode > 1011) && (statusCode <= 2999)) || (statusCode >= 5000))
|
||||
{
|
||||
throw new ProtocolException("Invalid close code: " + statusCode);
|
||||
}
|
||||
assertValidStatusCode(statusCode);
|
||||
}
|
||||
|
||||
if (data.remaining() > 0)
|
||||
|
@ -128,7 +124,28 @@ public class CloseInfo
|
|||
this.statusCode = statusCode;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
|
||||
private void assertValidStatusCode(int statusCode)
|
||||
{
|
||||
// Status Codes outside of RFC6455 defined scope
|
||||
if ((statusCode <= 999) || (statusCode >= 5000))
|
||||
{
|
||||
throw new ProtocolException("Out of range close status code: " + statusCode);
|
||||
}
|
||||
|
||||
// Status Codes not allowed to exist in a Close frame (per RFC6455)
|
||||
if ((statusCode == StatusCode.NO_CLOSE) || (statusCode == StatusCode.NO_CODE) || (statusCode == StatusCode.FAILED_TLS_HANDSHAKE))
|
||||
{
|
||||
throw new ProtocolException("Frame forbidden close status code: " + statusCode);
|
||||
}
|
||||
|
||||
// Status Code is in defined "reserved space" and is declared (all others are invalid)
|
||||
if ((statusCode >= 1000) && (statusCode <= 2999) && !StatusCode.isTransmittable(statusCode))
|
||||
{
|
||||
throw new ProtocolException("RFC6455 and IANA Undefined close status code: " + statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw status code and reason into a WebSocket Close frame payload buffer.
|
||||
*
|
||||
|
@ -143,11 +160,11 @@ public class CloseInfo
|
|||
// codes that are not allowed to be used in endpoint.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
int len = 2; // status code
|
||||
|
||||
|
||||
byte reasonBytes[] = null;
|
||||
|
||||
|
||||
if (reason != null)
|
||||
{
|
||||
byte[] utf8Bytes = reason.getBytes(StandardCharsets.UTF_8);
|
||||
|
@ -160,24 +177,24 @@ public class CloseInfo
|
|||
{
|
||||
reasonBytes = utf8Bytes;
|
||||
}
|
||||
|
||||
|
||||
if ((reasonBytes != null) && (reasonBytes.length > 0))
|
||||
{
|
||||
len += reasonBytes.length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer buf = BufferUtil.allocate(len);
|
||||
BufferUtil.flipToFill(buf);
|
||||
buf.put((byte) ((statusCode >>> 8) & 0xFF));
|
||||
buf.put((byte) ((statusCode >>> 0) & 0xFF));
|
||||
|
||||
|
||||
if ((reasonBytes != null) && (reasonBytes.length > 0))
|
||||
{
|
||||
buf.put(reasonBytes, 0, reasonBytes.length);
|
||||
}
|
||||
BufferUtil.flipToFlush(buf, 0);
|
||||
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -190,17 +207,15 @@ public class CloseInfo
|
|||
{
|
||||
CloseFrame frame = new CloseFrame();
|
||||
frame.setFin(true);
|
||||
if ((statusCode >= 1000) && (statusCode != StatusCode.NO_CLOSE) && (statusCode != StatusCode.NO_CODE))
|
||||
// Frame forbidden codes result in no status code (and no reason string)
|
||||
if ((statusCode != StatusCode.NO_CLOSE) && (statusCode != StatusCode.NO_CODE) && (statusCode != StatusCode.FAILED_TLS_HANDSHAKE))
|
||||
{
|
||||
if (statusCode == StatusCode.FAILED_TLS_HANDSHAKE)
|
||||
{
|
||||
throw new ProtocolException("Close Frame with status code " + statusCode + " not allowed (per RFC6455)");
|
||||
}
|
||||
assertValidStatusCode(statusCode);
|
||||
frame.setPayload(asByteBuffer());
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
public String getReason()
|
||||
{
|
||||
return this.reason;
|
||||
|
|
|
@ -22,11 +22,9 @@ import static org.eclipse.jetty.websocket.api.StatusCode.FAILED_TLS_HANDSHAKE;
|
|||
import static org.eclipse.jetty.websocket.api.StatusCode.NORMAL;
|
||||
import static org.eclipse.jetty.websocket.api.StatusCode.NO_CLOSE;
|
||||
import static org.eclipse.jetty.websocket.api.StatusCode.NO_CODE;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
@ -102,17 +100,11 @@ public class CloseInfoTest
|
|||
assertThat("close.code",close.getStatusCode(),is(FAILED_TLS_HANDSHAKE));
|
||||
assertThat("close.reason",close.getReason(),nullValue());
|
||||
|
||||
try
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
CloseFrame frame = close.asFrame();
|
||||
fail("Expected " + ProtocolException.class.getName());
|
||||
}
|
||||
catch (ProtocolException e)
|
||||
{
|
||||
// expected path
|
||||
assertThat("ProtocolException message",e.getMessage(),containsString("not allowed (per RFC6455)"));
|
||||
}
|
||||
CloseFrame frame = close.asFrame();
|
||||
assertThat("close frame op code",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
// should result in no payload
|
||||
assertThat("close frame has payload",frame.hasPayload(),is(false));
|
||||
assertThat("close frame payload length",frame.getPayloadLength(),is(0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,37 +46,37 @@ public class CloseHandling_BadStatusCodesTest extends AbstractLocalServerCase
|
|||
{
|
||||
// The various Good UTF8 sequences as a String (hex form)
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
|
||||
// @formatter:off
|
||||
data.add(new Object[]{"7.9.1", 0});
|
||||
data.add(new Object[]{"7.9.2", 999});
|
||||
data.add(new Object[]{"7.9.3", 1004});
|
||||
data.add(new Object[]{"7.9.4", 1005});
|
||||
data.add(new Object[]{"7.9.5", 1006});
|
||||
data.add(new Object[]{"7.9.6", 1012});
|
||||
data.add(new Object[]{"7.9.7", 1013});
|
||||
data.add(new Object[]{"7.9.8", 1014});
|
||||
data.add(new Object[]{"7.9.9", 1015});
|
||||
data.add(new Object[]{"7.9.10", 1016});
|
||||
data.add(new Object[]{"7.9.11", 1100});
|
||||
data.add(new Object[]{"7.9.12", 2000});
|
||||
data.add(new Object[]{"7.9.13", 2999});
|
||||
data.add(new Object[] { "7.9.1", 0 });
|
||||
data.add(new Object[] { "7.9.2", 999 });
|
||||
data.add(new Object[] { "7.9.3", 1004 }); // RFC6455/UNDEFINED
|
||||
data.add(new Object[] { "7.9.4", 1005 }); // RFC6455/Cannot Be Transmitted
|
||||
data.add(new Object[] { "7.9.5", 1006 }); // RFC6455/Cannot Be Transmitted
|
||||
// data.add(new Object[] { "7.9.6", 1012 }); - IANA Defined
|
||||
// data.add(new Object[] { "7.9.7", 1013 }); - IANA Defined
|
||||
// data.add(new Object[] { "7.9.8", 1014 }); - IANA Defined
|
||||
data.add(new Object[] { "7.9.9", 1015 }); // RFC6455/Cannot Be Transmitted
|
||||
data.add(new Object[] { "7.9.10", 1016 });
|
||||
data.add(new Object[] { "7.9.11", 1100 });
|
||||
data.add(new Object[] { "7.9.12", 2000 });
|
||||
data.add(new Object[] { "7.9.13", 2999 });
|
||||
// -- close status codes, with undefined events in spec
|
||||
data.add(new Object[]{"7.13.1", 5000});
|
||||
data.add(new Object[]{"7.13.2", 65536});
|
||||
// @formatter:on
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private final int statusCode;
|
||||
|
||||
|
||||
public CloseHandling_BadStatusCodesTest(String testId, int statusCode)
|
||||
{
|
||||
LOG.debug("Test ID: {}", testId);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* just the close code, no reason
|
||||
*
|
||||
|
@ -89,20 +89,20 @@ public class CloseHandling_BadStatusCodesTest extends AbstractLocalServerCase
|
|||
BufferUtil.clearToFill(payload);
|
||||
payload.putChar((char) statusCode);
|
||||
BufferUtil.flipToFlush(payload, 0);
|
||||
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new CloseFrame().setPayload(payload.slice()));
|
||||
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
session.sendBulk(send);
|
||||
session.expect(expect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* the bad close code, with reason
|
||||
*
|
||||
|
@ -116,13 +116,13 @@ public class CloseHandling_BadStatusCodesTest extends AbstractLocalServerCase
|
|||
payload.putChar((char) statusCode);
|
||||
payload.put(StringUtil.getBytes("Reason"));
|
||||
BufferUtil.flipToFlush(payload, 0);
|
||||
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new CloseFrame().setPayload(payload.slice()));
|
||||
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
session.sendBulk(send);
|
||||
|
|
|
@ -43,40 +43,43 @@ import org.junit.runners.Parameterized.Parameters;
|
|||
public class CloseHandling_GoodStatusCodesTest extends AbstractLocalServerCase
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(CloseHandling_GoodStatusCodesTest.class);
|
||||
|
||||
|
||||
@Parameters(name = "{0} {1}")
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// The various Good UTF8 sequences as a String (hex form)
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
|
||||
// @formatter:off
|
||||
data.add(new Object[]{"7.7.1", 1000});
|
||||
data.add(new Object[]{"7.7.2", 1001});
|
||||
data.add(new Object[]{"7.7.3", 1002});
|
||||
data.add(new Object[]{"7.7.4", 1003});
|
||||
data.add(new Object[]{"7.7.5", 1007});
|
||||
data.add(new Object[]{"7.7.6", 1008});
|
||||
data.add(new Object[]{"7.7.7", 1009});
|
||||
data.add(new Object[]{"7.7.8", 1010});
|
||||
data.add(new Object[]{"7.7.9", 1011});
|
||||
data.add(new Object[]{"7.7.10", 3000});
|
||||
data.add(new Object[]{"7.7.11", 3999});
|
||||
data.add(new Object[]{"7.7.12", 4000});
|
||||
data.add(new Object[]{"7.7.13", 4999});
|
||||
data.add(new Object[] { "7.7.1", 1000 });
|
||||
data.add(new Object[] { "7.7.2", 1001 });
|
||||
data.add(new Object[] { "7.7.3", 1002 });
|
||||
data.add(new Object[] { "7.7.4", 1003 });
|
||||
data.add(new Object[] { "7.7.5", 1007 });
|
||||
data.add(new Object[] { "7.7.6", 1008 });
|
||||
data.add(new Object[] { "7.7.7", 1009 });
|
||||
data.add(new Object[] { "7.7.8", 1010 });
|
||||
data.add(new Object[] { "7.7.9", 1011 });
|
||||
data.add(new Object[] { "IANA Assigned", 1012 });
|
||||
data.add(new Object[] { "IANA Assigned", 1013 });
|
||||
data.add(new Object[] { "IANA Assigned", 1014 });
|
||||
data.add(new Object[] { "7.7.10", 3000 });
|
||||
data.add(new Object[] { "7.7.11", 3999 });
|
||||
data.add(new Object[] { "7.7.12", 4000 });
|
||||
data.add(new Object[] { "7.7.13", 4999 });
|
||||
// @formatter:on
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private final int statusCode;
|
||||
|
||||
|
||||
public CloseHandling_GoodStatusCodesTest(String testId, int statusCode)
|
||||
{
|
||||
LOG.debug("Test ID: {}", testId);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* just the close code, no reason
|
||||
*
|
||||
|
@ -89,20 +92,20 @@ public class CloseHandling_GoodStatusCodesTest extends AbstractLocalServerCase
|
|||
BufferUtil.clearToFill(payload);
|
||||
payload.putChar((char) statusCode);
|
||||
BufferUtil.flipToFlush(payload, 0);
|
||||
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new CloseFrame().setPayload(payload.slice()));
|
||||
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseFrame().setPayload(DataUtils.copyOf(payload)));
|
||||
|
||||
|
||||
try (LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
session.sendBulk(send);
|
||||
session.expect(expect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* the good close code, with reason
|
||||
*
|
||||
|
@ -115,13 +118,13 @@ public class CloseHandling_GoodStatusCodesTest extends AbstractLocalServerCase
|
|||
payload.putChar((char) statusCode);
|
||||
payload.put(StringUtil.getBytes("Reason"));
|
||||
payload.flip();
|
||||
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new CloseFrame().setPayload(payload.slice()));
|
||||
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseFrame().setPayload(DataUtils.copyOf(payload)));
|
||||
|
||||
|
||||
try (LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
session.sendBulk(send);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new TextFrame().setPayload("small")); // echo on good frame
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new TextFrame().setPayload("small")); // echo on good frame
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new TextFrame().setPayload("small")); // echo on good frame
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
@ -216,7 +216,7 @@ public class ReservedBitTest extends AbstractLocalServerCase
|
|||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
|
||||
try (StacklessLogging ignored = new StacklessLogging(Parser.class);
|
||||
LocalFuzzer session = server.newLocalFuzzer())
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue