Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
This commit is contained in:
commit
62758122c3
|
@ -33,23 +33,12 @@
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<module name="TreeWalker">
|
<module name="TreeWalker">
|
||||||
<!--
|
|
||||||
Eclipse Jetty Specific.
|
|
||||||
===========================================================================================
|
|
||||||
-->
|
|
||||||
|
|
||||||
<module name="SuppressionCommentFilter">
|
<module name="SuppressionCommentFilter">
|
||||||
<property name="offCommentFormat" value="@checkstyle-disable-check : ([\w\|]+)"/>
|
<property name="offCommentFormat" value="@checkstyle-disable-check : ([\w\|]+)"/>
|
||||||
<property name="onCommentFormat" value="@checkstyle-enable-check : ([\w\|]+)"/>
|
<property name="onCommentFormat" value="@checkstyle-enable-check : ([\w\|]+)"/>
|
||||||
<property name="checkFormat" value="$1"/>
|
<property name="checkFormat" value="$1"/>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<!-- Check abbreviations(consecutive capital letters) length in identifier name -->
|
|
||||||
<module name="AbbreviationAsWordInName">
|
|
||||||
<property name="ignoreFinal" value="true"/>
|
|
||||||
<property name="allowedAbbreviations" value="ALPN, ASCII, AWT, CRLDP, CRLF, FCGI, GZIP, HTTP, HTTPS, ID, IP, ISO8859, JAAS, JDBC, JMXRMI, JNDI, JPMS, JSON, JSTL, LDAP, PROXY, RFC, SPNEGO, URI, URL, UTF8, XML"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- Location of Annotations -->
|
<!-- Location of Annotations -->
|
||||||
<module name="AnnotationLocation">
|
<module name="AnnotationLocation">
|
||||||
<property name="allowSamelineSingleParameterlessAnnotation" value="false"/>
|
<property name="allowSamelineSingleParameterlessAnnotation" value="false"/>
|
||||||
|
@ -90,7 +79,7 @@
|
||||||
|
|
||||||
<!-- Indentation Rules -->
|
<!-- Indentation Rules -->
|
||||||
<module name="Indentation">
|
<module name="Indentation">
|
||||||
<property name="throwsIndent" value="0"/>
|
<property name="arrayInitIndent" value="8"/>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<!-- Interface Type Parameter Name -->
|
<!-- Interface Type Parameter Name -->
|
||||||
|
@ -215,7 +204,9 @@
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<!-- all switch statements should have "default" label declared -->
|
<!-- all switch statements should have "default" label declared -->
|
||||||
|
<!-- Disabled: Is super noisy
|
||||||
<module name="MissingSwitchDefault"/>
|
<module name="MissingSwitchDefault"/>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- prevent line wrapping of import / package statements -->
|
<!-- prevent line wrapping of import / package statements -->
|
||||||
<module name="NoLineWrap"/>
|
<module name="NoLineWrap"/>
|
||||||
|
@ -226,9 +217,6 @@
|
||||||
<!-- Filename and Classname match -->
|
<!-- Filename and Classname match -->
|
||||||
<module name="OuterTypeFilename"/>
|
<module name="OuterTypeFilename"/>
|
||||||
|
|
||||||
<!-- Checks that overload methods are grouped together -->
|
|
||||||
<module name="OverloadMethodsDeclarationOrder"/>
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Checks based on the Java Language Specification recommendations.
|
Checks based on the Java Language Specification recommendations.
|
||||||
https://docs.oracle.com/javase/specs/jls/se8/html/index.html
|
https://docs.oracle.com/javase/specs/jls/se8/html/index.html
|
||||||
|
@ -284,8 +272,5 @@
|
||||||
<module name="UpperEll"/>
|
<module name="UpperEll"/>
|
||||||
<!-- TODO: look for float / double version of above -->
|
<!-- TODO: look for float / double version of above -->
|
||||||
|
|
||||||
<!-- Checks the distance between declaration of variable and its first usage -->
|
|
||||||
<module name="VariableDeclarationUsageDistance"/>
|
|
||||||
|
|
||||||
</module>
|
</module>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -188,11 +188,12 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletContainerInitializerOrdering
|
* ServletContainerInitializerOrdering
|
||||||
*
|
* <p>Applies an ordering to the {@link ServletContainerInitializer}s for the context, using
|
||||||
* A list of classnames of ServletContainerInitializers in the order in which
|
* the value of the "org.eclipse.jetty.containerInitializerOrder" context attribute.
|
||||||
* they are to be called back. One name only in the list can be "*", which is a
|
* The attribute value is a list of classnames of ServletContainerInitializers in the order in which
|
||||||
|
* they are to be called. One name only in the list can be "*", which is a
|
||||||
* wildcard which matches any other ServletContainerInitializer name not already
|
* wildcard which matches any other ServletContainerInitializer name not already
|
||||||
* matched.
|
* matched.</p>
|
||||||
*/
|
*/
|
||||||
public class ServletContainerInitializerOrdering
|
public class ServletContainerInitializerOrdering
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,14 +5,34 @@
|
||||||
<version>10.0.0-SNAPSHOT</version>
|
<version>10.0.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>cdi-2</artifactId>
|
<artifactId>jetty-cdi</artifactId>
|
||||||
<name>Jetty :: CDI 2</name>
|
<name>Jetty :: CDI</name>
|
||||||
<url>http://www.eclipse.org/jetty</url>
|
<url>http://www.eclipse.org/jetty</url>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
<bundle-symbolic-name>${project.groupId}.cdi2</bundle-symbolic-name>
|
<bundle-symbolic-name>${project.groupId}.cdi</bundle-symbolic-name>
|
||||||
</properties>
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-annotations</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<Call name="setAttribute">
|
||||||
|
<Arg type="String">org.eclipse.jetty.cdi</Arg>
|
||||||
|
<Arg><Property name="jetty.cdi.mode" default="CdiSpiDecorator"/></Arg>
|
||||||
|
</Call>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
|
||||||
|
<Call name="warn"><Arg>cdi2 module is deprecated!</Arg></Call>
|
||||||
|
</Get>
|
||||||
|
<Ref refid="DeploymentManager">
|
||||||
|
<Call name="addLifeCycleBinding">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.deploy.bindings.GlobalWebappConfigBinding">
|
||||||
|
<Set name="jettyXml"><Property name="jetty.home" default="." />/etc/cdi/jetty-web-cdi2.xml
|
||||||
|
</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Ref>
|
||||||
|
</Configure>
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
|
||||||
|
|
||||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
<Set name="contextPath">/demo</Set>
|
|
||||||
<Set name="war"><Property name="jetty.webapps"/>/demo/</Set>
|
|
||||||
<Get name="serverClassMatcher">
|
<Get name="serverClassMatcher">
|
||||||
<Call name="add">
|
<Call name="add">
|
||||||
<Arg>-org.eclipse.jetty.util.Decorator</Arg>
|
<Arg>-org.eclipse.jetty.util.Decorator</Arg>
|
|
@ -0,0 +1,18 @@
|
||||||
|
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
|
[description]
|
||||||
|
Configures Jetty to use the "CdiDecoratingListener" as the default
|
||||||
|
CDI integration mode that allows a webapp to register it's own CDI
|
||||||
|
decorator.
|
||||||
|
|
||||||
|
[tag]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[provides]
|
||||||
|
cdi-mode
|
||||||
|
|
||||||
|
[depend]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[ini]
|
||||||
|
jetty.cdi.mode=CdiDecoratingListener
|
|
@ -0,0 +1,17 @@
|
||||||
|
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
|
[description]
|
||||||
|
Configures Jetty to use the "CdiSpiDecorator" that calls the CDI SPI
|
||||||
|
as the default CDI integration mode.
|
||||||
|
|
||||||
|
[tag]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[provides]
|
||||||
|
cdi-mode
|
||||||
|
|
||||||
|
[depend]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[ini]
|
||||||
|
jetty.cdi.mode=CdiSpiDecorator
|
|
@ -1,7 +1,34 @@
|
||||||
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
[description]
|
[description]
|
||||||
Jetty setup to support Weld/CDI2 with WELD inside the webapp
|
Support for CDI inside the webapp.
|
||||||
|
This module does not provide CDI, but configures jetty to support various
|
||||||
|
integration modes with a CDI implementation on the webapp classpath.
|
||||||
|
CDI integration modes can be selected per webapp with the "org.eclipse.jetty.cdi"
|
||||||
|
init parameter or defaults to the mode set by the "org.eclipse.jetty.cdi" server
|
||||||
|
attribute (which is initialised from the "jetty.cdi.mode" start property).
|
||||||
|
Supported modes are:
|
||||||
|
CdiSpiDecorator - Jetty will call the CDI SPI within the webapp to decorate
|
||||||
|
objects (default).
|
||||||
|
CdiDecoratingLister - The webapp may register a decorator on the context attribute
|
||||||
|
"org.eclipse.jetty.cdi.decorator".
|
||||||
|
|
||||||
|
[tag]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[provides]
|
||||||
|
cdi
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
cdi2
|
deploy
|
||||||
|
|
||||||
|
[xml]
|
||||||
|
etc/cdi/jetty-cdi.xml
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
lib/jetty-cdi-${jetty.version}.jar
|
||||||
|
lib/apache-jsp/org.mortbay.jasper.apache-el-*.jar
|
||||||
|
|
||||||
|
[ini]
|
||||||
|
jetty.webapp.addSystemClasses+=,org.eclipse.jetty.cdi.CdiServletContainerInitializer
|
||||||
|
jetty.webapp.addServerClasses+=,-org.eclipse.jetty.cdi.CdiServletContainerInitializer
|
|
@ -1,20 +1,23 @@
|
||||||
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
[description]
|
[description]
|
||||||
Jetty setup to support Weld/CDI2 with WELD inside the webapp
|
Deprecated support for CDI integrations inside the webapp.
|
||||||
|
This module does not provide CDI, but configures jetty so that a CDI implementation
|
||||||
|
can enable itself as a decorator for Filters, Servlets and Listeners.
|
||||||
|
This modules uses the deprecated technique of exposing private Jetty decorate APIs to the CDI
|
||||||
|
implementation in the webapp.
|
||||||
|
|
||||||
|
[tag]
|
||||||
|
cdi
|
||||||
|
|
||||||
|
[provides]
|
||||||
|
cdi-mode
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
annotations
|
deploy
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
lib/apache-jsp/org.mortbay.jasper.apache-el-*.jar
|
lib/apache-jsp/org.mortbay.jasper.apache-el-*.jar
|
||||||
|
|
||||||
[ini]
|
[xml]
|
||||||
jetty.webapp.addServerClasses+=,-org.eclipse.jetty.util.Decorator,-org.eclipse.jetty.util.DecoratedObjectFactory
|
etc/cdi/jetty-cdi2.xml
|
||||||
jetty.webapp.addServerClasses+=,-org.eclipse.jetty.server.handler.ContextHandler.,-org.eclipse.jetty.server.handler.ContextHandler,-org.eclipse.jetty.servlet.ServletContextHandler
|
|
||||||
|
|
||||||
|
|
||||||
[license]
|
|
||||||
Weld is an open source project hosted on Github and released under the Apache 2.0 license.
|
|
||||||
http://weld.cdi-spec.org/
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.cdi;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.servlet.DecoratingListener;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DecoratingListener that listens for "org.eclipse.jetty.cdi.decorator"
|
||||||
|
*/
|
||||||
|
class CdiDecoratingListener extends DecoratingListener
|
||||||
|
{
|
||||||
|
public static final String MODE = "CdiDecoratingListener";
|
||||||
|
public static final String ATTRIBUTE = "org.eclipse.jetty.cdi.decorator";
|
||||||
|
|
||||||
|
public CdiDecoratingListener(ServletContextHandler contextHandler)
|
||||||
|
{
|
||||||
|
super(contextHandler, ATTRIBUTE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.cdi;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.servlet.ServletContainerInitializer;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.util.Loader;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A {@link ServletContainerInitializer} that introspects for a CDI API
|
||||||
|
* implementation within a web application and applies an integration
|
||||||
|
* mode if CDI is found. CDI integration modes can be selected per webapp with
|
||||||
|
* the "org.eclipse.jetty.cdi" init parameter or default to the mode set by the
|
||||||
|
* "org.eclipse.jetty.cdi" server attribute. Supported modes are:</p>
|
||||||
|
* <dl>
|
||||||
|
* <dt>CdiSpiDecorator</dt>
|
||||||
|
* <dd>Jetty will call the CDI SPI within the webapp to decorate objects (default).</dd>
|
||||||
|
* <dt>CdiDecoratingLister</dt>
|
||||||
|
* <dd>The webapp may register a decorator on the context attribute
|
||||||
|
* "org.eclipse.jetty.cdi.decorator".</dd>
|
||||||
|
* </dl>
|
||||||
|
*
|
||||||
|
* @see AnnotationConfiguration.ServletContainerInitializerOrdering
|
||||||
|
*/
|
||||||
|
public class CdiServletContainerInitializer implements ServletContainerInitializer
|
||||||
|
{
|
||||||
|
public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.cdi";
|
||||||
|
private static final Logger LOG = Log.getLogger(CdiServletContainerInitializer.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartup(Set<Class<?>> c, ServletContext ctx)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServletContextHandler context = ServletContextHandler.getServletContextHandler(ctx);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
|
||||||
|
// Test if CDI is in the webapp by trying to load the CDI class.
|
||||||
|
ClassLoader loader = context.getClassLoader();
|
||||||
|
if (loader == null)
|
||||||
|
Loader.loadClass("javax.enterprise.inject.spi.CDI");
|
||||||
|
else
|
||||||
|
loader.loadClass("javax.enterprise.inject.spi.CDI");
|
||||||
|
|
||||||
|
String mode = ctx.getInitParameter(CDI_INTEGRATION_ATTRIBUTE);
|
||||||
|
if (mode == null)
|
||||||
|
{
|
||||||
|
mode = (String)context.getServer().getAttribute(CDI_INTEGRATION_ATTRIBUTE);
|
||||||
|
if (mode == null)
|
||||||
|
mode = CdiSpiDecorator.MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case CdiSpiDecorator.MODE:
|
||||||
|
context.getObjectFactory().addDecorator(new CdiSpiDecorator(context));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CdiDecoratingListener.MODE:
|
||||||
|
context.addEventListener(new CdiDecoratingListener(context));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.setAttribute(CDI_INTEGRATION_ATTRIBUTE, mode);
|
||||||
|
LOG.info(mode + " enabled in " + ctx);
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException | ClassNotFoundException e)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("CDI not found in " + ctx, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.cdi;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.util.Decorator;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Decorator that invokes the CDI provider within a webapp to decorate objects created by
|
||||||
|
* the contexts {@link org.eclipse.jetty.util.DecoratedObjectFactory}
|
||||||
|
* (typically Listeners, Filters and Servlets).
|
||||||
|
* The CDI provider is invoked using {@link MethodHandle}s to avoid any CDI instance
|
||||||
|
* or dependencies within the server scope. The code invoked is equivalent to:
|
||||||
|
* <pre>
|
||||||
|
* public <T> T decorate(T o)
|
||||||
|
* {
|
||||||
|
* BeanManager manager = CDI.current().getBeanManager();
|
||||||
|
* manager.createInjectionTarget(manager.createAnnotatedType((Class<T>)o.getClass()))
|
||||||
|
* .inject(o,manager.createCreationalContext(null));
|
||||||
|
* return o;
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class CdiSpiDecorator implements Decorator
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(CdiServletContainerInitializer.class);
|
||||||
|
public static final String MODE = "CdiSpiDecorator";
|
||||||
|
|
||||||
|
private final ServletContextHandler _context;
|
||||||
|
private final Map<Object, Decorated> _decorated = new HashMap<>();
|
||||||
|
|
||||||
|
private final MethodHandle _current;
|
||||||
|
private final MethodHandle _getBeanManager;
|
||||||
|
private final MethodHandle _createAnnotatedType;
|
||||||
|
private final MethodHandle _createInjectionTarget;
|
||||||
|
private final MethodHandle _createCreationalContext;
|
||||||
|
private final MethodHandle _inject;
|
||||||
|
private final MethodHandle _dispose;
|
||||||
|
private final MethodHandle _release;
|
||||||
|
|
||||||
|
public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperationException
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
ClassLoader classLoader = _context.getClassLoader();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Class<?> cdiClass = classLoader.loadClass("javax.enterprise.inject.spi.CDI");
|
||||||
|
Class<?> beanManagerClass = classLoader.loadClass("javax.enterprise.inject.spi.BeanManager");
|
||||||
|
Class<?> annotatedTypeClass = classLoader.loadClass("javax.enterprise.inject.spi.AnnotatedType");
|
||||||
|
Class<?> injectionTargetClass = classLoader.loadClass("javax.enterprise.inject.spi.InjectionTarget");
|
||||||
|
Class<?> creationalContextClass = classLoader.loadClass("javax.enterprise.context.spi.CreationalContext");
|
||||||
|
Class<?> contextualClass = classLoader.loadClass("javax.enterprise.context.spi.Contextual");
|
||||||
|
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
_current = lookup.findStatic(cdiClass, "current", MethodType.methodType(cdiClass));
|
||||||
|
_getBeanManager = lookup.findVirtual(cdiClass, "getBeanManager", MethodType.methodType(beanManagerClass));
|
||||||
|
_createAnnotatedType = lookup.findVirtual(beanManagerClass, "createAnnotatedType", MethodType.methodType(annotatedTypeClass, Class.class));
|
||||||
|
_createInjectionTarget = lookup.findVirtual(beanManagerClass, "createInjectionTarget", MethodType.methodType(injectionTargetClass, annotatedTypeClass));
|
||||||
|
_createCreationalContext = lookup.findVirtual(beanManagerClass, "createCreationalContext", MethodType.methodType(creationalContextClass, contextualClass));
|
||||||
|
_inject = lookup.findVirtual(injectionTargetClass, "inject", MethodType.methodType(Void.TYPE, Object.class, creationalContextClass));
|
||||||
|
_dispose = lookup.findVirtual(injectionTargetClass, "dispose", MethodType.methodType(Void.TYPE, Object.class));
|
||||||
|
_release = lookup.findVirtual(creationalContextClass, "release", MethodType.methodType(Void.TYPE));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate an object.
|
||||||
|
* <p>The signature of this method must match what is introspected for by the
|
||||||
|
* Jetty DecoratingListener class. It is invoked dynamically.</p>
|
||||||
|
*
|
||||||
|
* @param o The object to be decorated
|
||||||
|
* @param <T> The type of the object to be decorated
|
||||||
|
* @return The decorated object
|
||||||
|
*/
|
||||||
|
public <T> T decorate(T o)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("decorate {} in {}", o, _context);
|
||||||
|
|
||||||
|
_decorated.put(o, new Decorated(o));
|
||||||
|
}
|
||||||
|
catch (Throwable th)
|
||||||
|
{
|
||||||
|
LOG.warn("Unable to decorate " + o, th);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a decorated object.
|
||||||
|
* <p>The signature of this method must match what is introspected for by the
|
||||||
|
* Jetty DecoratingListener class. It is invoked dynamically.</p>
|
||||||
|
*
|
||||||
|
* @param o The object to be destroyed
|
||||||
|
*/
|
||||||
|
public void destroy(Object o)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Decorated decorated = _decorated.remove(o);
|
||||||
|
if (decorated != null)
|
||||||
|
decorated.destroy(o);
|
||||||
|
}
|
||||||
|
catch (Throwable th)
|
||||||
|
{
|
||||||
|
LOG.warn("Unable to destroy " + o, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Decorated
|
||||||
|
{
|
||||||
|
private final Object _injectionTarget;
|
||||||
|
private final Object _creationalContext;
|
||||||
|
|
||||||
|
Decorated(Object o) throws Throwable
|
||||||
|
{
|
||||||
|
// BeanManager manager = CDI.current().getBeanManager();
|
||||||
|
Object manager = _getBeanManager.invoke(_current.invoke());
|
||||||
|
// AnnotatedType annotatedType = manager.createAnnotatedType((Class<T>)o.getClass());
|
||||||
|
Object annotatedType = _createAnnotatedType.invoke(manager, o.getClass());
|
||||||
|
// CreationalContext creationalContext = manager.createCreationalContext(null);
|
||||||
|
_creationalContext = _createCreationalContext.invoke(manager, null);
|
||||||
|
// InjectionTarget injectionTarget = manager.createInjectionTarget();
|
||||||
|
_injectionTarget = _createInjectionTarget.invoke(manager, annotatedType);
|
||||||
|
// injectionTarget.inject(o, creationalContext);
|
||||||
|
_inject.invoke(_injectionTarget, o, _creationalContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy(Object o) throws Throwable
|
||||||
|
{
|
||||||
|
_dispose.invoke(_injectionTarget, o);
|
||||||
|
_release.invoke(_creationalContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.eclipse.jetty.cdi.CdiServletContainerInitializer
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<!-- Bind the jetty-web-decorate.xml to every deployed webapp -->
|
||||||
|
<Ref refid="DeploymentManager">
|
||||||
|
<Call name="addLifeCycleBinding">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.deploy.bindings.GlobalWebappConfigBinding">
|
||||||
|
<Set name="jettyXml"><Property name="jetty.home" default="." />/etc/jetty-web-decorate.xml
|
||||||
|
</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Ref>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure class="org.eclipse.jetty.webapp.WebAppContext" id="context">
|
||||||
|
|
||||||
|
<Get class="org.eclipse.jetty.webapp.DecoratingListener" name="DECORATOR_ATTRIBUTE" id="decoratorAttribute"/>
|
||||||
|
|
||||||
|
<!-- Add the DecoratingListener to the webapp to look for dynamic decorators -->
|
||||||
|
<Call name="addEventListener">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.webapp.DecoratingListener">
|
||||||
|
<Arg><Ref refid="context" /></Arg>
|
||||||
|
<Arg type="String"><Ref refid="decoratorAttribute"/></Arg>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,14 @@
|
||||||
|
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
|
[description]
|
||||||
|
Jetty setup to support Decoration of Listeners, Filters and Servlets within a deployed webapp.
|
||||||
|
This module uses the DecoratingListener to register an object set as a context attribute
|
||||||
|
as a dynamic decorator. This module sets the "org.eclipse.jetty.webapp.DecoratingListener"
|
||||||
|
context attribute with the name of the context attribute that will be listened to.
|
||||||
|
By default the attribute is "org.eclipse.jetty.webapp.decorator".
|
||||||
|
|
||||||
|
[depend]
|
||||||
|
deploy
|
||||||
|
|
||||||
|
[xml]
|
||||||
|
etc/jetty-decorate.xml
|
|
@ -30,13 +30,13 @@
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<h2>examples ...</h2>
|
<h2>tests ...</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/test/">Test Jetty Webapp</a></li>
|
<li><a href="/test/">Test Jetty Webapp</a></li>
|
||||||
<li><a href="/async-rest/">Async Rest</a></li>
|
<li><a href="/test-spec/">Servlet 3.1 Test</a></li>
|
||||||
<li><a href="/test-jaas/">JAAS Test</a></li>
|
<li><a href="/test-jaas/">JAAS Test</a></li>
|
||||||
<li><a href="/test-jndi/">JNDI Test</a></li>
|
<li><a href="/test-jndi/">JNDI Test</a></li>
|
||||||
<li><a href="/test-spec/">Servlet 3.1 Test</a></li>
|
<li><a href="/async-rest/">Async Rest</a></li>
|
||||||
<li><a href="/oldContextPath/">Redirected Context</a></li>
|
<li><a href="/oldContextPath/">Redirected Context</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -689,8 +689,8 @@
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>cdi-2</artifactId>
|
<artifactId>jetty-cdi</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -31,9 +31,6 @@
|
||||||
<version>3.8.1</version>
|
<version>3.8.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.weld.servlet</groupId>
|
|
||||||
<artifactId>weld-servlet</artifactId>
|
|
||||||
<version>@weld.version@</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.weld.servlet</groupId>
|
|
||||||
<artifactId>weld-servlet</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
<artifactId>jetty-servlet-api</artifactId>
|
<artifactId>jetty-servlet-api</artifactId>
|
||||||
|
|
|
@ -58,6 +58,7 @@ import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServletMapping;
|
import javax.servlet.http.HttpServletMapping;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import javax.servlet.http.HttpUpgradeHandler;
|
import javax.servlet.http.HttpUpgradeHandler;
|
||||||
|
@ -484,57 +485,30 @@ public class Request implements HttpServletRequest
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int maxFormContentSize = -1;
|
int maxFormContentSize = ContextHandler.DEFAULT_MAX_FORM_CONTENT_SIZE;
|
||||||
int maxFormKeys = -1;
|
int maxFormKeys = ContextHandler.DEFAULT_MAX_FORM_KEYS;
|
||||||
|
|
||||||
if (_context != null)
|
if (_context != null)
|
||||||
{
|
{
|
||||||
maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
|
ContextHandler contextHandler = _context.getContextHandler();
|
||||||
maxFormKeys = _context.getContextHandler().getMaxFormKeys();
|
maxFormContentSize = contextHandler.getMaxFormContentSize();
|
||||||
|
maxFormKeys = contextHandler.getMaxFormKeys();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (maxFormContentSize < 0)
|
|
||||||
{
|
{
|
||||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
maxFormContentSize = lookupServerAttribute(ContextHandler.MAX_FORM_CONTENT_SIZE_KEY, maxFormContentSize);
|
||||||
if (obj == null)
|
maxFormKeys = lookupServerAttribute(ContextHandler.MAX_FORM_KEYS_KEY, maxFormKeys);
|
||||||
maxFormContentSize = 200000;
|
|
||||||
else if (obj instanceof Number)
|
|
||||||
{
|
|
||||||
Number size = (Number)obj;
|
|
||||||
maxFormContentSize = size.intValue();
|
|
||||||
}
|
|
||||||
else if (obj instanceof String)
|
|
||||||
{
|
|
||||||
maxFormContentSize = Integer.parseInt((String)obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxFormKeys < 0)
|
|
||||||
{
|
|
||||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
|
|
||||||
if (obj == null)
|
|
||||||
maxFormKeys = 1000;
|
|
||||||
else if (obj instanceof Number)
|
|
||||||
{
|
|
||||||
Number keys = (Number)obj;
|
|
||||||
maxFormKeys = keys.intValue();
|
|
||||||
}
|
|
||||||
else if (obj instanceof String)
|
|
||||||
{
|
|
||||||
maxFormKeys = Integer.parseInt((String)obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int contentLength = getContentLength();
|
int contentLength = getContentLength();
|
||||||
if (contentLength > maxFormContentSize && maxFormContentSize > 0)
|
if (maxFormContentSize >= 0 && contentLength > maxFormContentSize)
|
||||||
{
|
throw new IllegalStateException("Form is larger than max length " + maxFormContentSize);
|
||||||
throw new IllegalStateException("Form too large: " + contentLength + " > " + maxFormContentSize);
|
|
||||||
}
|
|
||||||
InputStream in = getInputStream();
|
InputStream in = getInputStream();
|
||||||
if (_input.isAsync())
|
if (_input.isAsync())
|
||||||
throw new IllegalStateException("Cannot extract parameters with async IO");
|
throw new IllegalStateException("Cannot extract parameters with async IO");
|
||||||
|
|
||||||
UrlEncoded.decodeTo(in, params, getCharacterEncoding(), contentLength < 0 ? maxFormContentSize : -1, maxFormKeys);
|
UrlEncoded.decodeTo(in, params, getCharacterEncoding(), maxFormContentSize, maxFormKeys);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
@ -543,6 +517,16 @@ public class Request implements HttpServletRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int lookupServerAttribute(String key, int dftValue)
|
||||||
|
{
|
||||||
|
Object attribute = _channel.getServer().getAttribute(key);
|
||||||
|
if (attribute instanceof Number)
|
||||||
|
return ((Number)attribute).intValue();
|
||||||
|
else if (attribute instanceof String)
|
||||||
|
return Integer.parseInt((String)attribute);
|
||||||
|
return dftValue;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AsyncContext getAsyncContext()
|
public AsyncContext getAsyncContext()
|
||||||
{
|
{
|
||||||
|
@ -2137,7 +2121,7 @@ public class Request implements HttpServletRequest
|
||||||
AsyncContextEvent event = new AsyncContextEvent(_context, _async, state, this, servletRequest, servletResponse);
|
AsyncContextEvent event = new AsyncContextEvent(_context, _async, state, this, servletRequest, servletResponse);
|
||||||
event.setDispatchContext(getServletContext());
|
event.setDispatchContext(getServletContext());
|
||||||
|
|
||||||
String uri = ((HttpServletRequest)servletRequest).getRequestURI();
|
String uri = unwrap(servletRequest).getRequestURI();
|
||||||
if (_contextPath != null && uri.startsWith(_contextPath))
|
if (_contextPath != null && uri.startsWith(_contextPath))
|
||||||
uri = uri.substring(_contextPath.length());
|
uri = uri.substring(_contextPath.length());
|
||||||
else
|
else
|
||||||
|
@ -2149,6 +2133,19 @@ public class Request implements HttpServletRequest
|
||||||
return _async;
|
return _async;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HttpServletRequest unwrap(ServletRequest servletRequest)
|
||||||
|
{
|
||||||
|
if (servletRequest instanceof HttpServletRequestWrapper)
|
||||||
|
{
|
||||||
|
return (HttpServletRequestWrapper)servletRequest;
|
||||||
|
}
|
||||||
|
if (servletRequest instanceof ServletRequestWrapper)
|
||||||
|
{
|
||||||
|
return unwrap(((ServletRequestWrapper)servletRequest).getRequest());
|
||||||
|
}
|
||||||
|
return ((HttpServletRequest)servletRequest);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,8 +32,11 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.ServletResponseWrapper;
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.CookieCompliance;
|
import org.eclipse.jetty.http.CookieCompliance;
|
||||||
|
@ -1292,6 +1295,19 @@ public class Response implements HttpServletResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HttpServletResponse unwrap(ServletResponse servletResponse)
|
||||||
|
{
|
||||||
|
if (servletResponse instanceof HttpServletResponseWrapper)
|
||||||
|
{
|
||||||
|
return (HttpServletResponseWrapper)servletResponse;
|
||||||
|
}
|
||||||
|
if (servletResponse instanceof ServletResponseWrapper)
|
||||||
|
{
|
||||||
|
return unwrap(((ServletResponseWrapper)servletResponse).getResponse());
|
||||||
|
}
|
||||||
|
return (HttpServletResponse)servletResponse;
|
||||||
|
}
|
||||||
|
|
||||||
private static class HttpFieldsSupplier implements Supplier<HttpFields>
|
private static class HttpFieldsSupplier implements Supplier<HttpFields>
|
||||||
{
|
{
|
||||||
private final Supplier<Map<String, String>> _supplier;
|
private final Supplier<Map<String, String>> _supplier;
|
||||||
|
|
|
@ -558,8 +558,8 @@ public class Server extends HandlerWrapper implements Attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
final String target = baseRequest.getPathInfo();
|
final String target = baseRequest.getPathInfo();
|
||||||
final HttpServletRequest request = (HttpServletRequest)event.getSuppliedRequest();
|
final HttpServletRequest request = Request.unwrap(event.getSuppliedRequest());
|
||||||
final HttpServletResponse response = (HttpServletResponse)event.getSuppliedResponse();
|
final HttpServletResponse response = Response.unwrap(event.getSuppliedResponse());
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("{} {} {} on {}", request.getDispatcherType(), request.getMethod(), target, channel);
|
LOG.debug("{} {} {} on {}", request.getDispatcherType(), request.getMethod(), target, channel);
|
||||||
|
|
|
@ -136,6 +136,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
|
|
||||||
public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
|
public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
|
||||||
|
|
||||||
|
public static final String MAX_FORM_KEYS_KEY = "org.eclipse.jetty.server.Request.maxFormKeys";
|
||||||
|
public static final String MAX_FORM_CONTENT_SIZE_KEY = "org.eclipse.jetty.server.Request.maxFormContentSize";
|
||||||
|
public static final int DEFAULT_MAX_FORM_KEYS = 1000;
|
||||||
|
public static final int DEFAULT_MAX_FORM_CONTENT_SIZE = 200000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current ServletContext implementation.
|
* Get the current ServletContext implementation.
|
||||||
*
|
*
|
||||||
|
@ -188,8 +193,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
|
|
||||||
private Logger _logger;
|
private Logger _logger;
|
||||||
private boolean _allowNullPathInfo;
|
private boolean _allowNullPathInfo;
|
||||||
private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", -1).intValue();
|
private int _maxFormKeys = Integer.getInteger(MAX_FORM_KEYS_KEY, DEFAULT_MAX_FORM_KEYS);
|
||||||
private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize", -1).intValue();
|
private int _maxFormContentSize = Integer.getInteger(MAX_FORM_CONTENT_SIZE_KEY, DEFAULT_MAX_FORM_CONTENT_SIZE);
|
||||||
private boolean _compactPath = false;
|
private boolean _compactPath = false;
|
||||||
private boolean _usingSecurityManager = System.getSecurityManager() != null;
|
private boolean _usingSecurityManager = System.getSecurityManager() != null;
|
||||||
|
|
||||||
|
@ -784,9 +789,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
throw new IllegalStateException("Null contextPath");
|
throw new IllegalStateException("Null contextPath");
|
||||||
|
|
||||||
if (_logger == null)
|
if (_logger == null)
|
||||||
{
|
|
||||||
_logger = Log.getLogger(ContextHandler.class.getName() + getLogNameSuffix());
|
_logger = Log.getLogger(ContextHandler.class.getName() + getLogNameSuffix());
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoader oldClassloader = null;
|
ClassLoader oldClassloader = null;
|
||||||
Thread currentThread = null;
|
Thread currentThread = null;
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.server;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.servlet.AsyncContext;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletRequestWrapper;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
|
||||||
|
public class ServletRequestWrapperTest
|
||||||
|
{
|
||||||
|
private Server server;
|
||||||
|
private LocalConnector connector;
|
||||||
|
private RequestHandler handler;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void init() throws Exception
|
||||||
|
{
|
||||||
|
server = new Server();
|
||||||
|
connector = new LocalConnector(server, new HttpConnectionFactory());
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
handler = new RequestHandler();
|
||||||
|
server.setHandler(handler);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServletRequestWrapper() throws Exception
|
||||||
|
{
|
||||||
|
String request = "GET / HTTP/1.1\r\n" +
|
||||||
|
"Host: whatever\r\n" +
|
||||||
|
"\n";
|
||||||
|
|
||||||
|
String response = connector.getResponse(request);
|
||||||
|
assertThat("Response", response, containsString("200"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RequestWrapper extends ServletRequestWrapper
|
||||||
|
{
|
||||||
|
public RequestWrapper(ServletRequest request)
|
||||||
|
{
|
||||||
|
super(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RequestHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request,
|
||||||
|
HttpServletResponse response)
|
||||||
|
throws IOException, ServletException
|
||||||
|
{
|
||||||
|
RequestWrapper requestWrapper = new RequestWrapper(request);
|
||||||
|
AsyncContext context = request.startAsync(requestWrapper, response);
|
||||||
|
context.complete();
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.servlet;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletContextAttributeEvent;
|
||||||
|
import javax.servlet.ServletContextAttributeListener;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.Decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ServletContextAttributeListener that listens for a context
|
||||||
|
* attribute to obtain a decorator instance. The instance is then either
|
||||||
|
* coerced to a {@link Decorator} or reflected for decorator compatible methods
|
||||||
|
* so it can be added to the {@link ServletContextHandler#getObjectFactory()} as a
|
||||||
|
* {@link Decorator}.
|
||||||
|
*/
|
||||||
|
public class DecoratingListener implements ServletContextAttributeListener
|
||||||
|
{
|
||||||
|
private static final MethodType DECORATE_TYPE;
|
||||||
|
private static final MethodType DESTROY_TYPE;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DECORATE_TYPE = MethodType.methodType(Object.class, Object.class);
|
||||||
|
DESTROY_TYPE = MethodType.methodType(void.class, Object.class);
|
||||||
|
|
||||||
|
// Check we have the right MethodTypes for the current Decorator signatures
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
lookup.findVirtual(Decorator.class, "decorate", DECORATE_TYPE);
|
||||||
|
lookup.findVirtual(Decorator.class, "destroy", DESTROY_TYPE);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ServletContextHandler _context;
|
||||||
|
private final String _attributeName;
|
||||||
|
private Decorator _decorator;
|
||||||
|
|
||||||
|
public DecoratingListener(ServletContextHandler context, String attributeName)
|
||||||
|
{
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
Objects.requireNonNull(attributeName);
|
||||||
|
_context = context;
|
||||||
|
_attributeName = attributeName;
|
||||||
|
Object decorator = _context.getAttribute(_attributeName);
|
||||||
|
if (decorator != null)
|
||||||
|
_context.getObjectFactory().addDecorator(asDecorator(decorator));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttributeName()
|
||||||
|
{
|
||||||
|
return _attributeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServletContext getServletContext()
|
||||||
|
{
|
||||||
|
return _context.getServletContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Decorator asDecorator(Object object)
|
||||||
|
{
|
||||||
|
if (object == null)
|
||||||
|
return null;
|
||||||
|
if (object instanceof Decorator)
|
||||||
|
return (Decorator)object;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Class<?> clazz = object.getClass();
|
||||||
|
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
MethodHandle decorate = lookup.findVirtual(clazz, "decorate", DECORATE_TYPE);
|
||||||
|
MethodHandle destroy = lookup.findVirtual(clazz, "destroy", DESTROY_TYPE);
|
||||||
|
return new DynamicDecorator(object, decorate, destroy);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attributeAdded(ServletContextAttributeEvent event)
|
||||||
|
{
|
||||||
|
if (_attributeName.equals(event.getName()))
|
||||||
|
{
|
||||||
|
_decorator = asDecorator(event.getValue());
|
||||||
|
_context.getObjectFactory().addDecorator(_decorator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attributeRemoved(ServletContextAttributeEvent event)
|
||||||
|
{
|
||||||
|
if (_attributeName.equals(event.getName()) && _decorator != null)
|
||||||
|
{
|
||||||
|
_context.getObjectFactory().removeDecorator(_decorator);
|
||||||
|
_decorator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attributeReplaced(ServletContextAttributeEvent event)
|
||||||
|
{
|
||||||
|
attributeRemoved(event);
|
||||||
|
attributeAdded(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DynamicDecorator implements Decorator
|
||||||
|
{
|
||||||
|
private final Object _object;
|
||||||
|
private final MethodHandle _decorate;
|
||||||
|
private final MethodHandle _destroy;
|
||||||
|
|
||||||
|
private DynamicDecorator(Object object, MethodHandle decorate, MethodHandle destroy)
|
||||||
|
{
|
||||||
|
_object = object;
|
||||||
|
_decorate = decorate;
|
||||||
|
_destroy = destroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T decorate(T o)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (T)_decorate.invoke(_object, o);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy(Object o)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_destroy.invoke(_object, o);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.servlet;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
|
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||||
|
import org.eclipse.jetty.client.util.FormContentProvider;
|
||||||
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
import org.eclipse.jetty.util.Fields;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class FormTest
|
||||||
|
{
|
||||||
|
private static final int MAX_FORM_CONTENT_SIZE = 128;
|
||||||
|
private static final int MAX_FORM_KEYS = 4;
|
||||||
|
|
||||||
|
private Server server;
|
||||||
|
private ServerConnector connector;
|
||||||
|
private HttpClient client;
|
||||||
|
private String contextPath = "/ctx";
|
||||||
|
private String servletPath = "/test_form";
|
||||||
|
|
||||||
|
private void start(Function<ServletContextHandler, HttpServlet> config) throws Exception
|
||||||
|
{
|
||||||
|
startServer(config);
|
||||||
|
startClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startServer(Function<ServletContextHandler, HttpServlet> config) throws Exception
|
||||||
|
{
|
||||||
|
server = new Server();
|
||||||
|
connector = new ServerConnector(server, 1, 1);
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
ServletContextHandler handler = new ServletContextHandler(server, contextPath);
|
||||||
|
HttpServlet servlet = config.apply(handler);
|
||||||
|
handler.addServlet(new ServletHolder(servlet), servletPath + "/*");
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startClient() throws Exception
|
||||||
|
{
|
||||||
|
client = new HttpClient();
|
||||||
|
client.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dispose() throws Exception
|
||||||
|
{
|
||||||
|
if (client != null)
|
||||||
|
client.stop();
|
||||||
|
if (server != null)
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Arguments> formContentSizeScenarios()
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(null, true),
|
||||||
|
Arguments.of(null, false),
|
||||||
|
Arguments.of(-1, true),
|
||||||
|
Arguments.of(-1, false),
|
||||||
|
Arguments.of(0, true),
|
||||||
|
Arguments.of(0, false),
|
||||||
|
Arguments.of(MAX_FORM_CONTENT_SIZE, true),
|
||||||
|
Arguments.of(MAX_FORM_CONTENT_SIZE, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("formContentSizeScenarios")
|
||||||
|
public void testMaxFormContentSizeExceeded(Integer maxFormContentSize, boolean withContentLength) throws Exception
|
||||||
|
{
|
||||||
|
start(handler ->
|
||||||
|
{
|
||||||
|
if (maxFormContentSize != null)
|
||||||
|
handler.setMaxFormContentSize(maxFormContentSize);
|
||||||
|
return new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
request.getParameterMap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
byte[] key = "foo=".getBytes(StandardCharsets.US_ASCII);
|
||||||
|
int length = (maxFormContentSize == null || maxFormContentSize < 0)
|
||||||
|
? ContextHandler.DEFAULT_MAX_FORM_CONTENT_SIZE
|
||||||
|
: maxFormContentSize;
|
||||||
|
// Avoid empty value.
|
||||||
|
length = length + 1;
|
||||||
|
byte[] value = new byte[length];
|
||||||
|
Arrays.fill(value, (byte)'x');
|
||||||
|
DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(key), ByteBuffer.wrap(value));
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.path(contextPath + servletPath)
|
||||||
|
.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.FORM_ENCODED.asString())
|
||||||
|
.content(content)
|
||||||
|
.onRequestBegin(request ->
|
||||||
|
{
|
||||||
|
if (withContentLength)
|
||||||
|
content.close();
|
||||||
|
})
|
||||||
|
.onRequestCommit(request ->
|
||||||
|
{
|
||||||
|
if (!withContentLength)
|
||||||
|
content.close();
|
||||||
|
})
|
||||||
|
.send();
|
||||||
|
|
||||||
|
int expected = (maxFormContentSize != null && maxFormContentSize < 0)
|
||||||
|
? HttpStatus.OK_200
|
||||||
|
: HttpStatus.BAD_REQUEST_400;
|
||||||
|
assertEquals(expected, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Integer> formKeysScenarios()
|
||||||
|
{
|
||||||
|
return Stream.of(null, -1, 0, MAX_FORM_KEYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("formKeysScenarios")
|
||||||
|
public void testMaxFormKeysExceeded(Integer maxFormKeys) throws Exception
|
||||||
|
{
|
||||||
|
start(handler ->
|
||||||
|
{
|
||||||
|
if (maxFormKeys != null)
|
||||||
|
handler.setMaxFormKeys(maxFormKeys);
|
||||||
|
return new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
request.getParameterMap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
int keys = (maxFormKeys == null || maxFormKeys < 0)
|
||||||
|
? ContextHandler.DEFAULT_MAX_FORM_KEYS
|
||||||
|
: maxFormKeys;
|
||||||
|
// Have at least one key.
|
||||||
|
keys = keys + 1;
|
||||||
|
Fields formParams = new Fields();
|
||||||
|
for (int i = 0; i < keys; ++i)
|
||||||
|
{
|
||||||
|
formParams.add("key_" + i, "value_" + i);
|
||||||
|
}
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.path(contextPath + servletPath)
|
||||||
|
.content(new FormContentProvider(formParams))
|
||||||
|
.send();
|
||||||
|
|
||||||
|
int expected = (maxFormKeys != null && maxFormKeys < 0)
|
||||||
|
? HttpStatus.OK_200
|
||||||
|
: HttpStatus.BAD_REQUEST_400;
|
||||||
|
assertEquals(expected, response.getStatus());
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,13 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
|
||||||
public void addDecorator(Decorator decorator)
|
public void addDecorator(Decorator decorator)
|
||||||
{
|
{
|
||||||
LOG.debug("Adding Decorator: {}", decorator);
|
LOG.debug("Adding Decorator: {}", decorator);
|
||||||
this.decorators.add(decorator);
|
decorators.add(decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeDecorator(Decorator decorator)
|
||||||
|
{
|
||||||
|
LOG.debug("Remove Decorator: {}", decorator);
|
||||||
|
return decorators.remove(decorator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear()
|
public void clear()
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
boolean delim = false;
|
boolean delim = false;
|
||||||
for (Map.Entry<String, List<String>> entry : map.entrySet())
|
for (Map.Entry<String, List<String>> entry : map.entrySet())
|
||||||
{
|
{
|
||||||
String key = entry.getKey().toString();
|
String key = entry.getKey();
|
||||||
List<String> list = entry.getValue();
|
List<String> list = entry.getValue();
|
||||||
int s = list.size();
|
int s = list.size();
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
|
|
||||||
if (val != null)
|
if (val != null)
|
||||||
{
|
{
|
||||||
String str = val.toString();
|
String str = val;
|
||||||
if (str.length() > 0)
|
if (str.length() > 0)
|
||||||
{
|
{
|
||||||
result.append('=');
|
result.append('=');
|
||||||
|
@ -232,7 +232,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
synchronized (map)
|
synchronized (map)
|
||||||
{
|
{
|
||||||
String key = null;
|
String key = null;
|
||||||
String value = null;
|
String value;
|
||||||
int mark = -1;
|
int mark = -1;
|
||||||
boolean encoded = false;
|
boolean encoded = false;
|
||||||
for (int i = 0; i < content.length(); i++)
|
for (int i = 0; i < content.length(); i++)
|
||||||
|
@ -269,8 +269,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
case '%':
|
case '%':
|
||||||
encoded = true;
|
encoded = true;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,146 +291,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decoded parameters to Map.
|
|
||||||
*
|
|
||||||
* @param in the stream containing the encoded parameters
|
|
||||||
* @param map the MultiMap to decode into
|
|
||||||
* @param charset the charset to use for decoding
|
|
||||||
* @param maxLength the maximum length of the form to decode
|
|
||||||
* @param maxKeys the maximum number of keys to decode
|
|
||||||
* @throws IOException if unable to decode input stream
|
|
||||||
*/
|
|
||||||
public static void decodeTo(InputStream in, MultiMap<String> map, String charset, int maxLength, int maxKeys)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (charset == null)
|
|
||||||
{
|
|
||||||
if (ENCODING.equals(StandardCharsets.UTF_8))
|
|
||||||
decodeUtf8To(in, map, maxLength, maxKeys);
|
|
||||||
else
|
|
||||||
decodeTo(in, map, ENCODING, maxLength, maxKeys);
|
|
||||||
}
|
|
||||||
else if (StringUtil.__UTF8.equalsIgnoreCase(charset))
|
|
||||||
decodeUtf8To(in, map, maxLength, maxKeys);
|
|
||||||
else if (StringUtil.__ISO_8859_1.equalsIgnoreCase(charset))
|
|
||||||
decode88591To(in, map, maxLength, maxKeys);
|
|
||||||
else if (StringUtil.__UTF16.equalsIgnoreCase(charset))
|
|
||||||
decodeUtf16To(in, map, maxLength, maxKeys);
|
|
||||||
else
|
|
||||||
decodeTo(in, map, Charset.forName(charset), maxLength, maxKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decoded parameters to Map.
|
|
||||||
*
|
|
||||||
* @param in the stream containing the encoded parameters
|
|
||||||
* @param map the MultiMap to decode into
|
|
||||||
* @param charset the charset to use for decoding
|
|
||||||
* @param maxLength the maximum length of the form to decode
|
|
||||||
* @param maxKeys the maximum number of keys to decode
|
|
||||||
* @throws IOException if unable to decode input stream
|
|
||||||
*/
|
|
||||||
public static void decodeTo(InputStream in, MultiMap<String> map, Charset charset, int maxLength, int maxKeys)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
//no charset present, use the configured default
|
|
||||||
if (charset == null)
|
|
||||||
charset = ENCODING;
|
|
||||||
|
|
||||||
if (StandardCharsets.UTF_8.equals(charset))
|
|
||||||
{
|
|
||||||
decodeUtf8To(in, map, maxLength, maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StandardCharsets.ISO_8859_1.equals(charset))
|
|
||||||
{
|
|
||||||
decode88591To(in, map, maxLength, maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StandardCharsets.UTF_16.equals(charset)) // Should be all 2 byte encodings
|
|
||||||
{
|
|
||||||
decodeUtf16To(in, map, maxLength, maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (map)
|
|
||||||
{
|
|
||||||
String key = null;
|
|
||||||
String value = null;
|
|
||||||
|
|
||||||
int c;
|
|
||||||
|
|
||||||
int totalLength = 0;
|
|
||||||
|
|
||||||
try (ByteArrayOutputStream2 output = new ByteArrayOutputStream2();)
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
while ((c = in.read()) > 0)
|
|
||||||
{
|
|
||||||
switch ((char)c)
|
|
||||||
{
|
|
||||||
case '&':
|
|
||||||
size = output.size();
|
|
||||||
value = size == 0 ? "" : output.toString(charset);
|
|
||||||
output.setCount(0);
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
map.add(key, value);
|
|
||||||
}
|
|
||||||
else if (value != null && value.length() > 0)
|
|
||||||
{
|
|
||||||
map.add(value, "");
|
|
||||||
}
|
|
||||||
key = null;
|
|
||||||
value = null;
|
|
||||||
if (maxKeys > 0 && map.size() > maxKeys)
|
|
||||||
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", map.size(), maxKeys));
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
output.write(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size = output.size();
|
|
||||||
key = size == 0 ? "" : output.toString(charset);
|
|
||||||
output.setCount(0);
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
output.write(' ');
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
int code0 = in.read();
|
|
||||||
int code1 = in.read();
|
|
||||||
output.write(decodeHexChar(code0, code1));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output.write(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalLength++;
|
|
||||||
if (maxLength >= 0 && totalLength > maxLength)
|
|
||||||
throw new IllegalStateException("Form is too large");
|
|
||||||
}
|
|
||||||
|
|
||||||
size = output.size();
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
value = size == 0 ? "" : output.toString(charset);
|
|
||||||
output.setCount(0);
|
|
||||||
map.add(key, value);
|
|
||||||
}
|
|
||||||
else if (size > 0)
|
|
||||||
map.add(output.toString(charset), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void decodeUtf8To(String query, MultiMap<String> map)
|
public static void decodeUtf8To(String query, MultiMap<String> map)
|
||||||
{
|
{
|
||||||
decodeUtf8To(query, 0, query.length(), map);
|
decodeUtf8To(query, 0, query.length(), map);
|
||||||
|
@ -521,14 +379,96 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoded parameters to MultiMap, using ISO8859-1 encodings.
|
||||||
|
*
|
||||||
|
* @param in InputSteam to read
|
||||||
|
* @param map MultiMap to add parameters to
|
||||||
|
* @param maxLength maximum length of form to read or -1 for no limit
|
||||||
|
* @param maxKeys maximum number of keys to read or -1 for no limit
|
||||||
|
* @throws IOException if unable to decode the InputStream as ISO8859-1
|
||||||
|
*/
|
||||||
|
public static void decode88591To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
synchronized (map)
|
||||||
|
{
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
String key = null;
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
int b;
|
||||||
|
|
||||||
|
int totalLength = 0;
|
||||||
|
while ((b = in.read()) >= 0)
|
||||||
|
{
|
||||||
|
switch ((char)b)
|
||||||
|
{
|
||||||
|
case '&':
|
||||||
|
value = buffer.length() == 0 ? "" : buffer.toString();
|
||||||
|
buffer.setLength(0);
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
map.add(key, value);
|
||||||
|
}
|
||||||
|
else if (value.length() > 0)
|
||||||
|
{
|
||||||
|
map.add(value, "");
|
||||||
|
}
|
||||||
|
key = null;
|
||||||
|
value = null;
|
||||||
|
checkMaxKeys(map, maxKeys);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
buffer.append((char)b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
key = buffer.toString();
|
||||||
|
buffer.setLength(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
buffer.append(' ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
int code0 = in.read();
|
||||||
|
int code1 = in.read();
|
||||||
|
buffer.append(decodeHexChar(code0, code1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buffer.append((char)b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
checkMaxLength(++totalLength, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
value = buffer.length() == 0 ? "" : buffer.toString();
|
||||||
|
buffer.setLength(0);
|
||||||
|
map.add(key, value);
|
||||||
|
}
|
||||||
|
else if (buffer.length() > 0)
|
||||||
|
{
|
||||||
|
map.add(buffer.toString(), "");
|
||||||
|
}
|
||||||
|
checkMaxKeys(map, maxKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decoded parameters to Map.
|
* Decoded parameters to Map.
|
||||||
*
|
*
|
||||||
* @param in InputSteam to read
|
* @param in InputSteam to read
|
||||||
* @param map MultiMap to add parameters to
|
* @param map MultiMap to add parameters to
|
||||||
* @param maxLength maximum form length to decode
|
* @param maxLength maximum form length to decode or -1 for no limit
|
||||||
* @param maxKeys the maximum number of keys to read or -1 for no limit
|
* @param maxKeys the maximum number of keys to read or -1 for no limit
|
||||||
* @throws IOException if unable to decode input stream
|
* @throws IOException if unable to decode the input stream
|
||||||
*/
|
*/
|
||||||
public static void decodeUtf8To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
|
public static void decodeUtf8To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
@ -559,8 +499,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
key = null;
|
key = null;
|
||||||
value = null;
|
value = null;
|
||||||
if (maxKeys > 0 && map.size() > maxKeys)
|
checkMaxKeys(map, maxKeys);
|
||||||
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", map.size(), maxKeys));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
|
@ -587,8 +526,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
buffer.append((byte)b);
|
buffer.append((byte)b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (maxLength >= 0 && (++totalLength > maxLength))
|
checkMaxLength(++totalLength, maxLength);
|
||||||
throw new IllegalStateException("Form is too large");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key != null)
|
if (key != null)
|
||||||
|
@ -601,6 +539,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
{
|
{
|
||||||
map.add(buffer.toReplacedString(), "");
|
map.add(buffer.toReplacedString(), "");
|
||||||
}
|
}
|
||||||
|
checkMaxKeys(map, maxKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,33 +554,91 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decoded parameters to MultiMap, using ISO8859-1 encodings.
|
* Decoded parameters to Map.
|
||||||
*
|
*
|
||||||
* @param in InputSteam to read
|
* @param in the stream containing the encoded parameters
|
||||||
* @param map MultiMap to add parameters to
|
* @param map the MultiMap to decode into
|
||||||
* @param maxLength maximum length of form to read
|
* @param charset the charset to use for decoding
|
||||||
* @param maxKeys maximum number of keys to read or -1 for no limit
|
* @param maxLength the maximum length of the form to decode or -1 for no limit
|
||||||
* @throws IOException if unable to decode inputstream as ISO8859-1
|
* @param maxKeys the maximum number of keys to decode or -1 for no limit
|
||||||
|
* @throws IOException if unable to decode the input stream
|
||||||
*/
|
*/
|
||||||
public static void decode88591To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
|
public static void decodeTo(InputStream in, MultiMap<String> map, String charset, int maxLength, int maxKeys)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
if (charset == null)
|
||||||
|
{
|
||||||
|
if (ENCODING.equals(StandardCharsets.UTF_8))
|
||||||
|
decodeUtf8To(in, map, maxLength, maxKeys);
|
||||||
|
else
|
||||||
|
decodeTo(in, map, ENCODING, maxLength, maxKeys);
|
||||||
|
}
|
||||||
|
else if (StringUtil.__UTF8.equalsIgnoreCase(charset))
|
||||||
|
decodeUtf8To(in, map, maxLength, maxKeys);
|
||||||
|
else if (StringUtil.__ISO_8859_1.equalsIgnoreCase(charset))
|
||||||
|
decode88591To(in, map, maxLength, maxKeys);
|
||||||
|
else if (StringUtil.__UTF16.equalsIgnoreCase(charset))
|
||||||
|
decodeUtf16To(in, map, maxLength, maxKeys);
|
||||||
|
else
|
||||||
|
decodeTo(in, map, Charset.forName(charset), maxLength, maxKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoded parameters to Map.
|
||||||
|
*
|
||||||
|
* @param in the stream containing the encoded parameters
|
||||||
|
* @param map the MultiMap to decode into
|
||||||
|
* @param charset the charset to use for decoding
|
||||||
|
* @param maxLength the maximum length of the form to decode
|
||||||
|
* @param maxKeys the maximum number of keys to decode
|
||||||
|
* @throws IOException if unable to decode input stream
|
||||||
|
*/
|
||||||
|
public static void decodeTo(InputStream in, MultiMap<String> map, Charset charset, int maxLength, int maxKeys)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
//no charset present, use the configured default
|
||||||
|
if (charset == null)
|
||||||
|
charset = ENCODING;
|
||||||
|
|
||||||
|
if (StandardCharsets.UTF_8.equals(charset))
|
||||||
|
{
|
||||||
|
decodeUtf8To(in, map, maxLength, maxKeys);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StandardCharsets.ISO_8859_1.equals(charset))
|
||||||
|
{
|
||||||
|
decode88591To(in, map, maxLength, maxKeys);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StandardCharsets.UTF_16.equals(charset)) // Should be all 2 byte encodings
|
||||||
|
{
|
||||||
|
decodeUtf16To(in, map, maxLength, maxKeys);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (map)
|
synchronized (map)
|
||||||
{
|
{
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
String key = null;
|
String key = null;
|
||||||
String value = null;
|
String value = null;
|
||||||
|
|
||||||
int b;
|
int c;
|
||||||
|
|
||||||
int totalLength = 0;
|
int totalLength = 0;
|
||||||
while ((b = in.read()) >= 0)
|
|
||||||
|
try (ByteArrayOutputStream2 output = new ByteArrayOutputStream2())
|
||||||
{
|
{
|
||||||
switch ((char)b)
|
int size = 0;
|
||||||
|
|
||||||
|
while ((c = in.read()) > 0)
|
||||||
|
{
|
||||||
|
switch ((char)c)
|
||||||
{
|
{
|
||||||
case '&':
|
case '&':
|
||||||
value = buffer.length() == 0 ? "" : buffer.toString();
|
size = output.size();
|
||||||
buffer.setLength(0);
|
value = size == 0 ? "" : output.toString(charset);
|
||||||
|
output.setCount(0);
|
||||||
if (key != null)
|
if (key != null)
|
||||||
{
|
{
|
||||||
map.add(key, value);
|
map.add(key, value);
|
||||||
|
@ -652,51 +649,62 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
key = null;
|
key = null;
|
||||||
value = null;
|
value = null;
|
||||||
if (maxKeys > 0 && map.size() > maxKeys)
|
checkMaxKeys(map, maxKeys);
|
||||||
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", map.size(), maxKeys));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
if (key != null)
|
if (key != null)
|
||||||
{
|
{
|
||||||
buffer.append((char)b);
|
output.write(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
key = buffer.toString();
|
size = output.size();
|
||||||
buffer.setLength(0);
|
key = size == 0 ? "" : output.toString(charset);
|
||||||
|
output.setCount(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
buffer.append(' ');
|
output.write(' ');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
int code0 = in.read();
|
int code0 = in.read();
|
||||||
int code1 = in.read();
|
int code1 = in.read();
|
||||||
buffer.append(decodeHexChar(code0, code1));
|
output.write(decodeHexChar(code0, code1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
buffer.append((char)b);
|
output.write(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (maxLength >= 0 && (++totalLength > maxLength))
|
checkMaxLength(++totalLength, maxLength);
|
||||||
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", map.size(), maxKeys));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size = output.size();
|
||||||
if (key != null)
|
if (key != null)
|
||||||
{
|
{
|
||||||
value = buffer.length() == 0 ? "" : buffer.toString();
|
value = size == 0 ? "" : output.toString(charset);
|
||||||
buffer.setLength(0);
|
output.setCount(0);
|
||||||
map.add(key, value);
|
map.add(key, value);
|
||||||
}
|
}
|
||||||
else if (buffer.length() > 0)
|
else if (size > 0)
|
||||||
{
|
{
|
||||||
map.add(buffer.toString(), "");
|
map.add(output.toString(charset), "");
|
||||||
|
}
|
||||||
|
checkMaxKeys(map, maxKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void checkMaxKeys(MultiMap<String> map, int maxKeys)
|
||||||
|
{
|
||||||
|
int size = map.size();
|
||||||
|
if (maxKeys >= 0 && size > maxKeys)
|
||||||
|
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", size, maxKeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkMaxLength(int length, int maxLength)
|
||||||
|
{
|
||||||
|
if (maxLength >= 0 && length > maxLength)
|
||||||
|
throw new IllegalStateException("Form is larger than max length " + maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode String with % encoding.
|
* Decode String with % encoding.
|
||||||
* This method makes the assumption that the majority of calls
|
* This method makes the assumption that the majority of calls
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.webapp;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extended org.eclipse.jetty.servlet.DecoratingListener.
|
||||||
|
* The context attribute "org.eclipse.jetty.webapp.DecoratingListener" if
|
||||||
|
* not set, is set to the name of the attribute this listener listens for.
|
||||||
|
*/
|
||||||
|
public class DecoratingListener extends org.eclipse.jetty.servlet.DecoratingListener
|
||||||
|
{
|
||||||
|
public static final String DECORATOR_ATTRIBUTE = "org.eclipse.jetty.webapp.decorator";
|
||||||
|
|
||||||
|
public DecoratingListener()
|
||||||
|
{
|
||||||
|
this(DECORATOR_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecoratingListener(String attributeName)
|
||||||
|
{
|
||||||
|
this(WebAppContext.getCurrentWebAppContext(), attributeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecoratingListener(ServletContextHandler context)
|
||||||
|
{
|
||||||
|
this(context, DECORATOR_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecoratingListener(ServletContextHandler context, String attributeName)
|
||||||
|
{
|
||||||
|
super(context, attributeName);
|
||||||
|
checkAndSetAttributeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkAndSetAttributeName()
|
||||||
|
{
|
||||||
|
// If not set (by another DecoratingListener), flag the attribute that are
|
||||||
|
// listening for. If more than one DecoratingListener is used then this
|
||||||
|
// attribute reflects only the first.
|
||||||
|
if (getServletContext().getAttribute(getClass().getName()) != null)
|
||||||
|
throw new IllegalStateException("Multiple DecoratingListeners detected");
|
||||||
|
getServletContext().setAttribute(getClass().getName(), getAttributeName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -946,7 +946,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
new DumpableCollection("Serverclasses " + name, serverClasses),
|
new DumpableCollection("Serverclasses " + name, serverClasses),
|
||||||
new DumpableCollection("Configurations " + name, _configurations),
|
new DumpableCollection("Configurations " + name, _configurations),
|
||||||
new DumpableCollection("Handler attributes " + name, ((AttributesMap)getAttributes()).getAttributeEntrySet()),
|
new DumpableCollection("Handler attributes " + name, ((AttributesMap)getAttributes()).getAttributeEntrySet()),
|
||||||
new DumpableCollection("Context attributes " + name, ((Context)getServletContext()).getAttributeEntrySet()),
|
new DumpableCollection("Context attributes " + name, getServletContext().getAttributeEntrySet()),
|
||||||
|
new DumpableCollection("EventListeners " + this, Arrays.asList(getEventListeners())),
|
||||||
new DumpableCollection("Initparams " + name, getInitParams().entrySet())
|
new DumpableCollection("Initparams " + name, getInitParams().entrySet())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
15
pom.xml
15
pom.xml
|
@ -37,7 +37,7 @@
|
||||||
<junit.version>5.5.1</junit.version>
|
<junit.version>5.5.1</junit.version>
|
||||||
<maven.version>3.6.0</maven.version>
|
<maven.version>3.6.0</maven.version>
|
||||||
<maven.resolver.version>1.3.1</maven.resolver.version>
|
<maven.resolver.version>1.3.1</maven.resolver.version>
|
||||||
<weld.version>2.4.5.Final</weld.version>
|
<weld.version>3.1.2.Final</weld.version>
|
||||||
<jetty.perf-helper.version>1.0.5</jetty.perf-helper.version>
|
<jetty.perf-helper.version>1.0.5</jetty.perf-helper.version>
|
||||||
<unix.socket.tmp></unix.socket.tmp>
|
<unix.socket.tmp></unix.socket.tmp>
|
||||||
<!-- enable or not TestTracker junit5 extension i.e log message when test method is starting -->
|
<!-- enable or not TestTracker junit5 extension i.e log message when test method is starting -->
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
otherwise depending on Spring Boot might be chicken and egg issue :) -->
|
otherwise depending on Spring Boot might be chicken and egg issue :) -->
|
||||||
<springboot.version>2.1.1.RELEASE</springboot.version>
|
<springboot.version>2.1.1.RELEASE</springboot.version>
|
||||||
<annotation-api.version>1.3.4</annotation-api.version>
|
<annotation-api.version>1.3.4</annotation-api.version>
|
||||||
<jackson-databind.version>2.9.7</jackson-databind.version>
|
<jackson-databind.version>2.9.9</jackson-databind.version>
|
||||||
<localRepoPath>${project.build.directory}/local-repo</localRepoPath>
|
<localRepoPath>${project.build.directory}/local-repo</localRepoPath>
|
||||||
<settingsPath>src/it/settings.xml</settingsPath>
|
<settingsPath>src/it/settings.xml</settingsPath>
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@
|
||||||
<id>attach-sources</id>
|
<id>attach-sources</id>
|
||||||
<phase>process-classes</phase>
|
<phase>process-classes</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>jar</goal>
|
<goal>jar-no-fork</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
|
@ -449,7 +449,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>build-resources</artifactId>
|
<artifactId>build-resources</artifactId>
|
||||||
<version>10.0.0-alpha0</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
|
@ -547,6 +547,11 @@
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>1.6</version>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
@ -1261,6 +1266,7 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- already part of the release-jetty.sh script
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
@ -1275,6 +1281,7 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
-->
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
|
@ -167,7 +167,7 @@ if proceedyn "Are you sure you want to release using above? (y/N)" n; then
|
||||||
# This is equivalent to 'mvn release:perform'
|
# This is equivalent to 'mvn release:perform'
|
||||||
if proceedyn "Build/Deploy from tag $TAG_NAME? (Y/n)" y; then
|
if proceedyn "Build/Deploy from tag $TAG_NAME? (Y/n)" y; then
|
||||||
git checkout $TAG_NAME
|
git checkout $TAG_NAME
|
||||||
mvn clean package source:jar javadoc:jar gpg:sign deploy \
|
mvn clean package gpg:sign javadoc:aggregate-jar deploy \
|
||||||
-Peclipse-release $DEPLOY_OPTS
|
-Peclipse-release $DEPLOY_OPTS
|
||||||
reportMavenTestFailures
|
reportMavenTestFailures
|
||||||
git checkout $GIT_BRANCH_ID
|
git checkout $GIT_BRANCH_ID
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.tests</groupId>
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
<artifactId>test-cdi2-webapp</artifactId>
|
<artifactId>test-weld-cdi-webapp</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
|
|
|
@ -127,6 +127,16 @@ public class DistributionTester
|
||||||
return start(Arrays.asList(args));
|
return start(Arrays.asList(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getJettyBase()
|
||||||
|
{
|
||||||
|
return config.jettyBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getJettyHome()
|
||||||
|
{
|
||||||
|
return config.jettyHome;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the distribution with the arguments
|
* Start the distribution with the arguments
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,27 +19,64 @@
|
||||||
package org.eclipse.jetty.tests.distribution;
|
package org.eclipse.jetty.tests.distribution;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jetty.client.api.ContentResponse;
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@Disabled("Until issue is fixed at weld -> https://github.com/eclipse/jetty.project/issues/3803")
|
|
||||||
public class CDITests extends AbstractDistributionTest
|
public class CDITests extends AbstractDistributionTest
|
||||||
{
|
{
|
||||||
|
// Tests from here use these parameters
|
||||||
|
public static Stream<Arguments> tests()
|
||||||
|
{
|
||||||
|
Consumer<DistributionTester> removeJettyWebXml = d ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Path jettyWebXml = d.getJettyBase().resolve("webapps/demo/WEB-INF/jetty-web.xml");
|
||||||
|
Files.deleteIfExists(jettyWebXml);
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Stream.of(
|
||||||
|
// -- Weld --
|
||||||
|
Arguments.of("weld", "cdi2", null),
|
||||||
|
Arguments.of("weld", "cdi-spi", null), // Weld >= 3.1.2
|
||||||
|
Arguments.of("weld", "decorate", null), // Weld >= 3.1.2
|
||||||
|
// TODO Arguments.of("weld", "cdi-decorate", null), // Weld >= 3.1.3
|
||||||
|
|
||||||
|
// -- Apache OpenWebBeans --
|
||||||
|
Arguments.of("owb", "cdi-spi", removeJettyWebXml),
|
||||||
|
Arguments.of("owb", "cdi2", null)
|
||||||
|
// Arguments.of("owb", "decorate", null), // Not supported
|
||||||
|
// Arguments.of("owb", "cdi-decorate", null) // Not supported
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a WAR file that is CDI complete as it includes the weld
|
* Tests a WAR file that includes the CDI
|
||||||
* library in its WEB-INF/lib directory.
|
* library in its WEB-INF/lib directory.
|
||||||
*/
|
*/
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testCDI2_IncludedInWebapp() throws Exception
|
@MethodSource("tests")
|
||||||
|
public void testCDIIncludedInWebapp(String implementation, String integration, Consumer<DistributionTester> configure) throws Exception
|
||||||
{
|
{
|
||||||
String jettyVersion = System.getProperty("jettyVersion");
|
String jettyVersion = System.getProperty("jettyVersion");
|
||||||
DistributionTester distribution = DistributionTester.Builder.newInstance()
|
DistributionTester distribution = DistributionTester.Builder.newInstance()
|
||||||
|
@ -50,76 +87,17 @@ public class CDITests extends AbstractDistributionTest
|
||||||
String[] args1 = {
|
String[] args1 = {
|
||||||
"--create-startd",
|
"--create-startd",
|
||||||
"--approve-all-licenses",
|
"--approve-all-licenses",
|
||||||
"--add-to-start=http,deploy,annotations,jsp"
|
"--add-to-start=http,deploy,annotations,jsp,"+integration
|
||||||
};
|
};
|
||||||
try (DistributionTester.Run run1 = distribution.start(args1))
|
try (DistributionTester.Run run1 = distribution.start(args1))
|
||||||
{
|
{
|
||||||
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
|
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
|
||||||
assertEquals(0, run1.getExitValue());
|
assertEquals(0, run1.getExitValue());
|
||||||
|
|
||||||
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-cdi2-webapp:war:" + jettyVersion);
|
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-" + implementation + "-cdi-webapp:war:" + jettyVersion);
|
||||||
distribution.installWarFile(war, "demo");
|
|
||||||
|
|
||||||
distribution.installBaseResource("cdi/demo_context.xml", "webapps/demo.xml");
|
|
||||||
|
|
||||||
int port = distribution.freePort();
|
|
||||||
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
|
|
||||||
{
|
|
||||||
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
startHttpClient();
|
|
||||||
ContentResponse response = client.GET("http://localhost:" + port + "/demo/greetings");
|
|
||||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
|
||||||
// Confirm Servlet based CDI
|
|
||||||
assertThat(response.getContentAsString(), containsString("Hello GreetingsServlet"));
|
|
||||||
// Confirm Listener based CDI (this has been a problem in the past, keep this for regression testing!)
|
|
||||||
assertThat(response.getHeaders().get("Server"), containsString("CDI-Demo-org.eclipse.jetty.test"));
|
|
||||||
|
|
||||||
run2.stop();
|
|
||||||
assertTrue(run2.awaitFor(5, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests a WAR file that is expects CDI to be configured by the server.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This means the WAR has the weld libs in its
|
|
||||||
* WEB-INF/lib directory.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The expectation is that a context xml deployable file is not
|
|
||||||
* required when using this `cdi2` module, and the appropriate
|
|
||||||
* server side libs are made available to allow weld to function.
|
|
||||||
* (the required server side javax.el support comes from the cdi2 module)
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCDI2_ConfiguredByServer() throws Exception
|
|
||||||
{
|
|
||||||
String jettyVersion = System.getProperty("jettyVersion");
|
|
||||||
DistributionTester distribution = DistributionTester.Builder.newInstance()
|
|
||||||
.jettyVersion(jettyVersion)
|
|
||||||
.mavenLocalRepository(System.getProperty("mavenRepoPath"))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
String[] args1 = {
|
|
||||||
"--create-startd",
|
|
||||||
"--approve-all-licenses",
|
|
||||||
// standard entries
|
|
||||||
"--add-to-start=http,deploy,annotations",
|
|
||||||
// cdi2 specific entry (should transitively pull in what it needs, the user should not be expected to know the transitive entries)
|
|
||||||
"--add-to-start=cdi2"
|
|
||||||
};
|
|
||||||
try (DistributionTester.Run run1 = distribution.start(args1))
|
|
||||||
{
|
|
||||||
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
|
|
||||||
assertEquals(0, run1.getExitValue());
|
|
||||||
|
|
||||||
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-cdi2-webapp:war:" + jettyVersion);
|
|
||||||
distribution.installWarFile(war, "demo");
|
distribution.installWarFile(war, "demo");
|
||||||
|
if (configure != null)
|
||||||
|
configure.accept(distribution);
|
||||||
|
|
||||||
int port = distribution.freePort();
|
int port = distribution.freePort();
|
||||||
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
|
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
<module>test-http2-webapp</module>
|
<module>test-http2-webapp</module>
|
||||||
<module>test-simple-webapp</module>
|
<module>test-simple-webapp</module>
|
||||||
<module>test-felix-webapp</module>
|
<module>test-felix-webapp</module>
|
||||||
<module>test-cdi2-webapp</module>
|
<module>test-cdi-common-webapp</module>
|
||||||
|
<module>test-weld-cdi-webapp</module>
|
||||||
|
<module>test-owb-cdi-webapp</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-webapps-parent</artifactId>
|
||||||
|
<version>10.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>test-cdi-common-webapp</artifactId>
|
||||||
|
<name>Test :: CDI :: Common Demo Webapp</name>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<bundle-symbolic-name>${project.groupId}.cdi.common</bundle-symbolic-name>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- provided by container -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.inject</groupId>
|
||||||
|
<artifactId>javax.inject</artifactId>
|
||||||
|
<version>1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.enterprise</groupId>
|
||||||
|
<artifactId>cdi-api</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -37,6 +37,8 @@ public class GreetingsServlet extends HttpServlet
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
|
||||||
{
|
{
|
||||||
resp.setContentType("text/plain");
|
resp.setContentType("text/plain");
|
||||||
resp.getWriter().println("[" + greetings.getGreeting() + "]");
|
resp.getWriter().print(greetings.getGreeting());
|
||||||
|
resp.getWriter().print(" from ");
|
||||||
|
resp.getWriter().println(getServletContext().getAttribute("ServerID"));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,8 +21,11 @@ package org.eclipse.jetty.test;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.enterprise.inject.Any;
|
||||||
import javax.enterprise.inject.spi.Bean;
|
import javax.enterprise.inject.spi.Bean;
|
||||||
import javax.enterprise.inject.spi.BeanManager;
|
import javax.enterprise.inject.spi.BeanManager;
|
||||||
|
import javax.enterprise.inject.spi.InjectionPoint;
|
||||||
|
import javax.enterprise.util.AnnotationLiteral;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import javax.servlet.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
|
@ -43,10 +46,12 @@ public class InfoServlet extends HttpServlet
|
||||||
|
|
||||||
PrintWriter out = resp.getWriter();
|
PrintWriter out = resp.getWriter();
|
||||||
out.println("Bean Manager: " + beanManager);
|
out.println("Bean Manager: " + beanManager);
|
||||||
Set<Bean<?>> beans = beanManager.getBeans("");
|
Set<Bean<?>> beans = beanManager.getBeans(Object.class, new AnnotationLiteral<Any>() {});
|
||||||
for (Bean<?> bean : beans)
|
for (Bean<?> bean : beans)
|
||||||
{
|
{
|
||||||
out.println(" " + bean);
|
out.printf("%16s => %s%n", bean.getName(), bean);
|
||||||
|
for (InjectionPoint ij : bean.getInjectionPoints())
|
||||||
|
out.printf("%16s -> %s%n", "", ij);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,6 +32,8 @@ public class MyContextListener implements ServletContextListener
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce)
|
public void contextInitialized(ServletContextEvent sce)
|
||||||
{
|
{
|
||||||
|
if (serverId == null)
|
||||||
|
throw new IllegalStateException("CDI did not inject!");
|
||||||
sce.getServletContext().setAttribute("ServerID", serverId.get());
|
sce.getServletContext().setAttribute("ServerID", serverId.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<H1>OWB CDI Test Webapp</H1>
|
||||||
|
|
||||||
|
<H2>CDI Info</H2>
|
||||||
|
<iframe src="info" width="100%" height="60%"></iframe>
|
||||||
|
|
||||||
|
<H2>Greetings test</H2>
|
||||||
|
<iframe src="greetings" width="100%"></iframe>
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-webapps-parent</artifactId>
|
||||||
|
<version>10.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>test-owb-cdi-webapp</artifactId>
|
||||||
|
<name>Test :: CDI On Jetty :: OWB Demo Webapp</name>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<bundle-symbolic-name>${project.groupId}.cdi.owb</bundle-symbolic-name>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>weld-owb-demo</finalName>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-cdi-common-webapp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- included in webapp -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-annotation_1.3_spec</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-atinject_1.0_spec</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-interceptor_1.2_spec</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.openwebbeans</groupId>
|
||||||
|
<artifactId>openwebbeans-web</artifactId>
|
||||||
|
<!-- TODO remove OwbServletContainerInitializer when updated to a version with https://issues.apache.org/jira/browse/OWB-1296 -->
|
||||||
|
<version>2.0.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.openwebbeans</groupId>
|
||||||
|
<artifactId>openwebbeans-jetty9</artifactId>
|
||||||
|
<version>2.0.11</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.cdi.owb;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.servlet.ServletContainerInitializer;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import org.apache.webbeans.servlet.WebBeansConfigurationListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This class will not be required once https://issues.apache.org/jira/browse/OWB-1296 is available
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public class OwbServletContainerInitializer implements ServletContainerInitializer
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
|
||||||
|
{
|
||||||
|
Listener listener = new Listener();
|
||||||
|
listener.preInitialize(new ServletContextEvent(ctx));
|
||||||
|
ctx.addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Listener extends WebBeansConfigurationListener
|
||||||
|
{
|
||||||
|
void preInitialize(ServletContextEvent event)
|
||||||
|
{
|
||||||
|
super.contextInitialized(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.eclipse.jetty.cdi.owb.OwbServletContainerInitializer
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
|
<New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||||
|
<Arg>
|
||||||
|
<Ref refid="webAppCtx"/>
|
||||||
|
</Arg>
|
||||||
|
<Arg>BeanManager</Arg>
|
||||||
|
<Arg>
|
||||||
|
<New class="javax.naming.Reference">
|
||||||
|
<Arg>javax.enterprise.inject.spi.BeanManager</Arg>
|
||||||
|
<Arg>org.apache.webbeans.container.ManagerObjectFactory</Arg>
|
||||||
|
<Arg/>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</New>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="wac" class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
|
<!-- This file is only needed for cdi2 integration and should be removed if using the cdi module -->
|
||||||
|
<Get id="wal" name="classLoader"/>
|
||||||
|
<Get id="objf" name="objectFactory">
|
||||||
|
<Call name="addDecorator">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.apache.webbeans.web.jetty9.JettyDecorator">
|
||||||
|
<Arg><Ref refid="wal"/></Arg>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Get>
|
||||||
|
</Configure>
|
|
@ -3,11 +3,9 @@
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||||
version="3.1">
|
version="3.1">
|
||||||
<display-name>CDI Integration Test WebApp</display-name>
|
<display-name>OWB CDI Integration Test WebApp</display-name>
|
||||||
|
|
||||||
<listener>
|
<!-- OWB Listener is added by OwbServletContainerInitializer -->
|
||||||
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
|
|
||||||
</listener>
|
|
||||||
|
|
||||||
<resource-env-ref>
|
<resource-env-ref>
|
||||||
<description>Object factory for the CDI Bean Manager</description>
|
<description>Object factory for the CDI Bean Manager</description>
|
|
@ -19,8 +19,6 @@
|
||||||
package com.acme.test;
|
package com.acme.test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -63,17 +61,13 @@ public class MultiPartTest extends HttpServlet
|
||||||
out.println("<p>");
|
out.println("<p>");
|
||||||
|
|
||||||
Collection<Part> parts = request.getParts();
|
Collection<Part> parts = request.getParts();
|
||||||
out.println("<b>Parts:</b> " + parts.size());
|
out.println("<b>Parts:</b> " + parts.size() + "<br>");
|
||||||
for (Part p : parts)
|
for (Part p : parts)
|
||||||
{
|
{
|
||||||
out.println("<h3>" + p.getName() + "</h3>");
|
out.println("<br><b>PartName:</b> " + sanitizeXmlString(p.getName()));
|
||||||
out.println("<b>Size:</b> " + p.getSize());
|
out.println("<br><b>Size:</b> " + p.getSize());
|
||||||
if (p.getContentType() == null || p.getContentType().startsWith("text/plain"))
|
String contentType = p.getContentType();
|
||||||
{
|
out.println("<br><b>ContentType:</b> " + contentType);
|
||||||
out.println("<p>");
|
|
||||||
copy(p.getInputStream(), out);
|
|
||||||
out.println("</p>");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
out.println("</body>");
|
out.println("</body>");
|
||||||
out.println("</html>");
|
out.println("</html>");
|
||||||
|
@ -109,20 +103,67 @@ public class MultiPartTest extends HttpServlet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove inline once 9.4.19 is released with a fix for #3726
|
public static String sanitizeXmlString(String html)
|
||||||
public static void copy(InputStream in,
|
|
||||||
OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
{
|
||||||
int bufferSize = 8192;
|
if (html == null)
|
||||||
byte[] buffer = new byte[bufferSize];
|
return null;
|
||||||
|
|
||||||
while (true)
|
int i = 0;
|
||||||
|
|
||||||
|
// Are there any characters that need sanitizing?
|
||||||
|
loop:
|
||||||
|
for (; i < html.length(); i++)
|
||||||
{
|
{
|
||||||
int len = in.read(buffer, 0, bufferSize);
|
char c = html.charAt(i);
|
||||||
if (len < 0)
|
switch (c)
|
||||||
break;
|
{
|
||||||
out.write(buffer, 0, len);
|
case '&':
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
case '\'':
|
||||||
|
case '"':
|
||||||
|
break loop;
|
||||||
|
default:
|
||||||
|
if (Character.isISOControl(c) && !Character.isWhitespace(c))
|
||||||
|
break loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// No characters need sanitizing, so return original string
|
||||||
|
if (i == html.length())
|
||||||
|
return html;
|
||||||
|
|
||||||
|
// Create builder with OK content so far
|
||||||
|
StringBuilder out = new StringBuilder(html.length() * 4 / 3);
|
||||||
|
out.append(html, 0, i);
|
||||||
|
|
||||||
|
// sanitize remaining content
|
||||||
|
for (; i < html.length(); i++)
|
||||||
|
{
|
||||||
|
char c = html.charAt(i);
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '&':
|
||||||
|
out.append("&");
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
out.append("<");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
out.append(">");
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
out.append("'");
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
out.append(""");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (Character.isISOControl(c) && !Character.isWhitespace(c))
|
||||||
|
out.append('?');
|
||||||
|
else
|
||||||
|
out.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,30 +7,32 @@
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>test-cdi2-webapp</artifactId>
|
<artifactId>test-weld-cdi-webapp</artifactId>
|
||||||
<name>Test :: CDI2 On Jetty :: Included in WebApp</name>
|
<name>Test :: CDI On Jetty :: Weld Demo Webapp</name>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<bundle-symbolic-name>${project.groupId}.cdi2.webapp</bundle-symbolic-name>
|
<bundle-symbolic-name>${project.groupId}.cdi.weld</bundle-symbolic-name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>cdi2-demo</finalName>
|
<finalName>weld-cdi-demo</finalName>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- provided by container -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>test-cdi-common-webapp</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<type>war</type>
|
||||||
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- included in webapp -->
|
<!-- included in webapp -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.weld.servlet</groupId>
|
<groupId>org.jboss.weld.servlet</groupId>
|
||||||
<artifactId>weld-servlet</artifactId>
|
<artifactId>weld-servlet-core</artifactId>
|
||||||
<version>${weld.version}</version>
|
<version>${weld.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||||
|
version="3.1">
|
||||||
|
<display-name>Weld CDI Integration Test WebApp</display-name>
|
||||||
|
|
||||||
|
<listener>
|
||||||
|
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
|
||||||
|
</listener>
|
||||||
|
|
||||||
|
<resource-env-ref>
|
||||||
|
<description>Object factory for the CDI Bean Manager</description>
|
||||||
|
<resource-env-ref-name>BeanManager</resource-env-ref-name>
|
||||||
|
<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
|
||||||
|
</resource-env-ref>
|
||||||
|
</web-app>
|
Loading…
Reference in New Issue