diff options
author | Greg Wilkins | 2013-06-17 06:29:39 +0000 |
---|---|---|
committer | Greg Wilkins | 2013-06-17 06:29:39 +0000 |
commit | 4e4ffaa54c5aad9085671c5ec35a77f865dfd3ba (patch) | |
tree | c41f5db60c1326352ae68f1b27f01f9f1bc32105 | |
parent | 3ddb1d97272790dd1bd0a75c9ae9fc6515d99b95 (diff) | |
parent | 6ed36160f0d893590320403f1abb528eda0d9094 (diff) | |
download | org.eclipse.jetty.project-4e4ffaa54c5aad9085671c5ec35a77f865dfd3ba.tar.gz org.eclipse.jetty.project-4e4ffaa54c5aad9085671c5ec35a77f865dfd3ba.tar.xz org.eclipse.jetty.project-4e4ffaa54c5aad9085671c5ec35a77f865dfd3ba.zip |
Merge remote-tracking branch 'origin/master' into servlet-3.1-api
Conflicts:
jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java
140 files changed, 3552 insertions, 1029 deletions
diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index 0ecda2131b..f7049bb157 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 0df4a96942..aeb3267ce6 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 2300e30d1a..253f08278a 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 41ae058ae9..c3b6cbd3b7 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-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java index 47ecd5bc0e..e00479020f 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java @@ -30,6 +30,7 @@ import java.security.CodeSource; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Enumeration; +import java.util.EventListener; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -50,9 +51,12 @@ import org.eclipse.jetty.ant.utils.TaskLog; import org.eclipse.jetty.plus.webapp.EnvConfiguration; import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.Holder; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -676,6 +680,13 @@ public class AntWebAppContext extends WebAppContext TaskLog.logWithTimestamp("Stopping web application "+this); Thread.currentThread().sleep(500L); super.doStop(); + //remove all filters, servlets and listeners. They will be recreated + //either via application of a context xml file or web.xml or annotation or servlet api + setEventListeners(new EventListener[0]); + getServletHandler().setFilters(new FilterHolder[0]); + getServletHandler().setFilterMappings(new FilterMapping[0]); + getServletHandler().setServlets(new ServletHolder[0]); + getServletHandler().setServletMappings(new ServletMapping[0]); } catch (InterruptedException e) { diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 00b4dcfa66..8b053c9456 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 488720a066..4683f8b89c 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-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index 2abb8412fe..4bb548a3a1 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -166,7 +166,17 @@ public class Servlet3Continuation implements Continuation @Override public boolean isSuspended() { - return _request.isAsyncStarted(); + if (_request.isAsyncStarted()) + return true; + try + { + return _request.getAsyncContext()!=null; + } + catch(IllegalStateException e) + { + // ignored + } + return false; } /* ------------------------------------------------------------ */ diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index e69a8c57d8..abd72178d7 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 26c4399a9b..0703d88b1f 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-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh index bfcb1fdabb..cbd9f24eb4 100755 --- a/jetty-distribution/src/main/resources/bin/jetty.sh +++ b/jetty-distribution/src/main/resources/bin/jetty.sh @@ -371,7 +371,7 @@ fi ##################################################### if [ "$JETTY_PORT" ] then - JAVA_OPTIONS+=("-Djetty.port=$JETTY_PORT") + JETTY_ARGS+=("jetty.port=$JETTY_PORT") fi ##################################################### 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 7cff20243d..930304c271 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 cfd1fd3708..6a698a7a25 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 5eea3b4b29..e65c83749f 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 07e346abea..f048e28d18 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 2c155ded43..404a420b8c 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 0cb400d2cc..4ee8294076 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-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java index 83df67c4de..0489a2d875 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.EventListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,6 +30,10 @@ import java.util.Set; import java.util.TreeSet; import org.eclipse.jetty.plus.webapp.EnvConfiguration; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -296,6 +301,14 @@ public class JettyWebAppContext extends WebAppContext //just wait a little while to ensure no requests are still being processed Thread.currentThread().sleep(500L); super.doStop(); + + //remove all listeners, servlets and filters. This is because we will re-apply + //any context xml file, which means they would potentially be added multiple times. + setEventListeners(new EventListener[0]); + getServletHandler().setFilters(new FilterHolder[0]); + getServletHandler().setFilterMappings(new FilterMapping[0]); + getServletHandler().setServlets(new ServletHolder[0]); + getServletHandler().setServletMappings(new ServletMapping[0]); } @Override diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index e0b154ef93..c95b52a9e2 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 2c0ac1b8a1..02c37e707f 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-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java index 48acc817da..d5ebdd2938 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java @@ -40,6 +40,7 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme private int _savePeriod=0; private int _idlePeriod=-1; private boolean _invalidateOnStop; + private boolean _preserveOnStop; private boolean _saveAllAttributes; /* ------------------------------------------------------------ */ @@ -104,7 +105,10 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme for (NoSqlSession session : sessions) { session.save(false); - removeSession(session,false); + + if (!_preserveOnStop) { + removeSession(session,false); + } } } else @@ -279,6 +283,16 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme /* ------------------------------------------------------------ */ /** + * Preserve sessions when the session manager is stopped otherwise remove them from the DB. + * @return the removeOnStop + */ + public boolean isPreserveOnStop() + { + return _preserveOnStop; + } + + /* ------------------------------------------------------------ */ + /** * Invalidate sessions when the session manager is stopped otherwise save them to the DB. * @param invalidateOnStop the invalidateOnStop to set */ @@ -289,6 +303,16 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme /* ------------------------------------------------------------ */ /** + * Preserve sessions when the session manager is stopped otherwise remove them from the DB. + * @param removeOnStop the removeOnStop to set + */ + public void setPreserveOnStop(boolean preserveOnStop) + { + _preserveOnStop = preserveOnStop; + } + + /* ------------------------------------------------------------ */ + /** * Save all attributes of a session or only update the dirty attributes. * @return the saveAllAttributes */ diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java index b078f08e90..0d1a0bb42c 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java @@ -137,25 +137,25 @@ public class MongoSessionManager extends NoSqlSessionManager BasicDBObject sets = new BasicDBObject(); BasicDBObject unsets = new BasicDBObject(); - // handle new or existing - if (version == null) - { - // New session - upsert = true; - version = new Long(1); - sets.put(__CREATED,session.getCreationTime()); - sets.put(__VALID,true); - sets.put(getContextKey(__VERSION),version); - } - else - { - version = new Long(((Number)version).longValue() + 1); - update.put("$inc",__version_1); - } - // handle valid or invalid if (session.isValid()) { + // handle new or existing + if (version == null) + { + // New session + upsert = true; + version = new Long(1); + sets.put(__CREATED,session.getCreationTime()); + sets.put(__VALID,true); + sets.put(getContextKey(__VERSION),version); + } + else + { + version = new Long(((Number)version).longValue() + 1); + update.put("$inc",__version_1); + } + sets.put(__ACCESSED,session.getAccessed()); Set<String> names = session.takeDirty(); if (isSaveAllAttributes() || upsert) @@ -253,6 +253,7 @@ public class MongoSessionManager extends NoSqlSessionManager DBObject attrs = (DBObject)getNestedValue(o,getContextKey()); + if (attrs != null) { for (String name : attrs.keySet()) @@ -286,6 +287,22 @@ public class MongoSessionManager extends NoSqlSessionManager } } + /* + * We are refreshing so we should update the last accessed time. + */ + BasicDBObject key = new BasicDBObject(__ID,session.getClusterId()); + BasicDBObject sets = new BasicDBObject(); + // Form updates + BasicDBObject update = new BasicDBObject(); + sets.put(__ACCESSED,System.currentTimeMillis()); + // Do the upsert + if (!sets.isEmpty()) + { + update.put("$set",sets); + } + + _sessions.update(key,update,false,false); + session.didActivate(); return version; diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 805664743a..b248d220ff 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 79edf06ea3..a2ad1f2830 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 3f80c17d1f..610e61ff01 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-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java index 03d3dcc0e3..5e3d5b6658 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java @@ -272,8 +272,13 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement if (tmp != null) { File defaultWebXml = getFile (tmp, bundleInstallLocation); - if (defaultWebXml != null && defaultWebXml.exists()) - _webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath()); + if (defaultWebXml != null) + { + if (defaultWebXml.exists()) + _webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath()); + else + LOG.warn(defaultWebXml.getAbsolutePath()+" does not exist"); + } } //Handle Require-TldBundle @@ -377,6 +382,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement HashMap properties = new HashMap(); properties.put("Server", getDeploymentManager().getServer()); properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); + properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); xmlConfiguration.getProperties().putAll(properties); xmlConfiguration.configure(_webApp); } @@ -390,11 +396,21 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement { if (file == null) return null; - - if (file.startsWith("/") || file.startsWith("file:/")) + + if (file.startsWith("/") || file.startsWith("file:/")) //absolute location return new File(file); else - return new File(bundleInstall, file); + { + //relative location + //try inside the bundle first + File f = new File (bundleInstall, file); + if (f.exists()) return f; + String jettyHome = (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME); + if (jettyHome != null) + return new File(jettyHome, file); + } + + return null; } } 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 4e79614030..b7ec57fdb5 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 8bdab30f01..48675f8655 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 046311a2c9..5eb121f629 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 3ce6131a3d..da2c45ea51 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 134d0525a7..c13513f70a 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-osgi/jetty-osgi-boot/jettyhome/etc/webdefault.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml index 366ff798c9..366ff798c9 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/webdefault.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml 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 7ecc32e642..84b3c81895 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 130b18f0e6..91efb8a05c 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 db7e7f622e..3d9f34a9d0 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 367b2e4696..96f41be149 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 738cf8273c..2853c156cf 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 f4c923d6c9..d01a90db9d 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/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 03e718c3fe..1ecb6b5f1b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -450,12 +450,21 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable LOG.ignore(e); path = _uri.getDecodedPath(StringUtil.__ISO_8859_1); } + String info = URIUtil.canonicalPath(path); if (info == null) { - info = "/"; - _request.setRequestURI(""); + if( path==null && _uri.getScheme()!=null &&_uri.getHost()!=null) + { + info = "/"; + _request.setRequestURI(""); + } + else + { + badMessage(400,null); + return true; + } } _request.setPathInfo(info); _version = version == null ? HttpVersion.HTTP_0_9 : version; @@ -680,7 +689,6 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable * @param content the content buffer to write * @param complete whether the content is complete for the response * @param callback Callback when complete or failed - * @throws IOException if the write fails */ protected void write(ByteBuffer content, boolean complete, Callback callback) { @@ -706,6 +714,14 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable return getEndPoint() instanceof ChannelEndPoint; } + /** + * If a write or similar to this channel fails this method should be called. The standard implementation + * of {@link #failed()} is a noop. But the different implementations of HttpChannel might want to take actions. + */ + public void failed() + { + } + private class CommitCallback implements Callback { private final Callback _callback; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index fdc2e96632..ce884eccf4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -578,6 +578,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _generator.setPersistent(false); super.handleException(x); } + + @Override + public void failed() + { + getEndPoint().shutdownOutput(); + } } private class CommitCallback extends IteratingNestedCallback 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 152567be74..e8927812a5 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 @@ -24,7 +24,6 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritePendingException; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; @@ -33,6 +32,7 @@ import javax.servlet.WriteListener; import org.eclipse.jetty.http.HttpContent; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.BlockingCallback; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; @@ -125,7 +125,7 @@ write completed - - - ASYNC READY->owp } catch(IOException e) { - _channel.getEndPoint().shutdownOutput(); + _channel.failed(); LOG.ignore(e); } releaseBuffer(); @@ -149,7 +149,7 @@ write completed - - - ASYNC READY->owp } catch(IOException e) { - _channel.getEndPoint().shutdownOutput(); + _channel.failed(); LOG.ignore(e); } releaseBuffer(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index f13df9df2c..ae3cfcd52a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.server; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -73,6 +74,7 @@ import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.server.session.AbstractSession; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStreamParser; @@ -350,6 +352,7 @@ public class Request implements HttpServletRequest } } } + } if (_parameters == null) @@ -359,6 +362,28 @@ public class Request implements HttpServletRequest // Merge parameters (needed if parameters extracted after a forward). _parameters.addAllValues(_baseParameters); } + + if (content_type != null && content_type.length()>0 && content_type.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT)!=null) + { + try + { + getParts(); + } + catch (IOException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + catch (ServletException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + } } finally { @@ -2021,38 +2046,8 @@ public class Request implements HttpServletRequest @Override public Part getPart(String name) throws IOException, ServletException { - if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) - throw new ServletException("Content-Type != multipart/form-data"); + getParts(); - if (_multiPartInputStream == null) - { - MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); - - if (config == null) - throw new IllegalStateException("No multipart config for servlet"); - - _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), - getContentType(),config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); - setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); - setAttribute(__MULTIPART_CONTEXT, _context); - Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing - for (Part p:parts) - { - MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; - if (mp.getContentDispositionFilename() == null && mp.getFile() == null) - { - //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params - String charset = null; - if (mp.getContentType() != null) - charset = MimeTypes.getCharsetFromContentType(mp.getContentType()); - - String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); - getParameter(""); //cause params to be evaluated - getParameters().add(mp.getName(), content); - } - } - } return _multiPartInputStream.getPart(name); } @@ -2064,6 +2059,9 @@ public class Request implements HttpServletRequest throw new ServletException("Content-Type != multipart/form-data"); if (_multiPartInputStream == null) + _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM); + + if (_multiPartInputStream == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); @@ -2080,19 +2078,32 @@ public class Request implements HttpServletRequest for (Part p:parts) { MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; - if (mp.getContentDispositionFilename() == null && mp.getFile() == null) + if (mp.getContentDispositionFilename() == null) { //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params String charset = null; if (mp.getContentType() != null) charset = MimeTypes.getCharsetFromContentType(mp.getContentType()); - String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); - getParameter(""); //cause params to be evaluated - getParameters().add(mp.getName(), content); + ByteArrayOutputStream os = null; + InputStream is = mp.getInputStream(); //get the bytes regardless of being in memory or in temp file + try + { + os = new ByteArrayOutputStream(); + IO.copy(is, os); + String content=new String(os.toByteArray(),charset==null?StringUtil.__UTF8:charset); + getParameter(""); //cause params to be evaluated + getParameters().add(mp.getName(), content); + } + finally + { + IO.close(os); + IO.close(is); + } } } } + return _multiPartInputStream.getParts(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 0a0a3ae431..ad2b22f294 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -169,6 +169,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu private final List<ServletContextAttributeListener> _contextAttributeListeners=new CopyOnWriteArrayList<>(); private final List<ServletRequestListener> _requestListeners=new CopyOnWriteArrayList<>(); private final List<ServletRequestAttributeListener> _requestAttributeListeners=new CopyOnWriteArrayList<>(); + private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>(); private Map<String, Object> _managedAttributes; private String[] _protectedTargets; private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>(); @@ -567,6 +568,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu { _eventListeners.add(listener); + if (!(isStarted() || isStarting())) + _durableListeners.add(listener); + if (listener instanceof ServletContextListener) _contextListeners.add((ServletContextListener)listener); @@ -623,6 +627,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu return _programmaticListeners.contains(listener); } + + /* ------------------------------------------------------------ */ /** * @return true if this context is accepting new requests @@ -821,6 +827,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu for (int i = _contextListeners.size(); i-->0;) callContextDestroyed(_contextListeners.get(i),event); } + + //retain only durable listeners + setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()])); + _durableListeners.clear(); if (_errorHandler != null) _errorHandler.stop(); @@ -1823,13 +1833,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu query = uriInContext.substring(q + 1); uriInContext = uriInContext.substring(0,q); } - // if ((q = uriInContext.indexOf(';')) > 0) - // uriInContext = uriInContext.substring(0,q); String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext)); - String uri = URIUtil.addPaths(getContextPath(),uriInContext); - ContextHandler context = ContextHandler.this; - return new Dispatcher(context,uri,pathInContext,query); + if (pathInContext!=null) + { + String uri = URIUtil.addPaths(getContextPath(),uriInContext); + ContextHandler context = ContextHandler.this; + return new Dispatcher(context,uri,pathInContext,query); + } } catch (Exception e) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index 5869d352eb..6e7a6d5e33 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -138,6 +138,66 @@ public class HttpConnectionTest checkContains(response,offset,"pathInfo=/"); } + @Test + public void testBadNoPath() throws Exception + { + String response=connector.getResponses("GET http://localhost:80/../cheat HTTP/1.1\n"+ + "Host: localhost:80\n"+ + "\n"); + int offset=0; + offset = checkContains(response,offset,"HTTP/1.1 400"); + } + + @Test + public void testOKPathDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 200 OK"); + checkContains(response,0,"pathInfo=/path"); + } + + @Test + public void testBadPathDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/../../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testOKPathEncodedDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 200 OK"); + checkContains(response,0,"pathInfo=/path"); + } + + @Test + public void testBadPathEncodedDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/%2e%2e/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testBadDotDotPath() throws Exception + { + String response=connector.getResponses("GET ../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testBadSlashDotDotPath() throws Exception + { + String response=connector.getResponses("GET /../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testEncodedBadDotDotPath() throws Exception + { + String response=connector.getResponses("GET %2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } @Test public void testEmpty() throws Exception diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index b1c9bde896..3249d964b8 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -1094,10 +1094,12 @@ public class RequestTest MultipartConfigElement mpce = new MultipartConfigElement(tmpDir.getAbsolutePath(),-1, -1, 2); request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce); + String field1 = request.getParameter("field1"); + assertNotNull(field1); + Part foo = request.getPart("stuff"); assertNotNull(foo); assertTrue(foo.getSize() > 0); - response.setStatus(200); } catch (IllegalStateException e) diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index fa901083d2..8328869aeb 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-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java index e69910480a..b63e40a3c6 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java @@ -53,7 +53,7 @@ public class FilterHolder extends Holder<Filter> */ public FilterHolder() { - super (Source.EMBEDDED); + this(Source.EMBEDDED); } @@ -62,7 +62,7 @@ public class FilterHolder extends Holder<Filter> */ public FilterHolder(Holder.Source source) { - super (source); + super(source); } /* ---------------------------------------------------------------- */ @@ -70,7 +70,7 @@ public class FilterHolder extends Holder<Filter> */ public FilterHolder(Class<? extends Filter> filter) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setHeldClass(filter); } @@ -79,7 +79,7 @@ public class FilterHolder extends Holder<Filter> */ public FilterHolder(Filter filter) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setFilter(filter); } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java index 9c12e3ec94..a7778a974a 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java @@ -57,7 +57,7 @@ public class Holder<T> extends AbstractLifeCycle implements Dumpable protected String _className; protected String _displayName; protected boolean _extInstance; - protected boolean _asyncSupported=true; + protected boolean _asyncSupported; /* ---------------------------------------------------------------- */ protected String _name; @@ -67,8 +67,19 @@ public class Holder<T> extends AbstractLifeCycle implements Dumpable protected Holder(Source source) { _source=source; + switch(_source) + { + case JAVAX_API: + case DESCRIPTOR: + case ANNOTATION: + _asyncSupported=false; + break; + default: + _asyncSupported=true; + } } + /* ------------------------------------------------------------ */ public Source getSource() { return _source; diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index 4224eb66e8..5080b8f461 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -1041,8 +1041,6 @@ public class ServletContextHandler extends ContextHandler if (!_enabled) throw new UnsupportedOperationException(); - //TODO handle partial registrations - final ServletHandler handler = ServletContextHandler.this.getServletHandler(); ServletHolder holder = handler.getServlet(servletName); if (holder == null) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 392d0a8c44..e64665840a 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -21,10 +21,12 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Queue; import java.util.Set; @@ -187,30 +189,81 @@ public class ServletHandler extends ScopedHandler super.doStop(); // Stop filters + List<FilterHolder> filterHolders = new ArrayList<FilterHolder>(); + List<FilterMapping> filterMappings = ArrayUtil.asMutableList(_filterMappings); if (_filters!=null) { for (int i=_filters.length; i-->0;) { try { _filters[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + if (_filters[i].getSource() != Source.EMBEDDED) + { + //remove all of the mappings that were for non-embedded filters + _filterNameMap.remove(_filters[i].getName()); + //remove any mappings associated with this filter + ListIterator<FilterMapping> fmitor = filterMappings.listIterator(); + while (fmitor.hasNext()) + { + FilterMapping fm = fmitor.next(); + if (fm.getFilterName().equals(_filters[i].getName())) + fmitor.remove(); + } + } + else + filterHolders.add(_filters[i]); //only retain embedded } } + + //Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED) + FilterHolder[] fhs = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class); + updateBeans(_filters, fhs); + _filters = fhs; + FilterMapping[] fms = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class); + updateBeans(_filterMappings, fms); + _filterMappings = fms; + + _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1); + _matchBeforeIndex = -1; // Stop servlets + List<ServletHolder> servletHolders = new ArrayList<ServletHolder>(); //will be remaining servlets + List<ServletMapping> servletMappings = ArrayUtil.asMutableList(_servletMappings); //will be remaining mappings if (_servlets!=null) { for (int i=_servlets.length; i-->0;) { try { _servlets[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + + if (_servlets[i].getSource() != Source.EMBEDDED) + { + //remove from servlet name map + _servletNameMap.remove(_servlets[i].getName()); + //remove any mappings associated with this servlet + ListIterator<ServletMapping> smitor = servletMappings.listIterator(); + while (smitor.hasNext()) + { + ServletMapping sm = smitor.next(); + if (sm.getServletName().equals(_servlets[i].getName())) + smitor.remove(); + } + } + else + servletHolders.add(_servlets[i]); //only retain embedded } } + //Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED) + ServletHolder[] shs = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class); + updateBeans(_servlets, shs); + _servlets = shs; + ServletMapping[] sms = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class); + updateBeans(_servletMappings, sms); + _servletMappings = sms; + + //will be regenerated on next start _filterPathMappings=null; _filterNameMappings=null; - _servletPathMap=null; - - _matchBeforeIndex=-1; - _matchAfterIndex=-1; } /* ------------------------------------------------------------ */ @@ -786,7 +839,7 @@ public class ServletHandler extends ScopedHandler */ public ServletHolder addServletWithMapping (String className,String pathSpec) { - ServletHolder holder = newServletHolder(null); + ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+(_servlets==null?0:_servlets.length)); holder.setClassName(className); addServletWithMapping(holder,pathSpec); @@ -801,7 +854,6 @@ public class ServletHandler extends ScopedHandler { ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setHeldClass(servlet); - setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class)); addServletWithMapping(holder,pathSpec); return holder; @@ -972,7 +1024,7 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches) { - FilterHolder holder = newFilterHolder(null); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+_filters.length); holder.setClassName(className); @@ -1119,7 +1171,7 @@ public class ServletHandler extends ScopedHandler { //programmatically defined filter mappings are prepended to mapping list in the order //in which they were defined. In other words, insert this mapping at the tail of the - //programmatically added filter mappings, BEFORE the first web.xml defined filter mapping. + //programmatically prepended filter mappings, BEFORE the first web.xml defined filter mapping. if (_matchBeforeIndex < 0) { @@ -1162,14 +1214,15 @@ public class ServletHandler extends ScopedHandler { if (pos < 0) throw new IllegalArgumentException("FilterMapping insertion pos < 0"); - FilterMapping[] mappings = getFilterMappings(); + if (mappings==null || mappings.length==0) { return new FilterMapping[] {mapping}; } FilterMapping[] new_mappings = new FilterMapping[mappings.length+1]; + if (before) { //copy existing filter mappings up to but not including the pos @@ -1382,6 +1435,7 @@ public class ServletHandler extends ScopedHandler if (holders!=null) for (ServletHolder holder:holders) holder.setServletHandler(this); + updateBeans(_servlets,holders); _servlets=holders; updateNameMappings(); diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index 297300199f..3a13a3f813 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -93,7 +93,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder() { - super (Source.EMBEDDED); + this(Source.EMBEDDED); } /* ---------------------------------------------------------------- */ @@ -101,7 +101,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder(Holder.Source creator) { - super (creator); + super(creator); } /* ---------------------------------------------------------------- */ @@ -109,7 +109,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder(Servlet servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setServlet(servlet); } @@ -118,7 +118,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder(String name, Class<? extends Servlet> servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setName(name); setHeldClass(servlet); } @@ -128,7 +128,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder(String name, Servlet servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setName(name); setServlet(servlet); } @@ -138,7 +138,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope */ public ServletHolder(Class<? extends Servlet> servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setHeldClass(servlet); } @@ -665,6 +665,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope Servlet servlet=_servlet; synchronized(this) { + if (!isStarted()) + throw new UnavailableException("Servlet not initialized", -1); if (_unavailable!=0 || !_initOnStartup) servlet=getServlet(); if (servlet==null) diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java index 0399280eca..df2aa5f7af 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java @@ -221,6 +221,32 @@ public class DispatcherTest } @Test + public void testServletForwardDotDot() throws Exception + { + _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); + _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); + + String requests="GET /context/dispatch/test?forward=/%2e%2e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + + String responses = _connector.getResponses(requests); + + assertThat(responses,startsWith("HTTP/1.1 404 ")); + } + + @Test + public void testServletForwardEncodedDotDot() throws Exception + { + _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); + _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); + + String requests="GET /context/dispatch/test?forward=/%252e%252e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + + String responses = _connector.getResponses(requests); + + assertThat(responses,startsWith("HTTP/1.1 404 ")); + } + + @Test public void testServletInclude() throws Exception { _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); @@ -412,7 +438,10 @@ public class DispatcherTest else if(request.getParameter("forward")!=null) { dispatcher = getServletContext().getRequestDispatcher(request.getParameter("forward")); - dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response)); + if (dispatcher!=null) + dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response)); + else + response.sendError(404); } } @@ -586,10 +615,14 @@ public class DispatcherTest assertEquals(null, request.getPathInfo()); assertEquals(null, request.getPathTranslated()); - UrlEncoded query = new UrlEncoded(request.getQueryString()); + UrlEncoded query = new UrlEncoded(); + query.decode(request.getQueryString()); assertThat(query.getString("do"), is("end")); + // Russian for "selected=Temperature" - String russian = new UrlEncoded(query.getString("else")).encode(); + UrlEncoded q2=new UrlEncoded(); + q2.decode(query.getString("else")); + String russian = q2.encode(); assertThat(russian, is("%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE=%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0")); assertThat(query.getString("test"), is("1")); assertThat(query.containsKey("foreign"), is(true)); diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 6585771d9a..e8c83e752d 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-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java index c7b2b4f1fb..9a34873f4e 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java @@ -22,6 +22,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.Charset; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; @@ -32,8 +35,11 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -222,35 +228,55 @@ public class CGI extends HttpServlet if ((pathTranslated == null) || (pathTranslated.length() == 0)) pathTranslated = path; + String bodyFormEncoded = null; + if ((HttpMethod.POST.equals(req.getMethod()) || HttpMethod.PUT.equals(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) + { + MultiMap<String> parameterMap = new MultiMap<String>(); + Enumeration names = req.getParameterNames(); + while (names.hasMoreElements()) + { + String parameterName = (String)names.nextElement(); + parameterMap.addValues(parameterName, req.getParameterValues(parameterName)); + } + bodyFormEncoded = UrlEncoded.encode(parameterMap, Charset.forName(req.getCharacterEncoding()), true); + } + EnvList env = new EnvList(_env); // these ones are from "The WWW Common Gateway Interface Version 1.1" // look at : // http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1 - env.set("AUTH_TYPE",req.getAuthType()); - env.set("CONTENT_LENGTH",Integer.toString(len)); - env.set("CONTENT_TYPE",req.getContentType()); - env.set("GATEWAY_INTERFACE","CGI/1.1"); + env.set("AUTH_TYPE", req.getAuthType()); + if (bodyFormEncoded != null) + { + env.set("CONTENT_LENGTH", Integer.toString(bodyFormEncoded.length())); + } + else + { + env.set("CONTENT_LENGTH", Integer.toString(len)); + } + env.set("CONTENT_TYPE", req.getContentType()); + env.set("GATEWAY_INTERFACE", "CGI/1.1"); if ((pathInfo != null) && (pathInfo.length() > 0)) { - env.set("PATH_INFO",pathInfo); + env.set("PATH_INFO", pathInfo); } - env.set("PATH_TRANSLATED",pathTranslated); - env.set("QUERY_STRING",req.getQueryString()); - env.set("REMOTE_ADDR",req.getRemoteAddr()); - env.set("REMOTE_HOST",req.getRemoteHost()); + env.set("PATH_TRANSLATED", pathTranslated); + env.set("QUERY_STRING", req.getQueryString()); + env.set("REMOTE_ADDR", req.getRemoteAddr()); + env.set("REMOTE_HOST", req.getRemoteHost()); // The identity information reported about the connection by a // RFC 1413 [11] request to the remote agent, if // available. Servers MAY choose not to support this feature, or // not to request the data for efficiency reasons. // "REMOTE_IDENT" => "NYI" - env.set("REMOTE_USER",req.getRemoteUser()); - env.set("REQUEST_METHOD",req.getMethod()); - env.set("SCRIPT_NAME",scriptName); - env.set("SCRIPT_FILENAME",scriptPath); - env.set("SERVER_NAME",req.getServerName()); - env.set("SERVER_PORT",Integer.toString(req.getServerPort())); - env.set("SERVER_PROTOCOL",req.getProtocol()); - env.set("SERVER_SOFTWARE",getServletContext().getServerInfo()); + env.set("REMOTE_USER", req.getRemoteUser()); + env.set("REQUEST_METHOD", req.getMethod()); + env.set("SCRIPT_NAME", scriptName); + env.set("SCRIPT_FILENAME", scriptPath); + env.set("SERVER_NAME", req.getServerName()); + env.set("SERVER_PORT", Integer.toString(req.getServerPort())); + env.set("SERVER_PROTOCOL", req.getProtocol()); + env.set("SERVER_SOFTWARE", getServletContext().getServerInfo()); Enumeration enm = req.getHeaderNames(); while (enm.hasMoreElements()) @@ -261,7 +287,7 @@ public class CGI extends HttpServlet } // these extra ones were from printenv on www.dev.nomura.co.uk - env.set("HTTPS",(req.isSecure()?"ON":"OFF")); + env.set("HTTPS", (req.isSecure()?"ON":"OFF")); // "DOCUMENT_ROOT" => root + "/docs", // "SERVER_URL" => "NYI - http://us0245", // "TZ" => System.getProperty("user.timezone"), @@ -275,31 +301,22 @@ public class CGI extends HttpServlet if (_cmdPrefix != null) execCmd = _cmdPrefix + " " + execCmd; - Process p = (dir == null)?Runtime.getRuntime().exec(execCmd,env.getEnvArray()):Runtime.getRuntime().exec(execCmd,env.getEnvArray(),dir); + LOG.debug("Environment: " + env.getExportString()); + LOG.debug("Command: " + execCmd); - // hook processes input to browser's output (async) - final InputStream inFromReq = req.getInputStream(); - final OutputStream outToCgi = p.getOutputStream(); - final int inLength = len; + Process p; + if (dir == null) + p = Runtime.getRuntime().exec(execCmd, env.getEnvArray()); + else + p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), dir); - IO.copyThread(p.getErrorStream(),System.err); + // hook processes input to browser's output (async) + if (bodyFormEncoded != null) + writeProcessInput(p, bodyFormEncoded); + else if (len > 0) + writeProcessInput(p, req.getInputStream(), len); - new Thread(new Runnable() - { - public void run() - { - try - { - if (inLength > 0) - IO.copy(inFromReq,outToCgi,inLength); - outToCgi.close(); - } - catch (IOException e) - { - LOG.ignore(e); - } - } - }).start(); + IO.copyThread(p.getErrorStream(), System.err); // hook processes output to browser's input (sync) // if browser closes stream, we should detect it and kill process... @@ -376,15 +393,56 @@ public class CGI extends HttpServlet } catch (Exception e) { - LOG.ignore(e); + LOG.debug(e); } } - os = null; p.destroy(); // LOG.debug("CGI: terminated!"); } } + private static void writeProcessInput(final Process p, final String input) + { + new Thread(new Runnable() + { + public void run() + { + try + { + Writer outToCgi = new OutputStreamWriter(p.getOutputStream()); + outToCgi.write(input); + outToCgi.close(); + } + catch (IOException e) + { + LOG.debug(e); + } + } + }).start(); + } + + private static void writeProcessInput(final Process p, final InputStream input, final int len) + { + if (len <= 0) return; + + new Thread(new Runnable() + { + public void run() + { + try + { + OutputStream outToCgi = p.getOutputStream(); + IO.copy(input, outToCgi, len); + outToCgi.close(); + } + catch (IOException e) + { + LOG.debug(e); + } + } + }).start(); + } + /** * Utility method to get a line of text from the input stream. * @@ -393,7 +451,7 @@ public class CGI extends HttpServlet * @return the line of text * @throws IOException */ - private String getTextLineFromStream(InputStream is) throws IOException + private static String getTextLineFromStream(InputStream is) throws IOException { StringBuilder buffer = new StringBuilder(); int b; @@ -411,16 +469,16 @@ public class CGI extends HttpServlet */ private static class EnvList { - private Map envMap; + private Map<String, String> envMap; EnvList() { - envMap = new HashMap(); + envMap = new HashMap<String, String>(); } EnvList(EnvList l) { - envMap = new HashMap(l.envMap); + envMap = new HashMap<String,String>(l.envMap); } /** @@ -434,7 +492,19 @@ public class CGI extends HttpServlet /** Get representation suitable for passing to exec. */ public String[] getEnvArray() { - return (String[])envMap.values().toArray(new String[envMap.size()]); + return envMap.values().toArray(new String[envMap.size()]); + } + + public String getExportString() + { + StringBuilder sb = new StringBuilder(); + for (String variable : getEnvArray()) + { + sb.append("export \""); + sb.append(variable); + sb.append("\"; "); + } + return sb.toString(); } @Override diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 23c671934d..3516327610 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 7cdc20c55f..05395c4b1f 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 38154ac959..3193517115 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 0d5d8d5e56..3816599fd2 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 5587da4ae3..a570389206 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 93006dcfc4..9dfb9455c6 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 ac61d4a539..f566cf60a7 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 ad39975cf1..217d9de12e 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 cd6ff52255..77b3227207 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-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 650c6a0873..4f37eae0d7 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -1083,6 +1083,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } + /* ------------------------------------------------------------ */ /** * @param extractWAR True if war files are extracted diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index aad8c963cd..776eecb132 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -120,25 +120,13 @@ public class WebXmlConfiguration extends AbstractConfiguration /* ------------------------------------------------------------------------------- */ @Override public void deconfigure (WebAppContext context) throws Exception - { - // TODO preserve any configuration that pre-existed. - - ServletHandler _servletHandler = context.getServletHandler(); - - _servletHandler.setFilters(null); - _servletHandler.setFilterMappings(null); - _servletHandler.setServlets(null); - _servletHandler.setServletMappings(null); - - context.setEventListeners(null); + { context.setWelcomeFiles(null); if (context.getErrorHandler() instanceof ErrorPageErrorHandler) ((ErrorPageErrorHandler) context.getErrorHandler()).setErrorPages(null); - // TODO remove classpaths from classloader - } } diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 3e85f43e80..e3f40f7e56 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/UpgradeConnection.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java index c24a17b6f9..ca5a9fe2f2 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java @@ -140,7 +140,7 @@ public class UpgradeConnection extends AbstractConnection public void onOpen() { super.onOpen(); - // TODO: handle timeout + // TODO: handle timeout? getExecutor().execute(new SendUpgradeRequest()); } 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 e3f1669a54..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 @@ -22,6 +22,7 @@ import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.concurrent.Executor; + import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.ByteBufferPool; @@ -87,7 +88,6 @@ public class WebSocketClientSelectorManager extends SelectorManager Connection connection = newUpgradeConnection(channel,sslEndPoint,connectPromise); sslEndPoint.setIdleTimeout(connectPromise.getClient().getMaxIdleTimeout()); sslEndPoint.setConnection(connection); - connectionOpened(connection); return sslConnection; } else @@ -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 6f9243bd78..6471390004 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 3864188454..781436126f 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.1.0-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> @@ -748,5 +748,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 f4deb814da..c71bd23b53 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 ffbdf27dc6..4cc8782adb 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 ba7813d547..a499af03d5 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 c8e740a0f4..c71dcc3325 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 21ba6eb3cc..9dab39c9de 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-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java index 05ca117513..c34bb6b012 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java @@ -113,7 +113,6 @@ public class ReloadedSessionMissingClassTest webApp.stop(); webApp.setClassLoader(loaderWithoutFoo); - webApp.addServlet("Bar", "/bar"); //restart webapp webApp.start(); 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-mongodb-sessions/src/test/resources/jetty-logging.properties b/tests/test-sessions/test-mongodb-sessions/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..fd2d21f974 --- /dev/null +++ b/tests/test-sessions/test-mongodb-sessions/src/test/resources/jetty-logging.properties @@ -0,0 +1,4 @@ +# Setup default logging implementation for during testing +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog + +#org.eclipse.jetty.server.LEVEL=DEBUG
\ No newline at end of file diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index d79e4f3ecf..d5aa814ad4 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 320da49f60..74a820efb1 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 7068937e46..fb957fa209 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 f3e432d579..f458ac0079 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> |