diff options
author | Jan Bartel | 2013-06-17 03:17:14 +0000 |
---|---|---|
committer | Jan Bartel | 2013-06-17 03:17:14 +0000 |
commit | 59889bc14985aa92e0c217b16158d627bc2fa75a (patch) | |
tree | 755eeb515dda2a5bd00af27de673f3abd55edb51 | |
parent | 232eb4491a4dff3c365c76aa13422792091a48e5 (diff) | |
parent | 5c7f6937fdc37a578a650004fe80f7e672cba86c (diff) | |
download | org.eclipse.jetty.project-59889bc14985aa92e0c217b16158d627bc2fa75a.tar.gz org.eclipse.jetty.project-59889bc14985aa92e0c217b16158d627bc2fa75a.tar.xz org.eclipse.jetty.project-59889bc14985aa92e0c217b16158d627bc2fa75a.zip |
Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project
114 files changed, 3038 insertions, 872 deletions
diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index d104b37682..fa9262c91c 100644 --- a/aggregates/jetty-all/pom.xml +++ b/aggregates/jetty-all/pom.xml @@ -9,6 +9,7 @@ <groupId>org.eclipse.jetty.aggregate</groupId> <artifactId>jetty-all</artifactId> <name>Jetty :: Aggregate :: All core Jetty</name> + <url>http://www.eclipse.org/jetty</url> <build> <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index 82df03d883..a19d752f3a 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -9,6 +9,7 @@ <artifactId>example-async-rest-jar</artifactId> <packaging>jar</packaging> <name>Example Async Rest :: Jar</name> + <url>http://www.eclipse.org/jetty</url> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml index d549d781be..0f30afe56f 100644 --- a/examples/embedded/pom.xml +++ b/examples/embedded/pom.xml @@ -10,6 +10,7 @@ <artifactId>example-jetty-embedded</artifactId> <name>Example :: Jetty Embedded</name> <description>Jetty Embedded Examples</description> + <url>http://www.eclipse.org/jetty</url> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml new file mode 100644 index 0000000000..9c23cae0f2 --- /dev/null +++ b/jetty-aggregate/jetty-all-server/pom.xml @@ -0,0 +1,212 @@ +<?xml version="1.0"?> +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-all-server</artifactId> + <name>Jetty :: Aggregate :: All Server</name> + <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.${project.artifactId}</bundle-symbolic-name> + </properties> + + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <excludes>**/MANIFEST.MF,javax/**</excludes> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + <configuration> + <instructions> + <Import-Package> + !org.eclipse.jetty*, + com.sun.org.apache.commons.logging;version="[2.1,3)";split="glassfish";resolution:=optional, + javax.annotation;version="1.0.0";resolution:=optional, + javax.servlet;version="2.5.0", + javax.servlet.http;version="2.5.0", + javax.mail;version="1.4.0";resolution:=optional, + javax.mail.event;version="1.4.0";resolution:=optional, + javax.mail.internet;version="1.4.0";resolution:=optional, + javax.mail.search;version="1.4.0";resolution:=optional, + javax.mail.util;version="1.4.0";resolution:=optional, + javax.transaction;version="1.1.0";resolution:=optional, + javax.transaction.xa;version="1.1.0";resolution:=optional, + org.slf4j;resolution:=optional, + org.slf4j.spi;resolution:=optional, + org.slf4j.helpers;resolution:=optional, + org.xml.sax, + org.xml.sax.helpers, + javax.security.cert, + javax.xml.parsers, + javax.net.ssl, + !org.mortbay.*, + org.objectweb.asm;version="3.1.0";resolution:=optional, + org.objectweb.asm.commons;version="3.1.0";resolution:=optional, + javax.security.auth.message*;resolution:=optional, + * + </Import-Package> + <Export-Package>org.eclipse.jetty*;version="${parsedVersion.osgiVersion}"</Export-Package> + <!-- disable the uses directive: jetty will accomodate pretty much any versions + of the packages it uses; no need to reflect some tight dependency determined at + compilation time. --> + <_nouses>true</_nouses> + <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-deploy</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.servlet</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jmx</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-plus</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-ajp</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-annotations</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jaspi</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jndi</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-rewrite</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-nested</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.security.auth.message</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.mail.glassfish</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.activation</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.annotation</artifactId> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml new file mode 100644 index 0000000000..1fc0ab7426 --- /dev/null +++ b/jetty-aggregate/jetty-client/pom.xml @@ -0,0 +1,87 @@ +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-client</artifactId> + <name>Jetty :: Aggregate :: HTTP Client</name> + <url>http://www.eclipse.org/jetty</url> + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <includes>META-INF/**,org/eclipse/**</includes> + <excludes>**/MANIFEST.MF</excludes> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>package</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifest> + </manifest> + <manifestEntries> + <mode>development</mode> + <url>http://eclipse.org/jetty</url> + <Built-By>${user.name}</Built-By> + <package>org.eclipse.jetty</package> + <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License> + <Bundle-Name>Jetty HTTP Client</Bundle-Name> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml new file mode 100644 index 0000000000..7c658ed4b8 --- /dev/null +++ b/jetty-aggregate/jetty-server/pom.xml @@ -0,0 +1,97 @@ +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-server</artifactId> + <name>Jetty :: Aggregate :: HTTP Server</name> + <url>http://www.eclipse.org/jetty</url> + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <excludes>**/MANIFEST.MF,javax/**</excludes> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins + </groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>package</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifest> + </manifest> + <manifestEntries> + <mode>development</mode> + <url>http://eclipse.org/jetty</url> + <Built-By>${user.name}</Built-By> + <package>org.eclipse.jetty</package> + <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License> + <Bundle-Name>Jetty HTTP Server</Bundle-Name> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml new file mode 100644 index 0000000000..ad4d4b13b3 --- /dev/null +++ b/jetty-aggregate/jetty-servlet/pom.xml @@ -0,0 +1,96 @@ +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-servlet</artifactId> + <name>Jetty :: Aggregate :: Servlet Server</name> + <url>http://www.eclipse.org/jetty</url> + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <excludes>**/MANIFEST.MF,javax/**</excludes> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>package</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifest> + </manifest> + <manifestEntries> + <mode>development</mode> + <url>http://eclipse.org/jetty</url> + <Built-By>${user.name}</Built-By> + <package>org.eclipse.jetty</package> + <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License> + <Bundle-Name>Jetty HTTP Server</Bundle-Name> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml new file mode 100644 index 0000000000..3eb1748eda --- /dev/null +++ b/jetty-aggregate/jetty-webapp/pom.xml @@ -0,0 +1,103 @@ +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-webapp</artifactId> + <name>Jetty :: Aggregate :: WebApp Server</name> + <url>http://www.eclipse.org/jetty</url> + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes> + <excludes>**/MANIFEST.MF,javax/**</excludes> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins + </groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>package</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifest> + </manifest> + <manifestEntries> + <mode>development</mode> + <url>http://eclipse.org/jetty</url> + <Built-By>${user.name}</Built-By> + <package>org.eclipse.jetty</package> + <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License> + <Bundle-Name>Jetty HTTP Server</Bundle-Name> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.servlet</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.servlet</artifactId> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/jetty-websocket/pom.xml b/jetty-aggregate/jetty-websocket/pom.xml new file mode 100644 index 0000000000..c45885c2cb --- /dev/null +++ b/jetty-aggregate/jetty-websocket/pom.xml @@ -0,0 +1,91 @@ +<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.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-websocket</artifactId> + <name>Jetty :: Aggregate :: Websocket</name> + <url>http://www.eclipse.org/jetty</url> + <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack-dependencies</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <excludes>**/MANIFEST.MF,javax/**,about.html</excludes> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <excludeArtifactIds>javax</excludeArtifactIds> + <excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins + </groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>package</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifest> + </manifest> + <manifestEntries> + <mode>development</mode> + <url>http://eclipse.org/jetty</url> + <Built-By>${user.name}</Built-By> + <package>org.eclipse.jetty</package> + <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License> + <Bundle-Name>Jetty HTTP Server</Bundle-Name> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml new file mode 100644 index 0000000000..b23767e4b5 --- /dev/null +++ b/jetty-aggregate/pom.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <groupId>org.eclipse.jetty.aggregate</groupId> + <artifactId>jetty-aggregate-project</artifactId> + <name>Jetty :: Aggregate Project</name> + <url>http://www.eclipse.org/jetty</url> + <packaging>pom</packaging> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <configuration> + <!-- No Point running PMD on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <!-- No Point running Findbugs on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + <modules> + <module>jetty-server</module> + <module>jetty-client</module> + <module>jetty-servlet</module> + <module>jetty-webapp</module> + <module>jetty-websocket</module> + <module>jetty-plus</module> + <module>jetty-all-server</module> + <module>jetty-all</module> + </modules> +</project> diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 8e12bc2118..13e2194554 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-annotations</artifactId> <name>Jetty :: Servlet Annotations</name> <description>Annotation support for deploying servlets in jetty.</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.annotations</bundle-symbolic-name> </properties> diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 8f2ad66c08..4ba11e2cf7 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -8,13 +8,11 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-client</artifactId> <name>Jetty :: Asynchronous HTTP Client</name> - <url>{$jetty.url}</url> - + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name> <jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc> </properties> - <build> <plugins> <plugin> diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index aec8ebbcd4..f71dc603ea 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-continuation</artifactId> <name>Jetty :: Continuation</name> <description>Asynchronous API</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.continuation</bundle-symbolic-name> </properties> diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 9ee520fb19..4ea462a633 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-deploy</artifactId> <name>Jetty :: Deployers</name> <description>Jetty deployers</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.deploy</bundle-symbolic-name> </properties> diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index d6b495c107..5aff528e62 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -7,6 +7,7 @@ </parent> <artifactId>jetty-distribution</artifactId> <name>Jetty :: Distribution Assemblies</name> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <properties> <assembly-directory>target/distribution</assembly-directory> diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 7dc16201b8..42439750c0 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -7,6 +7,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-http-spi</artifactId> <name>Jetty :: Http Service Provider Interface</name> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.http.spi</bundle-symbolic-name> </properties> diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 43e64a9ef9..bbf3d08ab6 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -8,6 +8,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-http</artifactId> <name>Jetty :: Http Utility</name> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.http</bundle-symbolic-name> </properties> diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index ef341a8f75..a9a4ed7853 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -7,6 +7,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-io</artifactId> <name>Jetty :: IO Utility</name> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.io</bundle-symbolic-name> </properties> diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java index c352f006b0..6af94f59f9 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ReadPendingException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.util.Callback; @@ -34,8 +35,7 @@ import org.eclipse.jetty.util.Callback; */ public abstract class FillInterest { - private final AtomicBoolean _interested = new AtomicBoolean(false); - private volatile Callback _callback; + private final AtomicReference<Callback> _interested = new AtomicReference<>(null); /* ------------------------------------------------------------ */ protected FillInterest() @@ -52,9 +52,11 @@ public abstract class FillInterest */ public <C> void register(Callback callback) throws ReadPendingException { - if (!_interested.compareAndSet(false,true)) + if (callback==null) + throw new IllegalArgumentException(); + + if (!_interested.compareAndSet(null,callback)) throw new ReadPendingException(); - _callback=callback; try { if (needsFill()) @@ -71,12 +73,9 @@ public abstract class FillInterest */ public void fillable() { - if (_interested.compareAndSet(true,false)) - { - Callback callback=_callback; - _callback=null; + Callback callback=_interested.get(); + if (callback!=null && _interested.compareAndSet(callback,null)) callback.succeeded(); - } } /* ------------------------------------------------------------ */ @@ -85,7 +84,7 @@ public abstract class FillInterest */ public boolean isInterested() { - return _interested.get(); + return _interested.get()!=null; } /* ------------------------------------------------------------ */ @@ -93,30 +92,24 @@ public abstract class FillInterest */ public void onFail(Throwable cause) { - if (_interested.compareAndSet(true,false)) - { - Callback callback=_callback; - _callback=null; + Callback callback=_interested.get(); + if (callback!=null && _interested.compareAndSet(callback,null)) callback.failed(cause); - } } /* ------------------------------------------------------------ */ public void onClose() { - if (_interested.compareAndSet(true,false)) - { - Callback callback=_callback; - _callback=null; + Callback callback=_interested.get(); + if (callback!=null && _interested.compareAndSet(callback,null)) callback.failed(new ClosedChannelException()); - } } /* ------------------------------------------------------------ */ @Override public String toString() { - return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_callback); + return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_interested.get()); } /* ------------------------------------------------------------ */ diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index a35bcb77dc..71728a363c 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-jaspi</artifactId> <name>Jetty :: JASPI Security</name> <description>Jetty security infrastructure</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.jaspi</bundle-symbolic-name> </properties> diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index ed18a5976f..f20145c4ef 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-jmx</artifactId> <name>Jetty :: JMX Management</name> <description>JMX management artifact for jetty.</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.jmx</bundle-symbolic-name> </properties> diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 376c5beb28..39b659790d 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-jndi</artifactId> <name>Jetty :: JNDI Naming</name> <description>JNDI spi impl for java namespace.</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.jndi</bundle-symbolic-name> </properties> diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index f48f73cdbe..83eda5dcbf 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -7,6 +7,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-jsp</artifactId> <name>Jetty :: JSP dependencies</name> + <url>http://www.eclipse.org/jetty</url> <packaging>jar</packaging> <build> </build> diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index 3538414741..e8bcf615ab 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -24,6 +24,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-monitor</artifactId> <name>Jetty :: Monitoring</name> + <url>http://www.eclipse.org/jetty</url> <description>Performance monitoring artifact for jetty.</description> <properties> <bundle-symbolic-name>${project.groupId}.monitor</bundle-symbolic-name> diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index c1aa0f040c..54850bce94 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -7,6 +7,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>jetty-nosql</artifactId> <name>Jetty :: NoSQL Session Managers</name> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.nosql</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index cb105aedc4..29a346103a 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-osgi-boot-jsp</artifactId> <name>Jetty :: OSGi :: Boot JSP</name> <description>Jetty OSGi Boot JSP bundle</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.boot.jsp</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml b/jetty-osgi/jetty-osgi-boot-logback/pom.xml new file mode 100644 index 0000000000..f1985b7e05 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot-logback/pom.xml @@ -0,0 +1,127 @@ +<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>7.6.11-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-osgi-boot-logback</artifactId> + <name>Jetty :: OSGi :: Boot Logback</name> + <description>Jetty OSGi Boot Logback bundle</description> + <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.boot.logback</bundle-symbolic-name> + </properties> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.osgi</groupId> + <artifactId>jetty-osgi-boot</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>org.eclipse.osgi</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>org.eclipse.osgi.services</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>log4j-over-slf4j</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>artifact-jar</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + <execution> + <id>test-jar</id> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + <configuration> + <archive> + <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + <configuration> + <instructions> + <Bundle-SymbolicName>org.eclipse.jetty.osgi.boot.logback;singleton:=true</Bundle-SymbolicName> + <Bundle-Name>Jetty-OSGi-Logback Integration</Bundle-Name> + <Fragment-Host>org.eclipse.jetty.osgi.boot</Fragment-Host> + <Import-Package> +ch.qos.logback.access.jetty;version="[0.9,1.1)";resolution:=optional, +ch.qos.logback.access.jetty.v7;version="[0.9,1.1)";resolution:=optional, +ch.qos.logback.*;version="[0.9,1.1)", +org.osgi.framework.*, +org.slf4j.*, +*;resolution:=optional + </Import-Package> + <Export-Package> +!org.eclipse.jetty.osgi.boot.logback.internal.*, +org.eclipse.jetty.osgi.boot.logback.*;version="${parsedVersion.osgiVersion}" + </Export-Package> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.boot.logback.*</onlyAnalyze> + </configuration> + </plugin> + </plugins> + </build> + + +</project> diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index 50f47542bb..b853eb80c9 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -9,6 +9,7 @@ <artifactId>jetty-osgi-boot-warurl</artifactId> <name>Jetty :: OSGi :: Boot :: Warurl</name> <description>Jetty OSGi Boot-Warurl bundle</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.boot.warurl</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 21e99b5046..d5ba596052 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-osgi-boot</artifactId> <name>Jetty :: OSGi :: Boot</name> <description>Jetty OSGi Boot bundle</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.boot</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml new file mode 100644 index 0000000000..1db3f81076 --- /dev/null +++ b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml @@ -0,0 +1,121 @@ +<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>7.6.11-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>jetty-osgi-equinoxtools</artifactId> + <name>Jetty :: OSGi :: Example Equinox Tools</name> + <description>Jetty OSGi Example Equinox Tools</description> + <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.equinoxtools</bundle-symbolic-name> + </properties> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-continuation</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>org.eclipse.osgi</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>org.eclipse.osgi.services</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <execution> + <phase>process-resources</phase> + <configuration> + <tasks> + <copy todir="target/classes/equinoxconsole"> + <fileset dir="equinoxconsole" /> + </copy> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>artifact-jar</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + <execution> + <id>test-jar</id> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + <configuration> + <archive> + <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + <configuration> + <instructions> + <Bundle-SymbolicName>org.eclipse.jetty.osgi.equinoxtools</Bundle-SymbolicName> + <Bundle-Name>Console</Bundle-Name> + <Bundle-Activator>org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator</Bundle-Activator> + <Export-Package>org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="${parsedVersion.osgiVersion}", + org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="${parsedVersion.osgiVersion}" + </Export-Package> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.equinoxtools.*</onlyAnalyze> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index 8d6be0af7e..df9b6c586a 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-httpservice</artifactId> <name>Jetty :: OSGi :: HttpService</name> <description>Jetty OSGi HttpService bundle</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.httpservice</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/jetty-osgi-servletbridge/pom.xml b/jetty-osgi/jetty-osgi-servletbridge/pom.xml new file mode 100644 index 0000000000..4da36c2e85 --- /dev/null +++ b/jetty-osgi/jetty-osgi-servletbridge/pom.xml @@ -0,0 +1,54 @@ +<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>7.6.5-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.jetty.osgi</groupId> + <artifactId>jetty-osgi-servletbridge</artifactId> + <name>Jetty :: OSGi :: Servletbridge</name> + <description>Jetty OSGi Servletbridge webapp</description> + <url>http://www.eclipse.org/jetty</url> + <packaging>war</packaging> + <properties><eclipse.pde>false</eclipse.pde></properties> + <dependencies> + <dependency> + <groupId>org.eclipse.equinox</groupId> + <artifactId>org.eclipse.equinox.servletbridge</artifactId> + <version>1.2.0.v20100503</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>org.eclipse.osgi</artifactId> + <version>3.6.0.v20100517</version> + <scope>provided</scope> + </dependency> + </dependencies> + <repositories> + <!-- can't find equinox servlet bridge jar on maven central. + uploaded it to intalio.org for now. --> + <repository> + <id>intalio-org</id> + <url>http://intalio.org/public/maven2</url> + </repository> + </repositories> + + <build> + <plugins><plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <configuration> + <pde>false</pde> + </configuration> + </plugin></plugins> + </build> + +</project> diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index c3919e6e11..f9a021d8a3 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -8,6 +8,7 @@ <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> <name>Jetty :: OSGi</name> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <properties> <osgi-version>3.6.0.v20100517</osgi-version> diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 3e0eb62490..86c24d4b55 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -8,6 +8,7 @@ <artifactId>test-jetty-osgi-context</artifactId> <name>Jetty :: OSGi :: Context</name> <description>Test Jetty OSGi bundle with a ContextHandler</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.testcontext</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index 29e9fb54ab..14ad31c49d 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -9,6 +9,7 @@ <artifactId>test-jetty-osgi-webapp</artifactId> <name>Jetty :: OSGi :: WebApp</name> <description>Test Jetty OSGi Webapp bundle</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.webapp</bundle-symbolic-name> </properties> diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 356d937e57..e4cd558238 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -8,7 +8,8 @@ <modelVersion>4.0.0</modelVersion> <artifactId>test-jetty-osgi</artifactId> <name>Jetty :: OSGi :: Test</name> - <description>Jetty OSGi Integration tests</description> + <description>Jetty OSGi Integration test</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.boot.test.spdy</bundle-symbolic-name> <jetty-orbit-url>http://download.eclipse.org/jetty/orbit/</jetty-orbit-url> diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml index 8b853167ee..53071fecb1 100644 --- a/jetty-overlay-deployer/pom.xml +++ b/jetty-overlay-deployer/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-overlay-deployer</artifactId> <name>Jetty :: Overlay Deployer</name> <description>Overlayed deployer</description> + <url>http://www.eclipse.org/jetty</url> <properties> </properties> <build> diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 9a78b88b10..aac004a02f 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-plus</artifactId> <name>Jetty :: Plus</name> <description>Jetty JavaEE style services</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.plus</bundle-symbolic-name> </properties> diff --git a/jetty-policy/pom.xml b/jetty-policy/pom.xml new file mode 100644 index 0000000000..e9fc1e8bd9 --- /dev/null +++ b/jetty-policy/pom.xml @@ -0,0 +1,139 @@ +<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"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-project</artifactId> + <version>7.6.11-SNAPSHOT</version> + </parent> + <artifactId>jetty-policy</artifactId> + <name>Jetty :: Policy Tool</name> + <packaging>jar</packaging> + <url>http://www.eclipse.org/jetty</url> + <properties> + <jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc> + <bundle-symbolic-name>${project.groupId}.policy</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.policy.*;version="${parsedVersion.osgiVersion}"</Export-Package> + </instructions> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <!-- + Required for OSGI + --> + <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> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>unpack</id> + <phase>generate-test-resources</phase> + <goals> + <goal>unpack</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-test-policy</artifactId> + <version>${jetty-test-policy-version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <includes>**/*.keystore</includes> + <outputDirectory>${jetty.test.policy.loc}</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + <execution> + <id>copy</id> + <phase>generate-test-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-test-policy</artifactId> + <version>${jetty-test-policy-version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${jetty.test.policy.loc}</outputDirectory> + <destFileName>jetty-test-policy.jar</destFileName> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.policy.*</onlyAnalyze> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jmx</artifactId> + <version>${project.version}</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-test-helper</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index 697f207939..490c4dc28a 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-proxy</artifactId> <name>Jetty :: Proxy</name> <description>Jetty Proxy</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.proxy</bundle-symbolic-name> </properties> diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index feca53c9c4..03ad237907 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-rewrite</artifactId> <name>Jetty :: Rewrite Handler</name> <description>Jetty Rewrite Handler</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.rewrite</bundle-symbolic-name> </properties> diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index c96a6efd00..0883fd8839 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -12,7 +12,7 @@ <properties> <assembly-directory>target/distribution</assembly-directory> </properties> - + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index c52cf73367..d551ab44a5 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-security</artifactId> <name>Jetty :: Security</name> <description>Jetty security infrastructure</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.security</bundle-symbolic-name> </properties> diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index f603245533..2f24762a9f 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-server</artifactId> <name>Jetty :: Server Core</name> <description>The core jetty server artifact.</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name> </properties> diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index 191232f6de..79f442f80d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; @@ -31,6 +30,7 @@ import javax.servlet.ServletResponse; import org.eclipse.jetty.http.HttpContent; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.BlockingCallback; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; @@ -168,7 +168,7 @@ public class HttpOutput extends ServletOutputStream public void write(byte[] b, int off, int len) throws IOException { if (isClosed()) - throw new EOFException("Closed"); + throw new EofException("Closed"); _written+=len; boolean complete=_channel.getResponse().isAllContentWritten(_written); diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 85fa527e4f..d503d2fac7 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -9,6 +9,7 @@ <artifactId>jetty-servlet</artifactId> <name>Jetty :: Servlet Handling</name> <description>Jetty Servlet Container</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.servlet</bundle-symbolic-name> </properties> diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index e0911d25eb..9d5de75af9 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -9,6 +9,7 @@ <artifactId>jetty-servlets</artifactId> <name>Jetty :: Utility Servlets and Filters</name> <description>Utility Servlets from Jetty</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.servlets</bundle-symbolic-name> </properties> diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 1ac8b84382..e276ff7e8f 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -11,7 +11,7 @@ <artifactId>spdy-parent</artifactId> <packaging>pom</packaging> <name>Jetty :: SPDY :: Parent</name> - + <url>http://www.eclipse.org/jetty</url> <properties> <npn.api.version>1.1.0.v20120525</npn.api.version> </properties> diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index fcaee371a4..a2ec7b0e58 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -14,6 +14,7 @@ <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name> </properties> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java index 2456a2228f..e2a0cba22a 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java @@ -143,7 +143,7 @@ public class SPDYClient protected SSLEngine newSSLEngine(SslContextFactory sslContextFactory, SocketChannel channel) { - String peerHost = channel.socket().getInetAddress().getHostAddress(); + String peerHost = channel.socket().getInetAddress().getHostName(); int peerPort = channel.socket().getPort(); SSLEngine engine = sslContextFactory.newSSLEngine(peerHost, peerPort); engine.setUseClientMode(true); diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index d2aee9d29f..858427eb2a 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -14,6 +14,7 @@ <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name> </properties> + <url>http://www.eclipse.org/jetty</url> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java index 30dc870721..067f7f7e48 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java @@ -490,9 +490,15 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable goAway(x.getSessionStatus(), 0, TimeUnit.SECONDS, new Callback.Adapter()); } - private void onSyn(SynStreamFrame frame) + private void onSyn(final SynStreamFrame frame) { - IStream stream = createStream(frame, null, false, null); + IStream stream = createStream(frame, null, false, new Promise.Adapter<Stream>(){ + @Override + public void failed(Throwable x) + { + LOG.debug("Received: {} but creating new Stream failed: {}", frame, x.getMessage()); + } + }); if (stream != null) processSyn(listener, stream, frame); } diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml index 28fd25184b..924536d62b 100644 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ b/jetty-spdy/spdy-example-webapp/pom.xml @@ -8,8 +8,8 @@ <modelVersion>4.0.0</modelVersion> <artifactId>spdy-example-webapp</artifactId> <packaging>war</packaging> - <name>Jetty :: SPDY :: Example Web Application</name> - + <name>Jetty :: SPDY :: Jetty HTTP Web Application</name> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml index feea74418c..b5d0a4c2fe 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml +++ b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml @@ -103,7 +103,8 @@ <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> <Arg name="version" type="int">3</Arg> <Arg name="config"><Ref refid="sslHttpConfig" /></Arg> - <Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg> + <!-- Uncomment to enable ReferrerPushStrategy --> + <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>--> </New> </Item> diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index b67bfffaa3..fc83aef1f4 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -23,7 +23,6 @@ import java.nio.ByteBuffer; import java.util.Queue; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http.HttpField; @@ -86,14 +85,14 @@ public class HttpTransportOverSPDY implements HttpTransport return requestHeaders; } - + @Override public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) { // TODO can this be more efficient? - send(null,responseBodyContent, lastContent, callback); + send(null, responseBodyContent, lastContent, callback); } - + @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { @@ -306,7 +305,7 @@ public class HttpTransportOverSPDY implements HttpTransport final Fields pushHeaders = createPushHeaders(scheme, host, pushResource); final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource); - stream.push(new PushInfo(pushHeaders, false), new Promise.Adapter<Stream>() + stream.push(new PushInfo(pushHeaders, false), new Promise<Stream>() { @Override public void succeeded(Stream pushStream) @@ -315,6 +314,12 @@ public class HttpTransportOverSPDY implements HttpTransport queue.offer(new PushResource(pushStream, pushRequestHeaders)); sendNextResourceData(); } + + @Override + public void failed(Throwable x) + { + LOG.debug("Creating push stream failed.", x); + } }); } diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java index ed0220c421..5b501fef8e 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java @@ -67,7 +67,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertThat; -@Ignore public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest { private static final Logger LOG = Log.getLogger(ReferrerPushStrategyTest.class); @@ -260,6 +259,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest public void testPushResourceOrder() throws Exception { final CountDownLatch allExpectedPushesReceivedLatch = new CountDownLatch(4); + final CountDownLatch allPushDataReceivedLatch = new CountDownLatch(4); Session pushCacheBuildSession = startClient(version, serverAddress, null); @@ -296,12 +296,22 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest break; } allExpectedPushesReceivedLatch.countDown(); - return super.onPush(stream, pushInfo); + return new Adapter() + { + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + if(dataInfo.isClose()) + allPushDataReceivedLatch.countDown(); + } + }; } }); assertThat("All expected push resources have been received", allExpectedPushesReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); + assertThat("All push data has been fully received", allPushDataReceivedLatch.await(5, TimeUnit.SECONDS), + is(true)); } @Test @@ -451,7 +461,6 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest private void sendRequest(Session session, Fields requestHeaders, final CountDownLatch pushSynHeadersValid, final CountDownLatch pushDataLatch, final boolean resetPush) throws InterruptedException { - LOG.info("sendRequest. headers={},resetPush={}", requestHeaders, resetPush); final CountDownLatch dataReceivedLatch = new CountDownLatch(1); session.syn(new SynInfo(requestHeaders, true), new StreamFrameListener.Adapter() { @@ -496,7 +505,6 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest } }, new Promise.Adapter<Stream>()); assertThat(dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - LOG.info("sendRequest done"); } private void run2ndClientRequests(final boolean validateHeaders, diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 1fa10b91a3..63175046b0 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -14,6 +14,7 @@ <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name> </properties> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 4d8269b8db..a1e501d538 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-start</artifactId> <name>Jetty :: Start</name> <description>The start utility</description> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java new file mode 100644 index 0000000000..4928fc0e05 --- /dev/null +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.start; + +import java.util.Enumeration; +import java.util.Properties; + +public class PropertyDump +{ + public static void main(String[] args) + { + Properties props = System.getProperties(); + Enumeration<?> names = props.propertyNames(); + while (names.hasMoreElements()) + { + String name = (String)names.nextElement(); + // only interested in "test." prefixed properties + if (name.startsWith("test.")) + { + System.out.printf("%s=%s%n",name,props.getProperty(name)); + } + } + System.exit(0); + } +} diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java new file mode 100644 index 0000000000..9275957109 --- /dev/null +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java @@ -0,0 +1,245 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.start; + +import static org.hamcrest.Matchers.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.toolchain.test.IO; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.OS; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; + +public class PropertyPassingTest +{ + private static class ConsoleCapture implements Runnable + { + private String mode; + private BufferedReader reader; + private StringWriter output; + + public ConsoleCapture(String mode, InputStream is) + { + this.mode = mode; + this.reader = new BufferedReader(new InputStreamReader(is)); + this.output = new StringWriter(); + } + + @Override + public void run() + { + String line; + try (PrintWriter out = new PrintWriter(output)) + { + while ((line = reader.readLine()) != (null)) + { + out.println(line); + } + } + catch (IOException ignore) + { + /* ignore */ + } + finally + { + IO.close(reader); + } + } + + public String getConsoleOutput() + { + return output.toString(); + } + + public ConsoleCapture start() + { + Thread thread = new Thread(this,"ConsoleCapture/" + mode); + thread.start(); + return this; + } + } + + @Rule + public TestingDir testingdir = new TestingDir(); + + @Test + public void testAsJvmArg() throws IOException, InterruptedException + { + File testCfg = MavenTestingUtils.getTestResourceFile("property-dump-start.config"); + File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml"); + + // Setup command line + List<String> commands = new ArrayList<>(); + commands.add(getJavaBin()); + commands.add("-cp"); + commands.add(getClassPath()); + // addDebug(commands); + commands.add("-Dtest.foo=bar"); // TESTING THIS + commands.add(getStartJarBin()); + commands.add("--config=" + testCfg.getAbsolutePath()); + commands.add(bogusXml.getAbsolutePath()); + + // Run command, collect output + String output = collectRunOutput(commands); + + // Test for values + Assert.assertThat("output",output,containsString("foo=bar")); + } + + @Test + @Ignore("not working yet") + public void testAsCommandLineArg() throws IOException, InterruptedException + { + File testCfg = MavenTestingUtils.getTestResourceFile("property-dump-start.config"); + File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml"); + + // Setup command line + List<String> commands = new ArrayList<>(); + commands.add(getJavaBin()); + commands.add("-cp"); + commands.add(getClassPath()); + // addDebug(commands); + commands.add(getStartJarBin()); + commands.add("test.foo=bar"); // TESTING THIS + commands.add("--config=" + testCfg.getAbsolutePath()); + commands.add(bogusXml.getAbsolutePath()); + + // Run command, collect output + String output = collectRunOutput(commands); + + // Test for values + Assert.assertThat("output",output,containsString("foo=bar")); + } + + @Test + public void testAsDashDCommandLineArg() throws IOException, InterruptedException + { + File testCfg = MavenTestingUtils.getTestResourceFile("property-dump-start.config"); + File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml"); + + // Setup command line + List<String> commands = new ArrayList<>(); + commands.add(getJavaBin()); + commands.add("-cp"); + commands.add(getClassPath()); + // addDebug(commands); + commands.add(getStartJarBin()); + commands.add("-Dtest.foo=bar"); // TESTING THIS + commands.add("--config=" + testCfg.getAbsolutePath()); + commands.add(bogusXml.getAbsolutePath()); + + // Run command, collect output + String output = collectRunOutput(commands); + + // Test for values + Assert.assertThat("output",output,containsString("foo=bar")); + } + + private String getClassPath() + { + StringBuilder cp = new StringBuilder(); + String pathSep = System.getProperty("path.separator"); + cp.append(MavenTestingUtils.getProjectDir("target/classes")); + cp.append(pathSep); + cp.append(MavenTestingUtils.getProjectDir("target/test-classes")); + return cp.toString(); + } + + protected void addDebug(List<String> commands) + { + commands.add("-Xdebug"); + commands.add("-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=y"); + } + + private String collectRunOutput(List<String> commands) throws IOException, InterruptedException + { + StringBuilder cline = new StringBuilder(); + for (String command : commands) + { + cline.append(command).append(" "); + } + System.out.println("Command line: " + cline); + + ProcessBuilder builder = new ProcessBuilder(commands); + Process pid = builder.start(); + + ConsoleCapture stdOutPump = new ConsoleCapture("STDOUT",pid.getInputStream()).start(); + ConsoleCapture stdErrPump = new ConsoleCapture("STDERR",pid.getErrorStream()).start(); + + int exitCode = pid.waitFor(); + if(exitCode != 0) { + System.out.printf("STDERR: [" + stdErrPump.getConsoleOutput() + "]%n"); + System.out.printf("STDOUT: [" + stdOutPump.getConsoleOutput() + "]%n"); + Assert.assertThat("Exit code",exitCode,is(0)); + } + return stdOutPump.getConsoleOutput(); + } + + private String getStartJarBin() + { + return org.eclipse.jetty.start.Main.class.getName(); + } + + private String getJavaBin() + { + File javaHome = new File(System.getProperty("java.home")); + if (!javaHome.exists()) + { + return null; + } + + File javabin = findExecutable(javaHome,"bin/java"); + if (javabin != null) + { + return javabin.getAbsolutePath(); + } + + javabin = findExecutable(javaHome,"bin/java.exe"); + if (javabin != null) + { + return javabin.getAbsolutePath(); + } + + return "java"; + } + + private File findExecutable(File root, String path) + { + String npath = OS.separators(path); + File exe = new File(root,npath); + if (!exe.exists()) + { + return null; + } + return exe; + } +} diff --git a/jetty-start/src/test/resources/bogus.xml b/jetty-start/src/test/resources/bogus.xml new file mode 100644 index 0000000000..6660498d7f --- /dev/null +++ b/jetty-start/src/test/resources/bogus.xml @@ -0,0 +1,2 @@ +<?xml version="1.0"?> +<Configure />
\ No newline at end of file diff --git a/jetty-start/src/test/resources/property-dump-start.config b/jetty-start/src/test/resources/property-dump-start.config new file mode 100644 index 0000000000..f38e5a426a --- /dev/null +++ b/jetty-start/src/test/resources/property-dump-start.config @@ -0,0 +1,8 @@ + +org.eclipse.jetty.start.PropertyDump.class + +[*] +$(basedir)/src/test/resources + +[default] +$(basedir)/src/test/resources diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index 4b2f3493bf..b6f4542785 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-util-ajax</artifactId> <name>Jetty :: Utilities :: Ajax(JSON)</name> <description>JSON/Ajax Utility classes for Jetty</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.util.ajax</bundle-symbolic-name> </properties> diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index b9d49b5d37..a201f0aaa6 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-util</artifactId> <name>Jetty :: Utilities</name> <description>Utility classes for Jetty</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.util</bundle-symbolic-name> </properties> diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index 85ee7a6327..198e9e747a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -84,7 +84,7 @@ import java.nio.charset.Charset; */ public class BufferUtil { - static final int TEMP_BUFFER_SIZE = 512; + static final int TEMP_BUFFER_SIZE = 4096; static final byte SPACE = 0x20; static final byte MINUS = '-'; static final byte[] DIGIT = diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StacklessLogging.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StacklessLogging.java new file mode 100644 index 0000000000..8d7f2ebbe5 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StacklessLogging.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.util.log; + +/** + * A try-with-resources compatible layer for {@link StdErrLog#setHideStacks(boolean) hiding stacktraces} within the scope of the <code>try</code> block when + * logging with {@link StdErrLog} implementation. + * <p> + * Use of other logging implementation cause no effect when using this class + * <p> + * Example: + * + * <pre> + * try (StacklessLogging scope = new StacklessLogging(EventDriver.class,Noisy.class)) + * { + * doActionThatCausesStackTraces(); + * } + * </pre> + */ +public class StacklessLogging implements AutoCloseable +{ + private final Class<?> clazzes[]; + + public StacklessLogging(Class<?>... classesToSquelch) + { + this.clazzes = classesToSquelch; + hideStacks(true); + } + + @Override + public void close() throws Exception + { + hideStacks(false); + } + + private void hideStacks(boolean hide) + { + for (Class<?> clazz : clazzes) + { + Logger log = Log.getLogger(clazz); + if (log == null) + { + // not interested in classes without loggers + continue; + } + if (log instanceof StdErrLog) + { + // only operate on loggers that are of type StdErrLog + ((StdErrLog)log).setHideStacks(hide); + } + } + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java index 6aa32877ea..0febc2423d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java @@ -157,9 +157,9 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo int size = _threads.size(); if (size > 0) { - LOG.warn("{} threads could not be stopped", size); - - if ((size <= Runtime.getRuntime().availableProcessors()) || LOG.isDebugEnabled()) + Thread.yield(); + + if (LOG.isDebugEnabled()) { for (Thread unstopped : _threads) { @@ -171,6 +171,11 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo LOG.warn("Couldn't stop {}{}", unstopped, dmp.toString()); } } + else + { + for (Thread unstopped : _threads) + LOG.warn("{} Couldn't stop {}",this,unstopped); + } } synchronized (_joinLock) diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index 5f2d0208eb..c2975ebd00 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-webapp</artifactId> <name>Jetty :: Webapp Application Support</name> <description>Jetty web application support</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.webapp</bundle-symbolic-name> </properties> diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index b9e8f15242..26c02b999b 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -11,7 +11,8 @@ <artifactId>websocket-parent</artifactId> <name>Jetty :: Websocket :: Parent</name> <packaging>pom</packaging> - + <url>http://www.eclipse.org/jetty</url> + <modules> <module>websocket-common</module> <module>websocket-api</module> diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java index 07b16dae9c..e805f8614b 100644 --- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java @@ -42,6 +42,7 @@ public class UpgradeRequest private String httpVersion; private String method; private String host; + private boolean secure = false; protected UpgradeRequest() { @@ -225,6 +226,11 @@ public class UpgradeRequest return test.equalsIgnoreCase(getOrigin()); } + public boolean isSecure() + { + return secure; + } + public void setCookies(List<HttpCookie> cookies) { this.cookies = cookies; @@ -261,6 +267,19 @@ public class UpgradeRequest public void setRequestURI(URI uri) { this.requestURI = uri; + String scheme = uri.getScheme(); + if ("ws".equalsIgnoreCase(scheme)) + { + secure = false; + } + else if ("wss".equalsIgnoreCase(scheme)) + { + secure = true; + } + else + { + throw new IllegalArgumentException("URI scheme must be 'ws' or 'wss'"); + } this.host = this.requestURI.getHost(); this.parameters.clear(); } diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java new file mode 100644 index 0000000000..27073cc98b --- /dev/null +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java @@ -0,0 +1,145 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.websocket.api.util; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Objects; + +/** + * Utility methods for converting a {@link URI} between a HTTP(S) and WS(S) URI. + */ +public final class WSURI +{ + /** + * Convert to HTTP <code>http</code> or <code>https</code> scheme URIs. + * <p> + * Converting <code>ws</code> and <code>wss</code> URIs to their HTTP equivalent + * + * @param inputUri + * the input URI + * @return the HTTP scheme URI for the input URI. + * @throws URISyntaxException + * if unable to convert the input URI + */ + public static URI toHttp(final URI inputUri) throws URISyntaxException + { + Objects.requireNonNull(inputUri,"Input URI must not be null"); + String wsScheme = inputUri.getScheme(); + String httpScheme = null; + if ("http".equalsIgnoreCase(wsScheme) || "https".equalsIgnoreCase(wsScheme)) + { + // leave alone + httpScheme = wsScheme; + } + else if ("ws".equalsIgnoreCase(wsScheme)) + { + // convert to http + httpScheme = "http"; + } + else if ("wss".equalsIgnoreCase(wsScheme)) + { + // convert to https + httpScheme = "https"; + } + else + { + throw new URISyntaxException(inputUri.toString(),"Unrecognized WebSocket scheme"); + } + + return new URI(httpScheme,inputUri.getUserInfo(),inputUri.getHost(),inputUri.getPort(),inputUri.getPath(),inputUri.getQuery(),inputUri.getFragment()); + } + + /** + * Convert to WebSocket <code>ws</code> or <code>wss</code> scheme URIs + * <p> + * Converting <code>http</code> and <code>https</code> URIs to their WebSocket equivalent + * + * @param inputUrl + * the input URI + * @return the WebSocket scheme URI for the input URI. + * @throws URISyntaxException + * if unable to convert the input URI + */ + public static URI toWebsocket(CharSequence inputUrl) throws URISyntaxException + { + return toWebsocket(new URI(inputUrl.toString())); + } + + /** + * Convert to WebSocket <code>ws</code> or <code>wss</code> scheme URIs + * <p> + * Converting <code>http</code> and <code>https</code> URIs to their WebSocket equivalent + * + * @param inputUrl + * the input URI + * @param query + * the optional query string + * @return the WebSocket scheme URI for the input URI. + * @throws URISyntaxException + * if unable to convert the input URI + */ + public static URI toWebsocket(CharSequence inputUrl, String query) throws URISyntaxException + { + if (query == null) + { + return toWebsocket(new URI(inputUrl.toString())); + } + return toWebsocket(new URI(inputUrl.toString() + '?' + query)); + } + + /** + * Convert to WebSocket <code>ws</code> or <code>wss</code> scheme URIs + * + * <p> + * Converting <code>http</code> and <code>https</code> URIs to their WebSocket equivalent + * + * @param inputUri + * the input URI + * @return the WebSocket scheme URI for the input URI. + * @throws URISyntaxException + * if unable to convert the input URI + */ + public static URI toWebsocket(final URI inputUri) throws URISyntaxException + { + Objects.requireNonNull(inputUri,"Input URI must not be null"); + String httpScheme = inputUri.getScheme(); + String wsScheme = null; + if ("ws".equalsIgnoreCase(httpScheme) || "wss".equalsIgnoreCase(httpScheme)) + { + // keep as-is + wsScheme = httpScheme; + } + else if ("http".equalsIgnoreCase(httpScheme)) + { + // convert to ws + wsScheme = "ws"; + } + else if ("https".equalsIgnoreCase(httpScheme)) + { + // convert to wss + wsScheme = "wss"; + } + else + { + throw new URISyntaxException(inputUri.toString(),"Unrecognized HTTP scheme"); + } + return new URI(wsScheme,inputUri.getUserInfo(),inputUri.getHost(),inputUri.getPort(),inputUri.getPath(),inputUri.getQuery(),inputUri.getFragment()); + } +} diff --git a/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/WSURITest.java b/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/WSURITest.java new file mode 100644 index 0000000000..a4aac8ea61 --- /dev/null +++ b/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/WSURITest.java @@ -0,0 +1,88 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.websocket.api.util; + +import static org.hamcrest.Matchers.*; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.junit.Assert; +import org.junit.Test; + +public class WSURITest +{ + private void assertURI(URI actual, URI expected) + { + Assert.assertThat(actual.toASCIIString(),is(expected.toASCIIString())); + } + + @Test + public void testHttpsToHttps() throws URISyntaxException + { + assertURI(WSURI.toHttp(URI.create("https://localhost/")),URI.create("https://localhost/")); + } + + @Test + public void testHttpsToWss() throws URISyntaxException + { + assertURI(WSURI.toWebsocket(URI.create("https://localhost/")),URI.create("wss://localhost/")); + } + + @Test + public void testHttpToHttp() throws URISyntaxException + { + assertURI(WSURI.toHttp(URI.create("http://localhost/")),URI.create("http://localhost/")); + } + + @Test + public void testHttpToWs() throws URISyntaxException + { + assertURI(WSURI.toWebsocket(URI.create("http://localhost/")),URI.create("ws://localhost/")); + assertURI(WSURI.toWebsocket(URI.create("http://localhost:8080/deeper/")),URI.create("ws://localhost:8080/deeper/")); + assertURI(WSURI.toWebsocket("http://localhost/"),URI.create("ws://localhost/")); + assertURI(WSURI.toWebsocket("http://localhost/",null),URI.create("ws://localhost/")); + assertURI(WSURI.toWebsocket("http://localhost/","a=b"),URI.create("ws://localhost/?a=b")); + } + + @Test + public void testWssToHttps() throws URISyntaxException + { + assertURI(WSURI.toHttp(URI.create("wss://localhost/")),URI.create("https://localhost/")); + } + + @Test + public void testWssToWss() throws URISyntaxException + { + assertURI(WSURI.toWebsocket(URI.create("wss://localhost/")),URI.create("wss://localhost/")); + } + + @Test + public void testWsToHttp() throws URISyntaxException + { + assertURI(WSURI.toHttp(URI.create("ws://localhost/")),URI.create("http://localhost/")); + } + + @Test + public void testWsToWs() throws URISyntaxException + { + assertURI(WSURI.toWebsocket(URI.create("ws://localhost/")),URI.create("ws://localhost/")); + } + +} diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java index 9144de9757..b17008a7f6 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java @@ -104,7 +104,7 @@ public class WebSocketClientSelectorManager extends SelectorManager } catch (IOException e) { - LOG.debug(e); + LOG.ignore(e); connectPromise.failed(e); // rethrow throw e; @@ -120,7 +120,7 @@ public class WebSocketClientSelectorManager extends SelectorManager public SSLEngine newSSLEngine(SslContextFactory sslContextFactory, SocketChannel channel) { - String peerHost = channel.socket().getInetAddress().getHostAddress(); + String peerHost = channel.socket().getInetAddress().getHostName(); int peerPort = channel.socket().getPort(); SSLEngine engine = sslContextFactory.newSSLEngine(peerHost,peerPort); engine.setUseClientMode(true); diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java index 7ca103d5b2..282c05f026 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java @@ -245,11 +245,14 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc @Override public RemoteEndpoint getRemote() { - if (!isOpen()) + ConnectionState state = connection.getIOState().getConnectionState(); + + if ((state == ConnectionState.OPEN) || (state == ConnectionState.CONNECTED)) { - throw new WebSocketException("Session has not been opened yet"); + return remote; } - return remote; + + throw new WebSocketException("RemoteEndpoint unavailable, current state [" + state + "], expecting [OPEN or CONNECTED]"); } @Override diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java index d217937d47..5461df4188 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java @@ -163,7 +163,14 @@ public abstract class EventDriver implements IncomingFrames { LOG.debug("openSession({})",session); this.session = session; - this.onConnect(); + try + { + this.onConnect(); + } + catch (Throwable t) + { + unhandled(t); + } } protected void terminateConnection(int statusCode, String rawreason) @@ -177,6 +184,7 @@ public abstract class EventDriver implements IncomingFrames private void unhandled(Throwable t) { LOG.warn("Unhandled Error (closing connection)",t); + onError(t); // Unhandled Error, close the connection. switch (policy.getBehavior()) diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml index d821deed89..a2551bdf1e 100644 --- a/jetty-websocket/websocket-server/pom.xml +++ b/jetty-websocket/websocket-server/pom.xml @@ -39,6 +39,11 @@ </dependency> <dependency> <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> <artifactId>websocket-servlet</artifactId> <version>${project.version}</version> </dependency> diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java index bd177d78cf..aee3a73aa1 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java @@ -24,6 +24,8 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.common.AcceptHash; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; /** * WebSocket Handshake for <a href="https://tools.ietf.org/html/rfc6455">RFC 6455</a>. @@ -34,7 +36,7 @@ public class HandshakeRFC6455 implements WebSocketHandshake public static final int VERSION = 13; @Override - public void doHandshakeResponse(ServletWebSocketRequest request, ServletWebSocketResponse response) throws IOException + public void doHandshakeResponse(ServletUpgradeRequest request, ServletUpgradeResponse response) throws IOException { String key = request.getHeader("Sec-WebSocket-Key"); diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java index e274c963ee..00f3b6265d 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java @@ -18,242 +18,20 @@ package org.eclipse.jetty.websocket.server; -import java.net.HttpCookie; -import java.net.InetSocketAddress; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.net.URISyntaxException; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; -import org.eclipse.jetty.websocket.api.UpgradeRequest; -import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; -import org.eclipse.jetty.websocket.api.util.QuoteUtil; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; -public class ServletWebSocketRequest extends UpgradeRequest +/** + * @deprecated use {@link org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest} instead + */ +@Deprecated +public class ServletWebSocketRequest extends ServletUpgradeRequest { - private HttpServletRequest req; - - public ServletWebSocketRequest(HttpServletRequest request) - { - super(request.getRequestURI()); - this.req = request; - - // Copy Request Line Details - setMethod(request.getMethod()); - setHttpVersion(request.getProtocol()); - - // Copy parameters - super.setParameterMap(request.getParameterMap()); - - // Copy Cookies - Cookie rcookies[] = request.getCookies(); - if (rcookies != null) - { - List<HttpCookie> cookies = new ArrayList<>(); - for (Cookie rcookie : rcookies) - { - HttpCookie hcookie = new HttpCookie(rcookie.getName(),rcookie.getValue()); - // no point handling domain/path/expires/secure/httponly on client request cookies - cookies.add(hcookie); - } - super.setCookies(cookies); - } - - // Copy Headers - Enumeration<String> headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) - { - String name = headerNames.nextElement(); - Enumeration<String> valuesEnum = request.getHeaders(name); - List<String> values = new ArrayList<>(); - while (valuesEnum.hasMoreElements()) - { - values.add(valuesEnum.nextElement()); - } - setHeader(name,values); - } - - // Parse Sub Protocols - Enumeration<String> protocols = request.getHeaders("Sec-WebSocket-Protocol"); - List<String> subProtocols = new ArrayList<>(); - String protocol = null; - while ((protocol == null) && (protocols != null) && protocols.hasMoreElements()) - { - String candidate = protocols.nextElement(); - for (String p : parseProtocols(candidate)) - { - subProtocols.add(p); - } - } - setSubProtocols(subProtocols); - - // Parse Extension Configurations - Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions"); - while (e.hasMoreElements()) - { - Iterator<String> extTokenIter = QuoteUtil.splitAt(e.nextElement(),","); - while (extTokenIter.hasNext()) - { - String extToken = extTokenIter.next(); - ExtensionConfig config = ExtensionConfig.parse(extToken); - addExtensions(config); - } - } - } - - /** - * Equivalent to {@link HttpServletRequest#getLocalAddr()} - * - * @return the local address - */ - public String getLocalAddress() - { - return req.getLocalAddr(); - } - - /** - * Equivalent to {@link HttpServletRequest#getLocalName()} - * - * @return the local host name - */ - public String getLocalHostName() - { - return req.getLocalName(); - } - - /** - * Equivalent to {@link HttpServletRequest#getLocalPort()} - * - * @return the local port - */ - public int getLocalPort() - { - return req.getLocalPort(); - } - - /** - * Return a {@link InetSocketAddress} for the local socket. - * <p> - * Warning: this can cause a DNS lookup - * - * @return the local socket address - */ - public InetSocketAddress getLocalSocketAddress() - { - return new InetSocketAddress(req.getLocalAddr(),req.getLocalPort()); - } - - public Principal getPrincipal() - { - return req.getUserPrincipal(); - } - - /** - * Equivalent to {@link HttpServletRequest#getRemoteAddr()} - * - * @return the remote address - */ - public String getRemoteAddress() - { - return req.getRemoteAddr(); - } - - /** - * Equivalent to {@link HttpServletRequest#getRemoteHost()} - * - * @return the remote host name - */ - public String getRemoteHostName() - { - return req.getRemoteHost(); - } - - /** - * Equivalent to {@link HttpServletRequest#getRemotePort()} - * - * @return the remote port - */ - public int getRemotePort() - { - return req.getRemotePort(); - } - - /** - * Return a {@link InetSocketAddress} for the remote socket. - * <p> - * Warning: this can cause a DNS lookup - * - * @return the remote socket address - */ - public InetSocketAddress getRemoteSocketAddress() - { - return new InetSocketAddress(req.getRemoteAddr(),req.getRemotePort()); - } - - public Map<String, Object> getServletAttributes() - { - Map<String, Object> attributes = new HashMap<String, Object>(); - - for (String name : Collections.list(req.getAttributeNames())) - { - attributes.put(name,req.getAttribute(name)); - } - - return attributes; - } - - public Map<String, List<String>> getServletParameters() - { - Map<String, List<String>> parameters = new HashMap<String, List<String>>(); - - for (String name : Collections.list(req.getParameterNames())) - { - parameters.put(name,Collections.unmodifiableList(Arrays.asList(req.getParameterValues(name)))); - } - - return parameters; - } - - /** - * Return the HttpSession if it exists. - * <p> - * Note: this is equivalent to {@link HttpServletRequest#getSession()} and will not create a new HttpSession. - */ - @Override - public Object getSession() - { - return this.req.getSession(false); - } - - protected String[] parseProtocols(String protocol) - { - if (protocol == null) - { - return new String[] - { null }; - } - protocol = protocol.trim(); - if ((protocol == null) || (protocol.length() == 0)) - { - return new String[] - { null }; - } - String[] passed = protocol.split("\\s*,\\s*"); - String[] protocols = new String[passed.length + 1]; - System.arraycopy(passed,0,protocols,0,passed.length); - return protocols; - } - - public void setServletAttribute(String name, Object o) + public ServletWebSocketRequest(HttpServletRequest request) throws URISyntaxException { - this.req.setAttribute(name,o); + super(request); } } diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketResponse.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketResponse.java index 0bf797ed0f..609c810d50 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketResponse.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketResponse.java @@ -18,66 +18,18 @@ package org.eclipse.jetty.websocket.server; -import java.io.IOException; - import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.websocket.api.UpgradeResponse; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; -public class ServletWebSocketResponse extends UpgradeResponse +/** + * @deprecated use {@link org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse} instead + */ +@Deprecated +public class ServletWebSocketResponse extends ServletUpgradeResponse { - private HttpServletResponse resp; - public ServletWebSocketResponse(HttpServletResponse resp) { - super(); - this.resp = resp; - } - - @Override - public void addHeader(String name, String value) - { - this.resp.addHeader(name,value); - } - - @Override - public int getStatusCode() - { - return this.resp.getStatus(); - } - - @Override - public String getStatusReason() - { - throw new UnsupportedOperationException("Server cannot get Status Reason Message"); - } - - public boolean isCommitted() - { - return this.resp.isCommitted(); - } - - public void sendError(int statusCode, String message) throws IOException - { - setSuccess(false); - this.resp.sendError(statusCode,message); - } - - @Override - public void sendForbidden(String message) throws IOException - { - setSuccess(false); - resp.sendError(HttpServletResponse.SC_FORBIDDEN,message); - } - - @Override - public void setHeader(String name, String value) - { - this.resp.setHeader(name,value); - } - - public void setStatus(int status) - { - this.resp.setStatus(status); + super(resp); } } diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java index b41ab7f55f..e7f6fb6abe 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java @@ -20,6 +20,9 @@ package org.eclipse.jetty.websocket.server; import java.io.IOException; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; + public interface WebSocketHandshake { /** @@ -29,5 +32,5 @@ public interface WebSocketHandshake * @param response * @param acceptedSubProtocol */ - public void doHandshakeResponse(ServletWebSocketRequest request, ServletWebSocketResponse response) throws IOException; + public void doHandshakeResponse(ServletUpgradeRequest request, ServletUpgradeResponse response) throws IOException; } diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java index edffd2f172..badda0c084 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.websocket.server; import java.io.IOException; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -51,6 +53,8 @@ import org.eclipse.jetty.websocket.common.events.EventDriver; import org.eclipse.jetty.websocket.common.events.EventDriverFactory; import org.eclipse.jetty.websocket.common.extensions.ExtensionStack; import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; import org.eclipse.jetty.websocket.servlet.WebSocketCreator; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; @@ -134,38 +138,45 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc @Override public boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException { - ServletWebSocketRequest sockreq = new ServletWebSocketRequest(request); - ServletWebSocketResponse sockresp = new ServletWebSocketResponse(response); + try + { + ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request); + ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response); - WebSocketCreator creator = getCreator(); + WebSocketCreator creator = getCreator(); - UpgradeContext context = getActiveUpgradeContext(); - if (context == null) - { - context = new UpgradeContext(); - setActiveUpgradeContext(context); - } - context.setRequest(sockreq); - context.setResponse(sockresp); + UpgradeContext context = getActiveUpgradeContext(); + if (context == null) + { + context = new UpgradeContext(); + setActiveUpgradeContext(context); + } + context.setRequest(sockreq); + context.setResponse(sockresp); - Object websocketPojo = creator.createWebSocket(sockreq,sockresp); + Object websocketPojo = creator.createWebSocket(sockreq,sockresp); - // Handle response forbidden (and similar paths) - if (sockresp.isCommitted()) - { - return false; - } + // Handle response forbidden (and similar paths) + if (sockresp.isCommitted()) + { + return false; + } - if (websocketPojo == null) + if (websocketPojo == null) + { + // no creation, sorry + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return false; + } + + // Send the upgrade + EventDriver driver = eventDriverFactory.wrap(websocketPojo); + return upgrade(sockreq,sockresp,driver); + } + catch (URISyntaxException e) { - // no creation, sorry - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); - return false; + throw new IOException("Unable to accept websocket due to mangled URI",e); } - - // Send the upgrade - EventDriver driver = eventDriverFactory.wrap(websocketPojo); - return upgrade(sockreq,sockresp,driver); } @Override @@ -307,7 +318,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc /* * (non-Javadoc) - * + * * @see org.eclipse.jetty.websocket.server.WebSocketServletFactory#register(java.lang.Class) */ @Override @@ -348,7 +359,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc * <p> * This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the * connection. - * + * * @param request * The request to upgrade * @param response @@ -357,7 +368,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc * The websocket handler implementation to use * @throws IOException */ - public boolean upgrade(ServletWebSocketRequest request, ServletWebSocketResponse response, EventDriver driver) throws IOException + public boolean upgrade(ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver) throws IOException { if (!"websocket".equalsIgnoreCase(request.getHeader("Upgrade"))) { diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java index 49866d30ff..b28d79f7f6 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java @@ -57,6 +57,7 @@ public class RequestHeadersTest return lastRequest; } + @SuppressWarnings("unused") public UpgradeResponse getLastResponse() { return lastResponse; diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java index ea9fe44d3a..5304e5f41f 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java @@ -19,35 +19,95 @@ package org.eclipse.jetty.websocket.server; import java.net.URI; + import javax.servlet.http.HttpServlet; -import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.ssl.SslContextFactory; public class SimpleServletServer { + private static final Logger LOG = Log.getLogger(SimpleServletServer.class); private Server server; private ServerConnector connector; private URI serverUri; private HttpServlet servlet; + private boolean ssl = false; + private SslContextFactory sslContextFactory; public SimpleServletServer(HttpServlet servlet) { this.servlet = servlet; } + public void enableSsl(boolean ssl) + { + this.ssl = ssl; + } + public URI getServerUri() { return serverUri; } + public SslContextFactory getSslContextFactory() + { + return sslContextFactory; + } + + public boolean isSslEnabled() + { + return ssl; + } + public void start() throws Exception { // Configure Server server = new Server(); - connector = new ServerConnector(server); + if (ssl) + { + // HTTP Configuration + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setSecureScheme("https"); + http_config.setSecurePort(0); + http_config.setOutputBufferSize(32768); + http_config.setRequestHeaderSize(8192); + http_config.setResponseHeaderSize(8192); + http_config.setSendServerVersion(true); + http_config.setSendDateHeader(false); + + sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath()); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setKeyManagerPassword("keypwd"); + sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA","SSL_DHE_RSA_WITH_DES_CBC_SHA","SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5","SSL_RSA_EXPORT_WITH_DES40_CBC_SHA","SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + + // SSL HTTP Configuration + HttpConfiguration https_config = new HttpConfiguration(http_config); + https_config.addCustomizer(new SecureRequestCustomizer()); + + // SSL Connector + connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,"http/1.1"),new HttpConnectionFactory(https_config)); + connector.setPort(0); + } + else + { + // Basic HTTP connector + connector = new ServerConnector(server); + connector.setPort(0); + } server.addConnector(connector); ServletContextHandler context = new ServletContextHandler(); @@ -60,13 +120,20 @@ public class SimpleServletServer // Start Server server.start(); + // Establish the Server URI String host = connector.getHost(); if (host == null) { host = "localhost"; } int port = connector.getLocalPort(); - serverUri = new URI(String.format("ws://%s:%d/",host,port)); + serverUri = new URI(String.format("%s://%s:%d/",ssl?"wss":"ws",host,port)); + + // Some debugging + if (LOG.isDebugEnabled()) + { + LOG.debug(server.dump()); + } } public void stop() diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java index 00c001bcd2..aafdea8946 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java @@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.UpgradeRequest; @@ -36,6 +37,7 @@ import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.events.EventDriver; import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture; import org.eclipse.jetty.websocket.server.helper.RFCSocket; @@ -52,6 +54,30 @@ import org.junit.Test; */ public class WebSocketCloseTest { + static class AbstractCloseSocket extends WebSocketAdapter + { + public CountDownLatch closeLatch = new CountDownLatch(1); + public String closeReason = null; + public int closeStatusCode = -1; + public List<Throwable> errors = new ArrayList<>(); + + @Override + public void onWebSocketClose(int statusCode, String reason) + { + LOG.debug("onWebSocketClose({}, {})",statusCode,reason); + this.closeStatusCode = statusCode; + this.closeReason = reason; + closeLatch.countDown(); + } + + @Override + public void onWebSocketError(Throwable cause) + { + errors.add(cause); + } + + } + @SuppressWarnings("serial") public static class CloseServlet extends WebSocketServlet implements WebSocketCreator { @@ -66,28 +92,25 @@ public class WebSocketCloseTest { if (req.hasSubProtocol("fastclose")) { - fastcloseSocket = new FastCloseSocket(); - return fastcloseSocket; + closeSocket = new FastCloseSocket(); + return closeSocket; + } + + if (req.hasSubProtocol("fastfail")) + { + closeSocket = new FastFailSocket(); + return closeSocket; } return new RFCSocket(); } } - public static class FastCloseSocket extends WebSocketAdapter + /** + * On Connect, close socket + */ + public static class FastCloseSocket extends AbstractCloseSocket { - public CountDownLatch closeLatch = new CountDownLatch(1); - public String closeReason = null; - public int closeStatusCode = -1; - public List<Throwable> errors = new ArrayList<>(); - - @Override - public void onWebSocketClose(int statusCode, String reason) - { - LOG.debug("onWebSocketClose({}, {})",statusCode,reason); - this.closeStatusCode = statusCode; - this.closeReason = reason; - closeLatch.countDown(); - } + private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastCloseSocket.class); @Override public void onWebSocketConnect(Session sess) @@ -102,6 +125,21 @@ public class WebSocketCloseTest e.printStackTrace(System.err); } } + } + + /** + * On Connect, throw unhandled exception + */ + public static class FastFailSocket extends AbstractCloseSocket + { + private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastFailSocket.class); + + @Override + public void onWebSocketConnect(Session sess) + { + LOG.debug("onWebSocketConnect({})",sess); + throw new RuntimeException("Intentional FastFail"); + } @Override public void onWebSocketError(Throwable cause) @@ -111,8 +149,9 @@ public class WebSocketCloseTest } private static final Logger LOG = Log.getLogger(WebSocketCloseTest.class); + private static SimpleServletServer server; - private static FastCloseSocket fastcloseSocket; + private static AbstractCloseSocket closeSocket; @BeforeClass public static void startServer() throws Exception @@ -150,8 +189,44 @@ public class WebSocketCloseTest client.write(close.asFrame()); // respond with close - Assert.assertThat("Fast Close Latch",fastcloseSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true)); - Assert.assertThat("Fast Close.statusCode",fastcloseSocket.closeStatusCode,is(StatusCode.NORMAL)); + Assert.assertThat("Fast Close Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true)); + Assert.assertThat("Fast Close.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL)); + } + finally + { + client.close(); + } + } + + /** + * Test fast fail (bug #410537) + */ + @Test + public void testFastFail() throws Exception + { + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.setProtocols("fastfail"); + client.setTimeout(TimeUnit.SECONDS,1); + try + { + try (StacklessLogging scope = new StacklessLogging(EventDriver.class)) + { + client.connect(); + client.sendStandardRequest(); + client.expectUpgradeResponse(); + + IncomingFramesCapture capture = client.readFrames(1,TimeUnit.SECONDS,1); + WebSocketFrame frame = capture.getFrames().poll(); + Assert.assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.CLOSE)); + CloseInfo close = new CloseInfo(frame); + Assert.assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.SERVER_ERROR)); + + client.write(close.asFrame()); // respond with close + + Assert.assertThat("Fast Fail Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true)); + Assert.assertThat("Fast Fail.statusCode",closeSocket.closeStatusCode,is(StatusCode.SERVER_ERROR)); + Assert.assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1)); + } } finally { diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketLoadRFC6455Test.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketLoadRFC6455Test.java deleted file mode 100644 index fec70b0b2d..0000000000 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketLoadRFC6455Test.java +++ /dev/null @@ -1,222 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2013 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.websocket.server; - -import static org.junit.Assert.*; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.lang.management.ManagementFactory; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.websocket.api.WebSocketBehavior; -import org.eclipse.jetty.websocket.api.WebSocketException; -import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.api.extensions.IncomingFrames; -import org.eclipse.jetty.websocket.common.Generator; -import org.eclipse.jetty.websocket.common.Parser; -import org.eclipse.jetty.websocket.common.WebSocketFrame; -import org.eclipse.jetty.websocket.server.examples.MyEchoSocket; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -public class WebSocketLoadRFC6455Test -{ - private class WebSocketClient implements Runnable - { - private final Socket socket; - private final BufferedWriter output; - private final BufferedReader input; - private final int iterations; - private final CountDownLatch latch; - private/* final */EndPoint _endp; - private final Generator _generator; - private final Parser _parser; - private final IncomingFrames _handler = new IncomingFrames() - { - @Override - public void incomingError(WebSocketException e) - { - } - - @Override - public void incomingFrame(Frame frame) - { - } - }; - private volatile ByteBuffer _response; - - public WebSocketClient(String host, int port, int readTimeout, CountDownLatch latch, int iterations) throws IOException - { - this.latch = latch; - socket = new Socket(host,port); - socket.setSoTimeout(readTimeout); - output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"ISO-8859-1")); - input = new BufferedReader(new InputStreamReader(socket.getInputStream(),"ISO-8859-1")); - this.iterations = iterations; - - WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT); - - // _endp=new SocketEndPoint(socket); - ByteBufferPool bufferPool = new MappedByteBufferPool(); - _generator = new Generator(policy,bufferPool); - _parser = new Parser(policy,bufferPool); - - } - - public void close() throws IOException - { - socket.close(); - } - - private void open() throws IOException - { - output.write("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" - + "Sec-WebSocket-Protocol: onConnect\r\n" + "Sec-WebSocket-Version: 7\r\n" + "\r\n"); - output.flush(); - - String responseLine = input.readLine(); - assertTrue(responseLine.startsWith("HTTP/1.1 101 Switching Protocols")); - // Read until we find an empty line, which signals the end of the http response - String line; - while ((line = input.readLine()) != null) - { - if (line.length() == 0) - { - break; - } - } - } - - @Override - public void run() - { - try - { - String message = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; - for (int i = 0; i < iterations; ++i) - { - WebSocketFrame txt = WebSocketFrame.text(message); - ByteBuffer buf = _generator.generate(txt); - - // TODO: Send it - // TODO: Receive response - - Assert.assertEquals(message,_response.toString()); - latch.countDown(); - } - } - catch (Throwable x) - { - throw new RuntimeException(x); - } - } - } - - private static Server _server; - - private static ServerConnector _connector; - - @BeforeClass - public static void startServer() throws Exception - { - QueuedThreadPool threadPool = new QueuedThreadPool(200); - threadPool.setStopTimeout(1000); - _server = new Server(threadPool); - _server.manage(threadPool); - - _connector = new ServerConnector(_server); - _server.addConnector(_connector); - - WebSocketHandler wsHandler = new WebSocketHandler.Simple(MyEchoSocket.class); - wsHandler.setHandler(new DefaultHandler()); - _server.setHandler(wsHandler); - - _server.start(); - } - - @AfterClass - public static void stopServer() throws Exception - { - _server.stop(); - _server.join(); - } - - @Test - @Ignore("Not yet converted to new jetty-9 structure") - public void testLoad() throws Exception - { - int count = 50; - int iterations = 100; - - ExecutorService threadPool = Executors.newCachedThreadPool(); - try - { - CountDownLatch latch = new CountDownLatch(count * iterations); - WebSocketClient[] clients = new WebSocketClient[count]; - for (int i = 0; i < clients.length; ++i) - { - clients[i] = new WebSocketClient("localhost",_connector.getLocalPort(),1000,latch,iterations); - clients[i].open(); - } - - // long start = System.nanoTime(); - for (WebSocketClient client : clients) - { - threadPool.execute(client); - } - - int parallelism = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); - long maxTimePerIteration = 5; - assertTrue(latch.await(iterations * ((count / parallelism) + 1) * maxTimePerIteration,TimeUnit.MILLISECONDS)); - // long end = System.nanoTime(); - // System.err.println("Elapsed: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - for (WebSocketClient client : clients) - { - client.close(); - } - } - finally - { - threadPool.shutdown(); - assertTrue(threadPool.awaitTermination(2,TimeUnit.SECONDS)); - } - } -} diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java index 56218c50d9..4297ca1bc8 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java @@ -18,155 +18,145 @@ package org.eclipse.jetty.websocket.server; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; +import static org.hamcrest.Matchers.*; + +import java.net.URI; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.toolchain.test.EventQueue; import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WebSocketAdapter; -import org.eclipse.jetty.websocket.server.examples.MyEchoSocket; -import org.junit.After; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.helper.CaptureSocket; +import org.eclipse.jetty.websocket.server.helper.SessionServlet; +import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Ignore; +import org.junit.BeforeClass; import org.junit.Test; public class WebSocketOverSSLTest { - private Server _server; - private int _port; - private QueuedThreadPool _threadPool; + private static SimpleServletServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new SimpleServletServer(new SessionServlet()); + server.enableSsl(true); + server.start(); + } - private Session _session; + @AfterClass + public static void stopServer() + { + server.stop(); + } - @After - public void destroy() throws Exception + /** + * Test the requirement of issuing socket and receiving echo response + */ + @Test + public void testEcho() throws Exception { - if (_session != null) + Assert.assertThat("server scheme",server.getServerUri().getScheme(),is("wss")); + WebSocketClient client = new WebSocketClient(server.getSslContextFactory()); + try { - _session.close(); - } + client.start(); - // if (_wsFactory != null) - // _wsFactory.stop(); + CaptureSocket clientSocket = new CaptureSocket(); + Future<Session> fut = client.connect(clientSocket,server.getServerUri()); - if (_threadPool != null) - { - _threadPool.stop(); - } + // wait for connect + Session session = fut.get(1,TimeUnit.SECONDS); + + // Generate text frame + String msg = "this is an echo ... cho ... ho ... o"; + session.getRemote().sendString(msg); + + // Read frame (hopefully text frame) + clientSocket.messages.awaitEventCount(1,500,TimeUnit.MILLISECONDS); + EventQueue<String> captured = clientSocket.messages; + Assert.assertThat("Text Message",captured.poll(),is(msg)); - if (_server != null) + // Shutdown the socket + clientSocket.close(); + } + finally { - _server.stop(); - _server.join(); + client.stop(); } } - private void startClient(final Object webSocket) throws Exception + /** + * Test that server session reports as secure + */ + @Test + public void testServerSessionIsSecure() throws Exception { - Assert.assertTrue(_server.isStarted()); + Assert.assertThat("server scheme",server.getServerUri().getScheme(),is("wss")); + WebSocketClient client = new WebSocketClient(server.getSslContextFactory()); + try + { + client.start(); - _threadPool = new QueuedThreadPool(); - _threadPool.setName("wsc-" + _threadPool.getName()); - _threadPool.start(); + CaptureSocket clientSocket = new CaptureSocket(); + Future<Session> fut = client.connect(clientSocket,server.getServerUri()); - // _wsFactory = new WebSocketClientFactory(_threadPool, new ZeroMasker()); - // SslContextFactory cf = _wsFactory.getSslContextFactory(); - // cf.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath()); - // cf.setKeyStorePassword("storepwd"); - // cf.setKeyManagerPassword("keypwd"); - // _wsFactory.start(); + // wait for connect + Session session = fut.get(3,TimeUnit.SECONDS); - // WebSocketClient client = new WebSocketClient(_wsFactory); - // _connection = client.open(new URI("wss://localhost:" + _port), webSocket).get(5, TimeUnit.SECONDS); - } + // Generate text frame + session.getRemote().sendString("session.isSecure"); - private void startServer(final Object websocket) throws Exception - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath()); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setKeyManagerPassword("keypwd"); - _server = new Server(); - ServerConnector connector = new ServerConnector(_server,sslContextFactory); - _server.addConnector(connector); - _server.setHandler(new WebSocketHandler.Simple(websocket.getClass())); - _server.start(); - _port = connector.getLocalPort(); - } + // Read frame (hopefully text frame) + clientSocket.messages.awaitEventCount(1,500,TimeUnit.MILLISECONDS); + EventQueue<String> captured = clientSocket.messages; + Assert.assertThat("Server.session.isSecure",captured.poll(),is("session.isSecure=true")); - @Test - @Ignore("SSL Not yet implemented") - public void testManyMessages() throws Exception - { - startServer(MyEchoSocket.class); - int count = 1000; - final CountDownLatch clientLatch = new CountDownLatch(count); - startClient(new WebSocketAdapter() - { - @Override - public void onWebSocketText(String message) - { - clientLatch.countDown(); - } - }); - - char[] chars = new char[256]; - Arrays.fill(chars,'x'); - String message = new String(chars); - for (int i = 0; i < count; ++i) + // Shutdown the socket + clientSocket.close(); + } + finally { - _session.getRemote().sendStringByFuture(message); + client.stop(); } - - Assert.assertTrue(clientLatch.await(20,TimeUnit.SECONDS)); - - // While messages may have all arrived, the SSL close alert - // may be in the way so give some time for it to be processed. - TimeUnit.SECONDS.sleep(1); } + /** + * Test that server session.upgradeRequest.requestURI reports correctly + */ @Test - @Ignore("SSL Not yet implemented") - public void testWebSocketOverSSL() throws Exception + public void testServerSessionRequestURI() throws Exception { - final String message = "message"; - final CountDownLatch serverLatch = new CountDownLatch(1); - startServer(new WebSocketAdapter() + Assert.assertThat("server scheme",server.getServerUri().getScheme(),is("wss")); + WebSocketClient client = new WebSocketClient(server.getSslContextFactory()); + try { - private Session session; - - @Override - public void onWebSocketConnect(Session session) - { - this.session = session; - } - - @Override - public void onWebSocketText(String message) - { - Assert.assertEquals(message,message); - session.getRemote().sendStringByFuture(message); - serverLatch.countDown(); - } - }); - final CountDownLatch clientLatch = new CountDownLatch(1); - startClient(new WebSocketAdapter() + client.start(); + + CaptureSocket clientSocket = new CaptureSocket(); + URI requestUri = server.getServerUri().resolve("/deep?a=b"); + Future<Session> fut = client.connect(clientSocket,requestUri); + + // wait for connect + Session session = fut.get(3,TimeUnit.SECONDS); + + // Generate text frame + session.getRemote().sendString("session.upgradeRequest.requestURI"); + + // Read frame (hopefully text frame) + clientSocket.messages.awaitEventCount(1,500,TimeUnit.MILLISECONDS); + EventQueue<String> captured = clientSocket.messages; + String expected = String.format("session.upgradeRequest.requestURI=%s",requestUri.toASCIIString()); + Assert.assertThat("session.upgradeRequest.requestURI",captured.poll(),is(expected)); + + // Shutdown the socket + clientSocket.close(); + } + finally { - @Override - public void onWebSocketText(String data) - { - Assert.assertEquals(message,data); - clientLatch.countDown(); - } - }); - _session.getRemote().sendStringByFuture(message); - - Assert.assertTrue(serverLatch.await(5,TimeUnit.SECONDS)); - Assert.assertTrue(clientLatch.await(5,TimeUnit.SECONDS)); + client.stop(); + } } } diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java index 8ca6db30d5..7d94243657 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java @@ -163,7 +163,7 @@ public class WebSocketServletRFCTest } /** - * Test the requirement of issuing + * Test the requirement of issuing socket and receiving echo response */ @Test public void testEcho() throws Exception diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java index fcb40ffe70..4b1f7358a0 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java @@ -55,6 +55,7 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.api.extensions.Frame; import org.eclipse.jetty.websocket.api.extensions.IncomingFrames; import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames; +import org.eclipse.jetty.websocket.api.util.WSURI; import org.eclipse.jetty.websocket.common.AcceptHash; import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.ConnectionState; @@ -128,9 +129,12 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames, Connecti if (destWebsocketURI.getScheme().equals("wss")) { scheme = "https"; + throw new RuntimeException("Sorry, BlockheadClient does not support SSL"); } - this.destHttpURI = new URI(scheme,destWebsocketURI.getUserInfo(),destWebsocketURI.getHost(),destWebsocketURI.getPort(),destWebsocketURI.getPath(), - destWebsocketURI.getQuery(),destWebsocketURI.getFragment()); + this.destHttpURI = WSURI.toHttp(destWebsocketURI); + + LOG.debug("WebSocket URI: {}",destWebsocketURI); + LOG.debug(" HTTP URI: {}",destHttpURI); this.bufferPool = new MappedByteBufferPool(8192); this.generator = new Generator(policy,bufferPool); diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClientConstructionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClientConstructionTest.java index c1e1d502bf..5a384911ed 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClientConstructionTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClientConstructionTest.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.websocket.server.blockhead; +import static org.hamcrest.Matchers.*; + import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -30,8 +32,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static org.hamcrest.Matchers.is; - /** * Gotta test some basic constructors of the BlockheadClient. */ @@ -47,7 +47,6 @@ public class BlockheadClientConstructionTest data.add(new Object[] { "ws://localhost:8080/", "http://localhost:8080/" }); data.add(new Object[] { "ws://webtide.com/", "http://webtide.com/" }); data.add(new Object[] { "ws://www.webtide.com/sockets/chat", "http://www.webtide.com/sockets/chat" }); - data.add(new Object[] { "wss://dummy.eclipse.org:5454/", "https://dummy.eclipse.org:5454/" }); // @formatter:on return data; } diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java index 3f03daf519..847d9c85e8 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java @@ -18,22 +18,22 @@ package org.eclipse.jetty.websocket.server.helper; +import java.io.IOException; import java.sql.Connection; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.toolchain.test.EventQueue; import org.eclipse.jetty.websocket.api.WebSocketAdapter; public class CaptureSocket extends WebSocketAdapter { private final CountDownLatch latch = new CountDownLatch(1); - public List<String> messages; + public EventQueue<String> messages; public CaptureSocket() { - messages = new ArrayList<String>(); + messages = new EventQueue<String>(); } public boolean awaitConnected(long timeout) throws InterruptedException @@ -41,6 +41,18 @@ public class CaptureSocket extends WebSocketAdapter return latch.await(timeout,TimeUnit.MILLISECONDS); } + public void close() + { + try + { + getSession().close(); + } + catch (IOException ignore) + { + /* ignore */ + } + } + public void onClose(int closeCode, String message) { } diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java index bbfc3c5da2..9c00b8ab8e 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java @@ -81,6 +81,20 @@ public class SessionSocket return; } + if ("session.isSecure".equals(message)) + { + String issecure = String.format("session.isSecure=%b",session.isSecure()); + session.getRemote().sendStringByFuture(issecure); + return; + } + + if ("session.upgradeRequest.requestURI".equals(message)) + { + String response = String.format("session.upgradeRequest.requestURI=%s",session.getUpgradeRequest().getRequestURI().toASCIIString()); + session.getRemote().sendStringByFuture(response); + return; + } + if ("harsh-disconnect".equals(message)) { session.disconnect(); diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java new file mode 100644 index 0000000000..fd739e0b51 --- /dev/null +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java @@ -0,0 +1,269 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.websocket.servlet; + +import java.net.HttpCookie; +import java.net.InetSocketAddress; +import java.net.URISyntaxException; +import java.security.Principal; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.websocket.api.UpgradeRequest; +import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; +import org.eclipse.jetty.websocket.api.util.QuoteUtil; +import org.eclipse.jetty.websocket.api.util.WSURI; + +/** + * Servlet specific {@link UpgradeRequest} implementation. + */ +public class ServletUpgradeRequest extends UpgradeRequest +{ + private HttpServletRequest req; + + public ServletUpgradeRequest(HttpServletRequest request) throws URISyntaxException + { + super(WSURI.toWebsocket(request.getRequestURL(),request.getQueryString())); + this.req = request; + + // Copy Request Line Details + setMethod(request.getMethod()); + setHttpVersion(request.getProtocol()); + + // Copy parameters + super.setParameterMap(request.getParameterMap()); + + // Copy Cookies + Cookie rcookies[] = request.getCookies(); + if (rcookies != null) + { + List<HttpCookie> cookies = new ArrayList<>(); + for (Cookie rcookie : rcookies) + { + HttpCookie hcookie = new HttpCookie(rcookie.getName(),rcookie.getValue()); + // no point handling domain/path/expires/secure/httponly on client request cookies + cookies.add(hcookie); + } + super.setCookies(cookies); + } + + // Copy Headers + Enumeration<String> headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) + { + String name = headerNames.nextElement(); + Enumeration<String> valuesEnum = request.getHeaders(name); + List<String> values = new ArrayList<>(); + while (valuesEnum.hasMoreElements()) + { + values.add(valuesEnum.nextElement()); + } + setHeader(name,values); + } + + // Parse Sub Protocols + Enumeration<String> protocols = request.getHeaders("Sec-WebSocket-Protocol"); + List<String> subProtocols = new ArrayList<>(); + String protocol = null; + while ((protocol == null) && (protocols != null) && protocols.hasMoreElements()) + { + String candidate = protocols.nextElement(); + for (String p : parseProtocols(candidate)) + { + subProtocols.add(p); + } + } + setSubProtocols(subProtocols); + + // Parse Extension Configurations + Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions"); + while (e.hasMoreElements()) + { + Iterator<String> extTokenIter = QuoteUtil.splitAt(e.nextElement(),","); + while (extTokenIter.hasNext()) + { + String extToken = extTokenIter.next(); + ExtensionConfig config = ExtensionConfig.parse(extToken); + addExtensions(config); + } + } + } + + public X509Certificate[] getCertificates() + { + return (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate"); + } + + /** + * Equivalent to {@link HttpServletRequest#getLocalAddr()} + * + * @return the local address + */ + public String getLocalAddress() + { + return req.getLocalAddr(); + } + + /** + * Equivalent to {@link HttpServletRequest#getLocalName()} + * + * @return the local host name + */ + public String getLocalHostName() + { + return req.getLocalName(); + } + + /** + * Equivalent to {@link HttpServletRequest#getLocalPort()} + * + * @return the local port + */ + public int getLocalPort() + { + return req.getLocalPort(); + } + + /** + * Return a {@link InetSocketAddress} for the local socket. + * <p> + * Warning: this can cause a DNS lookup + * + * @return the local socket address + */ + public InetSocketAddress getLocalSocketAddress() + { + return new InetSocketAddress(req.getLocalAddr(),req.getLocalPort()); + } + + public Principal getPrincipal() + { + return req.getUserPrincipal(); + } + + /** + * Equivalent to {@link HttpServletRequest#getRemoteAddr()} + * + * @return the remote address + */ + public String getRemoteAddress() + { + return req.getRemoteAddr(); + } + + /** + * Equivalent to {@link HttpServletRequest#getRemoteHost()} + * + * @return the remote host name + */ + public String getRemoteHostName() + { + return req.getRemoteHost(); + } + + /** + * Equivalent to {@link HttpServletRequest#getRemotePort()} + * + * @return the remote port + */ + public int getRemotePort() + { + return req.getRemotePort(); + } + + /** + * Return a {@link InetSocketAddress} for the remote socket. + * <p> + * Warning: this can cause a DNS lookup + * + * @return the remote socket address + */ + public InetSocketAddress getRemoteSocketAddress() + { + return new InetSocketAddress(req.getRemoteAddr(),req.getRemotePort()); + } + + public Map<String, Object> getServletAttributes() + { + Map<String, Object> attributes = new HashMap<String, Object>(); + + for (String name : Collections.list(req.getAttributeNames())) + { + attributes.put(name,req.getAttribute(name)); + } + + return attributes; + } + + public Map<String, List<String>> getServletParameters() + { + Map<String, List<String>> parameters = new HashMap<String, List<String>>(); + + for (String name : Collections.list(req.getParameterNames())) + { + parameters.put(name,Collections.unmodifiableList(Arrays.asList(req.getParameterValues(name)))); + } + + return parameters; + } + + /** + * Return the HttpSession if it exists. + * <p> + * Note: this is equivalent to {@link HttpServletRequest#getSession()} and will not create a new HttpSession. + */ + @Override + public Object getSession() + { + return this.req.getSession(false); + } + + protected String[] parseProtocols(String protocol) + { + if (protocol == null) + { + return new String[] {}; + } + protocol = protocol.trim(); + if ((protocol == null) || (protocol.length() == 0)) + { + return new String[] {}; + } + String[] passed = protocol.split("\\s*,\\s*"); + String[] protocols = new String[passed.length]; + System.arraycopy(passed,0,protocols,0,passed.length); + return protocols; + } + + public void setServletAttribute(String name, Object o) + { + this.req.setAttribute(name,o); + } + +} diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java new file mode 100644 index 0000000000..c7b50dc8be --- /dev/null +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java @@ -0,0 +1,87 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.websocket.servlet; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.websocket.api.UpgradeResponse; + +/** + * Servlet Specific UpgradeResponse implementation. + */ +public class ServletUpgradeResponse extends UpgradeResponse +{ + private HttpServletResponse resp; + + public ServletUpgradeResponse(HttpServletResponse resp) + { + super(); + this.resp = resp; + } + + @Override + public void addHeader(String name, String value) + { + this.resp.addHeader(name,value); + } + + @Override + public int getStatusCode() + { + return this.resp.getStatus(); + } + + @Override + public String getStatusReason() + { + throw new UnsupportedOperationException("Server cannot get Status Reason Message"); + } + + public boolean isCommitted() + { + return this.resp.isCommitted(); + } + + public void sendError(int statusCode, String message) throws IOException + { + setSuccess(false); + this.resp.sendError(statusCode,message); + } + + @Override + public void sendForbidden(String message) throws IOException + { + setSuccess(false); + resp.sendError(HttpServletResponse.SC_FORBIDDEN,message); + } + + @Override + public void setHeader(String name, String value) + { + this.resp.setHeader(name,value); + } + + public void setStatus(int status) + { + this.resp.setStatus(status); + } + +} diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java index 69a36502b0..aa3d1627cc 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.servlet; import org.eclipse.jetty.websocket.api.UpgradeRequest; import org.eclipse.jetty.websocket.api.UpgradeResponse; +import org.eclipse.jetty.websocket.api.extensions.Extension; /** * Abstract WebSocket creator interface. @@ -34,9 +35,16 @@ public interface WebSocketCreator { /** * Create a websocket from the incoming request. + * <p> + * Note: if you have Servlet specific information you need to access from the UpgradeRequest, cast the {@link UpgradeRequest} to + * {@link ServletUpgradeRequest} for this extra information. + * <p> + * Future versions of this interface will change to use the Servlet specific Upgrade Request and Response parameters. * * @param req * the request details + * @param resp + * the response details * @return a websocket object to use, or null if no websocket should be created from this request. */ Object createWebSocket(UpgradeRequest req, UpgradeResponse resp); diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index bb1055bf1d..e0fb01f924 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -8,6 +8,7 @@ <artifactId>jetty-xml</artifactId> <name>Jetty :: XML utilities</name> <description>The jetty xml utilities.</description> + <url>http://www.eclipse.org/jetty</url> <properties> <bundle-symbolic-name>${project.groupId}.xml</bundle-symbolic-name> </properties> @@ -8,12 +8,12 @@ <artifactId>jetty-project</artifactId> <version>9.0.4-SNAPSHOT</version> <name>Jetty :: Project</name> - <url>${jetty.url}</url> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jetty.url>http://www.eclipse.org/jetty</jetty.url> <orbit-servlet-api-version>3.0.0.v201112011016</orbit-servlet-api-version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <build-support-version>1.1</build-support-version> <slf4j-version>1.6.1</slf4j-version> <jetty-test-policy-version>1.2</jetty-test-policy-version> @@ -709,5 +709,30 @@ </plugins> </build> </profile> + <profile> + <id>api-change</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>clirr-maven-plugin</artifactId> + <version>2.5</version> + <executions> + <execution> + <id>compare-api</id> + <phase>package</phase> + <goals> + <goal>clirr</goal> + </goals> + </execution> + </executions> + <configuration> + <minSeverity>info</minSeverity> + <comparisonVersion>9.0.3.v20130506</comparisonVersion> + </configuration> + </plugin> + </plugins> + </build> + </profile> </profiles> </project> diff --git a/test-continuation-jetty6/pom.xml b/test-continuation-jetty6/pom.xml new file mode 100644 index 0000000000..9f7f4e1f1d --- /dev/null +++ b/test-continuation-jetty6/pom.xml @@ -0,0 +1,64 @@ +<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>7.6.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>test-continuation-jetty6</artifactId> + <packaging>jar</packaging> + <name>Test :: Continuation - (Jetty 6)</name> + <description>Asynchronous API</description> + <url>http://www.eclipse.org/jetty</url> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <!-- DO NOT DEPLOY (or Release) --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>test-continuation</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + <version>6.1.26</version> + <type>jar</type> + <scope>test</scope> + <exclusions> + <exclusion> + <artifactId>servlet-api-2.5</artifactId> + <groupId>org.mortbay.jetty</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${project.version}</version> + <type>jar</type> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/test-continuation/pom.xml b/test-continuation/pom.xml new file mode 100644 index 0000000000..9abbc299c2 --- /dev/null +++ b/test-continuation/pom.xml @@ -0,0 +1,38 @@ +<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>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>test-continuation</artifactId> + <packaging>jar</packaging> + <name>Test :: Continuation</name> + <description>Asynchronous API</description> + <url>http://www.eclipse.org/jetty</url> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <!-- DO NOT DEPLOY (or Release) --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/test-jetty-servlet/pom.xml b/test-jetty-servlet/pom.xml new file mode 100644 index 0000000000..a04abf7acd --- /dev/null +++ b/test-jetty-servlet/pom.xml @@ -0,0 +1,24 @@ +<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>7.6.11-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>test-jetty-servlet</artifactId> + <packaging>jar</packaging> + <name>Test :: Jetty Servlet Tester</name> + <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>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/tests/pom.xml b/tests/pom.xml index 66f5b61fe2..920b69b5af 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -27,6 +27,7 @@ <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> <name>Jetty Tests :: Parent</name> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <build> <plugins> diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index 35311f6ee1..fb5784a6e9 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -26,6 +26,7 @@ <artifactId>test-integration</artifactId> <packaging>jar</packaging> <name>Jetty Tests :: Integrations</name> + <url>http://www.eclipse.org/jetty</url> <properties> <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir> <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir> diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 3affb3977f..7ba45e0b92 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-loginservice</artifactId> <name>Jetty Tests :: Login Service</name> + <url>http://www.eclipse.org/jetty</url> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 9680dddda0..9330be8282 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-sessions-parent</artifactId> <name>Jetty Tests :: Sessions :: Parent</name> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <build> </build> diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index a992d9bd7e..a78216c8b4 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-hash-sessions</artifactId> <name>Jetty Tests :: Sessions :: Hash</name> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 990ae16efa..91c24996d5 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-jdbc-sessions</artifactId> <name>Jetty Tests :: Sessions :: JDBC</name> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml index 44c3ed9793..5e83b2a3a0 100644 --- a/tests/test-sessions/test-mongodb-sessions/pom.xml +++ b/tests/test-sessions/test-mongodb-sessions/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-mongodb-sessions</artifactId> <name>Jetty Tests :: Sessions :: Mongo</name> + <url>http://www.eclipse.org/jetty</url> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 9edc777e02..d72d95fb82 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-sessions-common</artifactId> <name>Jetty Tests :: Sessions :: Common</name> + <url>http://www.eclipse.org/jetty</url> <build> </build> <dependencies> diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index cc3291103b..cea8290cd1 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -26,6 +26,7 @@ </parent> <artifactId>test-webapps-parent</artifactId> <name>Jetty Tests :: WebApps :: Parent</name> + <url>http://www.eclipse.org/jetty</url> <packaging>pom</packaging> <build> <plugins> diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index cbf4a75f7d..f13b5f2772 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -27,6 +27,7 @@ <groupId>org.eclipse.jetty</groupId> <artifactId>test-jetty-webapp</artifactId> <name>Test :: Jetty Test Webapp</name> + <url>http://www.eclipse.org/jetty</url> <packaging>war</packaging> <build> <plugins> diff --git a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java index 42040f56fd..dabfacd81c 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java +++ b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java @@ -19,13 +19,11 @@ package com.acme; import java.io.IOException; -import java.io.PrintWriter; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -34,57 +32,70 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + // Simple asynchronous Chat room. // This does not handle duplicate usernames or multiple frames/tabs from the same browser // Some code is duplicated for clarity. @SuppressWarnings("serial") public class ChatServlet extends HttpServlet { + private static final Logger LOG = Log.getLogger(ChatServlet.class); + + private long asyncTimeout = 10000; + + public void init() + { + String parameter = getServletConfig().getInitParameter("asyncTimeout"); + if (parameter != null) + asyncTimeout = Long.parseLong(parameter); + } // inner class to hold message queue for each chat room member class Member implements AsyncListener { final String _name; - final AtomicReference<AsyncContext> _async=new AtomicReference<>(); - final Queue<String> _queue = new LinkedList<String>(); - + final AtomicReference<AsyncContext> _async = new AtomicReference<>(); + final Queue<String> _queue = new LinkedList<>(); + Member(String name) { - _name=name; + _name = name; } - + @Override public void onTimeout(AsyncEvent event) throws IOException { + LOG.debug("resume request"); AsyncContext async = _async.get(); - if (async!=null && _async.compareAndSet(async,null)) + if (async != null && _async.compareAndSet(async, null)) { HttpServletResponse response = (HttpServletResponse)async.getResponse(); response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"poll\"}"); + response.getOutputStream().write("{action:\"poll\"}".getBytes()); async.complete(); } } - + @Override public void onStartAsync(AsyncEvent event) throws IOException { event.getAsyncContext().addListener(this); } - + @Override public void onError(AsyncEvent event) throws IOException { } - + @Override public void onComplete(AsyncEvent event) throws IOException { } } - Map<String,Map<String,Member>> _rooms = new HashMap<String,Map<String, Member>>(); + Map<String, Map<String, Member>> _rooms = new HashMap<>(); // Handle Ajax calls from browser @@ -92,113 +103,119 @@ public class ChatServlet extends HttpServlet protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Ajax calls are form encoded - String action = request.getParameter("action"); + boolean join = Boolean.parseBoolean(request.getParameter("join")); String message = request.getParameter("message"); String username = request.getParameter("user"); - if (action.equals("join")) - join(request,response,username); - else if (action.equals("poll")) - poll(request,response,username); - else if (action.equals("chat")) - chat(request,response,username,message); - } + LOG.debug("doPost called. join={},message={},username={}", join, message, username); + if (username == null) + { + LOG.debug("no paramter user set, sending 503"); + response.sendError(503, "user==null"); + return; + } - private synchronized void join(HttpServletRequest request,HttpServletResponse response,String username) - throws IOException - { - Member member = new Member(username); - Map<String,Member> room=_rooms.get(request.getPathInfo()); - if (room==null) + Map<String, Member> room = getRoom(request.getPathInfo()); + Member member = getMember(username, room); + + if (message != null) { - room=new HashMap<String,Member>(); - _rooms.put(request.getPathInfo(),room); + sendMessageToAllMembers(message, username, room); + } + // If a message is set, we only want to enter poll mode if the user is a new user. This is necessary to avoid + // two parallel requests per user (one is already in async wait and the new one). Sending a message will + // dispatch to an existing poll request if necessary and the client will issue a new request to receive the + // next message or long poll again. + if (message == null || join) + { + synchronized (member) + { + LOG.debug("Queue size: {}", member._queue.size()); + if (member._queue.size() > 0) + { + sendSingleMessage(response, member); + } + else + { + LOG.debug("starting async"); + AsyncContext async = request.startAsync(); + async.setTimeout(asyncTimeout); + async.addListener(member); + if (!member._async.compareAndSet(null, async)) + throw new IllegalStateException(); + } + } } - room.put(username,member); - response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"join\"}"); } - private synchronized void poll(HttpServletRequest request,HttpServletResponse response,String username) - throws IOException + private Member getMember(String username, Map<String, Member> room) { - Map<String,Member> room=_rooms.get(request.getPathInfo()); - if (room==null) + Member member = room.get(username); + if (member == null) { - response.sendError(503); - return; + LOG.debug("user: {} in room: {} doesn't exist. Creating new user.", username, room); + member = new Member(username); + room.put(username, member); } - final Member member = room.get(username); - if (member==null) + return member; + } + + private Map<String, Member> getRoom(String path) + { + Map<String, Member> room = _rooms.get(path); + if (room == null) { - response.sendError(503); - return; + LOG.debug("room: {} doesn't exist. Creating new room.", path); + room = new HashMap<>(); + _rooms.put(path, room); } + return room; + } - synchronized(member) - { - if (member._queue.size()>0) - { - // Send one chat message - response.setContentType("text/json;charset=utf-8"); - StringBuilder buf=new StringBuilder(); + private void sendSingleMessage(HttpServletResponse response, Member member) throws IOException + { + response.setContentType("text/json;charset=utf-8"); + StringBuilder buf = new StringBuilder(); - buf.append("{\"action\":\"poll\","); - buf.append("\"from\":\""); - buf.append(member._queue.poll()); - buf.append("\","); + buf.append("{\"from\":\""); + buf.append(member._queue.poll()); + buf.append("\","); - String message = member._queue.poll(); - int quote=message.indexOf('"'); - while (quote>=0) - { - message=message.substring(0,quote)+'\\'+message.substring(quote); - quote=message.indexOf('"',quote+2); - } - buf.append("\"chat\":\""); - buf.append(message); - buf.append("\"}"); - byte[] bytes = buf.toString().getBytes("utf-8"); - response.setContentLength(bytes.length); - response.getOutputStream().write(bytes); - } - else - { - AsyncContext async = request.startAsync(); - async.setTimeout(10000); - async.addListener(member); - if (!member._async.compareAndSet(null,async)) - throw new IllegalStateException(); - } + String returnMessage = member._queue.poll(); + int quote = returnMessage.indexOf('"'); + while (quote >= 0) + { + returnMessage = returnMessage.substring(0, quote) + '\\' + returnMessage.substring(quote); + quote = returnMessage.indexOf('"', quote + 2); } + buf.append("\"chat\":\""); + buf.append(returnMessage); + buf.append("\"}"); + byte[] bytes = buf.toString().getBytes("utf-8"); + response.setContentLength(bytes.length); + response.getOutputStream().write(bytes); } - private synchronized void chat(HttpServletRequest request,HttpServletResponse response,String username,String message) - throws IOException + private void sendMessageToAllMembers(String message, String username, Map<String, Member> room) { - Map<String,Member> room=_rooms.get(request.getPathInfo()); - if (room!=null) + LOG.debug("Sending message: {} from: {}", message, username); + for (Member m : room.values()) { - // Post chat to all members - for (Member m:room.values()) + synchronized (m) { - synchronized (m) - { - m._queue.add(username); // from - m._queue.add(message); // chat + m._queue.add(username); // from + m._queue.add(message); // chat - // wakeup member if polling - AsyncContext async=m._async.get(); - if (async!=null & m._async.compareAndSet(async,null)) - async.dispatch(); + // wakeup member if polling + AsyncContext async = m._async.get(); + LOG.debug("Async found: {}", async); + if (async != null & m._async.compareAndSet(async, null)) + { + LOG.debug("dispatch"); + async.dispatch(); } } } - - response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"chat\"}"); } // Serve the HTML with embedded CSS and Javascript. @@ -206,10 +223,10 @@ public class ChatServlet extends HttpServlet @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (request.getParameter("action")!=null) - doPost(request,response); + if (request.getParameter("action") != null) + doPost(request, response); else - getServletContext().getNamedDispatcher("default").forward(request,response); + getServletContext().getNamedDispatcher("default").forward(request, response); } } diff --git a/tests/test-webapps/test-jetty-webapp/src/main/resources/jetty-logging.properties b/tests/test-webapps/test-jetty-webapp/src/main/resources/jetty-logging.properties new file mode 100644 index 0000000000..d474e35347 --- /dev/null +++ b/tests/test-webapps/test-jetty-webapp/src/main/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +com.acme.LEVEL=INFO diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/chat/index.html b/tests/test-webapps/test-jetty-webapp/src/main/webapp/chat/index.html index cc8f833154..53e4795b1c 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/chat/index.html +++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/chat/index.html @@ -30,38 +30,28 @@ req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); req.send(body); } - ; - function send(action, user, message, handler) + function send(user, message, handler, join) { if (message) message = message.replace('%', '%25').replace('&', '%26').replace('=', '%3D'); if (user) user = user.replace('%', '%25').replace('&', '%26').replace('=', '%3D'); - xhr('POST', 'chat', 'action=' + action + '&user=' + user + '&message=' + message, handler); + var requestBody = 'user=' + user + (message ? '&message=' + message : '') + (join ? '&join=true' : ''); + xhr('POST', 'chat', requestBody , handler); } - ; - var room = { - join:function (name) + join: function (name) { this._username = name; $('join').className = 'hidden'; $('joined').className = ''; $('phrase').focus(); - send('join', room._username, null, room._joined); - }, - _joined:function () - { - send('chat', room._username, 'has joined!', room._startPolling); - }, - _startPolling:function () - { - send('poll', room._username, null, room._poll); + send(room._username, 'has joined!', room._poll, true); }, - chat:function (text) + chat: function (text) { if (text != null && text.length > 0) - send('chat', room._username, text); + send(room._username, text, room._poll, false); }, - _poll:function (m) + _poll: function (m) { //console.debug(m); if (m.chat) @@ -79,10 +69,9 @@ chat.appendChild(lineBreak); chat.scrollTop = chat.scrollHeight - chat.clientHeight; } - if (m.action == 'poll') - send('poll', room._username, null, room._poll); + send(room._username, null, room._poll, false); }, - _end:'' + _end: '' }; </script> <style type='text/css'> @@ -106,7 +95,7 @@ padding: 4px; background-color: #e0e0e0; border: 1px solid black; - border-top: 0px + border-top: 0 } input#phrase { @@ -122,14 +111,6 @@ div.hidden { display: none; } - - span.from { - font-weight: bold; - } - - span.alert { - font-style: italic; - } </style> </head> <body> diff --git a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/ChatServletTest.java b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/ChatServletTest.java new file mode 100644 index 0000000000..eb8717f195 --- /dev/null +++ b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/ChatServletTest.java @@ -0,0 +1,93 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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; + +import com.acme.ChatServlet; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletTester; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(JUnit4.class) +public class ChatServletTest +{ + + private final ServletTester tester = new ServletTester(); + + @Before + public void setUp() throws Exception + { + tester.setContextPath("/"); + + ServletHolder dispatch = tester.addServlet(ChatServlet.class, "/chat/*"); + dispatch.setInitParameter("asyncTimeout", "500"); + tester.start(); + } + + @After + public void tearDown() throws Exception + { + tester.stop(); + } + + @Test + public void testLogin() throws Exception + { + assertResponse("user=test&join=true&message=has%20joined!", "{\"from\":\"test\",\"chat\":\"has joined!\"}"); + } + + @Test + public void testChat() throws Exception + { + assertResponse("user=test&join=true&message=has%20joined!", "{\"from\":\"test\",\"chat\":\"has joined!\"}"); + String response = tester.getResponses(createRequestString("user=test&message=message")); + assertThat(response.contains("{"), is(false)); // make sure we didn't get a json body + } + + @Test + public void testPoll() throws Exception + { + assertResponse("user=test", "{action:\"poll\"}"); + } + + private void assertResponse(String requestBody, String expectedResponse) throws Exception + { + String response = tester.getResponses(createRequestString(requestBody)); + assertThat(response.contains(expectedResponse), is(true)); + } + + private String createRequestString(String body) + { + StringBuilder req1 = new StringBuilder(); + req1.append("POST /chat/ HTTP/1.1\r\n"); + req1.append("Host: tester\r\n"); + req1.append("Content-length: " + body.length() + "\r\n"); + req1.append("Content-type: application/x-www-form-urlencoded\r\n"); + req1.append("Connection: close\r\n"); + req1.append("\r\n"); + req1.append(body); + return req1.toString(); + } +} diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index a9695fe5b6..2243dac04b 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -25,6 +25,7 @@ </parent> <artifactId>test-webapp-rfc2616</artifactId> <name>Jetty Tests :: WebApp :: RFC2616</name> + <url>http://www.eclipse.org/jetty</url> <packaging>war</packaging> <build> <plugins> |