Merge branch 'master' into release-9
This commit is contained in:
commit
7e846e513d
|
@ -0,0 +1,95 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<name>Jetty :: Apache JSP</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.${project.artifactId}</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-manifest</id>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Export-Package>org.eclipse.jetty.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Schemas -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-schemas</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet api -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSP Api -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>javax.servlet.jsp-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSP Impl -->
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jasper</groupId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Eclipse Java Compiler (for JSP Compilation) -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>org.eclipse.jdt.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Apache JSP Module
|
||||
#
|
||||
|
||||
[name]
|
||||
jsp-impl
|
||||
|
||||
[lib]
|
||||
lib/apache-jsp/*.jar
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.apache.jsp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.jasper.servlet.JasperInitializer;
|
||||
import org.apache.jasper.servlet.TldPreScanned;
|
||||
import org.apache.jasper.servlet.TldScanner;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* JettyJasperInitializer
|
||||
*
|
||||
*/
|
||||
public class JettyJasperInitializer extends JasperInitializer
|
||||
{
|
||||
|
||||
/**
|
||||
* NullTldScanner
|
||||
*
|
||||
* Does nothing. Used when we can tell that all jsps have been precompiled, in which case
|
||||
* the tlds are not needed.
|
||||
*/
|
||||
private final class NullTldScanner extends TldScanner
|
||||
{
|
||||
/**
|
||||
* @param context
|
||||
* @param namespaceAware
|
||||
* @param validation
|
||||
* @param blockExternal
|
||||
*/
|
||||
private NullTldScanner(ServletContext context, boolean namespaceAware, boolean validation, boolean blockExternal)
|
||||
{
|
||||
super(context, namespaceAware, validation, blockExternal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.jasper.servlet.TldScanner#scan()
|
||||
*/
|
||||
@Override
|
||||
public void scan() throws IOException, SAXException
|
||||
{
|
||||
return; //do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.jasper.servlet.TldScanner#getListeners()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getListeners()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.jasper.servlet.TldScanner#scanJars()
|
||||
*/
|
||||
@Override
|
||||
public void scanJars()
|
||||
{
|
||||
return; //do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a TldScanner, and prefeed it the tlds that have already been discovered in jar files
|
||||
* by the MetaInfConfiguration.
|
||||
*
|
||||
* @see org.apache.jasper.servlet.JasperInitializer#prepareScanner(javax.servlet.ServletContext, boolean, boolean, boolean)
|
||||
*/
|
||||
@Override
|
||||
public TldScanner newTldScanner(ServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal)
|
||||
{
|
||||
String tmp = context.getInitParameter("org.eclipse.jetty.jsp.precompiled");
|
||||
if (tmp!=null && !tmp.equals("") && Boolean.valueOf(tmp))
|
||||
{
|
||||
return new NullTldScanner(context, namespaceAware, validate, blockExternal);
|
||||
}
|
||||
|
||||
Collection<URL> tldUrls = (Collection<URL>)context.getAttribute("org.eclipse.jetty.tlds");
|
||||
if (tldUrls != null && !tldUrls.isEmpty())
|
||||
{
|
||||
return new TldPreScanned(context,namespaceAware,validate,blockExternal,tldUrls);
|
||||
}
|
||||
return super.newTldScanner(context, namespaceAware, validate, blockExternal);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.apache.jsp;
|
||||
|
||||
public class JuliLog implements org.apache.juli.logging.Log
|
||||
{
|
||||
public static org.apache.juli.logging.Log getInstance(String name)
|
||||
{
|
||||
return new JuliLog(name);
|
||||
}
|
||||
|
||||
private final org.eclipse.jetty.util.log.Logger _logger;
|
||||
private final org.eclipse.jetty.util.log.StdErrLog _stdErrLog;
|
||||
|
||||
public JuliLog()
|
||||
{
|
||||
_logger=org.eclipse.jetty.util.log.Log.getRootLogger();
|
||||
_stdErrLog=(_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger:null;
|
||||
}
|
||||
|
||||
public JuliLog(String name)
|
||||
{
|
||||
_logger=org.eclipse.jetty.util.log.Log.getLogger(name);
|
||||
_stdErrLog=(_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger:null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return _logger.isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled()
|
||||
{
|
||||
return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFatalEnabled()
|
||||
{
|
||||
return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled()
|
||||
{
|
||||
return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled()
|
||||
{
|
||||
return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.debug((String)message);
|
||||
else
|
||||
_logger.debug("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.debug((String)message,t);
|
||||
else
|
||||
_logger.debug("{}",message,t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.debug((String)message);
|
||||
else
|
||||
_logger.debug("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.debug((String)message,t);
|
||||
else
|
||||
_logger.debug("{}",message,t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.info((String)message);
|
||||
else
|
||||
_logger.info("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.info((String)message,t);
|
||||
else
|
||||
_logger.info("{}",message,t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message);
|
||||
else
|
||||
_logger.warn("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message,t);
|
||||
else
|
||||
_logger.warn("{}",message,t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message);
|
||||
else
|
||||
_logger.warn("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message,t);
|
||||
else
|
||||
_logger.warn("{}",message,t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message);
|
||||
else
|
||||
_logger.warn("{}",message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message, Throwable t)
|
||||
{
|
||||
if (message instanceof String)
|
||||
_logger.warn((String)message,t);
|
||||
else
|
||||
_logger.warn("{}",message,t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
org.eclipse.jetty.apache.jsp.JettyJasperInitializer
|
|
@ -0,0 +1 @@
|
|||
org.eclipse.jetty.apache.jsp.JuliLog
|
|
@ -0,0 +1,49 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
<name>Apache :: JSTL module</name>
|
||||
<url>http://tomcat.apache.org/taglibs/standard/</url>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- JSTL Api -->
|
||||
<dependency>
|
||||
<groupId>org.apache.taglibs</groupId>
|
||||
<artifactId>taglibs-standard-spec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSTL Impl -->
|
||||
<dependency>
|
||||
<groupId>org.apache.taglibs</groupId>
|
||||
<artifactId>taglibs-standard-impl</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Apache JSTL
|
||||
#
|
||||
[name]
|
||||
jstl-impl
|
||||
|
||||
[lib]
|
||||
lib/apache-jstl/*.jar
|
|
@ -0,0 +1,4 @@
|
|||
This empty jar file is purely to work around a problem with the Maven Dependency plugin.
|
||||
Several modules in jetty use the Dependency plugin to copy or unpack the dependencies of other modules.
|
||||
However, the Dependency plugin is not capable of unpacking or copying a dependency of type 'pom', which
|
||||
this module is, as it consists purely of external dependencies needed to run jsp.
|
|
@ -0,0 +1,76 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-client</artifactId>
|
||||
<name>Jetty :: ALPN Client</name>
|
||||
<description>Jetty ALPN client services</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.alpn.client</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>org.eclipse.jetty.alpn;resolution:=optional</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
|
||||
with a snapshot. -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.alpn.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.alpn</groupId>
|
||||
<artifactId>alpn-api</artifactId>
|
||||
<version>${alpn.api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.alpn.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.NegotiatingClientConnection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ALPNClientConnection extends NegotiatingClientConnection implements ALPN.ClientProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ALPNClientConnection.class);
|
||||
|
||||
private final String protocol;
|
||||
|
||||
public ALPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, String protocol)
|
||||
{
|
||||
super(endPoint, executor, sslEngine, connectionFactory, context);
|
||||
this.protocol = protocol;
|
||||
ALPN.put(sslEngine, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
ALPN.remove(getSSLEngine());
|
||||
completed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return Arrays.asList(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String protocol)
|
||||
{
|
||||
if (this.protocol.equals(protocol))
|
||||
{
|
||||
ALPN.remove(getSSLEngine());
|
||||
completed();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Could not negotiate protocol: server {} - client {}", protocol, this.protocol);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
ALPN.remove(getSSLEngine());
|
||||
super.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.alpn.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
||||
|
||||
public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory
|
||||
{
|
||||
private final Executor executor;
|
||||
private final String protocol;
|
||||
|
||||
public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol)
|
||||
{
|
||||
super(connectionFactory);
|
||||
this.executor = executor;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
|
||||
{
|
||||
return new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(),
|
||||
(SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
<name>Jetty :: ALPN Server</name>
|
||||
<description>Jetty ALPN server services</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.alpn.server</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>org.eclipse.jetty.alpn,*</Import-Package>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
|
||||
with a snapshot. -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.alpn.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.alpn</groupId>
|
||||
<artifactId>alpn-api</artifactId>
|
||||
<version>${alpn.api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<Configure id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
|
||||
<Arg name="protocols">
|
||||
<Array type="String">
|
||||
<Item>spdy/3</Item>
|
||||
<Item>spdy/2</Item>
|
||||
<Item>http/1.1</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
|
||||
<Set name="defaultProtocol">http/1.1</Set>
|
||||
|
||||
</Configure>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0/alpn-boot-7.0.0.jar:lib/alpn/alpn-boot-7.0.0.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.jar
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0/alpn-boot-7.0.0.jar:lib/alpn/alpn-boot-7.0.0.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.jar
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0/alpn-boot-7.0.0.jar:lib/alpn/alpn-boot-7.0.0.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.jar
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0/alpn-boot-8.0.0.jar:lib/alpn/alpn-boot-8.0.0.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.jar
|
|
@ -0,0 +1,36 @@
|
|||
# ALPN is provided via a -Xbootclasspath that modifies the secure connections
|
||||
# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2)
|
||||
#
|
||||
# This modification has a tight dependency on specific recent updates of
|
||||
# Java 1.7 and Java 1.8
|
||||
# (Java versions prior to 1.7u40 are not supported)
|
||||
#
|
||||
# The alpn protonego module will use an appropriate alpn-boot jar for your
|
||||
# specific version of Java.
|
||||
#
|
||||
# IMPORTANT: Versions of Java that exist after this module was created are
|
||||
# not guaranteed to work with existing alpn-boot jars, and might
|
||||
# need a new alpn-boot to be created / tested / deployed by the
|
||||
# Jetty project in order to provide support for these future
|
||||
# Java versions.
|
||||
#
|
||||
# All versions of alpn-boot can be found at
|
||||
# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
|
||||
|
||||
[name]
|
||||
protonego-impl
|
||||
|
||||
[depend]
|
||||
protonego-impl/alpn-${java.version}
|
||||
|
||||
[lib]
|
||||
lib/jetty-alpn-client-${jetty.version}.jar
|
||||
lib/jetty-alpn-server-${jetty.version}.jar
|
||||
|
||||
[xml]
|
||||
etc/protonego-alpn.xml
|
||||
|
||||
[files]
|
||||
lib/
|
||||
lib/alpn/
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.alpn.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.NegotiatingServerConnection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ALPNServerConnection extends NegotiatingServerConnection implements ALPN.ServerProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ALPNServerConnection.class);
|
||||
|
||||
public ALPNServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
|
||||
{
|
||||
super(connector, endPoint, engine, protocols, defaultProtocol);
|
||||
ALPN.put(engine, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
select(Collections.<String>emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String select(List<String> clientProtocols)
|
||||
{
|
||||
List<String> serverProtocols = getProtocols();
|
||||
String negotiated = null;
|
||||
for (String clientProtocol : clientProtocols)
|
||||
{
|
||||
if (serverProtocols.contains(clientProtocol))
|
||||
{
|
||||
negotiated = clientProtocol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (negotiated == null)
|
||||
{
|
||||
negotiated = getDefaultProtocol();
|
||||
}
|
||||
LOG.debug("{} protocol selected {}", this, negotiated);
|
||||
setProtocol(negotiated);
|
||||
ALPN.remove(getSSLEngine());
|
||||
return negotiated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
ALPN.remove(getSSLEngine());
|
||||
super.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.alpn.server;
|
||||
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class);
|
||||
|
||||
public ALPNServerConnectionFactory(@Name("protocols") String... protocols)
|
||||
{
|
||||
super("alpn", protocols);
|
||||
try
|
||||
{
|
||||
ClassLoader alpnClassLoader = ALPN.class.getClassLoader();
|
||||
if (alpnClassLoader != null)
|
||||
{
|
||||
LOG.warn("ALPN must be in the boot classloader, not in: " + alpnClassLoader);
|
||||
throw new IllegalStateException("ALPN must be in the boot classloader");
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.warn("ALPN not available", x);
|
||||
throw new IllegalStateException("ALPN not available", x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
|
||||
{
|
||||
return new ALPNServerConnection(connector, endPoint, engine, protocols, defaultProtocol);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Jetty :: ALPN :: Parent</name>
|
||||
<description>Jetty ALPN services parent</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<modules>
|
||||
<module>jetty-alpn-server</module>
|
||||
<module>jetty-alpn-client</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -43,7 +43,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package>
|
||||
<Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.objectweb.asm.*;version=4,*</Import-Package>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -298,8 +298,8 @@ public abstract class HttpReceiver
|
|||
if (decoder != null)
|
||||
{
|
||||
buffer = decoder.decode(buffer);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.getProperty("line.separator"), BufferUtil.toDetailString(buffer));
|
||||
// if (LOG.isDebugEnabled())
|
||||
LOG.info("Response content decoded ({}) {}{}{}", decoder, response, System.getProperty("line.separator"), BufferUtil.toDetailString(buffer));
|
||||
}
|
||||
|
||||
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
|
||||
|
|
|
@ -152,7 +152,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException(current.toString());
|
||||
throw illegalSenderState(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
if (expects100Continue(request))
|
||||
newSenderState = content.hasContent() ? SenderState.EXPECTING_WITH_CONTENT : SenderState.EXPECTING;
|
||||
if (!updateSenderState(SenderState.IDLE, newSenderState))
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(SenderState.IDLE);
|
||||
|
||||
// Setting the listener may trigger calls to onContent() by other
|
||||
// threads so we must set it only after the sender state has been updated
|
||||
|
@ -462,7 +462,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
{
|
||||
// There is content to send.
|
||||
if (!updateSenderState(current, SenderState.SENDING))
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(current);
|
||||
LOG.debug("Proceeding while waiting");
|
||||
sendContent(exchange, content, contentCallback); // TODO old style usage!
|
||||
return;
|
||||
|
@ -471,14 +471,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
{
|
||||
// No content to send yet - it's deferred.
|
||||
if (!updateSenderState(current, SenderState.IDLE))
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(current);
|
||||
LOG.debug("Proceeding deferred");
|
||||
return;
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException(current.toString());
|
||||
throw illegalSenderState(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,6 +532,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
}
|
||||
}
|
||||
|
||||
private RuntimeException illegalSenderState(SenderState current)
|
||||
{
|
||||
return new IllegalStateException("Expected " + current + " found " + senderState.get() + " instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* The request states {@link HttpSender} goes through when sending a request.
|
||||
*/
|
||||
|
@ -723,7 +728,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -792,11 +797,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
return Action.SCHEDULED;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(current);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
throw illegalSenderState(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,15 @@ public abstract class MultiplexHttpDestination<C extends Connection> extends Htt
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
C connection = this.connection;
|
||||
if (connection != null)
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Connection connection)
|
||||
{
|
||||
|
|
|
@ -77,9 +77,10 @@ public class HttpChannelOverHTTP extends HttpChannel
|
|||
public void exchangeTerminated(Result result)
|
||||
{
|
||||
super.exchangeTerminated(result);
|
||||
boolean close = result.isFailed();
|
||||
HttpFields responseHeaders = result.getResponse().getHeaders();
|
||||
close |= responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
|
||||
boolean close = result.isFailed() ||
|
||||
responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) ||
|
||||
receiver.isShutdown();
|
||||
if (close)
|
||||
connection.close();
|
||||
else
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -85,13 +86,8 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
protected boolean onReadTimeout()
|
||||
{
|
||||
LOG.debug("{} idle timeout", this);
|
||||
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
return exchange.getRequest().abort(new TimeoutException());
|
||||
|
||||
getHttpDestination().close(this);
|
||||
return true;
|
||||
close(new TimeoutException());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,14 +115,23 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(new AsynchronousCloseException());
|
||||
}
|
||||
|
||||
protected void close(Throwable failure)
|
||||
{
|
||||
if (softClose())
|
||||
{
|
||||
// First close then abort, to be sure that the connection cannot be reused
|
||||
// from an onFailure() handler or by blocking code waiting for completion.
|
||||
getHttpDestination().close(this);
|
||||
getEndPoint().shutdownOutput();
|
||||
LOG.debug("{} oshut", this);
|
||||
getEndPoint().close();
|
||||
LOG.debug("{} closed", this);
|
||||
|
||||
abort(failure);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,6 +140,12 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
return closed.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
private boolean abort(Throwable failure)
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
return exchange != null && exchange.getRequest().abort(failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.util.BufferUtil;
|
|||
public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
|
||||
{
|
||||
private final HttpParser parser = new HttpParser(this);
|
||||
private boolean shutdown;
|
||||
|
||||
public HttpReceiverOverHTTP(HttpChannelOverHTTP channel)
|
||||
{
|
||||
|
@ -124,11 +125,23 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
|||
|
||||
private void shutdown()
|
||||
{
|
||||
// Shutting down the parser may invoke messageComplete() or earlyEOF()
|
||||
// Mark this receiver as shutdown, so that we can
|
||||
// close the connection when the exchange terminates.
|
||||
// We cannot close the connection from here because
|
||||
// the request may still be in process.
|
||||
shutdown = true;
|
||||
|
||||
// Shutting down the parser may invoke messageComplete() or earlyEOF().
|
||||
// In case of content delimited by EOF, without a Connection: close
|
||||
// header, the connection will be closed at exchange termination
|
||||
// thanks to the flag we have set above.
|
||||
parser.atEOF();
|
||||
parser.parseNext(BufferUtil.EMPTY_BUFFER);
|
||||
if (!responseFailure(new EOFException()))
|
||||
getHttpConnection().close();
|
||||
}
|
||||
|
||||
protected boolean isShutdown()
|
||||
{
|
||||
return shutdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -200,7 +213,11 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
|||
@Override
|
||||
public void earlyEOF()
|
||||
{
|
||||
failAndClose(new EOFException());
|
||||
HttpExchange exchange = getHttpExchange();
|
||||
if (exchange == null)
|
||||
getHttpConnection().close();
|
||||
else
|
||||
failAndClose(new EOFException());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -232,7 +249,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
|||
private void failAndClose(Throwable failure)
|
||||
{
|
||||
if (responseFailure(failure))
|
||||
getHttpChannel().getHttpConnection().close();
|
||||
getHttpConnection().close(failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -82,9 +82,12 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
|
|||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
|
||||
// Wait some time to have the client is an idle state.
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
connector.stop();
|
||||
|
||||
// Give the connection some time to process the remote close
|
||||
// Give the connection some time to process the remote close.
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
HttpConnectionOverHTTP httpConnection = (HttpConnectionOverHTTP)connection;
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
||||
|
@ -244,8 +245,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRedirectFailed() throws Exception
|
||||
{
|
||||
// TODO this test is failing with timout after an ISP upgrade?? DNS dependent?
|
||||
try
|
||||
{
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
|||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||
import org.eclipse.jetty.client.util.BytesContentProvider;
|
||||
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -72,6 +73,7 @@ import org.eclipse.jetty.util.FuturePromise;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -1161,4 +1163,105 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertTrue(response.getHeaders().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPollIsAbortedWhenClientIsStopped() throws Exception
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
request.startAsync();
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
final CountDownLatch completeLatch = new CountDownLatch(1);
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.send(new Response.CompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isFailed())
|
||||
completeLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Stop the client, the complete listener must be invoked.
|
||||
client.stop();
|
||||
|
||||
Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallContentDelimitedByEOFWithSlowRequestHTTP10() throws Exception
|
||||
{
|
||||
testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_0, 1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigContentDelimitedByEOFWithSlowRequestHTTP10() throws Exception
|
||||
{
|
||||
testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_0, 128 * 1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallContentDelimitedByEOFWithSlowRequestHTTP11() throws Exception
|
||||
{
|
||||
testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_1, 1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigContentDelimitedByEOFWithSlowRequestHTTP11() throws Exception
|
||||
{
|
||||
testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_1, 128 * 1024);
|
||||
}
|
||||
|
||||
private void testContentDelimitedByEOFWithSlowRequest(final HttpVersion version, int length) throws Exception
|
||||
{
|
||||
// This test is crafted in a way that the response completes before the request is fully written.
|
||||
// With SSL, the response coming down will close the SSLEngine so it would not be possible to
|
||||
// write the last chunk of the request content, and the request will be failed, failing also the
|
||||
// test, which is not what we want.
|
||||
// This is a limit of Java's SSL implementation that does not allow half closes.
|
||||
Assume.assumeTrue(sslContextFactory == null);
|
||||
|
||||
final byte[] data = new byte[length];
|
||||
new Random().nextBytes(data);
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
// Send Connection: close to avoid that the server chunks the content with HTTP 1.1.
|
||||
if (version.compareTo(HttpVersion.HTTP_1_0) > 0)
|
||||
response.setHeader("Connection", "close");
|
||||
response.getOutputStream().write(data);
|
||||
}
|
||||
});
|
||||
|
||||
DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0}));
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.version(version)
|
||||
.content(content);
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
request.send(listener);
|
||||
// Wait some time to simulate a slow request.
|
||||
Thread.sleep(1000);
|
||||
content.close();
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertArrayEquals(data, response.getContent());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.client;
|
||||
|
||||
public class HttpReceiverTest
|
||||
{
|
||||
// @Rule
|
||||
// public final TestTracker tracker = new TestTracker();
|
||||
//
|
||||
// private HttpClient client;
|
||||
// private HttpDestination destination;
|
||||
// private ByteArrayEndPoint endPoint;
|
||||
// private HttpConnection connection;
|
||||
// private HttpConversation conversation;
|
||||
//
|
||||
// @Before
|
||||
// public void init() throws Exception
|
||||
// {
|
||||
// client = new HttpClient();
|
||||
// client.start();
|
||||
// destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// endPoint = new ByteArrayEndPoint();
|
||||
// connection = new HttpConnection(client, endPoint, destination);
|
||||
// conversation = new HttpConversation(client, 1);
|
||||
// }
|
||||
//
|
||||
// @After
|
||||
// public void destroy() throws Exception
|
||||
// {
|
||||
// client.stop();
|
||||
// }
|
||||
//
|
||||
// protected HttpExchange newExchange()
|
||||
// {
|
||||
// HttpRequest request = new HttpRequest(client, URI.create("http://localhost"));
|
||||
// FutureResponseListener listener = new FutureResponseListener(request);
|
||||
// HttpExchange exchange = new HttpExchange(conversation, destination, request, Collections.<Response.ResponseListener>singletonList(listener));
|
||||
// conversation.getExchanges().offer(exchange);
|
||||
// connection.associate(exchange);
|
||||
// exchange.requestComplete();
|
||||
// exchange.terminateRequest();
|
||||
// return exchange;
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_NoResponseContent() throws Exception
|
||||
// {
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-length: 0\r\n" +
|
||||
// "\r\n");
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
//
|
||||
// Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.assertNotNull(response);
|
||||
// Assert.assertEquals(200, response.getStatus());
|
||||
// Assert.assertEquals("OK", response.getReason());
|
||||
// Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
// HttpFields headers = response.getHeaders();
|
||||
// Assert.assertNotNull(headers);
|
||||
// Assert.assertEquals(1, headers.size());
|
||||
// Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_ResponseContent() throws Exception
|
||||
// {
|
||||
// String content = "0123456789ABCDEF";
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-length: " + content.length() + "\r\n" +
|
||||
// "\r\n" +
|
||||
// content);
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
//
|
||||
// Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.assertNotNull(response);
|
||||
// Assert.assertEquals(200, response.getStatus());
|
||||
// Assert.assertEquals("OK", response.getReason());
|
||||
// Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
// HttpFields headers = response.getHeaders();
|
||||
// Assert.assertNotNull(headers);
|
||||
// Assert.assertEquals(1, headers.size());
|
||||
// Assert.assertEquals(String.valueOf(content.length()), headers.get(HttpHeader.CONTENT_LENGTH));
|
||||
// String received = listener.getContentAsString(StandardCharsets.UTF_8);
|
||||
// Assert.assertEquals(content, received);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_ResponseContent_EarlyEOF() throws Exception
|
||||
// {
|
||||
// String content1 = "0123456789";
|
||||
// String content2 = "ABCDEF";
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
// "\r\n" +
|
||||
// content1);
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
// endPoint.setInputEOF();
|
||||
// connection.receive();
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.fail();
|
||||
// }
|
||||
// catch (ExecutionException e)
|
||||
// {
|
||||
// Assert.assertTrue(e.getCause() instanceof EOFException);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_ResponseContent_IdleTimeout() throws Exception
|
||||
// {
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-length: 1\r\n" +
|
||||
// "\r\n");
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
// // Simulate an idle timeout
|
||||
// connection.idleTimeout();
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.fail();
|
||||
// }
|
||||
// catch (ExecutionException e)
|
||||
// {
|
||||
// Assert.assertTrue(e.getCause() instanceof TimeoutException);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_BadResponse() throws Exception
|
||||
// {
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-length: A\r\n" +
|
||||
// "\r\n");
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.fail();
|
||||
// }
|
||||
// catch (ExecutionException e)
|
||||
// {
|
||||
// Assert.assertTrue(e.getCause() instanceof HttpResponseException);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Receive_GZIPResponseContent_Fragmented() throws Exception
|
||||
// {
|
||||
// byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
// try (GZIPOutputStream gzipOutput = new GZIPOutputStream(baos))
|
||||
// {
|
||||
// gzipOutput.write(data);
|
||||
// }
|
||||
// byte[] gzip = baos.toByteArray();
|
||||
//
|
||||
// endPoint.setInput("" +
|
||||
// "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-Length: " + gzip.length + "\r\n" +
|
||||
// "Content-Encoding: gzip\r\n" +
|
||||
// "\r\n");
|
||||
// HttpExchange exchange = newExchange();
|
||||
// FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
// connection.receive();
|
||||
// endPoint.reset();
|
||||
//
|
||||
// ByteBuffer buffer = ByteBuffer.wrap(gzip);
|
||||
// int fragment = buffer.limit() - 1;
|
||||
// buffer.limit(fragment);
|
||||
// endPoint.setInput(buffer);
|
||||
// connection.receive();
|
||||
// endPoint.reset();
|
||||
//
|
||||
// buffer.limit(gzip.length);
|
||||
// buffer.position(fragment);
|
||||
// endPoint.setInput(buffer);
|
||||
// connection.receive();
|
||||
//
|
||||
// ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
// Assert.assertNotNull(response);
|
||||
// Assert.assertEquals(200, response.getStatus());
|
||||
// Assert.assertArrayEquals(data, response.getContent());
|
||||
// }
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.client;
|
||||
|
||||
public class HttpSenderTest
|
||||
{
|
||||
// @Rule
|
||||
// public final TestTracker tracker = new TestTracker();
|
||||
//
|
||||
// private HttpClient client;
|
||||
//
|
||||
// @Before
|
||||
// public void init() throws Exception
|
||||
// {
|
||||
// client = new HttpClient();
|
||||
// client.start();
|
||||
// }
|
||||
//
|
||||
// @After
|
||||
// public void destroy() throws Exception
|
||||
// {
|
||||
// client.stop();
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_NoRequestContent() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
// final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onHeaders(Request request)
|
||||
// {
|
||||
// headersLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onSuccess(Request request)
|
||||
// {
|
||||
// successLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, (Response.CompleteListener)null);
|
||||
//
|
||||
// String requestString = endPoint.takeOutputString();
|
||||
// Assert.assertTrue(requestString.startsWith("GET "));
|
||||
// Assert.assertTrue(requestString.endsWith("\r\n\r\n"));
|
||||
// Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
// Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
//
|
||||
// @Slow
|
||||
// @Test
|
||||
// public void test_Send_NoRequestContent_IncompleteFlush() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// connection.send(request, (Response.CompleteListener)null);
|
||||
//
|
||||
// // This take will free space in the buffer and allow for the write to complete
|
||||
// StringBuilder builder = new StringBuilder(endPoint.takeOutputString());
|
||||
//
|
||||
// // Wait for the write to complete
|
||||
// TimeUnit.SECONDS.sleep(1);
|
||||
//
|
||||
// String chunk = endPoint.takeOutputString();
|
||||
// while (chunk.length() > 0)
|
||||
// {
|
||||
// builder.append(chunk);
|
||||
// chunk = endPoint.takeOutputString();
|
||||
// }
|
||||
//
|
||||
// String requestString = builder.toString();
|
||||
// Assert.assertTrue(requestString.startsWith("GET "));
|
||||
// Assert.assertTrue(requestString.endsWith("\r\n\r\n"));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_NoRequestContent_Exception() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// // Shutdown output to trigger the exception on write
|
||||
// endPoint.shutdownOutput();
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onFailure(Request request, Throwable x)
|
||||
// {
|
||||
// failureLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, new Response.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onComplete(Result result)
|
||||
// {
|
||||
// Assert.assertTrue(result.isFailed());
|
||||
// failureLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_NoRequestContent_IncompleteFlush_Exception() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onFailure(Request request, Throwable x)
|
||||
// {
|
||||
// failureLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, new Response.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onComplete(Result result)
|
||||
// {
|
||||
// Assert.assertTrue(result.isFailed());
|
||||
// failureLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // Shutdown output to trigger the exception on write
|
||||
// endPoint.shutdownOutput();
|
||||
// // This take will free space in the buffer and allow for the write to complete
|
||||
// // although it will fail because we shut down the output
|
||||
// endPoint.takeOutputString();
|
||||
//
|
||||
// Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_SmallRequestContent_InOneBuffer() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// String content = "abcdef";
|
||||
// request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content.getBytes(StandardCharsets.UTF_8))));
|
||||
// final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
// final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onHeaders(Request request)
|
||||
// {
|
||||
// headersLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onSuccess(Request request)
|
||||
// {
|
||||
// successLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, (Response.CompleteListener)null);
|
||||
//
|
||||
// String requestString = endPoint.takeOutputString();
|
||||
// Assert.assertTrue(requestString.startsWith("GET "));
|
||||
// Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content));
|
||||
// Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
// Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_SmallRequestContent_InTwoBuffers() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// String content1 = "0123456789";
|
||||
// String content2 = "abcdef";
|
||||
// request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content1.getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap(content2.getBytes(StandardCharsets.UTF_8))));
|
||||
// final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
// final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onHeaders(Request request)
|
||||
// {
|
||||
// headersLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onSuccess(Request request)
|
||||
// {
|
||||
// successLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, (Response.CompleteListener)null);
|
||||
//
|
||||
// String requestString = endPoint.takeOutputString();
|
||||
// Assert.assertTrue(requestString.startsWith("GET "));
|
||||
// Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content1 + content2));
|
||||
// Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
// Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void test_Send_SmallRequestContent_Chunked_InTwoChunks() throws Exception
|
||||
// {
|
||||
// ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080);
|
||||
// HttpConnection connection = new HttpConnection(client, endPoint, destination);
|
||||
// Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
// String content1 = "0123456789";
|
||||
// String content2 = "ABCDEF";
|
||||
// request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content1.getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap(content2.getBytes(StandardCharsets.UTF_8)))
|
||||
// {
|
||||
// @Override
|
||||
// public long getLength()
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
// });
|
||||
// final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
// final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
// request.listener(new Request.Listener.Adapter()
|
||||
// {
|
||||
// @Override
|
||||
// public void onHeaders(Request request)
|
||||
// {
|
||||
// headersLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onSuccess(Request request)
|
||||
// {
|
||||
// successLatch.countDown();
|
||||
// }
|
||||
// });
|
||||
// connection.send(request, (Response.CompleteListener)null);
|
||||
//
|
||||
// String requestString = endPoint.takeOutputString();
|
||||
// Assert.assertTrue(requestString.startsWith("GET "));
|
||||
// String content = Integer.toHexString(content1.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content1 + "\r\n";
|
||||
// content += Integer.toHexString(content2.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content2 + "\r\n";
|
||||
// content += "0\r\n\r\n";
|
||||
// Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content));
|
||||
// Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
// Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.client.http;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpReceiverOverHTTPTest
|
||||
{
|
||||
@Rule
|
||||
public final TestTracker tracker = new TestTracker();
|
||||
|
||||
private HttpClient client;
|
||||
private HttpDestinationOverHTTP destination;
|
||||
private ByteArrayEndPoint endPoint;
|
||||
private HttpConnectionOverHTTP connection;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
client = new HttpClient();
|
||||
client.start();
|
||||
destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
endPoint = new ByteArrayEndPoint();
|
||||
connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
protected HttpExchange newExchange()
|
||||
{
|
||||
HttpRequest request = (HttpRequest)client.newRequest("http://localhost");
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
HttpExchange exchange = new HttpExchange(destination, request, Collections.<Response.ResponseListener>singletonList(listener));
|
||||
connection.getHttpChannel().associate(exchange);
|
||||
exchange.requestComplete();
|
||||
exchange.terminateRequest(null);
|
||||
return exchange;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_NoResponseContent() throws Exception
|
||||
{
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length: 0\r\n" +
|
||||
"\r\n");
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals("OK", response.getReason());
|
||||
Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
HttpFields headers = response.getHeaders();
|
||||
Assert.assertNotNull(headers);
|
||||
Assert.assertEquals(1, headers.size());
|
||||
Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_ResponseContent() throws Exception
|
||||
{
|
||||
String content = "0123456789ABCDEF";
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length: " + content.length() + "\r\n" +
|
||||
"\r\n" +
|
||||
content);
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals("OK", response.getReason());
|
||||
Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
HttpFields headers = response.getHeaders();
|
||||
Assert.assertNotNull(headers);
|
||||
Assert.assertEquals(1, headers.size());
|
||||
Assert.assertEquals(String.valueOf(content.length()), headers.get(HttpHeader.CONTENT_LENGTH));
|
||||
String received = listener.getContentAsString(StandardCharsets.UTF_8);
|
||||
Assert.assertEquals(content, received);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_ResponseContent_EarlyEOF() throws Exception
|
||||
{
|
||||
String content1 = "0123456789";
|
||||
String content2 = "ABCDEF";
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1);
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
endPoint.setInputEOF();
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
try
|
||||
{
|
||||
listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
Assert.assertTrue(e.getCause() instanceof EOFException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_ResponseContent_IdleTimeout() throws Exception
|
||||
{
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length: 1\r\n" +
|
||||
"\r\n");
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
// Simulate an idle timeout
|
||||
connection.onReadTimeout();
|
||||
|
||||
try
|
||||
{
|
||||
listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
Assert.assertTrue(e.getCause() instanceof TimeoutException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_BadResponse() throws Exception
|
||||
{
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length: A\r\n" +
|
||||
"\r\n");
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
try
|
||||
{
|
||||
listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
Assert.assertTrue(e.getCause() instanceof HttpResponseException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_GZIPResponseContent_Fragmented() throws Exception
|
||||
{
|
||||
byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzipOutput = new GZIPOutputStream(baos))
|
||||
{
|
||||
gzipOutput.write(data);
|
||||
}
|
||||
byte[] gzip = baos.toByteArray();
|
||||
|
||||
endPoint.setInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: " + gzip.length + "\r\n" +
|
||||
"Content-Encoding: gzip\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpRequest request = (HttpRequest)client.newRequest("http://localhost");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
FutureResponseListener listener = new FutureResponseListener(request)
|
||||
{
|
||||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
super.onContent(response, content);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
HttpExchange exchange = new HttpExchange(destination, request, Collections.<Response.ResponseListener>singletonList(listener));
|
||||
connection.getHttpChannel().associate(exchange);
|
||||
exchange.requestComplete();
|
||||
exchange.terminateRequest(null);
|
||||
connection.getHttpChannel().receive();
|
||||
endPoint.reset();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(gzip);
|
||||
int fragment = buffer.limit() - 1;
|
||||
buffer.limit(fragment);
|
||||
endPoint.setInput(buffer);
|
||||
connection.getHttpChannel().receive();
|
||||
endPoint.reset();
|
||||
|
||||
buffer.limit(gzip.length);
|
||||
buffer.position(fragment);
|
||||
endPoint.setInput(buffer);
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertArrayEquals(data, response.getContent());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,302 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.client.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.ByteBufferContentProvider;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpSenderOverHTTPTest
|
||||
{
|
||||
@Rule
|
||||
public final TestTracker tracker = new TestTracker();
|
||||
|
||||
private HttpClient client;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
client = new HttpClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_NoRequestContent() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
headersLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, null);
|
||||
|
||||
String requestString = endPoint.takeOutputString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n"));
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Slow
|
||||
@Test
|
||||
public void test_Send_NoRequestContent_IncompleteFlush() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
connection.send(request, null);
|
||||
|
||||
// This take will free space in the buffer and allow for the write to complete
|
||||
StringBuilder builder = new StringBuilder(endPoint.takeOutputString());
|
||||
|
||||
// Wait for the write to complete
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
String chunk = endPoint.takeOutputString();
|
||||
while (chunk.length() > 0)
|
||||
{
|
||||
builder.append(chunk);
|
||||
chunk = endPoint.takeOutputString();
|
||||
}
|
||||
|
||||
String requestString = builder.toString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_NoRequestContent_Exception() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// Shutdown output to trigger the exception on write
|
||||
endPoint.shutdownOutput();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Request request, Throwable x)
|
||||
{
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, new Response.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertTrue(result.isFailed());
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_NoRequestContent_IncompleteFlush_Exception() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Request request, Throwable x)
|
||||
{
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, new Response.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertTrue(result.isFailed());
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
// Shutdown output to trigger the exception on write
|
||||
endPoint.shutdownOutput();
|
||||
// This take will free space in the buffer and allow for the write to complete
|
||||
// although it will fail because we shut down the output
|
||||
endPoint.takeOutputString();
|
||||
|
||||
Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_SmallRequestContent_InOneBuffer() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content = "abcdef";
|
||||
request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content.getBytes(StandardCharsets.UTF_8))));
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
headersLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, null);
|
||||
|
||||
String requestString = endPoint.takeOutputString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content));
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_SmallRequestContent_InTwoBuffers() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content1 = "0123456789";
|
||||
String content2 = "abcdef";
|
||||
request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content1.getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap(content2.getBytes(StandardCharsets.UTF_8))));
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
headersLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, null);
|
||||
|
||||
String requestString = endPoint.takeOutputString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content1 + content2));
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Send_SmallRequestContent_Chunked_InTwoChunks() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination);
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content1 = "0123456789";
|
||||
String content2 = "ABCDEF";
|
||||
request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content1.getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap(content2.getBytes(StandardCharsets.UTF_8)))
|
||||
{
|
||||
@Override
|
||||
public long getLength()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
final CountDownLatch successLatch = new CountDownLatch(1);
|
||||
request.listener(new Request.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
headersLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
connection.send(request, null);
|
||||
|
||||
String requestString = endPoint.takeOutputString();
|
||||
Assert.assertTrue(requestString.startsWith("GET "));
|
||||
String content = Integer.toHexString(content1.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content1 + "\r\n";
|
||||
content += Integer.toHexString(content2.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content2 + "\r\n";
|
||||
content += "0\r\n\r\n";
|
||||
Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content));
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SslBytesServerTest extends SslBytesTest
|
||||
|
@ -237,7 +238,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
threadPool.shutdownNow();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout=10000)
|
||||
public void testHandshake() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
|
@ -1390,7 +1391,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
closeClient(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
// TODO work out why this test frequently fails
|
||||
@Ignore
|
||||
@Test(timeout=10000)
|
||||
public void testRequestWithContentWithRenegotiationInMiddleOfContentWhenRenegotiationIsForbidden() throws Exception
|
||||
{
|
||||
assumeJavaVersionSupportsTLSRenegotiations();
|
||||
|
@ -1616,7 +1619,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
closeClient(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout=10000)
|
||||
public void testRequestWithBigContentWithRenegotiationInMiddleOfContentWithSplitBoundary() throws Exception
|
||||
{
|
||||
assumeJavaVersionSupportsTLSRenegotiations();
|
||||
|
|
|
@ -302,7 +302,7 @@
|
|||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs</excludeGroupIds>
|
||||
<excludeArtifactIds>jetty-all,jetty-jsp,jetty-start,jetty-monitor</excludeArtifactIds>
|
||||
<excludeArtifactIds>jetty-all,jetty-jsp,apache-jsp,jetty-start,jetty-monitor</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
|
@ -457,6 +457,20 @@
|
|||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-apache-jsp-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.toolchain,javax.servlet.jsp,org.mortbay.jasper,org.mortbay.jasper,org.eclipse.jetty.orbit</includeGroupIds>
|
||||
<includeArtifactIds>apache-jsp,javax.servlet.jsp-api,apache-el,org.eclipse.jdt.core</includeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<prependGroupId>true</prependGroupId>
|
||||
<outputDirectory>${assembly-directory}/lib/apache-jsp</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-jstl-api</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
@ -484,6 +498,20 @@
|
|||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-apache-jstl-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludeGroupIds>org.glassfish.web</excludeGroupIds>
|
||||
<includeArtifactIds>taglibs-standard-spec,taglibs-standard-impl</includeArtifactIds>
|
||||
<prependGroupId>true</prependGroupId>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib/apache-jstl</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-jaspi-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
@ -526,7 +554,7 @@
|
|||
<argument>jetty.home=${assembly-directory}</argument>
|
||||
<argument>jetty.base=${assembly-directory}</argument>
|
||||
<argument>--add-to-start=server,deploy,websocket,ext,resources</argument>
|
||||
<argument>--add-to-startd=jsp,http</argument>
|
||||
<argument>--add-to-startd=jsp,jstl,http</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
|
@ -542,7 +570,7 @@
|
|||
<argument>jetty.home=${assembly-directory}</argument>
|
||||
<argument>jetty.base=${assembly-directory}/demo-base</argument>
|
||||
<argument>--add-to-start=server,continuation,deploy,ext,resources,client,annotations,jndi,servlets</argument>
|
||||
<argument>--add-to-startd-ini=jsp,http,https</argument>
|
||||
<argument>--add-to-startd-ini=jsp,jstl,http,https</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
|
@ -667,6 +695,11 @@
|
|||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-quickstart</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-start</artifactId>
|
||||
|
@ -697,6 +730,16 @@
|
|||
<artifactId>jetty-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
@ -765,6 +808,11 @@
|
|||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
<artifactId>example-async-rest-webapp</artifactId>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# Jetty JSP Module
|
||||
#
|
||||
|
||||
[depend]
|
||||
servlet
|
||||
jsp-impl/${jsp-impl}-jsp
|
||||
|
||||
[ini-template]
|
||||
# JSP Configuration
|
||||
|
||||
# Select JSP implementation, choices are
|
||||
# glassfish : The reference implementation
|
||||
# default in jetty <= 9.1
|
||||
# apache : The apache version
|
||||
# default jetty >= 9.2
|
||||
jsp-impl=apache
|
||||
|
||||
# To use an non-jdk compiler for JSP compilation uncomment next line
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Jetty JSP Module
|
||||
#
|
||||
|
||||
[depend]
|
||||
jsp
|
||||
jsp-impl/${jsp-impl}-jstl
|
||||
|
||||
[ini-template]
|
||||
# JSTL Configuration
|
||||
# The glassfish jsp-impl includes JSTL by default and this module
|
||||
# is not required to activate it.
|
||||
# The apache jsp-impl does not include JSTL by default and this module
|
||||
# is required to put JSTL on the container classpath
|
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Protocol Negotiatin Selection Module
|
||||
#
|
||||
|
||||
[depend]
|
||||
protonego-impl/${protonego}
|
||||
|
||||
[ini-template]
|
||||
# Protocol Negotiation Implementation Selection
|
||||
# choices are:
|
||||
# 'npn' : original implementation for SPDY (now deprecated)
|
||||
# 'alpn' : replacement for NPN, in use by current SPDY implementations
|
||||
# and the future HTTP/2 spec
|
||||
# Note: java 1.8+ are ALPN only.
|
||||
protonego=alpn
|
|
@ -132,7 +132,7 @@ public class HttpChannelOverFCGI extends HttpChannel
|
|||
if (close)
|
||||
connection.close();
|
||||
else
|
||||
connection.release();
|
||||
connection.release(this);
|
||||
}
|
||||
|
||||
protected void flush(Generator.Result... results)
|
||||
|
@ -155,7 +155,7 @@ public class HttpChannelOverFCGI extends HttpChannel
|
|||
protected void onIdleExpired(TimeoutException timeout)
|
||||
{
|
||||
LOG.debug("Idle timeout for request {}", request);
|
||||
abort(timeout);
|
||||
connection.abort(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.client.http;
|
|||
|
||||
import java.io.EOFException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -139,25 +140,19 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
|
||||
private void shutdown()
|
||||
{
|
||||
// First close then abort, to be sure that the
|
||||
// connection cannot be reused from an onFailure()
|
||||
// handler or by blocking code waiting for completion.
|
||||
close();
|
||||
for (HttpChannelOverFCGI channel : channels.values())
|
||||
channel.abort(new EOFException());
|
||||
close(new EOFException());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReadTimeout()
|
||||
{
|
||||
for (HttpChannelOverFCGI channel : channels.values())
|
||||
channel.abort(new TimeoutException());
|
||||
close();
|
||||
close(new TimeoutException());
|
||||
return false;
|
||||
}
|
||||
|
||||
public void release()
|
||||
protected void release(HttpChannelOverFCGI channel)
|
||||
{
|
||||
channels.remove(channel.getRequest());
|
||||
if (destination instanceof PoolingHttpDestination)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -169,17 +164,37 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(new AsynchronousCloseException());
|
||||
}
|
||||
|
||||
private void close(Throwable failure)
|
||||
{
|
||||
if (closed.compareAndSet(false, true))
|
||||
{
|
||||
// First close then abort, to be sure that the connection cannot be reused
|
||||
// from an onFailure() handler or by blocking code waiting for completion.
|
||||
getHttpDestination().close(this);
|
||||
getEndPoint().shutdownOutput();
|
||||
LOG.debug("{} oshut", this);
|
||||
getEndPoint().close();
|
||||
LOG.debug("{} closed", this);
|
||||
|
||||
abort(failure);
|
||||
}
|
||||
}
|
||||
|
||||
protected void abort(Throwable failure)
|
||||
{
|
||||
for (HttpChannelOverFCGI channel : channels.values())
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
exchange.getRequest().abort(failure);
|
||||
}
|
||||
channels.clear();
|
||||
}
|
||||
|
||||
private int acquireRequest()
|
||||
{
|
||||
synchronized (requests)
|
||||
|
@ -304,7 +319,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onEnd(int request)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.remove(request);
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
if (channel != null)
|
||||
{
|
||||
channel.responseSuccess();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<version>9.1.4-SNAPSHOT</version>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<version>9.1.4-SNAPSHOT</version>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<version>9.1.4-SNAPSHOT</version>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.net.URI;
|
|||
import java.net.URLEncoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -37,6 +38,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.BytesContentProvider;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
@ -513,4 +515,40 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals(length, response.getContent().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPollIsAbortedWhenClientIsStopped() throws Exception
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
request.startAsync();
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
final CountDownLatch completeLatch = new CountDownLatch(1);
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.send(new Response.CompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isFailed())
|
||||
completeLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Stop the client, the complete listener must be invoked.
|
||||
client.stop();
|
||||
|
||||
Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ public enum HttpMethod
|
|||
DELETE,
|
||||
TRACE,
|
||||
CONNECT,
|
||||
MOVE;
|
||||
MOVE,
|
||||
PROXY;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -48,7 +49,7 @@ public enum HttpMethod
|
|||
* @param limit The first non valid index
|
||||
* @return A HttpMethod if a match or null if no easy match.
|
||||
*/
|
||||
public static HttpMethod lookAheadGet(byte[] bytes, int position, int limit)
|
||||
public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit)
|
||||
{
|
||||
int length=limit-position;
|
||||
if (length<4)
|
||||
|
@ -62,6 +63,8 @@ public enum HttpMethod
|
|||
case 'P':
|
||||
if (bytes[position+1]=='O' && bytes[position+2]=='S' && bytes[position+3]=='T' && length>=5 && bytes[position+4]==' ')
|
||||
return POST;
|
||||
if (bytes[position+1]=='R' && bytes[position+2]=='O' && bytes[position+3]=='X' && length>=6 && bytes[position+4]=='Y' && bytes[position+5]==' ')
|
||||
return PROXY;
|
||||
if (bytes[position+1]=='U' && bytes[position+2]=='T' && bytes[position+3]==' ')
|
||||
return PUT;
|
||||
break;
|
||||
|
|
|
@ -104,6 +104,7 @@ public class HttpParser
|
|||
SPACE2,
|
||||
REQUEST_VERSION,
|
||||
REASON,
|
||||
PROXY,
|
||||
HEADER,
|
||||
HEADER_IN_NAME,
|
||||
HEADER_VALUE,
|
||||
|
@ -403,7 +404,7 @@ public class HttpParser
|
|||
* otherwise skip white space until something else to parse.
|
||||
*/
|
||||
private boolean quickStart(ByteBuffer buffer)
|
||||
{
|
||||
{
|
||||
if (_requestHandler!=null)
|
||||
{
|
||||
_method = HttpMethod.lookAheadGet(buffer);
|
||||
|
@ -411,6 +412,7 @@ public class HttpParser
|
|||
{
|
||||
_methodString = _method.asString();
|
||||
buffer.position(buffer.position()+_methodString.length()+1);
|
||||
|
||||
setState(State.SPACE1);
|
||||
return false;
|
||||
}
|
||||
|
@ -655,7 +657,29 @@ public class HttpParser
|
|||
version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
|
||||
else
|
||||
version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
|
||||
if (version!=null)
|
||||
if (version==null)
|
||||
{
|
||||
if (_method==HttpMethod.PROXY)
|
||||
{
|
||||
if (!(_requestHandler instanceof ProxyHandler))
|
||||
throw new BadMessage();
|
||||
|
||||
_uri.flip();
|
||||
String protocol=BufferUtil.toString(_uri);
|
||||
// This is the proxy protocol, so we can assume entire first line is in buffer else 400
|
||||
buffer.position(buffer.position()-1);
|
||||
String sAddr = getProxyField(buffer);
|
||||
String dAddr = getProxyField(buffer);
|
||||
int sPort = BufferUtil.takeInt(buffer);
|
||||
next(buffer);
|
||||
int dPort = BufferUtil.takeInt(buffer);
|
||||
next(buffer);
|
||||
_state=State.START;
|
||||
((ProxyHandler)_requestHandler).proxied(protocol,sAddr,dAddr,sPort,dPort);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int pos = buffer.position()+version.asString().length()-1;
|
||||
if (pos<buffer.limit())
|
||||
|
@ -715,8 +739,7 @@ public class HttpParser
|
|||
if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
|
||||
{
|
||||
int header_cache = _handler.getHeaderCacheSize();
|
||||
if (header_cache>0)
|
||||
_connectionFields=new ArrayTernaryTrie<>(header_cache);
|
||||
_connectionFields=new ArrayTernaryTrie<>(header_cache);
|
||||
}
|
||||
|
||||
setState(State.HEADER);
|
||||
|
@ -1586,6 +1609,11 @@ public class HttpParser
|
|||
public int getHeaderCacheSize();
|
||||
}
|
||||
|
||||
public interface ProxyHandler
|
||||
{
|
||||
void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort);
|
||||
}
|
||||
|
||||
public interface RequestHandler<T> extends HttpHandler<T>
|
||||
{
|
||||
/**
|
||||
|
@ -1618,4 +1646,20 @@ public class HttpParser
|
|||
{
|
||||
return _connectionFields;
|
||||
}
|
||||
|
||||
private String getProxyField(ByteBuffer buffer)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_length=0;
|
||||
|
||||
while (buffer.hasRemaining())
|
||||
{
|
||||
// process each character
|
||||
byte ch=next(buffer);
|
||||
if (ch<=' ')
|
||||
return _string.toString();
|
||||
_string.append((char)ch);
|
||||
}
|
||||
throw new BadMessage();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1398,6 +1398,63 @@ public class HttpParserTest
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyProtocol() throws Exception
|
||||
{
|
||||
ByteBuffer buffer=BufferUtil
|
||||
.toBuffer("PROXY TCP4 107.47.45.254 10.0.1.116 27689 80\015\012"
|
||||
+"GET / HTTP/1.1\015\012"
|
||||
+"Host: localhost \015\012"
|
||||
+"Connection: close\015\012"+"\015\012"+"\015\012");
|
||||
|
||||
Handler handler=new Handler();
|
||||
HttpParser parser=new HttpParser((HttpParser.RequestHandler)handler);
|
||||
parseAll(parser, buffer);
|
||||
|
||||
assertTrue(_headerCompleted);
|
||||
assertTrue(_messageCompleted);
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
assertEquals("/", _uriOrStatus);
|
||||
assertEquals("HTTP/1.1", _versionOrReason);
|
||||
assertEquals("PROXY TCP4 107.47.45.254 10.0.1.116 27689 80", handler._proxy);
|
||||
assertEquals("Host", _hdr[0]);
|
||||
assertEquals("localhost", _val[0]);
|
||||
assertEquals("Connection", _hdr[1]);
|
||||
assertEquals("close", _val[1]);
|
||||
assertEquals(1, _headers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitProxyHeaderParseTest() throws Exception
|
||||
{
|
||||
Handler handler=new Handler();
|
||||
HttpParser parser=new HttpParser((HttpParser.RequestHandler)handler);
|
||||
|
||||
ByteBuffer buffer=BufferUtil.toBuffer("PROXY TCP4 207.47.45.254 10.0.1.116 27689 80\015\012");
|
||||
parser.parseNext(buffer);
|
||||
|
||||
buffer=BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+"Host: localhost \015\012"
|
||||
+"Connection: close\015\012"
|
||||
+"\015\012"
|
||||
+"\015\012");
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertTrue(_headerCompleted);
|
||||
assertTrue(_messageCompleted);
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
assertEquals("/", _uriOrStatus);
|
||||
assertEquals("HTTP/1.1", _versionOrReason);
|
||||
assertEquals("PROXY TCP4 207.47.45.254 10.0.1.116 27689 80", handler._proxy);
|
||||
assertEquals("Host", _hdr[0]);
|
||||
assertEquals("localhost", _val[0]);
|
||||
assertEquals("Connection", _hdr[1]);
|
||||
assertEquals("close", _val[1]);
|
||||
assertEquals(1, _headers);
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void init()
|
||||
{
|
||||
|
@ -1429,9 +1486,10 @@ public class HttpParserTest
|
|||
private boolean _headerCompleted;
|
||||
private boolean _messageCompleted;
|
||||
|
||||
private class Handler implements HttpParser.RequestHandler<ByteBuffer>, HttpParser.ResponseHandler<ByteBuffer>
|
||||
private class Handler implements HttpParser.RequestHandler<ByteBuffer>, HttpParser.ResponseHandler<ByteBuffer>, HttpParser.ProxyHandler
|
||||
{
|
||||
private HttpFields fields;
|
||||
String _proxy;
|
||||
|
||||
@Override
|
||||
public boolean content(ByteBuffer ref)
|
||||
|
@ -1539,5 +1597,11 @@ public class HttpParserTest
|
|||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort)
|
||||
{
|
||||
_proxy="PROXY "+protocol+" "+sAddr+" "+dAddr+" "+sPort+" "+dPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,18 +16,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.spdy.client;
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
|
@ -16,9 +16,8 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.spdy.client;
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
|
||||
public abstract class NegotiatingClientConnectionFactory implements ClientConnectionFactory
|
||||
{
|
|
@ -2,6 +2,9 @@
|
|||
# JMX Module
|
||||
#
|
||||
|
||||
[depend]
|
||||
server
|
||||
|
||||
[lib]
|
||||
lib/jetty-jmx-${jetty.version}.jar
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Glassfish JSP Module
|
||||
#
|
||||
[name]
|
||||
jsp-impl
|
||||
|
||||
[lib]
|
||||
lib/jsp/*.jar
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Glassfish JSTL
|
||||
[name]
|
||||
jstl-impl
|
||||
|
||||
# This file is empty as glassfish jstl is provided by glassfish jsp
|
|
@ -1,14 +0,0 @@
|
|||
#
|
||||
# Jetty JSP Module
|
||||
#
|
||||
|
||||
[depend]
|
||||
servlet
|
||||
|
||||
[lib]
|
||||
lib/jsp/*.jar
|
||||
|
||||
[ini-template]
|
||||
# JSP Configuration
|
||||
# To use an non-jdk compiler for JSP compilation uncomment next line
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
|
@ -72,9 +72,19 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<version>1.8.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp</artifactId>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -79,6 +79,7 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
public class JspcMojo extends AbstractMojo
|
||||
{
|
||||
public static final String END_OF_WEBAPP = "</web-app>";
|
||||
public static final String PRECOMPILED_FLAG = "org.eclipse.jetty.jsp.precompiled";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -207,7 +208,7 @@ public class JspcMojo extends AbstractMojo
|
|||
/**
|
||||
* Patterns of jars on the system path that contain tlds. Use | to separate each pattern.
|
||||
*
|
||||
* @parameter default-value=".*taglibs[^/]*\.jar|.*jstl-impl[^/]*\.jar$
|
||||
* @parameter default-value=".*taglibs[^/]*\.jar|.*jstl[^/]*\.jar$
|
||||
*/
|
||||
private String tldJarNamePatterns;
|
||||
|
||||
|
@ -294,9 +295,9 @@ public class JspcMojo extends AbstractMojo
|
|||
jspc.setWebXmlFragment(webXmlFragment);
|
||||
jspc.setUriroot(webAppSourceDirectory);
|
||||
jspc.setOutputDir(generatedClasses);
|
||||
jspc.setClassPath(webAppClassPath.toString());
|
||||
jspc.setClassPath(sysClassPath+System.getProperty("path.separator")+webAppClassPath.toString());
|
||||
jspc.setCompile(true);
|
||||
jspc.setSystemClassPath(sysClassPath);
|
||||
//jspc.setSystemClassPath(sysClassPath);
|
||||
|
||||
|
||||
// JspC#setExtensions() does not exist, so
|
||||
|
@ -419,6 +420,10 @@ public class JspcMojo extends AbstractMojo
|
|||
mergedWebXmlWriter.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
//put in a context init-param to flag that the contents have been precompiled
|
||||
mergedWebXmlWriter.println("<context-param><param-name>"+PRECOMPILED_FLAG+"</param-name><param-value>true</param-value></context-param>");
|
||||
|
||||
|
||||
// put in the generated fragment
|
||||
try (BufferedReader fragmentWebXmlReader = new BufferedReader(
|
||||
|
@ -541,13 +546,16 @@ public class JspcMojo extends AbstractMojo
|
|||
*/
|
||||
private List<URL> getSystemJarsWithTlds() throws Exception
|
||||
{
|
||||
getLog().debug("tld pattern=" + tldJarNamePatterns);
|
||||
final List<URL> list = new ArrayList<URL>();
|
||||
List<URI> artifactUris = new ArrayList<URI>();
|
||||
Pattern pattern = Pattern.compile(tldJarNamePatterns);
|
||||
for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact pluginArtifact = iter.next();
|
||||
artifactUris.add(Resource.newResource(pluginArtifact.getFile()).getURI());
|
||||
Resource res = Resource.newResource(pluginArtifact.getFile());
|
||||
getLog().debug("scan jar: "+res.getURI());
|
||||
artifactUris.add(res.getURI());
|
||||
}
|
||||
|
||||
PatternMatcher matcher = new PatternMatcher()
|
||||
|
|
|
@ -122,19 +122,19 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp</artifactId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>javax.activation</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency -->
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>javax.transaction-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>javax.transaction-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<reporting>
|
||||
<plugins>
|
||||
|
|
|
@ -62,7 +62,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyWebAppContext.class);
|
||||
|
||||
private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$";
|
||||
private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar";
|
||||
private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
|
||||
private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<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.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-alpn</artifactId>
|
||||
<name>Jetty :: OSGi ALPN Fragment</name>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<bundle-symbolic-name>org.eclipse.jetty.osgi.alpn.fragment</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>parse-version</id>
|
||||
<goals>
|
||||
<goal>parse-version</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Bundle-ManifestVersion>2</Bundle-ManifestVersion>
|
||||
<Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
|
||||
<Bundle-Name>Jetty OSGi ALPN Fragment</Bundle-Name>
|
||||
<Bundle-Version>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}</Bundle-Version>
|
||||
<Export-Package>org.eclipse.jetty.alpn;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
||||
<Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -37,37 +37,81 @@ import org.osgi.framework.Bundle;
|
|||
public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
|
||||
private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403};
|
||||
private static OSGiContainerType osgiContainer;
|
||||
private static Class Equinox_BundleHost_Class;
|
||||
private static Class Equinox_EquinoxBundle_Class;
|
||||
private static Class Felix_BundleImpl_Class;
|
||||
private static Class Felix_BundleWiring_Class;
|
||||
//old equinox
|
||||
private static Method Equinox_BundleHost_getBundleLoader_method;
|
||||
private static Method Equinox_BundleLoader_createClassLoader_method;
|
||||
//new equinox
|
||||
private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method;
|
||||
|
||||
//new felix
|
||||
private static Method Felix_BundleImpl_Adapt_Method;
|
||||
//old felix
|
||||
private static Field Felix_BundleImpl_m_Modules_Field;
|
||||
private static Field Felix_ModuleImpl_m_ClassLoader_Field;
|
||||
private static Method Felix_BundleWiring_getClassLoader_Method;
|
||||
|
||||
private static boolean identifiedOsgiImpl = false;
|
||||
|
||||
private static boolean isEquinox = false;
|
||||
|
||||
private static boolean isFelix = false;
|
||||
|
||||
private static void init(Bundle bundle)
|
||||
|
||||
private static void checkContainerType (Bundle bundle)
|
||||
{
|
||||
identifiedOsgiImpl = true;
|
||||
if (osgiContainer != null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null;
|
||||
Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
|
||||
osgiContainer = OSGiContainerType.EquinoxOld;
|
||||
return;
|
||||
}
|
||||
catch (Throwable t)
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
isEquinox = false;
|
||||
LOG.ignore(e);
|
||||
}
|
||||
if (!isEquinox)
|
||||
|
||||
try
|
||||
{
|
||||
Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
|
||||
osgiContainer = OSGiContainerType.EquinoxLuna;
|
||||
return;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//old felix or new felix?
|
||||
Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
|
||||
try
|
||||
{
|
||||
isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null;
|
||||
Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[] {Class.class});
|
||||
osgiContainer = OSGiContainerType.Felix403;
|
||||
return;
|
||||
}
|
||||
catch (Throwable t2)
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
isFelix = false;
|
||||
osgiContainer = OSGiContainerType.FelixOld;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.warn("Unknown OSGi container type");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Assuming the bundle is started.
|
||||
*
|
||||
|
@ -77,7 +121,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
|
|||
public ClassLoader getBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
|
||||
|
||||
|
||||
if (bundleActivator == null)
|
||||
{
|
||||
bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
|
||||
|
@ -93,80 +137,135 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
|
|||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
// resort to introspection
|
||||
if (!identifiedOsgiImpl)
|
||||
|
||||
// resort to introspection
|
||||
return getBundleClassLoaderForContainer(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bundle
|
||||
* @return
|
||||
*/
|
||||
private ClassLoader getBundleClassLoaderForContainer (Bundle bundle)
|
||||
{
|
||||
checkContainerType (bundle);
|
||||
if (osgiContainer == null)
|
||||
{
|
||||
init(bundle);
|
||||
}
|
||||
if (isEquinox)
|
||||
{
|
||||
return internalGetEquinoxBundleClassLoader(bundle);
|
||||
}
|
||||
else if (isFelix)
|
||||
{
|
||||
return internalGetFelixBundleClassLoader(bundle);
|
||||
LOG.warn("No classloader for unknown OSGi container type");
|
||||
return null;
|
||||
}
|
||||
|
||||
LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
|
||||
return null;
|
||||
switch (osgiContainer)
|
||||
{
|
||||
case EquinoxOld:
|
||||
case EquinoxLuna:
|
||||
{
|
||||
return internalGetEquinoxBundleClassLoader(bundle);
|
||||
}
|
||||
|
||||
case FelixOld:
|
||||
case Felix403:
|
||||
{
|
||||
return internalGetFelixBundleClassLoader(bundle);
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Method Equinox_BundleHost_getBundleLoader_method;
|
||||
|
||||
private static Method Equinox_BundleLoader_createClassLoader_method;
|
||||
|
||||
/**
|
||||
* @param bundle
|
||||
* @return
|
||||
*/
|
||||
private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
// assume equinox:
|
||||
try
|
||||
if (osgiContainer == OSGiContainerType.EquinoxOld)
|
||||
{
|
||||
if (Equinox_BundleHost_getBundleLoader_method == null)
|
||||
try
|
||||
{
|
||||
Equinox_BundleHost_getBundleLoader_method =
|
||||
bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost").getDeclaredMethod("getBundleLoader", new Class[] {});
|
||||
Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
|
||||
if (Equinox_BundleHost_getBundleLoader_method == null)
|
||||
{
|
||||
Equinox_BundleHost_getBundleLoader_method =
|
||||
Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {});
|
||||
Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
|
||||
}
|
||||
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
|
||||
if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
|
||||
{
|
||||
Equinox_BundleLoader_createClassLoader_method =
|
||||
bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
|
||||
Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
|
||||
}
|
||||
return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
|
||||
}
|
||||
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
|
||||
if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
|
||||
catch (ClassNotFoundException t)
|
||||
{
|
||||
Equinox_BundleLoader_createClassLoader_method =
|
||||
bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
|
||||
Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
|
||||
LOG.warn(t);
|
||||
return null;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
return null;
|
||||
}
|
||||
return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
|
||||
}
|
||||
catch (Throwable t)
|
||||
|
||||
if (osgiContainer == OSGiContainerType.EquinoxLuna)
|
||||
{
|
||||
LOG.warn(t);
|
||||
try
|
||||
{
|
||||
if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null)
|
||||
Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[] {Boolean.TYPE});
|
||||
|
||||
Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true);
|
||||
return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[] {Boolean.FALSE});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Field Felix_BundleImpl_m_modules_field;
|
||||
|
||||
|
||||
private static Field Felix_ModuleImpl_m_classLoader_field;
|
||||
|
||||
private static Method Felix_adapt_method;
|
||||
|
||||
private static Method Felix_bundle_wiring_getClassLoader_method;
|
||||
|
||||
private static Class Felix_bundleWiringClazz;
|
||||
|
||||
private static Boolean isFelix403 = null;
|
||||
|
||||
/**
|
||||
* @param bundle
|
||||
* @return
|
||||
*/
|
||||
private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
//firstly, try to find classes matching a newer version of felix
|
||||
initFelix403(bundle);
|
||||
|
||||
if (isFelix403.booleanValue())
|
||||
|
||||
if (osgiContainer == OSGiContainerType.Felix403)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object wiring = Felix_adapt_method.invoke(bundle, new Object[] {Felix_bundleWiringClazz});
|
||||
ClassLoader cl = (ClassLoader)Felix_bundle_wiring_getClassLoader_method.invoke(wiring);
|
||||
return cl;
|
||||
if (Felix_BundleWiring_Class == null)
|
||||
Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
|
||||
|
||||
|
||||
Felix_BundleImpl_Adapt_Method.setAccessible(true);
|
||||
|
||||
if (Felix_BundleWiring_getClassLoader_Method == null)
|
||||
{
|
||||
Felix_BundleWiring_getClassLoader_Method = Felix_BundleWiring_Class.getDeclaredMethod("getClassLoader");
|
||||
Felix_BundleWiring_getClassLoader_Method.setAccessible(true);
|
||||
}
|
||||
|
||||
|
||||
Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Felix_BundleWiring_Class});
|
||||
return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -176,123 +275,92 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
|
|||
}
|
||||
|
||||
|
||||
// Fallback to trying earlier versions of felix.
|
||||
if (Felix_BundleImpl_m_modules_field == null)
|
||||
{
|
||||
if (osgiContainer == OSGiContainerType.FelixOld)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
|
||||
Felix_BundleImpl_m_modules_field = bundleImplClazz.getDeclaredField("m_modules");
|
||||
Felix_BundleImpl_m_modules_field.setAccessible(true);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (NoSuchFieldException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
if (Felix_BundleImpl_m_Modules_Field == null)
|
||||
{
|
||||
Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
|
||||
Felix_BundleImpl_m_Modules_Field.setAccessible(true);
|
||||
}
|
||||
|
||||
// Figure out which version of the modules is exported
|
||||
Object currentModuleImpl;
|
||||
try
|
||||
{
|
||||
Object[] moduleArray = (Object[]) Felix_BundleImpl_m_modules_field.get(bundle);
|
||||
currentModuleImpl = moduleArray[moduleArray.length - 1];
|
||||
}
|
||||
catch (Throwable t2)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_modules_field.get(bundle);
|
||||
currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
|
||||
}
|
||||
// Figure out which version of the modules is exported
|
||||
Object currentModuleImpl;
|
||||
|
||||
try
|
||||
{
|
||||
Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle);
|
||||
currentModuleImpl = moduleArray[moduleArray.length - 1];
|
||||
}
|
||||
catch (Throwable t2)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_Modules_Field.get(bundle);
|
||||
currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
|
||||
Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// first make sure that the classloader is ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
ClassLoader cl = null;
|
||||
try
|
||||
{
|
||||
cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
|
||||
if (cl != null)
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// looks like it was not ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
// this call will do that.
|
||||
try
|
||||
{
|
||||
bundle.loadClass("java.lang.Object");
|
||||
cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
|
||||
Felix_ModuleImpl_m_classLoader_field.setAccessible(true);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
catch (NoSuchFieldException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// first make sure that the classloader is ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
ClassLoader cl = null;
|
||||
try
|
||||
{
|
||||
cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
|
||||
if (cl != null)
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// looks like it was not ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
// this call will do that.
|
||||
try
|
||||
{
|
||||
bundle.loadClass("java.lang.Object");
|
||||
cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void initFelix403 (Bundle bundle)
|
||||
{
|
||||
//see if the version of Felix is a new one
|
||||
if (isFelix403 == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
|
||||
Felix_bundleWiringClazz = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
|
||||
Felix_adapt_method = bundleImplClazz.getDeclaredMethod("adapt", new Class[] {Class.class});
|
||||
Felix_adapt_method.setAccessible(true);
|
||||
Felix_bundle_wiring_getClassLoader_method = Felix_bundleWiringClazz.getDeclaredMethod("getClassLoader");
|
||||
Felix_bundle_wiring_getClassLoader_method.setAccessible(true);
|
||||
isFelix403 = Boolean.TRUE;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.warn("Felix 4.x classes not found in environment");
|
||||
isFelix403 = Boolean.FALSE;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
LOG.warn("Felix 4.x classes not found in environment");
|
||||
isFelix403 = Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,25 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
// DirZipBundleEntry
|
||||
|
||||
private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile
|
||||
|
||||
private static final String[] FILE_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry","org.eclipse.osgi.storage.bundlefile.FileBundleEntry"};
|
||||
private static final String[] ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry","org.eclipse.osgi.storage.bundlefile.ZipBundleEntry"};
|
||||
private static final String[] DIR_ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry","org.eclipse.osgi.storage.bundlefile.DirZipBundleEntry"};
|
||||
private static final String[] BUNDLE_URL_CONNECTION_CLASSES = {"org.eclipse.osgi.framework.internal.core.BundleURLConnection", "org.eclipse.osgi.storage.url.BundleURLConnection"};
|
||||
|
||||
|
||||
public static boolean match (String name, String... names)
|
||||
{
|
||||
if (name == null || names == null)
|
||||
return false;
|
||||
boolean matched = false;
|
||||
for (int i=0; i< names.length && !matched; i++)
|
||||
if (name.equals(names[i]))
|
||||
matched = true;
|
||||
return matched;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Works with equinox, felix, nuxeo and probably more. Not exactly in the
|
||||
* spirit of OSGi but quite necessary to support self-contained webapps and
|
||||
|
@ -107,7 +125,8 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
BUNDLE_ENTRY_FIELD.setAccessible(true);
|
||||
}
|
||||
Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
|
||||
if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry"))
|
||||
|
||||
if (match(bundleEntry.getClass().getName(), FILE_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
if (FILE_FIELD == null)
|
||||
{
|
||||
|
@ -117,7 +136,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
File f = (File) FILE_FIELD.get(bundleEntry);
|
||||
return f.getParentFile().getParentFile();
|
||||
}
|
||||
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry"))
|
||||
else if (match(bundleEntry.getClass().getName(), ZIP_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
url = bundle.getEntry("/");
|
||||
|
||||
|
@ -144,7 +163,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
ZipFile zipFile = (ZipFile) ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
|
||||
return new File(zipFile.getName());
|
||||
}
|
||||
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry"))
|
||||
else if (match (bundleEntry.getClass().getName(), DIR_ZIP_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
// that will not happen as we did ask for the manifest not a
|
||||
// directory.
|
||||
|
@ -309,7 +328,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
|
||||
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
|
||||
|
@ -340,7 +359,9 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null
|
||||
&&
|
||||
match (conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
|
||||
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
|
||||
|
|
|
@ -22,12 +22,23 @@
|
|||
<module>jetty-osgi-boot</module>
|
||||
<module>jetty-osgi-boot-jsp</module>
|
||||
<module>jetty-osgi-boot-warurl</module>
|
||||
<module>jetty-osgi-npn</module>
|
||||
<module>jetty-osgi-httpservice</module>
|
||||
<module>test-jetty-osgi-webapp</module>
|
||||
<module>test-jetty-osgi-context</module>
|
||||
<module>test-jetty-osgi</module>
|
||||
<module>jetty-osgi-alpn</module>
|
||||
</modules>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>npn</id>
|
||||
<activation>
|
||||
<jdk>1.7</jdk>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>jetty-osgi-npn</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
</dependency-->
|
||||
|
||||
<!-- container is not bad but not enough config parameters yet
|
||||
can't pass the VMOption for npn-boot
|
||||
can't pass the VMOption for alpn-boot
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.exam</groupId>
|
||||
<artifactId>pax-exam-container-forked</artifactId>
|
||||
|
@ -192,11 +192,43 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-tree</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Jetty Deps -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-tree</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -324,14 +356,20 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty.npn</groupId>
|
||||
<artifactId>npn-boot</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<groupId>org.mortbay.jetty.alpn</groupId>
|
||||
<artifactId>alpn-boot</artifactId>
|
||||
<version>${alpn.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-npn</artifactId>
|
||||
<artifactId>jetty-osgi-alpn</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
@ -402,9 +440,8 @@
|
|||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- No point defining -Xbootclasspath as the actual OSGi VM is run as a forked process by pax-exam -->
|
||||
<!--argLine>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar</argLine-->
|
||||
<!-- But we do pass the sys property of the npn-boot jar -->
|
||||
<argLine>-Dmortbay-npn-boot=${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar</argLine>
|
||||
<!-- But we do pass the sys property of the alpn-boot jar so that it can be configued inside tests -->
|
||||
<argLine>-Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- HttpChannel Configuration -->
|
||||
<!-- Add HTTP Customizer for Secure request -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
|
||||
<Set name="secureScheme">https</Set>
|
||||
|
@ -16,7 +16,7 @@
|
|||
<Set name="responseHeaderSize">8192</Set>
|
||||
<Call name="addCustomizer">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/>
|
||||
<New class="org.eclipse.jetty.server.SecureRequestCustomizer"/>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
|
@ -35,53 +35,6 @@
|
|||
<Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
|
||||
</New>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add HTTP Customizer for Secure request -->
|
||||
<!-- =========================================================== -->
|
||||
<Ref refid="httpConfig">
|
||||
<Call name="addCustomizer">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.SecureRequestCustomizer"/>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Create a push strategy which can be used by reference by -->
|
||||
<!-- individual connection factories below. -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
|
||||
<!-- for all configuration that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
|
||||
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
|
||||
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
|
||||
<!--
|
||||
<Set name="UserAgentBlacklist">
|
||||
<Array type="String">
|
||||
<Item>.*(?i)firefox/14.*</Item>
|
||||
<Item>.*(?i)firefox/15.*</Item>
|
||||
<Item>.*(?i)firefox/16.*</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
|
||||
<!-- Uncomment to override default file extensions to push -->
|
||||
<!--
|
||||
<Set name="PushRegexps">
|
||||
<Array type="String">
|
||||
<Item>.*\.css</Item>
|
||||
<Item>.*\.js</Item>
|
||||
<Item>.*\.png</Item>
|
||||
<Item>.*\.jpg</Item>
|
||||
<Item>.*\.gif</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<Set name="referrerPushPeriod">5000</Set>
|
||||
<Set name="maxAssociatedResources">32</Set>
|
||||
</New>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Set connectors -->
|
||||
<!-- =========================================================== -->
|
||||
|
@ -95,7 +48,7 @@
|
|||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.SslConnectionFactory">
|
||||
<Arg name="next">npn</Arg>
|
||||
<Arg name="next">alpn</Arg>
|
||||
<Arg name="sslContextFactory">
|
||||
<Ref refid="sslContextFactory"/>
|
||||
</Arg>
|
||||
|
@ -103,7 +56,7 @@
|
|||
</Item>
|
||||
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory">
|
||||
<New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
|
||||
<Arg name="protocols">
|
||||
<Array type="String">
|
||||
<Item>spdy/3</Item>
|
||||
|
@ -124,8 +77,6 @@
|
|||
<!-- Set the initial window size for this SPDY connector. -->
|
||||
<!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
|
||||
<Set name="initialWindowSize">65536</Set>
|
||||
<!-- Uncomment to enable the push strategy with id "pushStrategy" -->
|
||||
<!-- <Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg> -->
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
|
|
|
@ -31,12 +31,14 @@ import java.util.List;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.ops4j.pax.exam.CoreOptions;
|
||||
import org.ops4j.pax.exam.Option;
|
||||
import org.ops4j.pax.exam.junit.Configuration;
|
||||
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
|
@ -64,9 +66,9 @@ public class TestJettyOSGiBootSpdy
|
|||
|
||||
options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort("jetty-spdy.xml"));
|
||||
options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
|
||||
options.addAll(spdyJettyDependencies());
|
||||
options.add(CoreOptions.junitBundles());
|
||||
options.addAll(TestJettyOSGiBootCore.httpServiceJetty());
|
||||
options.addAll(spdyJettyDependencies());
|
||||
|
||||
String logLevel = "WARN";
|
||||
|
||||
|
@ -90,37 +92,42 @@ public class TestJettyOSGiBootSpdy
|
|||
{
|
||||
List<Option> res = new ArrayList<Option>();
|
||||
res.add(CoreOptions.systemProperty(JETTY_SPDY_PORT).value(String.valueOf(DEFAULT_JETTY_SPDY_PORT)));
|
||||
// java
|
||||
// -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn-version}/npn-boot-${npn-version}.jar
|
||||
// res.add(CoreOptions.vmOptions("-Xbootclasspath/p:"+System.getenv("HOME")+"/.m2/repository/org/mortbay/jetty/npn/npn-boot/"+npnBootVersion+"/npn-boot-"+npnBootVersion+".jar"));
|
||||
String npnBoot = System.getProperty("mortbay-npn-boot");
|
||||
if (npnBoot == null) { throw new IllegalStateException("Define path to npn boot jar as system property -Dmortbay-npn-boot"); }
|
||||
File checkNpnBoot = new File(npnBoot);
|
||||
if (!checkNpnBoot.exists()) { throw new IllegalStateException("Unable to find the npn boot jar here: " + npnBoot); }
|
||||
|
||||
res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + npnBoot));
|
||||
// res.add(CoreOptions.bootDelegationPackages("org.eclipse.jetty.npn"));
|
||||
String alpnBoot = System.getProperty("mortbay-alpn-boot");
|
||||
if (alpnBoot == null) { throw new IllegalStateException("Define path to alpn boot jar as system property -Dmortbay-alpn-boot"); }
|
||||
File checkALPNBoot = new File(alpnBoot);
|
||||
if (!checkALPNBoot.exists()) { throw new IllegalStateException("Unable to find the alpn boot jar here: " + alpnBoot); }
|
||||
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-npn").versionAsInProject().noStart());
|
||||
|
||||
res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + alpnBoot));
|
||||
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-server").versionAsInProject().start());
|
||||
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-client").versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-core").versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-server").versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-common").versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-server").versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-client").versionAsInProject().noStart());
|
||||
return res;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void checkNpnBootOnBootstrapClasspath() throws Exception
|
||||
public void checkALPNBootOnBootstrapClasspath() throws Exception
|
||||
{
|
||||
Class<?> npn = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.npn.NextProtoNego");
|
||||
Assert.assertNotNull(npn);
|
||||
Assert.assertNull(npn.getClassLoader());
|
||||
Class<?> alpn = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.alpn.ALPN");
|
||||
Assert.assertNotNull(alpn);
|
||||
Assert.assertNull(alpn.getClassLoader());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertAllBundlesActiveOrResolved()
|
||||
{
|
||||
Bundle b = TestOSGiUtil.getBundle(bundleContext, "org.eclipse.jetty.spdy.client");
|
||||
TestOSGiUtil.diagnoseNonActiveOrNonResolvedBundle(b);
|
||||
b = TestOSGiUtil.getBundle(bundleContext, "org.eclipse.jetty.osgi.boot");
|
||||
TestOSGiUtil.diagnoseNonActiveOrNonResolvedBundle(b);
|
||||
TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.StartBenchmarkWar"
|
||||
|
||||
OR
|
||||
|
||||
mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.PreconfigureBenchmarkWar"
|
||||
mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.QuickStartBenchmarkWar"
|
|
@ -0,0 +1,170 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-quickstart</artifactId>
|
||||
<name>Example :: Jetty Quick Start</name>
|
||||
<description>Jetty Quick Start</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>javax.transaction-api</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-mock-resources</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>javax.mail.glassfish</artifactId>
|
||||
<version>1.4.1.v201005082020</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<configuration>
|
||||
<platforms>
|
||||
<platform>unix</platform>
|
||||
</platforms>
|
||||
<programs>
|
||||
<program>
|
||||
<id>preconfigure</id>
|
||||
<mainClass>org.eclipse.jetty.quickstart.PreconfigureQuickStartWar</mainClass>
|
||||
</program>
|
||||
<program>
|
||||
<mainClass>org.eclipse.jetty.quickstart.QuickStartWar</mainClass>
|
||||
<id>quickstart</id>
|
||||
</program>
|
||||
</programs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-jndi-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${basedir}/target</outputDirectory>
|
||||
<destFileName>test-jndi.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-spec-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${basedir}/target</outputDirectory>
|
||||
<destFileName>test-spec.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${basedir}/target</outputDirectory>
|
||||
<destFileName>test-standard.war</destFileName>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<!-- An example context XML for a quickstart webapp
|
||||
A quick started webapp has all the jar scanning and fragment resolution done in a
|
||||
Preconfigure phase, with all the discovered configuration encoded into a
|
||||
WEB-INF/quickstart-web.xml file.
|
||||
|
||||
This allows very rapid and precise starting of a webapp, without the risk of accidental
|
||||
deployment of other discovered resources. This is above and beyond what is available
|
||||
with web.xml meta-data-complete, as it also prevents scanning for ServletContainer
|
||||
initialisers and any annotations/classes they require.
|
||||
|
||||
If autoPreconfigure is set to true, then the webapp will be preconfigured the first
|
||||
time it is run.
|
||||
-->
|
||||
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
|
||||
<Set name="autoPreconfigure">true</Set>
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war"><Property name="jetty.webapps" default="."/>/application.war</Set>
|
||||
</Configure>
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Jetty Quickstart module
|
||||
#
|
||||
|
||||
[depend]
|
||||
server
|
||||
plus
|
||||
annotations
|
||||
|
||||
|
||||
[lib]
|
||||
lib/jetty-quickstart-${jetty.version}.jar
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.Descriptor;
|
||||
import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlParser;
|
||||
|
||||
/**
|
||||
* Preconfigure DescriptorProcessor
|
||||
*
|
||||
* Saves literal XML snippets
|
||||
*
|
||||
*/
|
||||
|
||||
public class PreconfigureDescriptorProcessor extends IterativeDescriptorProcessor
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(PreconfigureDescriptorProcessor.class);
|
||||
|
||||
private final StringBuilder _buffer = new StringBuilder();
|
||||
private final boolean _showOrigin;
|
||||
private String _origin;
|
||||
|
||||
public PreconfigureDescriptorProcessor ()
|
||||
{
|
||||
_showOrigin=LOG.isDebugEnabled();
|
||||
try
|
||||
{
|
||||
registerVisitor("env-entry", getClass().getDeclaredMethod("saveSnippet", __signature));
|
||||
registerVisitor("resource-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
|
||||
registerVisitor("resource-env-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
|
||||
registerVisitor("message-destination-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
|
||||
registerVisitor("data-source", getClass().getDeclaredMethod("saveSnippet", __signature));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(WebAppContext context, Descriptor descriptor)
|
||||
{
|
||||
LOG.debug("process {}",descriptor);
|
||||
_origin=(" <!-- "+descriptor+" -->\n");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void end(WebAppContext context,Descriptor descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void saveSnippet (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
|
||||
throws Exception
|
||||
{
|
||||
LOG.debug("save {}",node.getTag());
|
||||
if (_showOrigin)
|
||||
_buffer.append(_origin);
|
||||
_buffer.append(" ").append(node.toString()).append("\n");
|
||||
}
|
||||
|
||||
public String getXML()
|
||||
{
|
||||
return _buffer.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
public class PreconfigureQuickStartWar
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(PreconfigureQuickStartWar.class);
|
||||
static final boolean ORIGIN=LOG.isDebugEnabled();
|
||||
|
||||
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
Resource war = null;
|
||||
Resource dir = null;
|
||||
Resource xml = null;
|
||||
|
||||
switch (args.length)
|
||||
{
|
||||
case 0:
|
||||
error("No WAR file or directory given");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
dir = Resource.newResource(args[0]);
|
||||
|
||||
case 2:
|
||||
war = Resource.newResource(args[0]);
|
||||
if (war.isDirectory())
|
||||
{
|
||||
dir = war;
|
||||
war = null;
|
||||
xml = Resource.newResource(args[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = Resource.newResource(args[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
war = Resource.newResource(args[0]);
|
||||
dir = Resource.newResource(args[1]);
|
||||
xml = Resource.newResource(args[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Too many args");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
preconfigure(war,dir,xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param war The war (or directory) to preconfigure
|
||||
* @param dir The directory to expand the war into (or null if war is a directory)
|
||||
* @param xml A context XML to apply (or null if none)
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void preconfigure(Resource war, Resource dir, Resource xml) throws Exception
|
||||
{
|
||||
// Do we need to unpack a war?
|
||||
if (war != null)
|
||||
{
|
||||
if (war.isDirectory())
|
||||
error("war file is directory");
|
||||
|
||||
if (!dir.exists())
|
||||
dir.getFile().mkdirs();
|
||||
JarResource.newJarResource(war).copyTo(dir.getFile());
|
||||
}
|
||||
|
||||
final Server server = new Server();
|
||||
|
||||
QuickStartWebApp webapp = new QuickStartWebApp();
|
||||
|
||||
if (xml != null)
|
||||
{
|
||||
if (xml.isDirectory() || !xml.toString().toLowerCase().endsWith(".xml"))
|
||||
error("Bad context.xml: "+xml);
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(xml.getURL());
|
||||
xmlConfiguration.configure(webapp);
|
||||
}
|
||||
webapp.setResourceBase(dir.getFile().getAbsolutePath());
|
||||
webapp.setPreconfigure(true);
|
||||
server.setHandler(webapp);
|
||||
server.start();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static void error(String message)
|
||||
{
|
||||
System.err.println("ERROR: " + message);
|
||||
System.err.println("Usage: java -jar PreconfigureQuickStartWar.jar <war-directory>");
|
||||
System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-directory> <context-xml-file>");
|
||||
System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-file> <target-war-directory>");
|
||||
System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-file> <target-war-directory> <context-xml-file>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.annotations.AnnotationDecorator;
|
||||
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.StandardDescriptorProcessor;
|
||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
|
||||
/**
|
||||
* QuickStartConfiguration
|
||||
*
|
||||
* Re-inflate a deployable webapp from a saved effective-web.xml
|
||||
* which combines all pre-parsed web xml descriptors and annotations.
|
||||
*
|
||||
*/
|
||||
public class QuickStartConfiguration extends WebInfConfiguration
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class);
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
@Override
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
//check that webapp is suitable for quick start - it is not a packed war
|
||||
String war = context.getWar();
|
||||
if (war == null || war.length()<=0)
|
||||
throw new IllegalStateException ("No location for webapp");
|
||||
|
||||
//Make a temp directory for the webapp if one is not already set
|
||||
resolveTempDirectory(context);
|
||||
|
||||
Resource webApp = context.newResource(war);
|
||||
|
||||
// Accept aliases for WAR files
|
||||
if (webApp.getAlias() != null)
|
||||
{
|
||||
LOG.debug(webApp + " anti-aliased to " + webApp.getAlias());
|
||||
webApp = context.newResource(webApp.getAlias());
|
||||
}
|
||||
|
||||
// Is the WAR usable directly?
|
||||
if (!webApp.exists() || !webApp.isDirectory() || webApp.toString().startsWith("jar:"))
|
||||
throw new IllegalStateException("Webapp does not exist or is not unpacked");
|
||||
|
||||
context.setBaseResource(webApp);
|
||||
|
||||
LOG.debug("webapp={}",webApp);
|
||||
|
||||
|
||||
//look for effective-web.xml in WEB-INF of webapp
|
||||
Resource webInf = context.getWebInf();
|
||||
if (webInf == null || !webInf.exists())
|
||||
throw new IllegalStateException("No WEB-INF");
|
||||
LOG.debug("webinf={}",webInf);
|
||||
|
||||
Resource quickStartWebXml = webInf.addPath("quickstart-web.xml");
|
||||
if (!quickStartWebXml.exists())
|
||||
throw new IllegalStateException ("No WEB-INF/quickstart-web.xml");
|
||||
LOG.debug("quickStartWebXml={}",quickStartWebXml);
|
||||
|
||||
context.getMetaData().setWebXml(quickStartWebXml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
LOG.debug("configure {}",this);
|
||||
if (context.isStarted())
|
||||
{
|
||||
LOG.warn("Cannot configure webapp after it is started");
|
||||
return;
|
||||
}
|
||||
|
||||
//Temporary: set up the classpath here. This should be handled by the QuickStartDescriptorProcessor
|
||||
Resource webInf = context.getWebInf();
|
||||
|
||||
if (webInf != null && webInf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
|
||||
{
|
||||
// Look for classes directory
|
||||
Resource classes= webInf.addPath("classes/");
|
||||
if (classes.exists())
|
||||
((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
|
||||
|
||||
// Look for jars
|
||||
Resource lib= webInf.addPath("lib/");
|
||||
if (lib.exists() || lib.isDirectory())
|
||||
((WebAppClassLoader)context.getClassLoader()).addJars(lib);
|
||||
}
|
||||
|
||||
//add the processor to handle normal web.xml content
|
||||
context.getMetaData().addDescriptorProcessor(new StandardDescriptorProcessor());
|
||||
|
||||
//add a processor to handle extended web.xml format
|
||||
context.getMetaData().addDescriptorProcessor(new QuickStartDescriptorProcessor());
|
||||
|
||||
//add a decorator that will find introspectable annotations
|
||||
context.addDecorator(new AnnotationDecorator(context)); //this must be the last Decorator because they are run in reverse order!
|
||||
|
||||
//add a context bean that will run ServletContainerInitializers as the context starts
|
||||
ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER);
|
||||
if (starter != null)
|
||||
throw new IllegalStateException("ServletContainerInitializersStarter already exists");
|
||||
starter = new ServletContainerInitializersStarter(context);
|
||||
context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER, starter);
|
||||
context.addBean(starter, true);
|
||||
|
||||
LOG.debug("configured {}",this);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.Descriptor;
|
||||
import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlParser;
|
||||
|
||||
/**
|
||||
* QuickStartDescriptorProcessor
|
||||
*
|
||||
* Handle extended elements for quickstart-web.xml
|
||||
*/
|
||||
public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public QuickStartDescriptorProcessor()
|
||||
{
|
||||
try
|
||||
{
|
||||
registerVisitor("context-param", this.getClass().getDeclaredMethod("visitContextParam", __signature));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.Descriptor)
|
||||
*/
|
||||
@Override
|
||||
public void start(WebAppContext context, Descriptor descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.Descriptor)
|
||||
*/
|
||||
@Override
|
||||
public void end(WebAppContext context, Descriptor descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param descriptor
|
||||
* @param node
|
||||
*/
|
||||
public void visitContextParam (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
|
||||
throws Exception
|
||||
{
|
||||
String name = node.getString("param-name", false, true);
|
||||
String value = node.getString("param-value", false, true);
|
||||
List<String> values = new ArrayList<>();
|
||||
|
||||
// extract values
|
||||
switch(name)
|
||||
{
|
||||
case ServletContext.ORDERED_LIBS:
|
||||
case AnnotationConfiguration.CONTAINER_INITIALIZERS:
|
||||
case MetaInfConfiguration.METAINF_TLDS:
|
||||
case MetaInfConfiguration.METAINF_RESOURCES:
|
||||
|
||||
context.removeAttribute(name);
|
||||
|
||||
QuotedStringTokenizer tok = new QuotedStringTokenizer(value,",");
|
||||
while(tok.hasMoreElements())
|
||||
values.add(tok.nextToken().trim());
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
// handle values
|
||||
switch(name)
|
||||
{
|
||||
case ServletContext.ORDERED_LIBS:
|
||||
{
|
||||
List<Object> libs = new ArrayList<>();
|
||||
Object o=context.getAttribute(ServletContext.ORDERED_LIBS);
|
||||
if (o instanceof Collection<?>)
|
||||
libs.addAll((Collection<?>)o);
|
||||
libs.addAll(values);
|
||||
if (libs.size()>0)
|
||||
context.setAttribute(ServletContext.ORDERED_LIBS,libs);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AnnotationConfiguration.CONTAINER_INITIALIZERS:
|
||||
{
|
||||
for (String i : values)
|
||||
visitContainerInitializer(context, new ContainerInitializer(Thread.currentThread().getContextClassLoader(), i));
|
||||
break;
|
||||
}
|
||||
|
||||
case MetaInfConfiguration.METAINF_TLDS:
|
||||
{
|
||||
List<Object> tlds = new ArrayList<>();
|
||||
String war=context.getBaseResource().getURI().toString();
|
||||
Object o=context.getAttribute(MetaInfConfiguration.METAINF_TLDS);
|
||||
if (o instanceof Collection<?>)
|
||||
tlds.addAll((Collection<?>)o);
|
||||
for (String i : values)
|
||||
{
|
||||
Resource r = Resource.newResource(i.replace("${WAR}/",war));
|
||||
if (r.exists())
|
||||
tlds.add(r.getURL());
|
||||
else
|
||||
throw new IllegalArgumentException("TLD not found: "+r);
|
||||
}
|
||||
|
||||
if (tlds.size()>0)
|
||||
context.setAttribute(MetaInfConfiguration.METAINF_TLDS,tlds);
|
||||
break;
|
||||
}
|
||||
|
||||
case MetaInfConfiguration.METAINF_RESOURCES:
|
||||
{
|
||||
String war=context.getBaseResource().getURI().toString();
|
||||
for (String i : values)
|
||||
{
|
||||
Resource r = Resource.newResource(i.replace("${WAR}/",war));
|
||||
if (r.exists())
|
||||
visitMetaInfResource(context,r);
|
||||
else
|
||||
throw new IllegalArgumentException("Resource not found: "+r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void visitContainerInitializer (WebAppContext context, ContainerInitializer containerInitializer)
|
||||
{
|
||||
if (containerInitializer == null)
|
||||
return;
|
||||
|
||||
//add the ContainerInitializer to the list of container initializers
|
||||
List<ContainerInitializer> containerInitializers = (List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
|
||||
if (containerInitializers == null)
|
||||
{
|
||||
containerInitializers = new ArrayList<ContainerInitializer>();
|
||||
context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS, containerInitializers);
|
||||
}
|
||||
|
||||
containerInitializers.add(containerInitializer);
|
||||
|
||||
//Ensure a bean is set up on the context that will invoke the ContainerInitializers as the context starts
|
||||
ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER);
|
||||
if (starter == null)
|
||||
{
|
||||
starter = new ServletContainerInitializersStarter(context);
|
||||
context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER, starter);
|
||||
context.addBean(starter, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void visitMetaInfResource (WebAppContext context, Resource dir)
|
||||
{
|
||||
Collection<Resource> metaInfResources = (Collection<Resource>)context.getAttribute(MetaInfConfiguration.METAINF_RESOURCES);
|
||||
if (metaInfResources == null)
|
||||
{
|
||||
metaInfResources = new HashSet<Resource>();
|
||||
context.setAttribute(MetaInfConfiguration.METAINF_RESOURCES, metaInfResources);
|
||||
}
|
||||
metaInfResources.add(dir);
|
||||
//also add to base resource of webapp
|
||||
Resource[] collection=new Resource[metaInfResources.size()+1];
|
||||
int i=0;
|
||||
collection[i++]=context.getBaseResource();
|
||||
for (Resource resource : metaInfResources)
|
||||
collection[i++]=resource;
|
||||
context.setBaseResource(new ResourceCollection(collection));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,720 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
|
||||
import javax.servlet.descriptor.TaglibDescriptor;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
|
||||
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
|
||||
import org.eclipse.jetty.security.ConstraintAware;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.FilterMapping;
|
||||
import org.eclipse.jetty.servlet.Holder;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.MetaData;
|
||||
import org.eclipse.jetty.webapp.MetaData.OriginInfo;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlAppendable;
|
||||
|
||||
/**
|
||||
* QuickStartWar
|
||||
*
|
||||
*/
|
||||
public class QuickStartWebApp extends WebAppContext
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(QuickStartWebApp.class);
|
||||
|
||||
public static final String[] __configurationClasses = new String[]
|
||||
{
|
||||
org.eclipse.jetty.quickstart.QuickStartConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.plus.webapp.EnvConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.plus.webapp.PlusConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.webapp.JettyWebXmlConfiguration.class.getCanonicalName()
|
||||
};
|
||||
|
||||
|
||||
private boolean _preconfigure=false;
|
||||
private boolean _autoPreconfigure=false;
|
||||
private boolean _startWebapp=false;
|
||||
private PreconfigureDescriptorProcessor _preconfigProcessor;
|
||||
|
||||
|
||||
public static final String[] __preconfigurationClasses = new String[]
|
||||
{
|
||||
org.eclipse.jetty.webapp.WebInfConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.webapp.WebXmlConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.webapp.MetaInfConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.webapp.FragmentConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.plus.webapp.EnvConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.plus.webapp.PlusConfiguration.class.getCanonicalName(),
|
||||
org.eclipse.jetty.annotations.AnnotationConfiguration.class.getCanonicalName(),
|
||||
};
|
||||
|
||||
public QuickStartWebApp()
|
||||
{
|
||||
super();
|
||||
setConfigurationClasses(__preconfigurationClasses);
|
||||
setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*\\.jar");
|
||||
}
|
||||
|
||||
public boolean isPreconfigure()
|
||||
{
|
||||
return _preconfigure;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Preconfigure webapp
|
||||
* @param preconfigure If true, then starting the webapp will generate
|
||||
* the WEB-INF/quickstart-web.xml rather than start the webapp.
|
||||
*/
|
||||
public void setPreconfigure(boolean preconfigure)
|
||||
{
|
||||
_preconfigure = preconfigure;
|
||||
}
|
||||
|
||||
public boolean isAutoPreconfigure()
|
||||
{
|
||||
return _autoPreconfigure;
|
||||
}
|
||||
|
||||
public void setAutoPreconfigure(boolean autoPrecompile)
|
||||
{
|
||||
_autoPreconfigure = autoPrecompile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startWebapp() throws Exception
|
||||
{
|
||||
if (isPreconfigure())
|
||||
generateQuickstartWebXml(_preconfigProcessor.getXML());
|
||||
|
||||
if (_startWebapp)
|
||||
super.startWebapp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
// unpack and Adjust paths.
|
||||
Resource war = null;
|
||||
Resource dir = null;
|
||||
|
||||
Resource base = getBaseResource();
|
||||
if (base==null)
|
||||
base=Resource.newResource(getWar());
|
||||
|
||||
if (base.isDirectory())
|
||||
dir=base;
|
||||
else if (base.toString().toLowerCase().endsWith(".war"))
|
||||
{
|
||||
war=base;
|
||||
String w=war.toString();
|
||||
dir=Resource.newResource(w.substring(0,w.length()-4));
|
||||
|
||||
if (!dir.exists())
|
||||
{
|
||||
LOG.info("Quickstart Extract " + war + " to " + dir);
|
||||
dir.getFile().mkdirs();
|
||||
JarResource.newJarResource(war).copyTo(dir.getFile());
|
||||
}
|
||||
|
||||
setWar(null);
|
||||
setBaseResource(dir);
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
|
||||
Resource qswebxml=dir.addPath("/WEB-INF/quickstart-web.xml");
|
||||
|
||||
if (isPreconfigure())
|
||||
{
|
||||
_preconfigProcessor = new PreconfigureDescriptorProcessor();
|
||||
getMetaData().addDescriptorProcessor(_preconfigProcessor);
|
||||
_startWebapp=false;
|
||||
}
|
||||
else if (qswebxml.exists())
|
||||
{
|
||||
setConfigurationClasses(__configurationClasses);
|
||||
_startWebapp=true;
|
||||
}
|
||||
else if (_autoPreconfigure)
|
||||
{
|
||||
LOG.info("Quickstart preconfigure: {}(war={},dir={})",this,war,dir);
|
||||
|
||||
_preconfigProcessor = new PreconfigureDescriptorProcessor();
|
||||
|
||||
getMetaData().addDescriptorProcessor(_preconfigProcessor);
|
||||
setPreconfigure(true);
|
||||
_startWebapp=true;
|
||||
}
|
||||
else
|
||||
_startWebapp=true;
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
public void generateQuickstartWebXml(String extraXML) throws IOException
|
||||
{
|
||||
getMetaData().getOrigins();
|
||||
// dumpStdErr();
|
||||
|
||||
if (getBaseResource()==null)
|
||||
throw new IllegalArgumentException("No base resource for "+this);
|
||||
|
||||
File webxml = new File(getWebInf().getFile(),"quickstart-web.xml");
|
||||
|
||||
LOG.info("Quickstart generate {}",webxml);
|
||||
|
||||
XmlAppendable out = new XmlAppendable(new FileOutputStream(webxml),"UTF-8");
|
||||
MetaData md = getMetaData();
|
||||
|
||||
Map<String, String> webappAttr = new HashMap<>();
|
||||
webappAttr.put("xmlns","http://xmlns.jcp.org/xml/ns/javaee");
|
||||
webappAttr.put("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
|
||||
webappAttr.put("xsi:schemaLocation","http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd");
|
||||
webappAttr.put("metadata-complete","true");
|
||||
webappAttr.put("version","3.1");
|
||||
|
||||
out.open("web-app",webappAttr);
|
||||
|
||||
if (getDisplayName() != null)
|
||||
out.tag("display-name",getDisplayName());
|
||||
|
||||
// Set some special context parameters
|
||||
|
||||
// The location of the war file on disk
|
||||
String resourceBase=getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString();
|
||||
|
||||
// The library order
|
||||
addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS);
|
||||
//the servlet container initializers
|
||||
addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS);
|
||||
//the tlds discovered
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase);
|
||||
//the META-INF/resources discovered
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase);
|
||||
|
||||
|
||||
// init params
|
||||
for (String p : getInitParams().keySet())
|
||||
out.open("context-param",origin(md,"context-param." + p))
|
||||
.tag("param-name",p)
|
||||
.tag("param-value",getInitParameter(p))
|
||||
.close();
|
||||
|
||||
if (getEventListeners() != null)
|
||||
for (EventListener e : getEventListeners())
|
||||
out.open("listener",origin(md,e.getClass().getCanonicalName() + ".listener"))
|
||||
.tag("listener-class",e.getClass().getCanonicalName())
|
||||
.close();
|
||||
|
||||
ServletHandler servlets = getServletHandler();
|
||||
|
||||
if (servlets.getFilters() != null)
|
||||
{
|
||||
for (FilterHolder holder : servlets.getFilters())
|
||||
outholder(out,md,"filter",holder);
|
||||
}
|
||||
|
||||
if (servlets.getFilterMappings() != null)
|
||||
{
|
||||
for (FilterMapping mapping : servlets.getFilterMappings())
|
||||
{
|
||||
out.open("filter-mapping");
|
||||
out.tag("filter-name",mapping.getFilterName());
|
||||
if (mapping.getPathSpecs() != null)
|
||||
for (String s : mapping.getPathSpecs())
|
||||
out.tag("url-pattern",s);
|
||||
if (mapping.getServletNames() != null)
|
||||
for (String n : mapping.getServletNames())
|
||||
out.tag("servlet-name",n);
|
||||
|
||||
if (!mapping.isDefaultDispatches())
|
||||
{
|
||||
if (mapping.appliesTo(DispatcherType.REQUEST))
|
||||
out.tag("dispatcher","REQUEST");
|
||||
if (mapping.appliesTo(DispatcherType.ASYNC))
|
||||
out.tag("dispatcher","ASYNC");
|
||||
if (mapping.appliesTo(DispatcherType.ERROR))
|
||||
out.tag("dispatcher","ERROR");
|
||||
if (mapping.appliesTo(DispatcherType.FORWARD))
|
||||
out.tag("dispatcher","FORWARD");
|
||||
if (mapping.appliesTo(DispatcherType.INCLUDE))
|
||||
out.tag("dispatcher","INCLUDE");
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (servlets.getServlets() != null)
|
||||
{
|
||||
for (ServletHolder holder : servlets.getServlets())
|
||||
outholder(out,md,"servlet",holder);
|
||||
}
|
||||
|
||||
if (servlets.getServletMappings() != null)
|
||||
{
|
||||
for (ServletMapping mapping : servlets.getServletMappings())
|
||||
{
|
||||
out.open("servlet-mapping",origin(md,mapping.getServletName() + ".servlet.mappings"));
|
||||
out.tag("servlet-name",mapping.getServletName());
|
||||
if (mapping.getPathSpecs() != null)
|
||||
for (String s : mapping.getPathSpecs())
|
||||
out.tag("url-pattern",s);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Security elements
|
||||
SecurityHandler security = getSecurityHandler();
|
||||
|
||||
if (security!=null && (security.getRealmName()!=null || security.getAuthMethod()!=null))
|
||||
{
|
||||
out.open("login-config");
|
||||
if (security.getAuthMethod()!=null)
|
||||
out.tag("auth-method",origin(md,"auth-method"),security.getAuthMethod());
|
||||
if (security.getRealmName()!=null)
|
||||
out.tag("realm-name",origin(md,"realm-name"),security.getRealmName());
|
||||
|
||||
|
||||
if (Constraint.__FORM_AUTH.equalsIgnoreCase(security.getAuthMethod()))
|
||||
{
|
||||
out.open("form-login-config");
|
||||
out.tag("form-login-page",origin(md,"form-login-page"),security.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE));
|
||||
out.tag("form-error-page",origin(md,"form-error-page"),security.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE));
|
||||
out.close();
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
if (security instanceof ConstraintAware)
|
||||
{
|
||||
ConstraintAware ca = (ConstraintAware)security;
|
||||
for (String r:ca.getRoles())
|
||||
out.open("security-role")
|
||||
.tag("role-name",r)
|
||||
.close();
|
||||
|
||||
for (ConstraintMapping m : ca.getConstraintMappings())
|
||||
{
|
||||
out.open("security-constraint");
|
||||
|
||||
if (m.getConstraint().getAuthenticate())
|
||||
{
|
||||
out.open("auth-constraint");
|
||||
if (m.getConstraint().getRoles()!=null)
|
||||
for (String r : m.getConstraint().getRoles())
|
||||
out.tag("role-name",r);
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
switch (m.getConstraint().getDataConstraint())
|
||||
{
|
||||
case Constraint.DC_NONE:
|
||||
out.open("user-data-constraint").tag("transport-guarantee","NONE").close();
|
||||
break;
|
||||
|
||||
case Constraint.DC_INTEGRAL:
|
||||
out.open("user-data-constraint").tag("transport-guarantee","INTEGRAL").close();
|
||||
break;
|
||||
|
||||
case Constraint.DC_CONFIDENTIAL:
|
||||
out.open("user-data-constraint").tag("transport-guarantee","CONFIDENTIAL").close();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
out.open("web-resource-collection");
|
||||
{
|
||||
if (m.getConstraint().getName()!=null)
|
||||
out.tag("web-resource-name",m.getConstraint().getName());
|
||||
if (m.getPathSpec()!=null)
|
||||
out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec());
|
||||
if (m.getMethod()!=null)
|
||||
out.tag("http-method",m.getMethod());
|
||||
|
||||
if (m.getMethodOmissions()!=null)
|
||||
for (String o:m.getMethodOmissions())
|
||||
out.tag("http-method-omission",o);
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (getWelcomeFiles() != null)
|
||||
{
|
||||
out.open("welcome-file-list");
|
||||
for (String welcomeFile:getWelcomeFiles())
|
||||
{
|
||||
out.tag("welcome-file", welcomeFile);
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
Map<String,String> localeEncodings = getLocaleEncodings();
|
||||
if (localeEncodings != null && !localeEncodings.isEmpty())
|
||||
{
|
||||
out.open("locale-encoding-mapping-list");
|
||||
for (Map.Entry<String, String> entry:localeEncodings.entrySet())
|
||||
{
|
||||
out.open("locale-encoding-mapping", origin(md,"locale-encoding."+entry.getKey()));
|
||||
out.tag("locale", entry.getKey());
|
||||
out.tag("encoding", entry.getValue());
|
||||
out.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
//session-config
|
||||
if (getSessionHandler().getSessionManager() != null)
|
||||
{
|
||||
out.open("session-config");
|
||||
int maxInactiveSec = getSessionHandler().getSessionManager().getMaxInactiveInterval();
|
||||
out.tag("session-timeout", (maxInactiveSec==0?"0":Integer.toString(maxInactiveSec/60)));
|
||||
|
||||
Set<SessionTrackingMode> modes = getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes();
|
||||
if (modes != null)
|
||||
{
|
||||
for (SessionTrackingMode mode:modes)
|
||||
out.tag("tracking-mode", mode.toString());
|
||||
}
|
||||
|
||||
//cookie-config
|
||||
SessionCookieConfig cookieConfig = getSessionHandler().getSessionManager().getSessionCookieConfig();
|
||||
if (cookieConfig != null)
|
||||
{
|
||||
out.open("cookie-config");
|
||||
if (cookieConfig.getName() != null)
|
||||
out.tag("name", origin(md,"cookie-config.name"), cookieConfig.getName());
|
||||
|
||||
if (cookieConfig.getDomain() != null)
|
||||
out.tag("domain", origin(md, "cookie-config.domain"), cookieConfig.getDomain());
|
||||
|
||||
if (cookieConfig.getPath() != null)
|
||||
out.tag("path", origin(md, "cookie-config.path"), cookieConfig.getPath());
|
||||
|
||||
if (cookieConfig.getComment() != null)
|
||||
out.tag("comment", origin(md, "cookie-config.comment"), cookieConfig.getComment());
|
||||
|
||||
out.tag("http-only", origin(md, "cookie-config.http-only"), Boolean.toString(cookieConfig.isHttpOnly()));
|
||||
out.tag("secure", origin(md, "cookie-config.secure"), Boolean.toString(cookieConfig.isSecure()));
|
||||
out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge()));
|
||||
out.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
//error-pages
|
||||
Map<String,String> errorPages = ((ErrorPageErrorHandler)getErrorHandler()).getErrorPages();
|
||||
if (errorPages != null)
|
||||
{
|
||||
for (Map.Entry<String, String> entry:errorPages.entrySet())
|
||||
{
|
||||
out.open("error-page", origin(md, "error."+entry.getKey()));
|
||||
//a global or default error page has no code or exception
|
||||
if (!ErrorPageErrorHandler.GLOBAL_ERROR_PAGE.equals(entry.getKey()))
|
||||
{
|
||||
if (entry.getKey().matches("\\d{3}"))
|
||||
out.tag("error-code", entry.getKey());
|
||||
else
|
||||
out.tag("exception-type", entry.getKey());
|
||||
}
|
||||
out.tag("location", entry.getValue());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
//mime-types
|
||||
MimeTypes mimeTypes = getMimeTypes();
|
||||
if (mimeTypes != null)
|
||||
{
|
||||
for (Map.Entry<String, String> entry:mimeTypes.getMimeMap().entrySet())
|
||||
{
|
||||
out.open("mime-mapping");
|
||||
out.tag("extension", origin(md, "extension."+entry.getKey()), entry.getKey());
|
||||
out.tag("mime-type", entry.getValue());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
//jsp-config
|
||||
JspConfig jspConfig = (JspConfig)getServletContext().getJspConfigDescriptor();
|
||||
if (jspConfig != null)
|
||||
{
|
||||
out.open("jsp-config");
|
||||
Collection<TaglibDescriptor> tlds = jspConfig.getTaglibs();
|
||||
if (tlds != null && !tlds.isEmpty())
|
||||
{
|
||||
for (TaglibDescriptor tld:tlds)
|
||||
{
|
||||
out.open("taglib");
|
||||
out.tag("taglib-uri", tld.getTaglibURI());
|
||||
out.tag("taglib-location", tld.getTaglibLocation());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
Collection<JspPropertyGroupDescriptor> jspPropertyGroups = jspConfig.getJspPropertyGroups();
|
||||
if (jspPropertyGroups != null && !jspPropertyGroups.isEmpty())
|
||||
{
|
||||
for (JspPropertyGroupDescriptor jspPropertyGroup:jspPropertyGroups)
|
||||
{
|
||||
out.open("jsp-property-group");
|
||||
Collection<String> strings = jspPropertyGroup.getUrlPatterns();
|
||||
if (strings != null && !strings.isEmpty())
|
||||
{
|
||||
for (String urlPattern:strings)
|
||||
out.tag("url-pattern", urlPattern);
|
||||
}
|
||||
|
||||
if (jspPropertyGroup.getElIgnored() != null)
|
||||
out.tag("el-ignored", jspPropertyGroup.getElIgnored());
|
||||
|
||||
if (jspPropertyGroup.getPageEncoding() != null)
|
||||
out.tag("page-encoding", jspPropertyGroup.getPageEncoding());
|
||||
|
||||
if (jspPropertyGroup.getScriptingInvalid() != null)
|
||||
out.tag("scripting-invalid", jspPropertyGroup.getScriptingInvalid());
|
||||
|
||||
if (jspPropertyGroup.getIsXml() != null)
|
||||
out.tag("is-xml", jspPropertyGroup.getIsXml());
|
||||
|
||||
if (jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral() != null)
|
||||
out.tag("deferred-syntax-allowed-as-literal", jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral());
|
||||
|
||||
if (jspPropertyGroup.getTrimDirectiveWhitespaces() != null)
|
||||
out.tag("trim-directive-whitespaces", jspPropertyGroup.getTrimDirectiveWhitespaces());
|
||||
|
||||
if (jspPropertyGroup.getDefaultContentType() != null)
|
||||
out.tag("default-content-type", jspPropertyGroup.getDefaultContentType());
|
||||
|
||||
if (jspPropertyGroup.getBuffer() != null)
|
||||
out.tag("buffer", jspPropertyGroup.getBuffer());
|
||||
|
||||
if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null)
|
||||
out.tag("error-on-undeclared-namespace", jspPropertyGroup.getErrorOnUndeclaredNamespace());
|
||||
|
||||
strings = jspPropertyGroup.getIncludePreludes();
|
||||
if (strings != null && !strings.isEmpty())
|
||||
{
|
||||
for (String prelude:strings)
|
||||
out.tag("include-prelude", prelude);
|
||||
}
|
||||
|
||||
strings = jspPropertyGroup.getIncludeCodas();
|
||||
if (strings != null && !strings.isEmpty())
|
||||
{
|
||||
for (String coda:strings)
|
||||
out.tag("include-coda", coda);
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
//lifecycle: post-construct, pre-destroy
|
||||
LifeCycleCallbackCollection lifecycles = ((LifeCycleCallbackCollection)getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION));
|
||||
if (lifecycles != null)
|
||||
{
|
||||
Collection<LifeCycleCallback> tmp = lifecycles.getPostConstructCallbacks();
|
||||
|
||||
for (LifeCycleCallback c:tmp)
|
||||
{
|
||||
out.open("post-construct");
|
||||
out.tag("lifecycle-callback-class", c.getTargetClassName());
|
||||
out.tag("lifecycle-callback-method", c.getMethodName());
|
||||
out.close();
|
||||
}
|
||||
|
||||
tmp = lifecycles.getPreDestroyCallbacks();
|
||||
for (LifeCycleCallback c:tmp)
|
||||
{
|
||||
out.open("pre-destroy");
|
||||
out.tag("lifecycle-callback-class", c.getTargetClassName());
|
||||
out.tag("lifecycle-callback-method", c.getMethodName());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
out.literal(extraXML);
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException
|
||||
{
|
||||
addContextParamFromAttribute(out,attribute,null);
|
||||
}
|
||||
|
||||
private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException
|
||||
{
|
||||
Object o=getAttribute(attribute);
|
||||
if (o==null)
|
||||
return;
|
||||
|
||||
Collection<?> c = (o instanceof Collection)? (Collection<?>)o:Collections.singletonList(o);
|
||||
StringBuilder v=new StringBuilder();
|
||||
for (Object i:c)
|
||||
{
|
||||
if (i!=null)
|
||||
{
|
||||
if (v.length()>0)
|
||||
v.append(",\n ");
|
||||
else
|
||||
v.append("\n ");
|
||||
if (resourceBase==null)
|
||||
QuotedStringTokenizer.quote(v,i.toString());
|
||||
else
|
||||
QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/"));
|
||||
}
|
||||
}
|
||||
out.open("context-param")
|
||||
.tag("param-name",attribute)
|
||||
.tagCDATA("param-value",v.toString())
|
||||
.close();
|
||||
}
|
||||
|
||||
private static void outholder(XmlAppendable out, MetaData md, String tag, Holder<?> holder) throws IOException
|
||||
{
|
||||
out.open(tag,Collections.singletonMap("source",holder.getSource().toString()));
|
||||
String n = holder.getName();
|
||||
out.tag(tag + "-name",n);
|
||||
|
||||
String ot = n + "." + tag + ".";
|
||||
|
||||
out.tag(tag + "-class",origin(md,ot + tag + "-class"),holder.getClassName());
|
||||
|
||||
for (String p : holder.getInitParameters().keySet())
|
||||
{
|
||||
if ("scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output
|
||||
continue;
|
||||
out.open("init-param",origin(md,ot + "init-param." + p))
|
||||
.tag("param-name",p)
|
||||
.tag("param-value",holder.getInitParameter(p))
|
||||
.close();
|
||||
}
|
||||
|
||||
if (holder instanceof ServletHolder)
|
||||
{
|
||||
ServletHolder s = (ServletHolder)holder;
|
||||
if (s.getForcedPath() != null)
|
||||
out.tag("jsp-file",s.getForcedPath());
|
||||
|
||||
if (s.getInitOrder() != 0)
|
||||
out.tag("load-on-startup",Integer.toString(s.getInitOrder()));
|
||||
|
||||
if (s.getRunAsRole() != null)
|
||||
out.open("run-as",origin(md,ot + "run-as"))
|
||||
.tag("role-name",s.getRunAsRole())
|
||||
.close();
|
||||
|
||||
Map<String,String> roles = s.getRoleRefMap();
|
||||
if (roles!=null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : roles.entrySet())
|
||||
{
|
||||
out.open("security-role-ref",origin(md,ot+"role-name."+e.getKey()))
|
||||
.tag("role-name",e.getKey())
|
||||
.tag("role-link",e.getValue())
|
||||
.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.isEnabled())
|
||||
out.tag("enabled",origin(md,ot + "enabled"),"false");
|
||||
|
||||
//multipart-config
|
||||
MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig();
|
||||
if (multipartConfig != null)
|
||||
{
|
||||
out.open("multipart-config", origin(md, s.getName()+".servlet.multipart-config"));
|
||||
if (multipartConfig.getLocation() != null)
|
||||
out.tag("location", multipartConfig.getLocation());
|
||||
out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize()));
|
||||
out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize()));
|
||||
out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold()));
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false");
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static Map<String, String> origin(MetaData md, String name)
|
||||
{
|
||||
if (!LOG.isDebugEnabled())
|
||||
return Collections.emptyMap();
|
||||
if (name == null)
|
||||
return Collections.emptyMap();
|
||||
OriginInfo origin = md.getOriginInfo(name);
|
||||
// System.err.println("origin of "+name+" is "+origin);
|
||||
if (origin == null)
|
||||
return Collections.emptyMap();
|
||||
return Collections.singletonMap("origin",origin.toString());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class PreconfigureJNDIWar
|
||||
{
|
||||
private static final long __start=System.nanoTime();
|
||||
private static final Logger LOG = Log.getLogger(Server.class);
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String target="target/test-jndi-preconfigured";
|
||||
File file = new File(target);
|
||||
if (file.exists())
|
||||
IO.delete(file);
|
||||
|
||||
PreconfigureQuickStartWar.main("target/test-jndi.war",target, "src/test/resources/test-jndi.xml");
|
||||
|
||||
LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start));
|
||||
|
||||
IO.copy(new FileInputStream("target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"),System.out);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
public class PreconfigureSpecWar
|
||||
{
|
||||
private static final long __start=System.nanoTime();
|
||||
private static final Logger LOG = Log.getLogger(Server.class);
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String target="target/test-spec-preconfigured";
|
||||
File file = new File(target);
|
||||
if (file.exists())
|
||||
IO.delete(file);
|
||||
|
||||
File realmPropertiesDest = new File ("target/test-spec-realm.properties");
|
||||
if (realmPropertiesDest.exists())
|
||||
IO.delete(realmPropertiesDest);
|
||||
|
||||
Resource realmPropertiesSrc = Resource.newResource("src/test/resources/realm.properties");
|
||||
realmPropertiesSrc.copyTo(realmPropertiesDest);
|
||||
System.setProperty("jetty.home", "target");
|
||||
|
||||
PreconfigureQuickStartWar.main("target/test-spec.war",target, "src/test/resources/test-spec.xml");
|
||||
|
||||
LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start));
|
||||
|
||||
IO.copy(new FileInputStream("target/test-spec-preconfigured/WEB-INF/quickstart-web.xml"),System.out);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* PreconfigureStandardTestWar
|
||||
*
|
||||
*/
|
||||
public class PreconfigureStandardTestWar
|
||||
{
|
||||
|
||||
private static final long __start=System.nanoTime();
|
||||
private static final Logger LOG = Log.getLogger(Server.class);
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String target="target/test-standard-preconfigured";
|
||||
File file = new File(target);
|
||||
if (file.exists())
|
||||
IO.delete(file);
|
||||
|
||||
File realmPropertiesDest = new File ("target/test-standard-realm.properties");
|
||||
if (realmPropertiesDest.exists())
|
||||
IO.delete(realmPropertiesDest);
|
||||
|
||||
Resource realmPropertiesSrc = Resource.newResource("src/test/resources/realm.properties");
|
||||
realmPropertiesSrc.copyTo(realmPropertiesDest);
|
||||
System.setProperty("jetty.home", "target");
|
||||
|
||||
PreconfigureQuickStartWar.main("target/test-standard.war",target, "src/test/resources/test.xml");
|
||||
|
||||
LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start));
|
||||
|
||||
IO.copy(new FileInputStream("target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"),System.out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
public class QuickStartJNDIWar
|
||||
{
|
||||
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
// Log.getRootLogger().setDebugEnabled(true);
|
||||
Quickstart.main("target/test-jndi-preconfigured", "src/test/resources/test-jndi.xml");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
|
||||
public class QuickStartSpecWar
|
||||
{
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
// Log.getRootLogger().setDebugEnabled(true);
|
||||
System.setProperty("jetty.home", "target");
|
||||
Quickstart.main("target/test-spec-preconfigured", "src/test/resources/test-spec.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
public class QuickStartStandardTestWar
|
||||
{
|
||||
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
// Log.getRootLogger().setDebugEnabled(true);
|
||||
System.setProperty("jetty.home", "target");
|
||||
Quickstart.main("target/test-standard-preconfigured", "src/test/resources/test.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.quickstart;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
public class Quickstart
|
||||
{
|
||||
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
if (args.length<1)
|
||||
error("No WAR file or directory given");
|
||||
|
||||
//war file or dir to start
|
||||
String war = args[0];
|
||||
|
||||
//optional jetty context xml file to configure the webapp
|
||||
Resource contextXml = null;
|
||||
if (args.length > 1)
|
||||
contextXml = Resource.newResource(args[1]);
|
||||
|
||||
Server server = new Server(8080);
|
||||
|
||||
QuickStartWebApp webapp = new QuickStartWebApp();
|
||||
webapp.setAutoPreconfigure(true);
|
||||
webapp.setWar(war);
|
||||
webapp.setContextPath("/");
|
||||
|
||||
//apply context xml file
|
||||
if (contextXml != null)
|
||||
{
|
||||
// System.err.println("Applying "+contextXml);
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL());
|
||||
xmlConfiguration.configure(webapp);
|
||||
}
|
||||
|
||||
server.setHandler(webapp);
|
||||
|
||||
server.start();
|
||||
|
||||
|
||||
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
private static void error(String message)
|
||||
{
|
||||
System.err.println("ERROR: "+message);
|
||||
System.err.println("Usage: java -jar QuickStartWar.jar <war-directory> <context-xml>");
|
||||
System.err.println(" java -jar QuickStartWar.jar <war-file> <context-xml>");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# This file defines users passwords and roles for a HashUserRealm
|
||||
#
|
||||
# The format is
|
||||
# <username>: <password>[,<rolename> ...]
|
||||
#
|
||||
# Passwords may be clear text, obfuscated or checksummed. The class
|
||||
# org.eclipse.util.Password should be used to generate obfuscated
|
||||
# passwords or password checksums
|
||||
#
|
||||
# If DIGEST Authentication is used, the password must be in a recoverable
|
||||
# format, either plain text or OBF:.
|
||||
#
|
||||
jetty: MD5:164c88b302622e17050af52c89945d44,user
|
||||
admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin,user
|
||||
other: OBF:1xmk1w261u9r1w1c1xmq,user
|
||||
plain: plain,user
|
||||
user: password,user
|
||||
|
||||
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
|
||||
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the test-jndi webapp -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
|
||||
<Arg>
|
||||
<New class="com.acme.MockUserTransaction"/>
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
<!-- Define an env entry with Server scope for java:comp/env -->
|
||||
<New id="woggle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<Arg><Property name='server'/></Arg>
|
||||
<Arg>woggle</Arg>
|
||||
<Arg type="java.lang.Integer">4000</Arg>
|
||||
<Arg type="boolean">false</Arg>
|
||||
</New>
|
||||
|
||||
<!-- Define an env entry with webapp scope for java:comp/env -->
|
||||
<New id="wiggle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>wiggle</Arg>
|
||||
<Arg type="java.lang.Double">100</Arg>
|
||||
<Arg type="boolean">true</Arg>
|
||||
</New>
|
||||
|
||||
<!-- Mail Session setup -->
|
||||
<New id="xxxmail" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>mail/Session</Arg>
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.jndi.factories.MailSessionReference">
|
||||
<Set name="user">CHANGE-ME</Set>
|
||||
<Set name="password">CHANGE-ME</Set>
|
||||
<Set name="properties">
|
||||
<New class="java.util.Properties">
|
||||
<Put name="mail.smtp.auth">false</Put> <!-- change to true if you want to authenticate -->
|
||||
<Put name="mail.smtp.host">CHANGE-ME</Put>
|
||||
<Put name="mail.from">CHANGE-ME</Put>
|
||||
<Put name="mail.debug">false</Put>
|
||||
</New>
|
||||
</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
<!-- A mock DataSource -->
|
||||
<New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>jdbc/mydatasource</Arg>
|
||||
<Arg>
|
||||
<New class="com.acme.MockDataSource"/>
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
</Configure>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
|
||||
<Arg>
|
||||
<New class="com.acme.MockUserTransaction"/>
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
<Get name="securityHandler">
|
||||
<Set name="loginService">
|
||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||
<Set name="name">Test Realm</Set>
|
||||
<Set name="config"><SystemProperty name="jetty.home" default="."/>/test-spec-realm.properties</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
|
||||
|
||||
<New id="maxAmount" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>maxAmount</Arg>
|
||||
<Arg type="java.lang.Double">100</Arg>
|
||||
<Arg type="boolean">true</Arg>
|
||||
</New>
|
||||
|
||||
|
||||
<New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>jdbc/mydatasource</Arg>
|
||||
<Arg>
|
||||
<New class="com.acme.MockDataSource">
|
||||
</New>
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
</Configure>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<!-- ==================================================================
|
||||
Configure and deploy the test web application in $(jetty.home)/webapps/test
|
||||
|
||||
Note. If this file did not exist or used a context path other that /test
|
||||
then the default configuration of jetty.xml would discover the test
|
||||
webapplication with a WebAppDeployer. By specifying a context in this
|
||||
directory, additional configuration may be specified and hot deployments
|
||||
detected.
|
||||
===================================================================== -->
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<Set name="contextPath">/test</Set>
|
||||
|
||||
<Get name="securityHandler">
|
||||
<Set name="loginService">
|
||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||
<Set name="name">Test Realm</Set>
|
||||
<Set name="config"><SystemProperty name="jetty.home" default="."/>/test-standard-realm.properties</Set>
|
||||
</New>
|
||||
</Set>
|
||||
<Set name="authenticator">
|
||||
<New class="org.eclipse.jetty.security.authentication.FormAuthenticator">
|
||||
<Set name="alwaysSaveUri">true</Set>
|
||||
</New>
|
||||
</Set>
|
||||
<Set name="checkWelcomeFiles">true</Set>
|
||||
</Get>
|
||||
|
||||
<!-- Non standard error page mapping -->
|
||||
<!--
|
||||
<Get name="errorHandler">
|
||||
<Call name="addErrorPage">
|
||||
<Arg type="int">500</Arg>
|
||||
<Arg type="int">599</Arg>
|
||||
<Arg type="String">/dump/errorCodeRangeMapping</Arg>
|
||||
</Call>
|
||||
</Get>
|
||||
-->
|
||||
|
||||
|
||||
</Configure>
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
# Module to add all lib/ext/*.jar files to classpath
|
||||
# Module to add all lib/ext/**.jar files to classpath
|
||||
#
|
||||
|
||||
[lib]
|
||||
regex:lib/ext/.*\.jar$
|
||||
lib/ext/**.jar
|
||||
|
||||
[files]
|
||||
lib/
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
[optional]
|
||||
jvm
|
||||
jmx
|
||||
ext
|
||||
resources
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
* HttpTransport.completed().
|
||||
*
|
||||
*/
|
||||
public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
||||
public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, HttpParser.ProxyHandler
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpChannel.class);
|
||||
private static final ThreadLocal<HttpChannel<?>> __currentChannel = new ThreadLocal<>();
|
||||
|
@ -477,6 +477,15 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort)
|
||||
{
|
||||
_request.setAttribute("PROXY", protocol);
|
||||
_request.setServerName(sAddr);
|
||||
_request.setServerPort(dPort);
|
||||
_request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
|
||||
{
|
||||
|
@ -842,4 +851,5 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.spdy.server;
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.spdy.server;
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
|
@ -115,37 +115,13 @@ public class GzipHttpOutput extends HttpOutput
|
|||
|
||||
private void gzip(ByteBuffer content, boolean complete, final Callback callback)
|
||||
{
|
||||
if (content.hasRemaining())
|
||||
if (content.hasRemaining() || complete)
|
||||
{
|
||||
if (content.hasArray())
|
||||
new GzipArrayCB(content,complete,callback).iterate();
|
||||
else
|
||||
new GzipBufferCB(content,complete,callback).iterate();
|
||||
}
|
||||
else if (complete)
|
||||
{
|
||||
_deflater.finish();
|
||||
|
||||
int produced=_deflater.deflate(_buffer.array(),_buffer.arrayOffset()+_buffer.limit(),_buffer.capacity()-_buffer.limit(),Deflater.NO_FLUSH);
|
||||
_buffer.limit(_buffer.limit()+produced);
|
||||
addTrailer();
|
||||
superWrite(_buffer,complete,new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
getHttpChannel().getByteBufferPool().release(_buffer);
|
||||
_buffer=null;
|
||||
callback.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
callback.failed(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void commit(ByteBuffer content, boolean complete, Callback callback)
|
||||
|
|
|
@ -21,18 +21,19 @@
|
|||
<module>spdy-http-server</module>
|
||||
<module>spdy-http-client-transport</module>
|
||||
<module>spdy-example-webapp</module>
|
||||
<module>spdy-alpn-tests</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jdk7-npn</id>
|
||||
<activation>
|
||||
<jdk>[1.7,1.8)</jdk>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>spdy-npn-tests</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>npn</id>
|
||||
<activation>
|
||||
<jdk>1.7</jdk>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>spdy-npn-tests</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<?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/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-alpn-tests</artifactId>
|
||||
<name>Jetty :: SPDY :: ALPN Tests</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.mortbay.jetty.alpn</groupId>
|
||||
<artifactId>alpn-boot</artifactId>
|
||||
<version>${alpn.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${project.build.directory}/alpn</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.alpn</groupId>
|
||||
<artifactId>alpn-api</artifactId>
|
||||
<version>${alpn.api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-http-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-http-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,216 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.spdy.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ALPNNegotiationTest extends AbstractALPNTest
|
||||
{
|
||||
@Test
|
||||
public void testClientAdvertisingHTTPServerSpeaksHTTP() throws Exception
|
||||
{
|
||||
InetSocketAddress address = prepare();
|
||||
connector.addConnectionFactory(new HttpConnectionFactory());
|
||||
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.start();
|
||||
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||
|
||||
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
|
||||
{
|
||||
client.setUseClientMode(true);
|
||||
client.setSoTimeout(5000);
|
||||
|
||||
ALPN.put(client, new ALPN.ClientProvider()
|
||||
{
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return Arrays.asList("http/1.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String protocol)
|
||||
{
|
||||
Assert.assertEquals("http/1.1", protocol);
|
||||
}
|
||||
});
|
||||
|
||||
client.startHandshake();
|
||||
|
||||
// Verify that the server really speaks http/1.1
|
||||
|
||||
OutputStream output = client.getOutputStream();
|
||||
output.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost:" + address.getPort() + "\r\n" +
|
||||
"\r\n" +
|
||||
"").getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
InputStream input = client.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.contains(" 404 "));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientAdvertisingMultipleProtocolsServerSpeaksHTTPWhenNegotiated() throws Exception
|
||||
{
|
||||
InetSocketAddress address = prepare();
|
||||
connector.addConnectionFactory(new HttpConnectionFactory());
|
||||
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.start();
|
||||
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
|
||||
{
|
||||
client.setUseClientMode(true);
|
||||
client.setSoTimeout(5000);
|
||||
|
||||
ALPN.put(client, new ALPN.ClientProvider()
|
||||
{
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return Arrays.asList("unknown/1.0", "http/1.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String protocol)
|
||||
{
|
||||
Assert.assertEquals("http/1.1", protocol);
|
||||
}
|
||||
});
|
||||
|
||||
client.startHandshake();
|
||||
|
||||
// Verify that the server really speaks http/1.1
|
||||
|
||||
OutputStream output = client.getOutputStream();
|
||||
output.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost:" + address.getPort() + "\r\n" +
|
||||
"\r\n" +
|
||||
"").getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
InputStream input = client.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.contains(" 404 "));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
|
||||
{
|
||||
InetSocketAddress address = prepare();
|
||||
connector.addConnectionFactory(new HttpConnectionFactory());
|
||||
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.start();
|
||||
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
|
||||
{
|
||||
client.setUseClientMode(true);
|
||||
client.setSoTimeout(5000);
|
||||
|
||||
ALPN.put(client, new ALPN.ClientProvider()
|
||||
{
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String s)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
client.startHandshake();
|
||||
|
||||
// Verify that the server really speaks http/1.1
|
||||
|
||||
OutputStream output = client.getOutputStream();
|
||||
output.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost:" + address.getPort() + "\r\n" +
|
||||
"\r\n" +
|
||||
"").getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
InputStream input = client.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.contains(" 404 "));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.spdy.server;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ALPNSynReplyTest extends AbstractALPNTest
|
||||
{
|
||||
@Test
|
||||
public void testGentleCloseDuringHandshake() throws Exception
|
||||
{
|
||||
InetSocketAddress address = prepare();
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.start();
|
||||
SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
|
||||
sslEngine.setUseClientMode(true);
|
||||
ALPN.put(sslEngine, new ALPN.ClientProvider()
|
||||
{
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String protocol)
|
||||
{
|
||||
}
|
||||
});
|
||||
sslEngine.beginHandshake();
|
||||
|
||||
ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
|
||||
sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
|
||||
encrypted.flip();
|
||||
|
||||
try (SocketChannel channel = SocketChannel.open(address))
|
||||
{
|
||||
// Send ClientHello, immediately followed by TLS Close Alert and then by FIN
|
||||
channel.write(encrypted);
|
||||
sslEngine.closeOutbound();
|
||||
encrypted.clear();
|
||||
sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
|
||||
encrypted.flip();
|
||||
channel.write(encrypted);
|
||||
channel.shutdownOutput();
|
||||
|
||||
// Read ServerHello from server
|
||||
encrypted.clear();
|
||||
int read = channel.read(encrypted);
|
||||
encrypted.flip();
|
||||
Assert.assertTrue(read > 0);
|
||||
// Cannot decrypt, as the SSLEngine has been already closed
|
||||
|
||||
// Now if we read more, we should either read the TLS Close Alert, or directly -1
|
||||
encrypted.clear();
|
||||
read = channel.read(encrypted);
|
||||
// Sending a TLS Close Alert during handshake results in an exception when
|
||||
// unwrapping that the server react to by closing the connection abruptly.
|
||||
Assert.assertTrue(read < 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbruptCloseDuringHandshake() throws Exception
|
||||
{
|
||||
InetSocketAddress address = prepare();
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.start();
|
||||
SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
|
||||
sslEngine.setUseClientMode(true);
|
||||
ALPN.put(sslEngine, new ALPN.ClientProvider()
|
||||
{
|
||||
@Override
|
||||
public boolean supports()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String s)
|
||||
{
|
||||
}
|
||||
});
|
||||
sslEngine.beginHandshake();
|
||||
|
||||
ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
|
||||
sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
|
||||
encrypted.flip();
|
||||
|
||||
try (SocketChannel channel = SocketChannel.open(address))
|
||||
{
|
||||
// Send ClientHello, immediately followed by FIN (no TLS Close Alert)
|
||||
channel.write(encrypted);
|
||||
channel.shutdownOutput();
|
||||
|
||||
// Read ServerHello from server
|
||||
encrypted.clear();
|
||||
int read = channel.read(encrypted);
|
||||
encrypted.flip();
|
||||
Assert.assertTrue(read > 0);
|
||||
ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
|
||||
sslEngine.unwrap(encrypted, decrypted);
|
||||
|
||||
// Now if we read more, we should either read the TLS Close Alert, or directly -1
|
||||
encrypted.clear();
|
||||
read = channel.read(encrypted);
|
||||
// Since we have close the connection abruptly, the server also does so
|
||||
Assert.assertTrue(read < 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.spdy.server;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.eclipse.jetty.alpn.ALPN;
|
||||
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.spdy.client.SPDYClient;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
|
||||
public class AbstractALPNTest
|
||||
{
|
||||
@Rule
|
||||
public final TestTracker tracker = new TestTracker();
|
||||
protected Server server;
|
||||
protected SPDYServerConnector connector;
|
||||
protected SPDYClient.Factory clientFactory;
|
||||
|
||||
protected InetSocketAddress prepare() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SPDYServerConnector(server, newSslContextFactory(), null, new ALPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"));
|
||||
connector.setPort(0);
|
||||
connector.setIdleTimeout(30000);
|
||||
server.addConnector(connector);
|
||||
server.start();
|
||||
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setName(threadPool.getName() + "-client");
|
||||
clientFactory = new SPDYClient.Factory(threadPool);
|
||||
clientFactory.start();
|
||||
|
||||
ALPN.debug = true;
|
||||
|
||||
return new InetSocketAddress("localhost", connector.getLocalPort());
|
||||
}
|
||||
|
||||
protected SslContextFactory newSslContextFactory()
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
|
||||
sslContextFactory.setTrustStorePassword("storepwd");
|
||||
sslContextFactory.setProtocol("TLSv1");
|
||||
sslContextFactory.setIncludeProtocols("TLSv1");
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
@After
|
||||
public void dispose() throws Exception
|
||||
{
|
||||
clientFactory.stop();
|
||||
server.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
#org.eclipse.jetty.spdy.LEVEL=DEBUG
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue