diff options
Diffstat (limited to 'jetty-spdy')
252 files changed, 0 insertions, 32931 deletions
diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml deleted file mode 100644 index 7b5466489c..0000000000 --- a/jetty-spdy/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-project</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <packaging>pom</packaging> - <name>Jetty :: SPDY :: Parent</name> - <url>http://www.eclipse.org/jetty</url> - - <modules> - <module>spdy-core</module> - <module>spdy-client</module> - <module>spdy-server</module> - <module>spdy-http-common</module> - <module>spdy-http-server</module> - <module>spdy-http-client-transport</module> - <module>spdy-example-webapp</module> - <module>spdy-alpn-tests</module> - </modules> - - <profiles> - <profile> - <id>npn</id> - <activation> - <jdk>1.7</jdk> - </activation> - <modules> -<!-- - <module>spdy-npn-tests</module> ---> - </modules> - </profile> - </profiles> - - <build> - <plugins> - <plugin> - <artifactId>maven-pmd-plugin</artifactId> - <configuration> - <skip>true</skip> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.*;version="9.1"</Export-Package> - <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.toolchain</groupId> - <artifactId>jetty-test-helper</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml deleted file mode 100644 index 3bca84b9a0..0000000000 --- a/jetty-spdy/spdy-alpn-tests/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-alpn-tests</artifactId> - <name>Jetty :: SPDY :: ALPN Tests</name> - - <build> - <plugins> - <plugin> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy</id> - <phase>generate-resources</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>org.mortbay.jetty.alpn</groupId> - <artifactId>alpn-boot</artifactId> - <version>${alpn.version}</version> - <type>jar</type> - <overWrite>false</overWrite> - <outputDirectory>${project.build.directory}/alpn</outputDirectory> - </artifactItem> - </artifactItems> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine> - </configuration> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.alpn</groupId> - <artifactId>alpn-api</artifactId> - <version>${alpn.api.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-alpn-server</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - <classifier>tests</classifier> - <scope>test</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java deleted file mode 100644 index 767cec96b0..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java +++ /dev/null @@ -1,198 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; - -import org.eclipse.jetty.alpn.ALPN; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Test; - -public class ALPNNegotiationTest extends AbstractALPNTest -{ - @Test - public void testClientAdvertisingHTTPServerSpeaksHTTP() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - ALPN.put(client, new ALPN.ClientProvider() - { - @Override - public void unsupported() - { - } - - @Override - public List<String> protocols() - { - return Arrays.asList("http/1.1"); - } - - @Override - public void selected(String protocol) - { - Assert.assertEquals("http/1.1", protocol); - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } - - @Test - public void testClientAdvertisingMultipleProtocolsServerSpeaksHTTPWhenNegotiated() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - ALPN.put(client, new ALPN.ClientProvider() - { - @Override - public void unsupported() - { - } - - @Override - public List<String> protocols() - { - return Arrays.asList("unknown/1.0", "http/1.1"); - } - - @Override - public void selected(String protocol) - { - Assert.assertEquals("http/1.1", protocol); - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } - - @Test - public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - ALPN.put(client, new ALPN.ClientProvider() - { - @Override - public void unsupported() - { - } - - @Override - public List<String> protocols() - { - return null; - } - - @Override - public void selected(String s) - { - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } -} diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java deleted file mode 100644 index 42e0e194dc..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java +++ /dev/null @@ -1,149 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; -import java.util.Arrays; -import java.util.List; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.alpn.ALPN; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Test; - -public class ALPNSynReplyTest extends AbstractALPNTest -{ - @Test - public void testGentleCloseDuringHandshake() throws Exception - { - InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); - sslEngine.setUseClientMode(true); - ALPN.put(sslEngine, new ALPN.ClientProvider() - { - @Override - public void unsupported() - { - } - - @Override - public List<String> protocols() - { - return Arrays.asList("test"); - } - - @Override - public void selected(String protocol) - { - } - }); - sslEngine.beginHandshake(); - - ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - - try (SocketChannel channel = SocketChannel.open(address)) - { - // Send ClientHello, immediately followed by TLS Close Alert and then by FIN - channel.write(encrypted); - sslEngine.closeOutbound(); - encrypted.clear(); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - channel.write(encrypted); - channel.shutdownOutput(); - - // Read ServerHello from server - encrypted.clear(); - int read = channel.read(encrypted); - encrypted.flip(); - Assert.assertTrue(read > 0); - // Cannot decrypt, as the SSLEngine has been already closed - - // Now if we read more, we should either read the TLS Close Alert, or directly -1 - encrypted.clear(); - read = channel.read(encrypted); - // Sending a TLS Close Alert during handshake results in an exception when - // unwrapping that the server react to by closing the connection abruptly. - Assert.assertTrue(read < 0); - } - } - - @Test - public void testAbruptCloseDuringHandshake() throws Exception - { - InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); - sslEngine.setUseClientMode(true); - ALPN.put(sslEngine, new ALPN.ClientProvider() - { - @Override - public void unsupported() - { - } - - @Override - public List<String> protocols() - { - return Arrays.asList("test"); - } - - @Override - public void selected(String s) - { - } - }); - sslEngine.beginHandshake(); - - ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - - try (SocketChannel channel = SocketChannel.open(address)) - { - // Send ClientHello, immediately followed by FIN (no TLS Close Alert) - channel.write(encrypted); - channel.shutdownOutput(); - - // Read ServerHello from server - encrypted.clear(); - int read = channel.read(encrypted); - encrypted.flip(); - Assert.assertTrue(read > 0); - ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize()); - sslEngine.unwrap(encrypted, decrypted); - - // Now if we read more, we should either read the TLS Close Alert, or directly -1 - encrypted.clear(); - read = channel.read(encrypted); - // Since we have close the connection abruptly, the server also does so - Assert.assertTrue(read < 0); - } - } -} diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java deleted file mode 100644 index 53a6c0b264..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java +++ /dev/null @@ -1,78 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; - -import org.eclipse.jetty.alpn.ALPN; -import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Rule; - -public class AbstractALPNTest -{ - @Rule - public final TestTracker tracker = new TestTracker(); - protected Server server; - protected SPDYServerConnector connector; - protected SPDYClient.Factory clientFactory; - - protected InetSocketAddress prepare() throws Exception - { - server = new Server(); - connector = new SPDYServerConnector(server, newSslContextFactory(), null, new ALPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); - connector.setPort(0); - connector.setIdleTimeout(30000); - server.addConnector(connector); - server.start(); - - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = new SPDYClient.Factory(threadPool); - clientFactory.start(); - - ALPN.debug = true; - - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected SslContextFactory newSslContextFactory() - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslContextFactory.setProtocol("TLSv1"); - sslContextFactory.setIncludeProtocols("TLSv1"); - return sslContextFactory; - } - - @After - public void dispose() throws Exception - { - clientFactory.stop(); - server.stop(); - } -} diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties deleted file mode 100644 index ead13ec197..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.spdy.LEVEL=DEBUG diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/keystore.jks b/jetty-spdy/spdy-alpn-tests/src/test/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/truststore.jks b/jetty-spdy/spdy-alpn-tests/src/test/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-alpn-tests/src/test/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml deleted file mode 100644 index 7b3bed1ee0..0000000000 --- a/jetty-spdy/spdy-client/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-client</artifactId> - <name>Jetty :: SPDY :: Client Binding</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name> - </properties> - - <url>http://www.eclipse.org/jetty</url> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.client;version="9.1"</Export-Package> - <Import-Package>!org.eclipse.jetty.npn,!org.eclipse.jetty.alpn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-alpn-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.alpn</groupId> - <artifactId>alpn-api</artifactId> - <version>${alpn.api.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.npn</groupId> - <artifactId>npn-api</artifactId> - <version>${npn.api.version}</version> - <scope>provided</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java deleted file mode 100644 index 439b32a4e0..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import org.eclipse.jetty.spdy.FlowControlStrategy; -import org.eclipse.jetty.spdy.SPDYv3FlowControlStrategy; -import org.eclipse.jetty.spdy.api.SPDY; - -public class FlowControlStrategyFactory -{ - private FlowControlStrategyFactory() - { - } - - public static FlowControlStrategy newFlowControlStrategy(short version) - { - switch (version) - { - case SPDY.V2: - return new FlowControlStrategy.None(); - case SPDY.V3: - return new SPDYv3FlowControlStrategy(); - default: - throw new IllegalStateException(); - } - } -} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java deleted file mode 100644 index 10c2a13b83..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.NegotiatingClientConnection; -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class NPNClientConnection extends NegotiatingClientConnection implements NextProtoNego.ClientProvider -{ - private static final Logger LOG = Log.getLogger(NPNClientConnection.class); - - private final String protocol; - - public NPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, String protocol) - { - super(endPoint, executor, sslEngine, connectionFactory, context); - this.protocol = protocol; - NextProtoNego.put(sslEngine, this); - } - - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - NextProtoNego.remove(getSSLEngine()); - completed(); - } - - @Override - public String selectProtocol(List<String> protocols) - { - if (protocols.contains(protocol)) - { - NextProtoNego.remove(getSSLEngine()); - completed(); - return protocol; - } - else - { - LOG.info("Could not negotiate protocol: server {} - client {}", protocols, protocol); - close(); - return null; - } - } - - @Override - public void close() - { - NextProtoNego.remove(getSSLEngine()); - super.close(); - } -} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java deleted file mode 100644 index 2f23057aff..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.Executor; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; -import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; - -public class NPNClientConnectionFactory extends NegotiatingClientConnectionFactory -{ - private final Executor executor; - private final String protocol; - - public NPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol) - { - super(connectionFactory); - this.executor = executor; - this.protocol = protocol; - } - - @Override - public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException - { - return new NPNClientConnection(endPoint, executor, getClientConnectionFactory(), - (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol); - } -} 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 deleted file mode 100644 index c1b8ee5b9a..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java +++ /dev/null @@ -1,440 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.channels.SelectionKey; -import java.nio.channels.SocketChannel; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; -import org.eclipse.jetty.io.SelectChannelEndPoint; -import org.eclipse.jetty.io.SelectorManager; -import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; -import org.eclipse.jetty.spdy.FlowControlStrategy; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; -import org.eclipse.jetty.util.thread.Scheduler; - -/** - * A {@link SPDYClient} allows applications to connect to one or more SPDY servers, - * obtaining {@link Session} objects that can be used to send/receive SPDY frames. - * <p/> - * {@link SPDYClient} instances are created through a {@link Factory}: - * <pre> - * SPDYClient.Factory factory = new SPDYClient.Factory(); - * SPDYClient client = factory.newSPDYClient(SPDY.V3); - * </pre> - * and then used to connect to the server: - * <pre> - * FuturePromise<Session> promise = new FuturePromise<>(); - * client.connect("server.com", null, promise); - * Session session = promise.get(); - * </pre> - */ -public class SPDYClient -{ - private final short version; - private final Factory factory; - private volatile SocketAddress bindAddress; - private volatile long idleTimeout = -1; - private volatile int initialWindowSize; - private volatile boolean dispatchIO; - private volatile ClientConnectionFactory connectionFactory; - - protected SPDYClient(short version, Factory factory) - { - this.version = version; - this.factory = factory; - setInitialWindowSize(65536); - setDispatchIO(true); - } - - public short getVersion() - { - return version; - } - - public Factory getFactory() - { - return factory; - } - - /** - * Equivalent to: - * <pre> - * Future<Session> promise = new FuturePromise<>(); - * connect(address, listener, promise); - * </pre> - * - * @param address the address to connect to - * @param listener the session listener that will be notified of session events - * @return a {@link Session} when connected - */ - public Session connect(SocketAddress address, SessionFrameListener listener) throws ExecutionException, InterruptedException - { - FuturePromise<Session> promise = new FuturePromise<>(); - connect(address, listener, promise); - return promise.get(); - } - - /** - * Equivalent to: - * <pre> - * connect(address, listener, promise, null); - * </pre> - * - * @param address the address to connect to - * @param listener the session listener that will be notified of session events - * @param promise the promise notified of connection success/failure - */ - public void connect(SocketAddress address, SessionFrameListener listener, Promise<Session> promise) - { - connect(address, listener, promise, new HashMap<String, Object>()); - } - - /** - * Connects to the given {@code address}, binding the given {@code listener} to session events, - * and notified the given {@code promise} of the connect result. - * <p/> - * If the connect operation is successful, the {@code promise} will be invoked with the {@link Session} - * object that applications can use to perform SPDY requests. - * - * @param address the address to connect to - * @param listener the session listener that will be notified of session events - * @param promise the promise notified of connection success/failure - * @param context a context object passed to the {@link #getClientConnectionFactory() ConnectionFactory} - * for the creation of the connection - */ - public void connect(final SocketAddress address, final SessionFrameListener listener, final Promise<Session> promise, Map<String, Object> context) - { - if (!factory.isStarted()) - throw new IllegalStateException(Factory.class.getSimpleName() + " is not started"); - - try - { - SocketChannel channel = SocketChannel.open(); - if (bindAddress != null) - channel.bind(bindAddress); - configure(channel); - channel.configureBlocking(false); - - context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, ((InetSocketAddress)address).getHostString()); - context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, ((InetSocketAddress)address).getPort()); - context.put(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY, this); - context.put(SPDYClientConnectionFactory.SPDY_SESSION_LISTENER_CONTEXT_KEY, listener); - context.put(SPDYClientConnectionFactory.SPDY_SESSION_PROMISE_CONTEXT_KEY, promise); - - if (channel.connect(address)) - factory.selector.accept(channel, context); - else - factory.selector.connect(channel, context); - } - catch (IOException x) - { - promise.failed(x); - } - } - - protected void configure(SocketChannel channel) throws IOException - { - channel.socket().setTcpNoDelay(true); - } - - /** - * @return the address to bind the socket channel to - * @see #setBindAddress(SocketAddress) - */ - public SocketAddress getBindAddress() - { - return bindAddress; - } - - /** - * @param bindAddress the address to bind the socket channel to - * @see #getBindAddress() - */ - public void setBindAddress(SocketAddress bindAddress) - { - this.bindAddress = bindAddress; - } - - public long getIdleTimeout() - { - return idleTimeout; - } - - public void setIdleTimeout(long idleTimeout) - { - this.idleTimeout = idleTimeout; - } - - public int getInitialWindowSize() - { - return initialWindowSize; - } - - public void setInitialWindowSize(int initialWindowSize) - { - this.initialWindowSize = initialWindowSize; - } - - public boolean isDispatchIO() - { - return dispatchIO; - } - - public void setDispatchIO(boolean dispatchIO) - { - this.dispatchIO = dispatchIO; - } - - public ClientConnectionFactory getClientConnectionFactory() - { - return connectionFactory; - } - - public void setClientConnectionFactory(ClientConnectionFactory connectionFactory) - { - this.connectionFactory = connectionFactory; - } - - protected FlowControlStrategy newFlowControlStrategy() - { - return FlowControlStrategyFactory.newFlowControlStrategy(version); - } - - public static class Factory extends ContainerLifeCycle - { - private final Queue<Session> sessions = new ConcurrentLinkedQueue<>(); - private final Scheduler scheduler; - private final Executor executor; - private final ByteBufferPool bufferPool; - private final SslContextFactory sslContextFactory; - private final SelectorManager selector; - private final long idleTimeout; - private long connectTimeout; - - public Factory() - { - this(null, null); - } - - public Factory(SslContextFactory sslContextFactory) - { - this(null, null, sslContextFactory); - } - - public Factory(Executor executor) - { - this(executor, null); - } - - public Factory(Executor executor, Scheduler scheduler) - { - this(executor, scheduler, null); - } - - public Factory(Executor executor, Scheduler scheduler, SslContextFactory sslContextFactory) - { - this(executor, scheduler, sslContextFactory, 30000); - } - - public Factory(Executor executor, Scheduler scheduler, SslContextFactory sslContextFactory, long idleTimeout) - { - this(executor, scheduler, null, sslContextFactory, idleTimeout); - } - - public Factory(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, SslContextFactory sslContextFactory, long idleTimeout) - { - this.idleTimeout = idleTimeout; - setConnectTimeout(15000); - - if (executor == null) - executor = new QueuedThreadPool(); - this.executor = executor; - addBean(executor); - - if (scheduler == null) - scheduler = new ScheduledExecutorScheduler(); - this.scheduler = scheduler; - addBean(scheduler); - - if (bufferPool == null) - bufferPool = new MappedByteBufferPool(); - this.bufferPool = bufferPool; - addBean(bufferPool); - - this.sslContextFactory = sslContextFactory; - if (sslContextFactory != null) - addBean(sslContextFactory); - - selector = new ClientSelectorManager(executor, scheduler); - selector.setConnectTimeout(getConnectTimeout()); - addBean(selector); - } - - public ByteBufferPool getByteBufferPool() - { - return bufferPool; - } - - public Scheduler getScheduler() - { - return scheduler; - } - - public Executor getExecutor() - { - return executor; - } - - public SslContextFactory getSslContextFactory() - { - return sslContextFactory; - } - - public long getConnectTimeout() - { - return connectTimeout; - } - - public void setConnectTimeout(long connectTimeout) - { - this.connectTimeout = connectTimeout; - } - - public SPDYClient newSPDYClient(short version) - { - return newSPDYClient(version, new NPNClientConnectionFactory(getExecutor(), new SPDYClientConnectionFactory(), "spdy/" + version)); - } - - public SPDYClient newSPDYClient(short version, NegotiatingClientConnectionFactory negotiatingFactory) - { - SPDYClient client = new SPDYClient(version, this); - - ClientConnectionFactory connectionFactory = negotiatingFactory.getClientConnectionFactory(); - if (sslContextFactory != null) - connectionFactory = new SslClientConnectionFactory(getSslContextFactory(), getByteBufferPool(), getExecutor(), negotiatingFactory); - - client.setClientConnectionFactory(connectionFactory); - return client; - } - - @Override - protected void doStop() throws Exception - { - closeConnections(); - super.doStop(); - } - - boolean sessionOpened(Session session) - { - // Add sessions only if the factory is not stopping - return isRunning() && sessions.offer(session); - } - - boolean sessionClosed(Session session) - { - // Remove sessions only if the factory is not stopping - // to avoid concurrent removes during iterations - return isRunning() && sessions.remove(session); - } - - private void closeConnections() - { - for (Session session : sessions) - session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE); - sessions.clear(); - } - - public Collection<Session> getSessions() - { - return Collections.unmodifiableCollection(sessions); - } - - @Override - protected void dumpThis(Appendable out) throws IOException - { - super.dumpThis(out); - dump(out, "", sessions); - } - - private class ClientSelectorManager extends SelectorManager - { - private ClientSelectorManager(Executor executor, Scheduler scheduler) - { - super(executor, scheduler); - } - - @Override - protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException - { - @SuppressWarnings("unchecked") - Map<String, Object> context = (Map<String, Object>)key.attachment(); - SPDYClient client = (SPDYClient)context.get(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY); - long clientIdleTimeout = client.getIdleTimeout(); - if (clientIdleTimeout < 0) - clientIdleTimeout = idleTimeout; - return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), clientIdleTimeout); - } - - @Override - public Connection newConnection(SocketChannel channel, EndPoint endPoint, Object attachment) throws IOException - { - @SuppressWarnings("unchecked") - Map<String, Object> context = (Map<String, Object>)attachment; - try - { - SPDYClient client = (SPDYClient)context.get(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY); - return client.getClientConnectionFactory().newConnection(endPoint, context); - } - catch (Throwable x) - { - @SuppressWarnings("unchecked") - Promise<Session> promise = (Promise<Session>)context.get(SPDYClientConnectionFactory.SPDY_SESSION_PROMISE_CONTEXT_KEY); - promise.failed(x); - throw x; - } - } - } - } -} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java deleted file mode 100644 index dc6663228f..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import java.io.IOException; -import java.util.Map; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.FlowControlStrategy; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.StandardSession; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient.Factory; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Promise; - -public class SPDYClientConnectionFactory implements ClientConnectionFactory -{ - public static final String SPDY_CLIENT_CONTEXT_KEY = "spdy.client"; - public static final String SPDY_SESSION_LISTENER_CONTEXT_KEY = "spdy.session.listener"; - public static final String SPDY_SESSION_PROMISE_CONTEXT_KEY = "spdy.session.promise"; - - @Override - public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException - { - SPDYClient client = (SPDYClient)context.get(SPDY_CLIENT_CONTEXT_KEY); - SPDYClient.Factory factory = client.getFactory(); - ByteBufferPool byteBufferPool = factory.getByteBufferPool(); - CompressionFactory compressionFactory = new StandardCompressionFactory(); - Parser parser = new Parser(compressionFactory.newDecompressor()); - Generator generator = new Generator(byteBufferPool, compressionFactory.newCompressor()); - - SPDYConnection connection = new ClientSPDYConnection(endPoint, byteBufferPool, parser, factory, client.isDispatchIO()); - - FlowControlStrategy flowControlStrategy = client.newFlowControlStrategy(); - - SessionFrameListener listener = (SessionFrameListener)context.get(SPDY_SESSION_LISTENER_CONTEXT_KEY); - StandardSession session = new StandardSession(client.getVersion(), byteBufferPool, - factory.getScheduler(), connection, endPoint, connection, 1, listener, generator, flowControlStrategy); - - session.setWindowSize(client.getInitialWindowSize()); - parser.addListener(session); - connection.setSession(session); - - @SuppressWarnings("unchecked") - Promise<Session> promise = (Promise<Session>)context.get(SPDY_SESSION_PROMISE_CONTEXT_KEY); - promise.succeeded(session); - - return connection; - } - - private class ClientSPDYConnection extends SPDYConnection - { - private final Factory factory; - - public ClientSPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Factory factory, boolean dispatchIO) - { - super(endPoint, bufferPool, parser, factory.getExecutor(), dispatchIO); - this.factory = factory; - } - - @Override - public void onOpen() - { - super.onOpen(); - factory.sessionOpened(getSession()); - } - - @Override - public void onClose() - { - super.onClose(); - factory.sessionClosed(getSession()); - } - } -} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java deleted file mode 100644 index 3a6719876a..0000000000 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java +++ /dev/null @@ -1,191 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.Executor; - -import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.RuntimeIOException; -import org.eclipse.jetty.spdy.Controller; -import org.eclipse.jetty.spdy.ISession; -import org.eclipse.jetty.spdy.IdleListener; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class SPDYConnection extends AbstractConnection implements Controller, IdleListener -{ - private static final Logger LOG = Log.getLogger(SPDYConnection.class); - private final ByteBufferPool bufferPool; - private final Parser parser; - private final int bufferSize; - private volatile ISession session; - private volatile boolean idle = false; - - public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, boolean dispatchIO) - { - this(endPoint, bufferPool, parser, executor, dispatchIO, 8192); - } - - public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, boolean dispatchIO, int bufferSize) - { - // Since SPDY is multiplexed, onFillable() must never block while calling application code. In fact, - // the SPDY code always dispatches to a new thread when calling application code, - // so here we can safely pass false as last parameter, and avoid to dispatch to onFillable(). - // The IO operation (read, parse, etc.) will not block and will be fast in almost all cases. - // Big uploads to a server, however, might occupy the Selector thread for a long time and - // therefore starve other connections, so by default dispatchIO is true. - super(endPoint, executor, dispatchIO); - this.bufferPool = bufferPool; - this.parser = parser; - onIdle(true); - this.bufferSize = bufferSize; - } - - @Override - public void onOpen() - { - super.onOpen(); - fillInterested(); - } - - @Override - public void onFillable() - { - ByteBuffer buffer = bufferPool.acquire(bufferSize, false); - boolean readMore = read(buffer) == 0; - bufferPool.release(buffer); - if (readMore) - fillInterested(); - } - - protected int read(ByteBuffer buffer) - { - EndPoint endPoint = getEndPoint(); - while (true) - { - int filled = fill(endPoint, buffer); - if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled' - LOG.debug("Read {} bytes", filled); - if (filled == 0) - { - return 0; - } - else if (filled < 0) - { - shutdown(session); - return -1; - } - else - { - parser.parse(buffer); - } - } - } - - private int fill(EndPoint endPoint, ByteBuffer buffer) - { - try - { - if (endPoint.isInputShutdown()) - return -1; - return endPoint.fill(buffer); - } - catch (IOException x) - { - endPoint.close(); - throw new RuntimeIOException(x); - } - } - - @Override - public void write(final Callback callback, ByteBuffer... buffers) - { - EndPoint endPoint = getEndPoint(); - endPoint.write(callback, buffers); - } - - @Override - public void close() - { - goAway(session); - } - - @Override - public void close(boolean onlyOutput) - { - EndPoint endPoint = getEndPoint(); - // We need to gently close first, to allow - // SSL close alerts to be sent by Jetty - if (LOG.isDebugEnabled()) - LOG.debug("Shutting down output {}", endPoint); - endPoint.shutdownOutput(); - if (!onlyOutput) - { - if (LOG.isDebugEnabled()) - LOG.debug("Closing {}", endPoint); - endPoint.close(); - } - } - - @Override - public void onIdle(boolean idle) - { - this.idle = idle; - } - - @Override - protected boolean onReadTimeout() - { - boolean idle = this.idle; - if (LOG.isDebugEnabled()) - LOG.debug("Idle timeout on {}, idle={}", this, idle); - if (idle) - goAway(session); - return false; - } - - protected void goAway(ISession session) - { - if (session != null) - session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE); - } - - private void shutdown(ISession session) - { - if (session != null && !getEndPoint().isOutputShutdown()) - session.shutdown(); - } - - protected ISession getSession() - { - return session; - } - - public void setSession(ISession session) - { - this.session = session; - } -} diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml deleted file mode 100644 index 2cb325d492..0000000000 --- a/jetty-spdy/spdy-core/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-core</artifactId> - <name>Jetty :: SPDY :: Core</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name> - </properties> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java deleted file mode 100644 index c97b579dea..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java +++ /dev/null @@ -1,87 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.SPDY; - -public class CompressionDictionary -{ - private static final byte[] DICTIONARY_V2 = ("" + - "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" + - "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" + - "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" + - "-agent10010120020120220320420520630030130230330430530630740040140240340440" + - "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" + - "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" + - "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" + - "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" + - "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" + - "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" + - "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" + - "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" + - ".1statusversionurl" + - // Must be NUL terminated - "\u0000").getBytes(); - - private static final byte[] DICTIONARY_V3 = ("" + - "\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004head\u0000\u0000\u0000\u0004post" + - "\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006delete\u0000\u0000\u0000\u0005trace" + - "\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000\u000Eaccept-charset" + - "\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Faccept-language" + - "\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000\u0000\u0000\u0005allow" + - "\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-control" + - "\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000\u0000\u0010content-encoding" + - "\u0000\u0000\u0000\u0010content-language\u0000\u0000\u0000\u000Econtent-length" + - "\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000\u000Bcontent-md5" + - "\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type\u0000\u0000\u0000\u0004date" + - "\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expect\u0000\u0000\u0000\u0007expires" + - "\u0000\u0000\u0000\u0004from\u0000\u0000\u0000\u0004host\u0000\u0000\u0000\bif-match" + - "\u0000\u0000\u0000\u0011if-modified-since\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range" + - "\u0000\u0000\u0000\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified" + - "\u0000\u0000\u0000\blocation\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma" + - "\u0000\u0000\u0000\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization" + - "\u0000\u0000\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after" + - "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trailer" + - "\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000\u0000\u0000\nuser-agent" + - "\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via\u0000\u0000\u0000\u0007warning" + - "\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000\u0000\u0006method\u0000\u0000\u0000\u0003get" + - "\u0000\u0000\u0000\u0006status\u0000\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version" + - "\u0000\u0000\u0000\bHTTP/1.1\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public" + - "\u0000\u0000\u0000\nset-cookie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin" + - "100101201202205206300302303304305306307402405406407408409410411412413414415416417502504505" + - "203 Non-Authoritative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized" + - "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Unavailable" + - "Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Thu, Fri, Sat, Sun, GMT" + - "chunked,text/html,image/png,image/jpg,image/gif,application/xml,application/xhtml+xml,text/plain," + - "text/javascript,publicprivatemax-age=gzip,deflate,sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.") - .getBytes(); - - public static byte[] get(short version) - { - switch (version) - { - case SPDY.V2: - return DICTIONARY_V2; - case SPDY.V3: - return DICTIONARY_V3; - default: - throw new IllegalStateException(); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java deleted file mode 100644 index 6955bbfa80..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.util.zip.ZipException; - -public interface CompressionFactory -{ - public Compressor newCompressor(); - - public Decompressor newDecompressor(); - - public interface Compressor - { - public void setInput(byte[] input); - - public void setDictionary(byte[] dictionary); - - public int compress(byte[] output); - } - - public interface Decompressor - { - public void setDictionary(byte[] dictionary); - - public void setInput(byte[] input); - - public int decompress(byte[] output) throws ZipException; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java deleted file mode 100644 index b63695332c..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java +++ /dev/null @@ -1,30 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.Callback; - -public interface Controller -{ - public void write(Callback callback, ByteBuffer... buffers); - - public void close(boolean onlyOutput); -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java deleted file mode 100644 index d367b5e3e8..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java +++ /dev/null @@ -1,92 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.DataInfo; - -// TODO: add methods that tell how much written and whether we're TCP congested ? -public interface FlowControlStrategy -{ - public int getWindowSize(ISession session); - - public void setWindowSize(ISession session, int windowSize); - - public void onNewStream(ISession session, IStream stream); - - public void onWindowUpdate(ISession session, IStream stream, int delta); - - public void updateWindow(ISession session, IStream stream, int delta); - - public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo); - - public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta); - - public static class None implements FlowControlStrategy - { - private volatile int windowSize; - - public None() - { - this(65536); - } - - public None(int windowSize) - { - this.windowSize = windowSize; - } - - @Override - public int getWindowSize(ISession session) - { - return windowSize; - } - - @Override - public void setWindowSize(ISession session, int windowSize) - { - this.windowSize = windowSize; - } - - @Override - public void onNewStream(ISession session, IStream stream) - { - stream.updateWindowSize(windowSize); - } - - @Override - public void onWindowUpdate(ISession session, IStream stream, int delta) - { - } - - @Override - public void updateWindow(ISession session, IStream stream, int delta) - { - } - - @Override - public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo) - { - } - - @Override - public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta) - { - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java deleted file mode 100644 index 9bb7125833..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java +++ /dev/null @@ -1,266 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.jetty.spdy.StandardSession.FrameBytes; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.util.ArrayQueue; -import org.eclipse.jetty.util.IteratingCallback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class Flusher -{ - private static final Logger LOG = Log.getLogger(Flusher.class); - - private final IteratingCallback callback = new FlusherCallback(); - private final Object lock = new Object(); - private final ArrayQueue<StandardSession.FrameBytes> queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH, lock); - private final Controller controller; - private final int maxGather; - private Throwable failure; - - public Flusher(Controller controller) - { - this(controller, 8); - } - - public Flusher(Controller controller, int maxGather) - { - this.controller = controller; - this.maxGather = maxGather; - } - - public void removeFrameBytesFromQueue(Stream stream) - { - synchronized (lock) - { - for (StandardSession.FrameBytes frameBytes : queue) - if (frameBytes.getStream() == stream) - queue.remove(frameBytes); - } - } - - public Throwable prepend(StandardSession.FrameBytes frameBytes) - { - synchronized (lock) - { - Throwable failure = this.failure; - if (failure == null) - { - // Scan from the front of the queue looking to skip higher priority messages - int index = 0; - int size = queue.size(); - while (index < size) - { - StandardSession.FrameBytes element = queue.getUnsafe(index); - if (element.compareTo(frameBytes) <= 0) - break; - ++index; - } - queue.add(index, frameBytes); - } - return failure; - } - } - - public Throwable append(StandardSession.FrameBytes frameBytes) - { - synchronized (lock) - { - Throwable failure = this.failure; - if (failure == null) - { - // Non DataFrameBytes are inserted last - queue.add(frameBytes); - } - return failure; - } - } - - public Throwable append(StandardSession.DataFrameBytes frameBytes) - { - synchronized (lock) - { - Throwable failure = this.failure; - if (failure == null) - { - // DataFrameBytes are inserted by priority - int index = queue.size(); - while (index > 0) - { - StandardSession.FrameBytes element = queue.getUnsafe(index - 1); - if (element.compareTo(frameBytes) >= 0) - break; - --index; - } - queue.add(index, frameBytes); - } - return failure; - } - } - - public void flush() - { - callback.iterate(); - } - - public int getQueueSize() - { - synchronized (lock) - { - return queue.size(); - } - } - - private class FlusherCallback extends IteratingCallback - { - private final List<StandardSession.FrameBytes> active = new ArrayList<>(maxGather); - private final List<StandardSession.FrameBytes> succeeded = new ArrayList<>(maxGather); - private final Set<IStream> stalled = new HashSet<>(); - - @Override - protected Action process() throws Exception - { - synchronized (lock) - { - // Scan queue for data to write from first non stalled stream. - int index = 0; // The index of the first non-stalled frame. - int size = queue.size(); - while (index < size) - { - FrameBytes frameBytes = queue.getUnsafe(index); - IStream stream = frameBytes.getStream(); - - if (stream != null) - { - // Is it a frame belonging to an already stalled stream ? - if (stalled.size() > 0 && stalled.contains(stream)) - { - ++index; - continue; - } - - // Has the stream consumed all its flow control window ? - if (stream.getWindowSize() <= 0) - { - stalled.add(stream); - ++index; - continue; - } - } - - // We will be possibly writing this frame, so take the frame off the queue. - queue.remove(index); - --size; - - // Has the stream been reset for this data frame ? - if (stream != null && stream.isReset() && frameBytes instanceof StandardSession.DataFrameBytes) - { - // TODO: notify from within sync block ! - frameBytes.failed(new StreamException(frameBytes.getStream().getId(), - StreamStatus.INVALID_STREAM, "Stream: " + frameBytes.getStream() + " is reset!")); - continue; - } - - active.add(frameBytes); - } - stalled.clear(); - - if (LOG.isDebugEnabled()) - LOG.debug("Flushing {} of {} frame(s) in queue", active.size(), queue.size()); - } - - if (active.isEmpty()) - return Action.IDLE; - - // Get the bytes to write - ByteBuffer[] buffers = new ByteBuffer[active.size()]; - for (int i = 0; i < buffers.length; i++) - buffers[i] = active.get(i).getByteBuffer(); - - if (controller != null) - controller.write(this, buffers); - - // TODO: optimization - // If the callback completely immediately, it means that - // the connection is not congested, and therefore we can - // write more data without blocking. - // Therefore we should check this condition and increase - // the write window, which means two things: autotune the - // maxGather parameter, and/or autotune the buffer returned - // by FrameBytes.getByteBuffer() (see also comment there). - - return Action.SCHEDULED; - } - - @Override - protected void onCompleteSuccess() - { - // will never be called as process always returns SCHEDULED or IDLE - throw new IllegalStateException(); - } - - @Override - public void succeeded() - { - synchronized (lock) - { - if (LOG.isDebugEnabled()) - LOG.debug("Succeeded write of {}, q={}", active, queue.size()); - succeeded.addAll(active); - active.clear(); - } - // Notify outside the synchronized block. - for (FrameBytes frame : succeeded) - frame.succeeded(); - succeeded.clear(); - super.succeeded(); - } - - @Override - public void onCompleteFailure(Throwable x) - { - List<StandardSession.FrameBytes> failed = new ArrayList<>(); - synchronized (lock) - { - failure = x; - if (LOG.isDebugEnabled()) - { - String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue", this, queue.size()); - LOG.debug(logMessage, x); - } - failed.addAll(active); - active.clear(); - failed.addAll(queue); - queue.clear(); - } - // Notify outside the synchronized block. - for (StandardSession.FrameBytes frame : failed) - frame.failed(x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java deleted file mode 100644 index 23a5a47f5d..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java +++ /dev/null @@ -1,39 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.util.Callback; - -public interface ISession extends Session -{ - public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback); - - public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback); - - /** - * <p>Gracefully shuts down this session.</p> - * <p>A special item is queued that will close the connection when it will be dequeued.</p> - */ - public void shutdown(); -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java deleted file mode 100644 index 43582700f9..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java +++ /dev/null @@ -1,120 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.util.Callback; - -/** - * <p>The internal interface that represents a stream.</p> - * <p>{@link IStream} contains additional methods used by a SPDY - * implementation (and not by an application).</p> - */ -public interface IStream extends Stream, Callback -{ - /** - * <p>Senders of data frames need to know the current window size - * to determine whether they can send more data.</p> - * - * @return the current window size for this stream. - * @see #updateWindowSize(int) - */ - public int getWindowSize(); - - /** - * <p>Updates the window size for this stream by the given amount, - * that can be positive or negative.</p> - * <p>Senders and recipients of data frames update the window size, - * respectively, with negative values and positive values.</p> - * - * @param delta the signed amount the window size needs to be updated - * @see #getWindowSize() - */ - public void updateWindowSize(int delta); - - /** - * @param listener the stream frame listener associated to this stream - * as returned by {@link SessionFrameListener#onSyn(Stream, SynInfo)} - */ - public void setStreamFrameListener(StreamFrameListener listener); - - /** - * @return the stream frame listener associated to this stream - */ - public StreamFrameListener getStreamFrameListener(); - - /** - * <p>A stream can be open, {@link #isHalfClosed() half closed} or - * {@link #isClosed() closed} and this method updates the close state - * of this stream.</p> - * <p>If the stream is open, calling this method with a value of true - * puts the stream into half closed state.</p> - * <p>If the stream is half closed, calling this method with a value - * of true puts the stream into closed state.</p> - * - * @param close whether the close state should be updated - * @param local whether the close is local or remote - */ - public void updateCloseState(boolean close, boolean local); - - /** - * <p>Processes the given control frame, - * for example by updating the stream's state or by calling listeners.</p> - * - * @param frame the control frame to process - * @see #process(DataInfo) - */ - public void process(ControlFrame frame); - - /** - * <p>Processes the given {@code dataInfo}, - * for example by updating the stream's state or by calling listeners.</p> - * - * @param dataInfo the DataInfo to process - * @see #process(ControlFrame) - */ - public void process(DataInfo dataInfo); - - /** - * <p>Associate the given {@link IStream} to this {@link IStream}.</p> - * - * @param stream the stream to associate with this stream - */ - public void associate(IStream stream); - - /** - * <p>remove the given associated {@link IStream} from this stream</p> - * - * @param stream the stream to be removed - */ - public void disassociate(IStream stream); - - /** - * <p>Overrides Stream.getAssociatedStream() to return an instance of IStream instead of Stream - * - * @see Stream#getAssociatedStream() - */ - @Override - public IStream getAssociatedStream(); -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java deleted file mode 100644 index ff190d474e..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java +++ /dev/null @@ -1,24 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -public interface IdleListener -{ - public void onIdle(boolean idle); -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java deleted file mode 100644 index 39d13112ca..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java +++ /dev/null @@ -1,60 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.SynInfo; - -/* ------------------------------------------------------------ */ -/** - * <p>A subclass container of {@link SynInfo} for unidirectional streams</p> - */ -public class PushSynInfo extends SynInfo -{ - public static final byte FLAG_UNIDIRECTIONAL = 2; - - private int associatedStreamId; - - public PushSynInfo(int associatedStreamId, PushInfo pushInfo){ - super(pushInfo.getTimeout(), pushInfo.getUnit(), pushInfo.getHeaders(), pushInfo.isClose(), (byte)0); - this.associatedStreamId = associatedStreamId; - } - - /** - * @return the close and unidirectional flags as integer - * @see #FLAG_CLOSE - * @see #FLAG_UNIDIRECTIONAL - */ - @Override - public byte getFlags() - { - byte flags = super.getFlags(); - flags += FLAG_UNIDIRECTIONAL; - return flags; - } - - /** - * @return the id of the associated stream - */ - public int getAssociatedStreamId() - { - return associatedStreamId; - } - -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java deleted file mode 100644 index fe37965aa2..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.frames.WindowUpdateFrame; -import org.eclipse.jetty.util.Callback; - -public class SPDYv3FlowControlStrategy implements FlowControlStrategy -{ - private volatile int windowSize; - - @Override - public int getWindowSize(ISession session) - { - return windowSize; - } - - @Override - public void setWindowSize(ISession session, int windowSize) - { - int prevWindowSize = this.windowSize; - this.windowSize = windowSize; - for (Stream stream : session.getStreams()) - ((IStream)stream).updateWindowSize(windowSize - prevWindowSize); - } - - @Override - public void onNewStream(ISession session, IStream stream) - { - stream.updateWindowSize(windowSize); - } - - @Override - public void onWindowUpdate(ISession session, IStream stream, int delta) - { - if (stream != null) - stream.updateWindowSize(delta); - } - - @Override - public void updateWindow(ISession session, IStream stream, int delta) - { - stream.updateWindowSize(delta); - } - - @Override - public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo) - { - // Do nothing - } - - @Override - public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta) - { - // This is the algorithm for flow control. - // This method may be called multiple times with delta=1, but we only send a window - // update when the whole dataInfo has been consumed. - // Other policies may be to send window updates when consumed() is greater than - // a certain threshold, etc. but for now the policy is not pluggable for simplicity. - // Note that the frequency of window updates depends on the read buffer, that - // should not be too smaller than the window size to avoid frequent window updates. - // Therefore, a pluggable policy should be able to modify the read buffer capacity. - int length = dataInfo.length(); - if (dataInfo.consumed() == length && !stream.isClosed() && length > 0) - { - WindowUpdateFrame windowUpdateFrame = new WindowUpdateFrame(session.getVersion(), stream.getId(), length); - session.control(stream, windowUpdateFrame, 0, TimeUnit.MILLISECONDS, Callback.Adapter.INSTANCE); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java deleted file mode 100644 index 26bc843e5c..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.SessionStatus; - -public class SessionException extends RuntimeException -{ - private final SessionStatus sessionStatus; - - public SessionException(SessionStatus sessionStatus) - { - this.sessionStatus = sessionStatus; - } - - public SessionException(SessionStatus sessionStatus, String message) - { - super(message); - this.sessionStatus = sessionStatus; - } - - public SessionException(SessionStatus sessionStatus, Throwable cause) - { - super(cause); - this.sessionStatus = sessionStatus; - } - - public SessionStatus getSessionStatus() - { - return sessionStatus; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java deleted file mode 100644 index 35150cfae0..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java +++ /dev/null @@ -1,92 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.Inflater; -import java.util.zip.ZipException; - -public class StandardCompressionFactory implements CompressionFactory -{ - @Override - public Compressor newCompressor() - { - return new StandardCompressor(); - } - - @Override - public Decompressor newDecompressor() - { - return new StandardDecompressor(); - } - - public static class StandardCompressor implements Compressor - { - private final Deflater deflater = new Deflater(); - - @Override - public void setInput(byte[] input) - { - deflater.setInput(input); - } - - @Override - public void setDictionary(byte[] dictionary) - { - deflater.setDictionary(dictionary); - } - - @Override - public int compress(byte[] output) - { - return deflater.deflate(output, 0, output.length, Deflater.SYNC_FLUSH); - } - } - - public static class StandardDecompressor implements CompressionFactory.Decompressor - { - private final Inflater inflater = new Inflater(); - - @Override - public void setDictionary(byte[] dictionary) - { - inflater.setDictionary(dictionary); - } - - @Override - public void setInput(byte[] input) - { - inflater.setInput(input); - } - - @Override - public int decompress(byte[] output) throws ZipException - { - try - { - return inflater.inflate(output); - } - catch (DataFormatException x) - { - throw (ZipException)new ZipException().initCause(x); - } - } - } -} 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 deleted file mode 100644 index c03cb4bf51..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java +++ /dev/null @@ -1,1303 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.InterruptedByTimeoutException; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.PingInfo; -import org.eclipse.jetty.spdy.api.PingResultInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDYException; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.CredentialFrame; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.spdy.frames.GoAwayFrame; -import org.eclipse.jetty.spdy.frames.HeadersFrame; -import org.eclipse.jetty.spdy.frames.PingFrame; -import org.eclipse.jetty.spdy.frames.RstStreamFrame; -import org.eclipse.jetty.spdy.frames.SettingsFrame; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.frames.WindowUpdateFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Atomics; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FutureCallback; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Scheduler; - -public class StandardSession implements ISession, Parser.Listener, Dumpable -{ - private static final Logger LOG = Log.getLogger(Session.class); - - private final Flusher flusher; - private final Map<String, Object> attributes = new ConcurrentHashMap<>(); - private final List<Listener> listeners = new CopyOnWriteArrayList<>(); - private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>(); - private final ByteBufferPool bufferPool; - private final Scheduler scheduler; - private final short version; - private final Controller controller; - private final EndPoint endPoint; - private final IdleListener idleListener; - private final AtomicInteger streamIds; - private final AtomicInteger pingIds; - private final SessionFrameListener listener; - private final Generator generator; - private final AtomicBoolean goAwaySent = new AtomicBoolean(); - private final AtomicBoolean goAwayReceived = new AtomicBoolean(); - private final AtomicInteger lastStreamId = new AtomicInteger(); - private final AtomicInteger localStreamCount = new AtomicInteger(0); - private final FlowControlStrategy flowControlStrategy; - private volatile int maxConcurrentLocalStreams = -1; - - public StandardSession(short version, ByteBufferPool bufferPool, Scheduler scheduler, - Controller controller, EndPoint endPoint, IdleListener idleListener, int initialStreamId, - SessionFrameListener listener, Generator generator, FlowControlStrategy flowControlStrategy) - { - // TODO this should probably be an aggregate lifecycle - this.version = version; - this.bufferPool = bufferPool; - this.scheduler = scheduler; - this.controller = controller; - this.endPoint = endPoint; - this.idleListener = idleListener; - this.streamIds = new AtomicInteger(initialStreamId); - this.pingIds = new AtomicInteger(initialStreamId); - this.listener = listener; - this.generator = generator; - this.flowControlStrategy = flowControlStrategy; - this.flusher = new Flusher(controller); - } - - @Override - public short getVersion() - { - return version; - } - - @Override - public void addListener(Listener listener) - { - listeners.add(listener); - } - - @Override - public void removeListener(Listener listener) - { - listeners.remove(listener); - } - - @Override - public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException - { - FuturePromise<Stream> result = new FuturePromise<>(); - syn(synInfo, listener, result); - if (synInfo.getTimeout() > 0) - return result.get(synInfo.getTimeout(), synInfo.getUnit()); - else - return result.get(); - } - - @Override - public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise) - { - // Synchronization is necessary. - // SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent - // so we cannot allow thread1 to create stream1 and thread2 create stream3 and - // have stream3 hit the network before stream1, not only to comply with the spec - // but also because the compression context for the headers would be wrong, as the - // frame with a compression history will come before the first compressed frame. - int associatedStreamId = 0; - if (synInfo instanceof PushSynInfo) - associatedStreamId = ((PushSynInfo)synInfo).getAssociatedStreamId(); - - synchronized (this) - { - int streamId = streamIds.getAndAdd(2); - // TODO: for SPDYv3 we need to support the "slot" argument - SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders()); - IStream stream = createStream(synStream, listener, true, promise); - if (stream == null) - return; - generateAndEnqueueControlFrame(stream, synStream, synInfo.getTimeout(), synInfo.getUnit(), stream); - } - } - - @Override - public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException - { - FutureCallback result = new FutureCallback(); - rst(rstInfo, result); - if (rstInfo.getTimeout() > 0) - result.get(rstInfo.getTimeout(), rstInfo.getUnit()); - else - result.get(); - } - - @Override - public void rst(RstInfo rstInfo, Callback callback) - { - // SPEC v3, 2.2.2 - if (goAwaySent.get()) - { - complete(callback); - } - else - { - int streamId = rstInfo.getStreamId(); - IStream stream = streams.get(streamId); - RstStreamFrame frame = new RstStreamFrame(version, streamId, rstInfo.getStreamStatus().getCode(version)); - control(stream, frame, rstInfo.getTimeout(), rstInfo.getUnit(), callback); - if (stream != null) - { - stream.process(frame); - flusher.removeFrameBytesFromQueue(stream); - removeStream(stream); - } - } - } - - @Override - public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException - { - FutureCallback result = new FutureCallback(); - settings(settingsInfo, result); - if (settingsInfo.getTimeout() > 0) - result.get(settingsInfo.getTimeout(), settingsInfo.getUnit()); - else - result.get(); - } - - @Override - public void settings(SettingsInfo settingsInfo, Callback callback) - { - SettingsFrame frame = new SettingsFrame(version, settingsInfo.getFlags(), settingsInfo.getSettings()); - control(null, frame, settingsInfo.getTimeout(), settingsInfo.getUnit(), callback); - } - - @Override - public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException - { - FuturePromise<PingResultInfo> result = new FuturePromise<>(); - ping(pingInfo, result); - if (pingInfo.getTimeout() > 0) - return result.get(pingInfo.getTimeout(), pingInfo.getUnit()); - else - return result.get(); - } - - @Override - public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise) - { - int pingId = pingIds.getAndAdd(2); - PingInfoCallback pingInfoCallback = new PingInfoCallback(pingId, promise); - PingFrame frame = new PingFrame(version, pingId); - control(null, frame, pingInfo.getTimeout(), pingInfo.getUnit(), pingInfoCallback); - } - - @Override - public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException - { - goAway(goAwayInfo, SessionStatus.OK); - } - - private void goAway(GoAwayInfo goAwayInfo, SessionStatus sessionStatus) throws ExecutionException, InterruptedException, TimeoutException - { - FutureCallback result = new FutureCallback(); - goAway(sessionStatus, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), result); - if (goAwayInfo.getTimeout() > 0) - result.get(goAwayInfo.getTimeout(), goAwayInfo.getUnit()); - else - result.get(); - } - - @Override - public void goAway(GoAwayInfo goAwayInfo, Callback callback) - { - goAway(SessionStatus.OK, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), callback); - } - - private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback callback) - { - if (goAwaySent.compareAndSet(false, true)) - { - if (!goAwayReceived.get()) - { - GoAwayFrame frame = new GoAwayFrame(version, lastStreamId.get(), sessionStatus.getCode()); - control(null, frame, timeout, unit, callback); - return; - } - } - complete(callback); - } - - @Override - public Set<Stream> getStreams() - { - Set<Stream> result = new HashSet<>(); - result.addAll(streams.values()); - return result; - } - - @Override - public IStream getStream(int streamId) - { - return streams.get(streamId); - } - - @Override - public Object getAttribute(String key) - { - return attributes.get(key); - } - - @Override - public void setAttribute(String key, Object value) - { - attributes.put(key, value); - } - - @Override - public Object removeAttribute(String key) - { - return attributes.remove(key); - } - - @Override - public InetSocketAddress getLocalAddress() - { - return endPoint.getLocalAddress(); - } - - @Override - public InetSocketAddress getRemoteAddress() - { - return endPoint.getRemoteAddress(); - } - - @Override - public void onControlFrame(ControlFrame frame) - { - notifyIdle(idleListener, false); - try - { - if (LOG.isDebugEnabled()) - LOG.debug("Processing {}", frame); - - if (goAwaySent.get()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Skipped processing of {}", frame); - return; - } - - switch (frame.getType()) - { - case SYN_STREAM: - { - onSyn((SynStreamFrame)frame); - break; - } - case SYN_REPLY: - { - onReply((SynReplyFrame)frame); - break; - } - case RST_STREAM: - { - onRst((RstStreamFrame)frame); - break; - } - case SETTINGS: - { - onSettings((SettingsFrame)frame); - break; - } - case NOOP: - { - // Just ignore it - break; - } - case PING: - { - onPing((PingFrame)frame); - break; - } - case GO_AWAY: - { - onGoAway((GoAwayFrame)frame); - break; - } - case HEADERS: - { - onHeaders((HeadersFrame)frame); - break; - } - case WINDOW_UPDATE: - { - onWindowUpdate((WindowUpdateFrame)frame); - break; - } - case CREDENTIAL: - { - onCredential((CredentialFrame)frame); - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - finally - { - notifyIdle(idleListener, true); - } - } - - @Override - public void onDataFrame(DataFrame frame, ByteBuffer data) - { - notifyIdle(idleListener, false); - try - { - if (LOG.isDebugEnabled()) - LOG.debug("Processing {}, {} data bytes", frame, data.remaining()); - - if (goAwaySent.get()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Skipped processing of {}", frame); - return; - } - - int streamId = frame.getStreamId(); - IStream stream = streams.get(streamId); - if (stream == null) - { - RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM); - if (LOG.isDebugEnabled()) - LOG.debug("Unknown stream {}", rstInfo); - rst(rstInfo, Callback.Adapter.INSTANCE); - } - else - { - processData(stream, frame, data); - } - } - finally - { - notifyIdle(idleListener, true); - } - } - - private void notifyIdle(IdleListener listener, boolean idle) - { - if (listener != null) - listener.onIdle(idle); - } - - private void processData(final IStream stream, DataFrame frame, ByteBuffer data) - { - ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - flowControlStrategy.onDataConsumed(StandardSession.this, stream, this, delta); - } - }; - flowControlStrategy.onDataReceived(this, stream, dataInfo); - stream.process(dataInfo); - if (stream.isClosed()) - removeStream(stream); - } - - @Override - public void onStreamException(StreamException x) - { - notifyOnFailure(listener, x); // TODO: notify StreamFrameListener if exists? - rst(new RstInfo(x.getStreamId(), x.getStreamStatus()), Callback.Adapter.INSTANCE); - } - - @Override - public void onSessionException(SessionException x) - { - Throwable cause = x.getCause(); - notifyOnFailure(listener, cause == null ? x : cause); - goAway(x.getSessionStatus(), 0, TimeUnit.SECONDS, Callback.Adapter.INSTANCE); - } - - private void onSyn(final SynStreamFrame frame) - { - 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); - } - - private void processSyn(SessionFrameListener listener, IStream stream, SynStreamFrame frame) - { - stream.process(frame); - // Update the last stream id before calling the application (which may send a GO_AWAY) - updateLastStreamId(stream); - StreamFrameListener streamListener; - if (stream.isUnidirectional()) - { - PushInfo pushInfo = new PushInfo(frame.getHeaders(), frame.isClose()); - streamListener = notifyOnPush(stream.getAssociatedStream().getStreamFrameListener(), stream, pushInfo); - } - else - { - SynInfo synInfo = new SynInfo(frame.getHeaders(), frame.isClose(), frame.getPriority()); - streamListener = notifyOnSyn(listener, stream, synInfo); - } - stream.setStreamFrameListener(streamListener); - // The onSyn() listener may have sent a frame that closed the stream - if (stream.isClosed()) - removeStream(stream); - } - - private IStream createStream(SynStreamFrame frame, StreamFrameListener listener, boolean local, Promise<Stream> promise) - { - IStream associatedStream = streams.get(frame.getAssociatedStreamId()); - IStream stream = new StandardStream(frame.getStreamId(), frame.getPriority(), this, associatedStream, - scheduler, promise); - stream.setIdleTimeout(endPoint.getIdleTimeout()); - flowControlStrategy.onNewStream(this, stream); - - stream.updateCloseState(frame.isClose(), local); - stream.setStreamFrameListener(listener); - - if (stream.isUnidirectional()) - { - // Unidirectional streams are implicitly half closed - stream.updateCloseState(true, !local); - if (!stream.isClosed()) - stream.getAssociatedStream().associate(stream); - } - - int streamId = stream.getId(); - - if (local) - { - while (true) - { - int oldStreamCountValue = localStreamCount.get(); - int maxConcurrentStreams = maxConcurrentLocalStreams; - if (maxConcurrentStreams > -1 && oldStreamCountValue >= maxConcurrentStreams) - { - String message = String.format("Max concurrent local streams (%d) exceeded.", - maxConcurrentStreams); - LOG.debug(message); - promise.failed(new SPDYException(message)); - return null; - } - if (localStreamCount.compareAndSet(oldStreamCountValue, oldStreamCountValue + 1)) - break; - } - } - - if (streams.putIfAbsent(streamId, stream) != null) - { - String message = "Duplicate stream id " + streamId; - IllegalStateException duplicateIdException = new IllegalStateException(message); - promise.failed(duplicateIdException); - if (local) - { - localStreamCount.decrementAndGet(); - throw duplicateIdException; - } - RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR); - if (LOG.isDebugEnabled()) - LOG.debug("Duplicate stream, {}", rstInfo); - rst(rstInfo, Callback.Adapter.INSTANCE); // We don't care (too much) if the reset fails. - return null; - } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Created {}", stream); - notifyStreamCreated(stream); - return stream; - } - } - - private void notifyStreamCreated(IStream stream) - { - for (Listener listener : listeners) - { - if (listener instanceof StreamListener) - { - try - { - ((StreamListener)listener).onStreamCreated(stream); - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - } - } - - private void removeStream(IStream stream) - { - if (stream.isUnidirectional()) - stream.getAssociatedStream().disassociate(stream); - - IStream removed = streams.remove(stream.getId()); - if (removed != null) - { - assert removed == stream; - - if (streamIds.get() % 2 == stream.getId() % 2) - localStreamCount.decrementAndGet(); - - if (LOG.isDebugEnabled()) - LOG.debug("Removed {}", stream); - notifyStreamClosed(stream); - } - } - - private void notifyStreamClosed(IStream stream) - { - for (Listener listener : listeners) - { - if (listener instanceof StreamListener) - { - try - { - ((StreamListener)listener).onStreamClosed(stream); - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - } - } - - private void onReply(SynReplyFrame frame) - { - int streamId = frame.getStreamId(); - IStream stream = streams.get(streamId); - if (stream == null) - { - RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM); - if (LOG.isDebugEnabled()) - LOG.debug("Unknown stream {}", rstInfo); - rst(rstInfo, Callback.Adapter.INSTANCE); - } - else - { - processReply(stream, frame); - } - } - - private void processReply(IStream stream, SynReplyFrame frame) - { - stream.process(frame); - if (stream.isClosed()) - removeStream(stream); - } - - private void onRst(RstStreamFrame frame) - { - IStream stream = streams.get(frame.getStreamId()); - - if (stream != null) - stream.process(frame); - - RstInfo rstInfo = new RstInfo(frame.getStreamId(), StreamStatus.from(frame.getVersion(), frame.getStatusCode())); - notifyOnRst(listener, rstInfo); - - if (stream != null) - removeStream(stream); - } - - private void onSettings(SettingsFrame frame) - { - Settings.Setting windowSizeSetting = frame.getSettings().get(Settings.ID.INITIAL_WINDOW_SIZE); - if (windowSizeSetting != null) - { - int windowSize = windowSizeSetting.value(); - setWindowSize(windowSize); - if (LOG.isDebugEnabled()) - LOG.debug("Updated session window size to {}", windowSize); - } - Settings.Setting maxConcurrentStreamsSetting = frame.getSettings().get(Settings.ID.MAX_CONCURRENT_STREAMS); - if (maxConcurrentStreamsSetting != null) - { - int maxConcurrentStreamsValue = maxConcurrentStreamsSetting.value(); - maxConcurrentLocalStreams = maxConcurrentStreamsValue; - if (LOG.isDebugEnabled()) - LOG.debug("Updated session maxConcurrentLocalStreams to {}", maxConcurrentStreamsValue); - } - SettingsInfo settingsInfo = new SettingsInfo(frame.getSettings(), frame.isClearPersisted()); - notifyOnSettings(listener, settingsInfo); - } - - private void onPing(PingFrame frame) - { - int pingId = frame.getPingId(); - if (pingId % 2 == pingIds.get() % 2) - { - PingResultInfo pingResultInfo = new PingResultInfo(frame.getPingId()); - notifyOnPing(listener, pingResultInfo); - } - else - { - control(null, frame, 0, TimeUnit.MILLISECONDS, Callback.Adapter.INSTANCE); - } - } - - private void onGoAway(GoAwayFrame frame) - { - if (goAwayReceived.compareAndSet(false, true)) - { - GoAwayResultInfo goAwayResultInfo = new GoAwayResultInfo(frame.getLastStreamId(), SessionStatus.from(frame.getStatusCode())); - notifyOnGoAway(listener, goAwayResultInfo); - // SPDY does not require to send back a response to a GO_AWAY. - // We notified the application of the last good stream id and - // tried our best to flush remaining data. - } - } - - private void onHeaders(HeadersFrame frame) - { - int streamId = frame.getStreamId(); - IStream stream = streams.get(streamId); - if (stream == null) - { - RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM); - if (LOG.isDebugEnabled()) - LOG.debug("Unknown stream, {}", rstInfo); - rst(rstInfo, Callback.Adapter.INSTANCE); - } - else - { - processHeaders(stream, frame); - } - } - - private void processHeaders(IStream stream, HeadersFrame frame) - { - stream.process(frame); - if (stream.isClosed()) - removeStream(stream); - } - - private void onWindowUpdate(WindowUpdateFrame frame) - { - int streamId = frame.getStreamId(); - IStream stream = streams.get(streamId); - flowControlStrategy.onWindowUpdate(this, stream, frame.getWindowDelta()); - flusher.flush(); - } - - private void onCredential(CredentialFrame frame) - { - LOG.warn("{} frame not yet supported", frame.getType()); - } - - protected void close() - { - // Check for null to support tests - if (controller != null) - controller.close(false); - } - - private void notifyOnFailure(SessionFrameListener listener, Throwable x) - { - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", x, listener); - listener.onFailure(this, x); - } - } - catch (Exception xx) - { - LOG.info("Exception while notifying listener " + listener, xx); - } - catch (Error xx) - { - LOG.info("Exception while notifying listener " + listener, xx); - throw xx; - } - } - - private StreamFrameListener notifyOnPush(StreamFrameListener listener, Stream stream, PushInfo pushInfo) - { - try - { - if (listener == null) - return null; - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", pushInfo, listener); - return listener.onPush(stream, pushInfo); - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - return null; - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private StreamFrameListener notifyOnSyn(SessionFrameListener listener, Stream stream, SynInfo synInfo) - { - try - { - if (listener == null) - return null; - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", synInfo, listener); - return listener.onSyn(stream, synInfo); - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - return null; - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnRst(SessionFrameListener listener, RstInfo rstInfo) - { - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", rstInfo, listener); - listener.onRst(this, rstInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnSettings(SessionFrameListener listener, SettingsInfo settingsInfo) - { - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", settingsInfo, listener); - listener.onSettings(this, settingsInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnPing(SessionFrameListener listener, PingResultInfo pingResultInfo) - { - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", pingResultInfo, listener); - listener.onPing(this, pingResultInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnGoAway(SessionFrameListener listener, GoAwayResultInfo goAwayResultInfo) - { - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking callback with {} on listener {}", goAwayResultInfo, listener); - listener.onGoAway(this, goAwayResultInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - @Override - public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback) - { - generateAndEnqueueControlFrame(stream, frame, timeout, unit, callback); - } - - private void generateAndEnqueueControlFrame(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback) - { - try - { - // Synchronization is necessary, since we may have concurrent replies - // and those needs to be generated and enqueued atomically in order - // to maintain a correct compression context - ControlFrameBytes frameBytes; - Throwable throwable; - synchronized (this) - { - ByteBuffer buffer = generator.control(frame); - if (LOG.isDebugEnabled()) - LOG.debug("Queuing {} on {}", frame, stream); - frameBytes = new ControlFrameBytes(stream, callback, frame, buffer); - if (timeout > 0) - frameBytes.task = scheduler.schedule(frameBytes, timeout, unit); - - // Special handling for PING frames, they must be sent as soon as possible - if (ControlFrameType.PING == frame.getType()) - throwable = flusher.prepend(frameBytes); - else - throwable = flusher.append(frameBytes); - } - // Flush MUST be done outside synchronized blocks - flush(frameBytes, throwable); - } - catch (Exception x) - { - notifyCallbackFailed(callback, x); - } - } - - private void updateLastStreamId(IStream stream) - { - int streamId = stream.getId(); - if (streamId % 2 != streamIds.get() % 2) - Atomics.updateMax(lastStreamId, streamId); - } - - @Override - public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback) - { - if (LOG.isDebugEnabled()) - LOG.debug("Queuing {} on {}", dataInfo, stream); - DataFrameBytes frameBytes = new DataFrameBytes(stream, callback, dataInfo); - if (timeout > 0) - frameBytes.task = scheduler.schedule(frameBytes, timeout, unit); - flush(frameBytes, flusher.append(frameBytes)); - } - - @Override - public void shutdown() - { - CloseFrameBytes frameBytes = new CloseFrameBytes(); - flush(frameBytes, flusher.append(frameBytes)); - } - - private void flush(FrameBytes frameBytes, Throwable throwable) - { - if (throwable != null) - frameBytes.failed(throwable); - else - flusher.flush(); - } - - private void complete(final Callback callback) - { - try - { - if (callback != null) - callback.succeeded(); - } - catch (Throwable x) - { - LOG.info("Exception while notifying callback " + callback, x); - } - } - - private void notifyCallbackFailed(Callback callback, Throwable failure) - { - try - { - if (callback != null) - callback.failed(failure); - } - catch (Throwable x) - { - LOG.info("Exception while notifying callback " + callback, x); - } - } - - public int getWindowSize() - { - return flowControlStrategy.getWindowSize(this); - } - - public void setWindowSize(int initialWindowSize) - { - flowControlStrategy.setWindowSize(this, initialWindowSize); - } - - @Override - public String toString() - { - return String.format("%s@%x{v%d,queueSize=%d,windowSize=%d,streams=%d}", getClass().getSimpleName(), - hashCode(), version, flusher.getQueueSize(), getWindowSize(), streams.size()); - } - - @Override - public String dump() - { - return ContainerLifeCycle.dump(this); - } - - @Override - public void dump(Appendable out, String indent) throws IOException - { - ContainerLifeCycle.dumpObject(out, this); - ContainerLifeCycle.dump(out, indent, Collections.singletonList(controller), streams.values()); - } - - public interface FrameBytes extends Comparable<FrameBytes>, Callback - { - public IStream getStream(); - - public abstract ByteBuffer getByteBuffer(); - } - - abstract class AbstractFrameBytes implements FrameBytes, Runnable - { - private final IStream stream; - private final Callback callback; - protected volatile Scheduler.Task task; - - protected AbstractFrameBytes(IStream stream, Callback callback) - { - this.stream = stream; - this.callback = Objects.requireNonNull(callback); - } - - @Override - public IStream getStream() - { - return stream; - } - - @Override - public int compareTo(FrameBytes that) - { - // FrameBytes may have or not have a related stream (for example, PING do not have a related stream) - // FrameBytes without related streams have higher priority - IStream thisStream = getStream(); - IStream thatStream = that.getStream(); - if (thisStream == null) - return thatStream == null ? 0 : -1; - if (thatStream == null) - return 1; - // If this.stream.priority > that.stream.priority => this.stream has less priority than that.stream - return thatStream.getPriority() - thisStream.getPriority(); - } - - private void cancelTask() - { - Scheduler.Task task = this.task; - if (task != null) - task.cancel(); - } - - @Override - public void run() - { - close(); - failed(new InterruptedByTimeoutException()); - } - - @Override - public void succeeded() - { - cancelTask(); - StandardSession.this.complete(callback); - } - - @Override - public void failed(Throwable x) - { - cancelTask(); - notifyCallbackFailed(callback, x); - } - } - - protected class ControlFrameBytes extends AbstractFrameBytes - { - private final ControlFrame frame; - private final ByteBuffer buffer; - - private ControlFrameBytes(IStream stream, Callback callback, ControlFrame frame, ByteBuffer buffer) - { - super(stream, callback); - this.frame = frame; - this.buffer = buffer; - } - - @Override - public ByteBuffer getByteBuffer() - { - return buffer; - } - - @Override - public void succeeded() - { - bufferPool.release(buffer); - - super.succeeded(); - - if (frame.getType() == ControlFrameType.GO_AWAY) - { - // After sending a GO_AWAY we need to hard close the connection. - // Recipients will know the last good stream id and act accordingly. - close(); - } - IStream stream = getStream(); - if (stream != null && stream.isClosed()) - removeStream(stream); - } - - @Override - public String toString() - { - return frame.toString(); - } - } - - protected class DataFrameBytes extends AbstractFrameBytes - { - private final DataInfo dataInfo; - private int size; - private volatile ByteBuffer buffer; - - private DataFrameBytes(IStream stream, Callback handler, DataInfo dataInfo) - { - super(stream, handler); - this.dataInfo = dataInfo; - } - - @Override - public ByteBuffer getByteBuffer() - { - try - { - IStream stream = getStream(); - int windowSize = stream.getWindowSize(); - - // TODO: optimization - // Right now, we use the windowSize to chunk big buffers. - // However, if the window size is large, we may congest the - // connection, or favor one stream that does a big download, - // starving the other streams. - // Also, SPDY DATA frames have a maximum of 16 MiB size, which - // is not enforced here. - // We should have a configurable "preferredDataFrameSize" - // (or even better autotuning) that will allow to send chunks - // that will not starve other streams and small enough to - // not congest the connection, while avoiding to send too many - // TCP packets. - // See also comment in class Flusher. - - size = dataInfo.available(); - if (size > windowSize) - size = windowSize; - - buffer = generator.data(stream.getId(), size, dataInfo); - return buffer; - } - catch (Throwable x) - { - failed(x); - return null; - } - } - - @Override - public void succeeded() - { - bufferPool.release(buffer); - IStream stream = getStream(); - dataInfo.consume(size); - flowControlStrategy.updateWindow(StandardSession.this, stream, -size); - if (dataInfo.available() > 0) - { - // We have written a frame out of this DataInfo, but there is more to write. - // We need to keep the correct ordering of frames, to avoid that another - // DataInfo for the same stream is written before this one is finished. - flush(this, flusher.prepend(this)); - } - else - { - super.succeeded(); - stream.updateCloseState(dataInfo.isClose(), true); - if (stream.isClosed()) - removeStream(stream); - } - } - - @Override - public String toString() - { - return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), getStream()); - } - } - - protected class CloseFrameBytes extends AbstractFrameBytes - { - private CloseFrameBytes() - { - super(null, Callback.Adapter.INSTANCE); - } - - @Override - public ByteBuffer getByteBuffer() - { - return BufferUtil.EMPTY_BUFFER; - } - - @Override - public void succeeded() - { - super.succeeded(); - close(); - } - } - - private static class PingInfoCallback extends PingResultInfo implements Callback - { - private final Promise<PingResultInfo> promise; - - public PingInfoCallback(int pingId, Promise<PingResultInfo> promise) - { - super(pingId); - this.promise = promise; - } - - @Override - public void succeeded() - { - if (promise != null) - promise.succeeded(this); - } - - @Override - public void failed(Throwable x) - { - if (promise != null) - promise.failed(x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java deleted file mode 100644 index e5f5641e8a..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java +++ /dev/null @@ -1,602 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.io.IdleTimeout; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.HeadersFrame; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FutureCallback; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Scheduler; - -public class StandardStream extends IdleTimeout implements IStream -{ - private static final Logger LOG = Log.getLogger(Stream.class); - private final Map<String, Object> attributes = new ConcurrentHashMap<>(); - private final int id; - private final byte priority; - private final ISession session; - private final IStream associatedStream; - private final Promise<Stream> promise; - private final AtomicInteger windowSize = new AtomicInteger(); - private final Set<Stream> pushedStreams = Collections.newSetFromMap(new ConcurrentHashMap<Stream, Boolean>()); - private volatile StreamFrameListener listener; - private volatile OpenState openState = OpenState.SYN_SENT; - private volatile CloseState closeState = CloseState.OPENED; - private volatile boolean reset = false; - - public StandardStream(int id, byte priority, ISession session, IStream associatedStream, Scheduler scheduler, Promise<Stream> promise) - { - super(scheduler); - this.id = id; - this.priority = priority; - this.session = session; - this.associatedStream = associatedStream; - this.promise = promise; - } - - @Override - public int getId() - { - return id; - } - - @Override - public IStream getAssociatedStream() - { - return associatedStream; - } - - @Override - public Set<Stream> getPushedStreams() - { - return pushedStreams; - } - - @Override - public void associate(IStream stream) - { - pushedStreams.add(stream); - } - - @Override - public void disassociate(IStream stream) - { - pushedStreams.remove(stream); - } - - @Override - public byte getPriority() - { - return priority; - } - - @Override - protected void onIdleExpired(TimeoutException timeout) - { - StreamFrameListener listener = this.listener; - if (listener != null) - listener.onFailure(this, timeout); - // The stream is now gone, we must close it to - // avoid that its idle timeout is rescheduled. - close(); - } - - private void close() - { - closeState = CloseState.CLOSED; - onClose(); - } - - @Override - public boolean isOpen() - { - return !isClosed(); - } - - @Override - public int getWindowSize() - { - return windowSize.get(); - } - - @Override - public void updateWindowSize(int delta) - { - int size = windowSize.addAndGet(delta); - if (LOG.isDebugEnabled()) - LOG.debug("Updated window size {} -> {} for {}", size - delta, size, this); - } - - @Override - public ISession getSession() - { - return session; - } - - @Override - public Object getAttribute(String key) - { - return attributes.get(key); - } - - @Override - public void setAttribute(String key, Object value) - { - attributes.put(key, value); - } - - @Override - public Object removeAttribute(String key) - { - return attributes.remove(key); - } - - @Override - public void setStreamFrameListener(StreamFrameListener listener) - { - this.listener = listener; - } - - @Override - public StreamFrameListener getStreamFrameListener() - { - return listener; - } - - @Override - public void updateCloseState(boolean close, boolean local) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} close={} local={}", this, close, local); - if (close) - { - switch (closeState) - { - case OPENED: - { - closeState = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED; - break; - } - case LOCALLY_CLOSED: - { - if (local) - throw new IllegalStateException(); - else - close(); - break; - } - case REMOTELY_CLOSED: - { - if (local) - close(); - else - throw new IllegalStateException(); - break; - } - default: - { - LOG.warn("Already CLOSED! {} local={}", this, local); - } - } - } - } - - @Override - public void process(ControlFrame frame) - { - notIdle(); - switch (frame.getType()) - { - case SYN_STREAM: - { - openState = OpenState.SYN_RECV; - break; - } - case SYN_REPLY: - { - openState = OpenState.REPLY_RECV; - SynReplyFrame synReply = (SynReplyFrame)frame; - updateCloseState(synReply.isClose(), false); - ReplyInfo replyInfo = new ReplyInfo(synReply.getHeaders(), synReply.isClose()); - notifyOnReply(replyInfo); - break; - } - case HEADERS: - { - HeadersFrame headers = (HeadersFrame)frame; - updateCloseState(headers.isClose(), false); - HeadersInfo headersInfo = new HeadersInfo(headers.getHeaders(), headers.isClose(), headers.isResetCompression()); - notifyOnHeaders(headersInfo); - break; - } - case RST_STREAM: - { - reset = true; - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - - @Override - public void process(DataInfo dataInfo) - { - notIdle(); - // TODO: in v3 we need to send a rst instead of just ignoring - // ignore data frame if this stream is remotelyClosed already - if (isRemotelyClosed()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Stream is remotely closed, ignoring {}", dataInfo); - return; - } - - if (!canReceive()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Protocol error receiving {}, resetting", dataInfo); - session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), Callback.Adapter.INSTANCE); - return; - } - - updateCloseState(dataInfo.isClose(), false); - notifyOnData(dataInfo); - } - - @Override - public void succeeded() - { - if (promise != null) - promise.succeeded(this); - } - - @Override - public void failed(Throwable x) - { - if (promise != null) - promise.failed(x); - } - - private void notifyOnReply(ReplyInfo replyInfo) - { - final StreamFrameListener listener = this.listener; - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking reply callback with {} on listener {}", replyInfo, listener); - listener.onReply(this, replyInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnHeaders(HeadersInfo headersInfo) - { - final StreamFrameListener listener = this.listener; - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking headers callback with {} on listener {}", headersInfo, listener); - listener.onHeaders(this, headersInfo); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - private void notifyOnData(DataInfo dataInfo) - { - final StreamFrameListener listener = this.listener; - try - { - if (listener != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Invoking data callback with {} on listener {}", dataInfo, listener); - listener.onData(this, dataInfo); - if (LOG.isDebugEnabled()) - LOG.debug("Invoked data callback with {} on listener {}", dataInfo, listener); - } - } - catch (Exception x) - { - LOG.info("Exception while notifying listener " + listener, x); - } - catch (Error x) - { - LOG.info("Exception while notifying listener " + listener, x); - throw x; - } - } - - @Override - public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException - { - FuturePromise<Stream> result = new FuturePromise<>(); - push(pushInfo, result); - if (pushInfo.getTimeout() > 0) - return result.get(pushInfo.getTimeout(), pushInfo.getUnit()); - else - return result.get(); - } - - @Override - public void push(PushInfo pushInfo, Promise<Stream> promise) - { - notIdle(); - if (isClosed() || isReset()) - { - close(); - promise.failed(new StreamException(getId(), StreamStatus.STREAM_ALREADY_CLOSED, - "Stream: " + this + " already closed or reset!")); - return; - } - PushSynInfo pushSynInfo = new PushSynInfo(getId(), pushInfo); - session.syn(pushSynInfo, null, new StreamPromise(promise)); - } - - @Override - public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException - { - FutureCallback result = new FutureCallback(); - reply(replyInfo, result); - if (replyInfo.getTimeout() > 0) - result.get(replyInfo.getTimeout(), replyInfo.getUnit()); - else - result.get(); - } - - @Override - public void reply(ReplyInfo replyInfo, Callback callback) - { - notIdle(); - if (isUnidirectional()) - { - close(); - throw new IllegalStateException("Protocol violation: cannot send SYN_REPLY frames in unidirectional streams"); - } - openState = OpenState.REPLY_SENT; - updateCloseState(replyInfo.isClose(), true); - SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders()); - session.control(this, frame, replyInfo.getTimeout(), replyInfo.getUnit(), new StreamCallback(callback)); - } - - @Override - public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException - { - FutureCallback result = new FutureCallback(); - data(dataInfo, result); - if (dataInfo.getTimeout() > 0) - result.get(dataInfo.getTimeout(), dataInfo.getUnit()); - else - result.get(); - } - - @Override - public void data(DataInfo dataInfo, Callback callback) - { - notIdle(); - if (!canSend()) - { - session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback()); - throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame"); - } - if (isLocallyClosed()) - { - session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback()); - throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a locally closed stream"); - } - - // Cannot update the close state here, because the data that we send may - // be flow controlled, so we need the stream to update the window size. - session.data(this, dataInfo, dataInfo.getTimeout(), dataInfo.getUnit(), new StreamCallback(callback)); - } - - @Override - public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException - { - FutureCallback result = new FutureCallback(); - headers(headersInfo, result); - if (headersInfo.getTimeout() > 0) - result.get(headersInfo.getTimeout(), headersInfo.getUnit()); - else - result.get(); - } - - @Override - public void headers(HeadersInfo headersInfo, Callback callback) - { - notIdle(); - if (!canSend()) - { - session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback()); - throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame"); - } - if (isLocallyClosed()) - { - session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback()); - throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream"); - } - - updateCloseState(headersInfo.isClose(), true); - HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders()); - session.control(this, frame, headersInfo.getTimeout(), headersInfo.getUnit(), new StreamCallback(callback)); - } - - @Override - public boolean isUnidirectional() - { - return associatedStream != null; - } - - @Override - public boolean isReset() - { - return reset; - } - - @Override - public boolean isHalfClosed() - { - CloseState closeState = this.closeState; - return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.REMOTELY_CLOSED || closeState == CloseState.CLOSED; - } - - @Override - public boolean isClosed() - { - return closeState == CloseState.CLOSED; - } - - private boolean isLocallyClosed() - { - CloseState closeState = this.closeState; - return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.CLOSED; - } - - private boolean isRemotelyClosed() - { - CloseState closeState = this.closeState; - return closeState == CloseState.REMOTELY_CLOSED || closeState == CloseState.CLOSED; - } - - @Override - public String toString() - { - return String.format("stream=%d v%d windowSize=%d reset=%s prio=%d %s %s", getId(), session.getVersion(), - getWindowSize(), isReset(), priority, openState, closeState); - } - - private boolean canSend() - { - OpenState openState = this.openState; - return openState == OpenState.SYN_SENT || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT; - } - - private boolean canReceive() - { - OpenState openState = this.openState; - return openState == OpenState.SYN_RECV || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT; - } - - private enum OpenState - { - SYN_SENT, SYN_RECV, REPLY_SENT, REPLY_RECV - } - - private enum CloseState - { - OPENED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED - } - - private class StreamCallback implements Callback - { - private final Callback callback; - - private StreamCallback() - { - this(Callback.Adapter.INSTANCE); - } - - private StreamCallback(Callback callback) - { - this.callback = callback; - } - - @Override - public void succeeded() - { - callback.succeeded(); - } - - @Override - public void failed(Throwable x) - { - close(); - callback.failed(x); - } - } - - private class StreamPromise implements Promise<Stream> - { - private final Promise<Stream> promise; - - public StreamPromise(Promise<Stream> promise) - { - this.promise = promise; - } - - @Override - public void succeeded(Stream result) - { - promise.succeeded(result); - } - - @Override - public void failed(Throwable x) - { - close(); - promise.failed(x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java deleted file mode 100644 index cb1c400219..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java +++ /dev/null @@ -1,50 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import org.eclipse.jetty.spdy.api.StreamStatus; - -public class StreamException extends RuntimeException -{ - private final int streamId; - private final StreamStatus streamStatus; - - public StreamException(int streamId, StreamStatus streamStatus) - { - this.streamId = streamId; - this.streamStatus = streamStatus; - } - - public StreamException(int streamId, StreamStatus streamStatus, String message) - { - super(message); - this.streamId = streamId; - this.streamStatus = streamStatus; - } - - public int getStreamId() - { - return streamId; - } - - public StreamStatus getStreamStatus() - { - return streamStatus; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java deleted file mode 100644 index 163f3449b7..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.ByteBuffer; -import java.util.concurrent.TimeUnit; - -/** - * <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p> - */ -public class ByteBufferDataInfo extends DataInfo -{ - private final ByteBuffer buffer; - private final int length; - - public ByteBufferDataInfo(ByteBuffer buffer, boolean close) - { - this(0, TimeUnit.SECONDS, buffer, close); - } - - public ByteBufferDataInfo(long timeout, TimeUnit unit, ByteBuffer buffer, boolean close) - { - super(timeout, unit, close); - this.buffer = buffer; - this.length = buffer.remaining(); - } - - @Override - public int length() - { - return length; - } - - @Override - public int available() - { - return buffer.remaining(); - } - - @Override - public int readInto(ByteBuffer output) - { - int space = output.remaining(); - if (available() > space) - { - int limit = buffer.limit(); - buffer.limit(buffer.position() + space); - output.put(buffer); - buffer.limit(limit); - } - else - { - space = buffer.remaining(); - output.put(buffer); - } - return space; - } - - @Override - public int readInto(byte[] bytes, int offset, int length) - { - int available = available(); - if (available < length) - length = available; - buffer.get(bytes, offset, length); - return length; - } - - @Override - protected ByteBuffer allocate(int size) - { - return buffer.isDirect() ? ByteBuffer.allocateDirect(size) : super.allocate(size); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java deleted file mode 100644 index 05cd88ea5c..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java +++ /dev/null @@ -1,83 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.ByteBuffer; -import java.util.concurrent.TimeUnit; - -/** - * <p>Specialized {@link DataInfo} for byte array content.</p> - */ -public class BytesDataInfo extends DataInfo -{ - private final byte[] bytes; - private final int offset; - private final int length; - private int index; - - public BytesDataInfo(byte[] bytes, boolean close) - { - this(0, TimeUnit.SECONDS, bytes, close); - } - - public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, boolean close) - { - this(timeout, unit, bytes, 0, bytes.length, close); - } - - public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, int offset, int length, boolean close) - { - super(timeout, unit, close); - this.bytes = bytes; - this.offset = offset; - this.length = length; - this.index = offset; - } - - @Override - public int length() - { - return length; - } - - @Override - public int available() - { - return length - index + offset; - } - - @Override - public int readInto(ByteBuffer output) - { - int space = output.remaining(); - int chunk = Math.min(available(), space); - output.put(bytes, index, chunk); - index += chunk; - return chunk; - } - - @Override - public int readInto(byte[] bytes, int offset, int length) - { - int chunk = Math.min(available(), length); - System.arraycopy(this.bytes, index, bytes, offset, chunk); - index += chunk; - return chunk; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java deleted file mode 100644 index c2c1018530..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java +++ /dev/null @@ -1,264 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * <p>A container for DATA frames metadata and content bytes.</p> - * <p>Specialized subclasses (like {@link StringDataInfo}) may be used by applications - * to send specific types of content.</p> - * <p>Applications may send multiple instances of {@link DataInfo}, usually of the same - * type, via {@link Stream#data(DataInfo)}. The last instance must have the - * {@link #isClose() close flag} set, so that the client knows that no more content is - * expected.</p> - * <p>Receivers of {@link DataInfo} via {@link StreamFrameListener#onData(Stream, DataInfo)} - * have two different APIs to read the data content bytes: a {@link #readInto(ByteBuffer) read} - * API that does not interact with flow control, and a {@link #consumeInto(ByteBuffer) drain} - * API that interacts with flow control.</p> - * <p>Flow control is defined so that when the sender wants to sends a number of bytes larger - * than the {@link Settings.ID#INITIAL_WINDOW_SIZE} value, it will stop sending as soon as it - * has sent a number of bytes equal to the window size. The receiver has to <em>consume</em> - * the data bytes that it received in order to tell the sender to send more bytes.</p> - * <p>Consuming the data bytes can be done only via {@link #consumeInto(ByteBuffer)} or by a combination - * of {@link #readInto(ByteBuffer)} and {@link #consume(int)} (possibly at different times).</p> - */ -public abstract class DataInfo extends Info -{ - /** - * <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p> - * - * @see #isClose() - * @see #getFlags() - */ - public final static byte FLAG_CLOSE = 1; - - private final AtomicInteger consumed = new AtomicInteger(); - private boolean close; - - /** - * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p> - * - * @param close the value of the close flag - */ - public DataInfo(boolean close) - { - setClose(close); - } - - /** - * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p> - * - * @param timeout - * @param unit - * @param close the value of the close flag - */ - protected DataInfo(long timeout, TimeUnit unit, boolean close) - { - super(timeout, unit); - this.close = close; - } - - /** - * @return the value of the close flag - * @see #setClose(boolean) - */ - public boolean isClose() - { - return close; - } - - /** - * @param close the value of the close flag - * @see #isClose() - */ - public void setClose(boolean close) - { - this.close = close; - } - - /** - * @return the close and compress flags as integer - * @see #FLAG_CLOSE - */ - public byte getFlags() - { - return isClose() ? FLAG_CLOSE : 0; - } - - /** - * @return the total number of content bytes - * @see #available() - */ - public abstract int length(); - - /** - * <p>Returns the available content bytes that can be read via {@link #readInto(ByteBuffer)}.</p> - * <p>Each invocation to {@link #readInto(ByteBuffer)} modifies the value returned by this method, - * until no more content bytes are available.</p> - * - * @return the available content bytes - * @see #readInto(ByteBuffer) - */ - public abstract int available(); - - /** - * <p>Copies the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p> - * <p>If the given {@link ByteBuffer} cannot contain the whole content of this {@link DataInfo} - * then after the read {@link #available()} will return a positive value, and further content - * may be retrieved by invoking again this method with a new output buffer.</p> - * - * @param output the {@link ByteBuffer} to copy the bytes into - * @return the number of bytes copied - * @see #available() - * @see #consumeInto(ByteBuffer) - */ - public abstract int readInto(ByteBuffer output); - - /** - * <p>Copies the content bytes of this {@link DataInfo} into the given byte array.</p> - * <p>If the given byte array cannot contain the whole content of this {@link DataInfo} - * then after the read {@link #available()} will return a positive value, and further content - * may be retrieved by invoking again this method with a new byte array.</p> - * - * @param bytes the byte array to copy the bytes into - * @param offset the index of the byte array to start copying - * @param length the number of bytes to copy - * @return the number of bytes copied - */ - public abstract int readInto(byte[] bytes, int offset, int length); - - /** - * <p>Reads and consumes the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p> - * - * @param output the {@link ByteBuffer} to copy the bytes into - * @return the number of bytes copied - * @see #consume(int) - */ - public int consumeInto(ByteBuffer output) - { - int read = readInto(output); - consume(read); - return read; - } - - /** - * <p>Reads and consumes the content bytes of this {@link DataInfo} into the given byte array, - * starting from index {@code offset} for {@code length} bytes.</p> - * - * @param bytes the byte array to copy the bytes into - * @param offset the offset of the byte array to start copying - * @param length the number of bytes to copy - * @return the number of bytes copied - */ - public int consumeInto(byte[] bytes, int offset, int length) - { - int read = readInto(bytes, offset, length); - consume(read); - return read; - } - - /** - * <p>Consumes the given number of bytes from this {@link DataInfo}.</p> - * - * @param delta the number of bytes consumed - */ - public void consume(int delta) - { - if (delta < 0) - throw new IllegalArgumentException(); - int read = length() - available(); - int newConsumed = consumed() + delta; -// if (newConsumed > read) -// throw new IllegalStateException("Consuming without reading: consumed " + newConsumed + " but only read " + read); - consumed.addAndGet(delta); - } - - /** - * @return the number of bytes consumed - */ - public int consumed() - { - return consumed.get(); - } - - /** - * - * @param charset the charset used to convert the bytes - * @param consume whether to consume the content - * @return a String with the content of this {@link DataInfo} - */ - public String asString(String charset, boolean consume) - { - return asString(Charset.forName(charset), consume); - } - - /** - * - * @param charset the charset used to convert the bytes - * @param consume whether to consume the content - * @return a String with the content of this {@link DataInfo} - */ - public String asString(Charset charset, boolean consume) - { - ByteBuffer buffer = asByteBuffer(consume); - return charset.decode(buffer).toString(); - } - - /** - * @return a byte array with the content of this {@link DataInfo} - * @param consume whether to consume the content - */ - public byte[] asBytes(boolean consume) - { - ByteBuffer buffer = asByteBuffer(consume); - byte[] result = new byte[buffer.remaining()]; - buffer.get(result); - return result; - } - - /** - * @return a {@link ByteBuffer} with the content of this {@link DataInfo} - * @param consume whether to consume the content - */ - public ByteBuffer asByteBuffer(boolean consume) - { - ByteBuffer buffer = allocate(available()); - if (consume) - consumeInto(buffer); - else - readInto(buffer); - buffer.flip(); - return buffer; - } - - protected ByteBuffer allocate(int size) - { - return ByteBuffer.allocate(size); - } - - @Override - public String toString() - { - return String.format("DATA @%x available=%d consumed=%d close=%b", hashCode(), available(), consumed(), isClose()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java deleted file mode 100644 index e97f6c5f60..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -/** - * A GoAwayInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in - * future versions when we need to pass more info to the methods having a {@link GoAwayInfo} parameter. - */ -public class GoAwayInfo extends Info -{ - public GoAwayInfo(long timeout, TimeUnit unit) - { - super(timeout, unit); - } - - public GoAwayInfo() - { - super(); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java deleted file mode 100644 index 42f17cc695..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -/** - * <p>A container for GOAWAY frames metadata: the last good stream id and - * the session status.</p> - */ -public class GoAwayResultInfo -{ - private final int lastStreamId; - private final SessionStatus sessionStatus; - - /** - * <p>Creates a new {@link GoAwayResultInfo} with the given last good stream id and session status</p> - * - * @param lastStreamId the last good stream id - * @param sessionStatus the session status - */ - public GoAwayResultInfo(int lastStreamId, SessionStatus sessionStatus) - { - this.lastStreamId = lastStreamId; - this.sessionStatus = sessionStatus; - } - - /** - * @return the last good stream id - */ - public int getLastStreamId() - { - return lastStreamId; - } - - /** - * @return the session status - */ - public SessionStatus getSessionStatus() - { - return sessionStatus; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java deleted file mode 100644 index 2b5e5ce427..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java +++ /dev/null @@ -1,135 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.Fields; - -/** - * <p>A container for HEADERS frame metadata and headers.</p> - */ -public class HeadersInfo extends Info -{ - /** - * <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p> - * - * @see #isClose() - * @see #getFlags() - */ - public static final byte FLAG_CLOSE = 1; - /** - * <p>Flag that indicates that the compression of the stream must be reset.</p> - * - * @see #isResetCompression() - * @see #getFlags() - */ - public static final byte FLAG_RESET_COMPRESSION = 2; - - private final boolean close; - private final boolean resetCompression; - private final Fields headers; - - /** - * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and no reset - * compression flag</p> - * - * @param headers the {@link Fields} - * @param close the value of the close flag - */ - public HeadersInfo(Fields headers, boolean close) - { - this(headers, close, false); - } - - /** - * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset - * compression flag</p> - * - * @param headers the {@link Fields} - * @param close the value of the close flag - * @param resetCompression the value of the reset compression flag - */ - public HeadersInfo(Fields headers, boolean close, boolean resetCompression) - { - this.headers = headers; - this.close = close; - this.resetCompression = resetCompression; - } - - /** - * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset - * compression flag</p> - * - * @param timeout the operation's timeout - * @param unit the timeout's unit - * @param headers the {@link Fields} - * @param close the value of the close flag - * @param resetCompression the value of the reset compression flag - */ - public HeadersInfo(long timeout, TimeUnit unit, boolean close, boolean resetCompression, Fields headers) - { - super(timeout, unit); - this.close = close; - this.resetCompression = resetCompression; - this.headers = headers; - } - - /** - * @return the value of the close flag - */ - public boolean isClose() - { - return close; - } - - /** - * @return the value of the reset compression flag - */ - public boolean isResetCompression() - { - return resetCompression; - } - - /** - * @return the {@link Fields} - */ - public Fields getHeaders() - { - return headers; - } - - /** - * @return the close and reset compression flags as integer - * @see #FLAG_CLOSE - * @see #FLAG_RESET_COMPRESSION - */ - public byte getFlags() - { - byte flags = isClose() ? FLAG_CLOSE : 0; - flags += isResetCompression() ? FLAG_RESET_COMPRESSION : 0; - return flags; - } - - @Override - public String toString() - { - return String.format("HEADER close=%b %s", close, headers); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java deleted file mode 100644 index 315a9572a3..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -/** - * A base class for all *Info classes providing timeout and unit and api to access them - */ -public class Info -{ - private final long timeout; - private final TimeUnit unit; - - public Info(long timeout, TimeUnit unit) - { - this.timeout = timeout; - this.unit = unit; - } - - public Info() - { - timeout = 0; - unit = TimeUnit.SECONDS; - } - - public long getTimeout() - { - return timeout; - } - - public TimeUnit getUnit() - { - return unit; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java deleted file mode 100644 index 0cc693593f..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -/** - * A PingInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in - * future versions when we need to pass more info to the methods having a {@link PingInfo} parameter. - */ -public class PingInfo extends Info -{ - public PingInfo(long timeout, TimeUnit unit) - { - super(timeout, unit); - } - - public PingInfo() - { - this(0, TimeUnit.SECONDS); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java deleted file mode 100644 index ef71eb3f65..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java +++ /dev/null @@ -1,44 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -/** - * <p>A container for PING frames data.</p> - */ -public class PingResultInfo -{ - private final int pingId; - - /** - * <p>Creates a {@link PingResultInfo} with the given ping id</p> - * @param pingId the ping id - */ - public PingResultInfo(int pingId) - { - this.pingId = pingId; - } - - /** - * @return the ping id - */ - public int getPingId() - { - return pingId; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java deleted file mode 100644 index 8f7598b8f0..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java +++ /dev/null @@ -1,101 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.Fields; - -/** - * <p>A container for PUSH_SYN_STREAM frames metadata and data.</p> - */ -public class PushInfo extends Info -{ - /** - * <p>Flag that indicates that this {@link PushInfo} is the last frame in the stream.</p> - * - * @see #isClose() - * @see #getFlags() - */ - public static final byte FLAG_CLOSE = 1; - - private final boolean close; - private final Fields headers; - - /** - * <p>Creates a {@link PushInfo} instance with the given headers and the given close flag, - * not unidirectional, without associated stream, and with default priority.</p> - * - * @param headers the {@link Fields} - * @param close the value of the close flag - */ - public PushInfo(Fields headers, boolean close) - { - this(0, TimeUnit.SECONDS, headers, close); - // either builder or setters for timeout - } - - /** - * <p> - * Creates a {@link PushInfo} instance with the given headers, the given close flag and with the given priority. - * </p> - * @param timeout the timeout value - * @param unit the TimeUnit of the timeout - * @param headers - * the {@link Fields} - * @param close - */ - public PushInfo(long timeout, TimeUnit unit, Fields headers, boolean close) - { - super(timeout, unit); - this.close = close; - this.headers = headers; - } - - /** - * @return the value of the close flag - */ - public boolean isClose() - { - return close; - } - - /** - * @return the {@link Fields} - */ - public Fields getHeaders() - { - return headers; - } - - /** - * @return the close flag as integer - * @see #FLAG_CLOSE - */ - public byte getFlags() - { - return isClose() ? FLAG_CLOSE : 0; - } - - @Override - public String toString() - { - return String.format("SYN push close=%b headers=%s", close, headers); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java deleted file mode 100644 index 6586eeb0ae..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java +++ /dev/null @@ -1,107 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.Fields; - -/** - * <p>A container for SYN_REPLY frames metadata and headers.</p> - */ -public class ReplyInfo extends Info -{ - /** - * <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p> - * - * @see #isClose() - * @see #getFlags() - */ - public static final byte FLAG_CLOSE = 1; - - private final Fields headers; - private final boolean close; - - /** - * <p>Creates a new {@link ReplyInfo} instance with empty headers and the given close flag.</p> - * - * @param close the value of the close flag - */ - public ReplyInfo(boolean close) - { - this(new Fields(), close); - } - - /** - * <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p> - * - * @param headers the {@link Fields} - * @param close the value of the close flag - */ - public ReplyInfo(Fields headers, boolean close) - { - this(0, TimeUnit.SECONDS, headers, close); - } - - /** - * <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p> - * - * @param timeout the timeout - * @param unit the time unit for the timeout - * @param headers the {@link Fields} - * @param close the value of the close flag - */ - public ReplyInfo(long timeout, TimeUnit unit, Fields headers, boolean close) - { - super(timeout, unit); - this.headers = headers; - this.close = close; - } - - /** - * @return the {@link Fields} - */ - public Fields getHeaders() - { - return headers; - } - - /** - * @return the value of the close flag - */ - public boolean isClose() - { - return close; - } - - /** - * @return the close and reset compression flags as integer - * @see #FLAG_CLOSE - */ - public byte getFlags() - { - return isClose() ? FLAG_CLOSE : 0; - } - - @Override - public String toString() - { - return String.format("REPLY close=%b %s", close, headers); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java deleted file mode 100644 index bbf1fc9e95..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java +++ /dev/null @@ -1,78 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -/** - * <p>A container for RST_STREAM frames data: the stream id and the stream status.</p> - */ -public class RstInfo extends Info -{ - private final int streamId; - private final StreamStatus streamStatus; - - /** - * <p>Creates a new {@link RstInfo} with the given stream id and stream status</p> - * - * @param timeout the operation's timeout - * @param unit the timeout's unit - * @param streamId the stream id - * @param streamStatus the stream status - */ - public RstInfo(long timeout, TimeUnit unit, int streamId, StreamStatus streamStatus) - { - super(timeout, unit); - this.streamId = streamId; - this.streamStatus = streamStatus; - } - - /** - * <p>Creates a new {@link RstInfo} with the given stream id and stream status</p> - * - * @param streamId - * @param streamStatus - */ - public RstInfo(int streamId, StreamStatus streamStatus) - { - this(0, TimeUnit.SECONDS, streamId, streamStatus); - } - - /** - * @return the stream id - */ - public int getStreamId() - { - return streamId; - } - - /** - * @return the stream status - */ - public StreamStatus getStreamStatus() - { - return streamStatus; - } - - @Override - public String toString() - { - return String.format("RST stream=%d %s", streamId, streamStatus); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java deleted file mode 100644 index 9374843737..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java +++ /dev/null @@ -1,39 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -/** - * <p>Helper class that holds useful SPDY constants.</p> - */ -public class SPDY -{ - /** - * <p>Constant that indicates the version 2 of the SPDY protocol</p> - */ - public static final short V2 = 2; - - /** - * <p>Constant that indicates the version 3 of the SPDY protocol</p> - */ - public static final short V3 = 3; - - private SPDY() - { - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java deleted file mode 100644 index 0df87c8f27..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java +++ /dev/null @@ -1,50 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -/** - * <p>An unrecoverable exception that signals to the application that - * something wrong happened.</p> - */ -public class SPDYException extends RuntimeException -{ - public SPDYException() - { - } - - public SPDYException(String message) - { - super(message); - } - - public SPDYException(String message, Throwable cause) - { - super(message, cause); - } - - public SPDYException(Throwable cause) - { - super(cause); - } - - public SPDYException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) - { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java deleted file mode 100644 index 5841551f25..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java +++ /dev/null @@ -1,261 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.net.InetSocketAddress; -import java.util.EventListener; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Promise; - -/** - * <p>A {@link Session} represents the client-side endpoint of a SPDY connection to a single origin server.</p> - * <p>Once a {@link Session} has been obtained, it can be used to open SPDY streams:</p> - * <pre> - * Session session = ...; - * SynInfo synInfo = new SynInfo(true); - * session.push(synInfo, new Stream.FrameListener.Adapter() - * { - * public void onReply(Stream stream, ReplyInfo replyInfo) - * { - * // Stream reply received - * } - * }); - * </pre> - * <p>A {@link Session} is the active part of the endpoint, and by calling its API applications can generate - * events on the connection; conversely {@link SessionFrameListener} is the passive part of the endpoint, and - * has callbacks that are invoked when events happen on the connection.</p> - * - * @see SessionFrameListener - */ -public interface Session -{ - /** - * @return the SPDY protocol version used by this session - */ - public short getVersion(); - - /** - * <p>Registers the given {@code listener} to be notified of session events.</p> - * - * @param listener the listener to register - * @see #removeListener(Listener) - */ - public void addListener(Listener listener); - - /** - * <p>Deregisters the give {@code listener} from being notified of session events.</p> - * - * @param listener the listener to deregister - * @see #addListener(Listener) - */ - public void removeListener(Listener listener); - - /** - * <p>Sends a SYN_FRAME to create a new {@link Stream SPDY stream}.</p> - * <p>Callers may use the returned Stream for example, to send data frames.</p> - * - * @param synInfo the metadata to send on stream creation - * @param listener the listener to invoke when events happen on the stream just created - * @return the stream that will be created - * @see #syn(SynInfo, StreamFrameListener, Promise) - */ - public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException; - - /** - * <p>Sends asynchronously a SYN_FRAME to create a new {@link Stream SPDY stream}.</p> - * <p>Callers may pass a non-null completion callback to be notified of when the - * stream has been created and use the stream, for example, to send data frames.</p> - * - * - * @param synInfo the metadata to send on stream creation - * @param listener the listener to invoke when events happen on the stream just created - * @param promise the completion callback that gets notified of stream creation - * @see #syn(SynInfo, StreamFrameListener) - */ - public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise); - - /** - * <p>Sends synchronously a RST_STREAM to abort a stream.</p> - * - * @param rstInfo the metadata to reset the stream - * @see #rst(RstInfo, Callback) - */ - public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException; - - /** - * <p>Sends asynchronously a RST_STREAM to abort a stream.</p> - * <p>Callers may pass a non-null completion callback to be notified of when the - * reset has been actually sent.</p> - * - * @param rstInfo the metadata to reset the stream - * @param callback the completion callback that gets notified of reset's send - * @see #rst(RstInfo) - */ - public void rst(RstInfo rstInfo, Callback callback); - - /** - * <p>Sends synchronously a SETTINGS to configure the SPDY connection.</p> - * - * @param settingsInfo the metadata to send - * @see #settings(SettingsInfo, Callback) - */ - public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException; - - /** - * <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p> - * <p>Callers may pass a non-null completion callback to be notified of when the - * settings has been actually sent.</p> - * - * - * @param settingsInfo the metadata to send - * @param callback the completion callback that gets notified of settings' send - * @see #settings(SettingsInfo) - */ - public void settings(SettingsInfo settingsInfo, Callback callback); - - /** - * <p>Sends synchronously a PING, normally to measure round-trip time.</p> - * - * @see #ping(PingInfo, Promise) - * @param pingInfo - */ - public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException; - - /** - * <p>Sends asynchronously a PING, normally to measure round-trip time.</p> - * <p>Callers may pass a non-null completion callback to be notified of when the - * ping has been actually sent.</p> - * - * @param pingInfo - * @param promise the completion callback that gets notified of ping's send - * @see #ping(PingInfo) - */ - public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise); - - /** - * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p> - * - * @see #goAway(GoAwayInfo, Callback) - * @param goAwayInfo - */ - public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException; - - /** - * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p> - * <p>Callers may pass a non-null completion callback to be notified of when the - * go away has been actually sent.</p> - * - * @param goAwayInfo - * @param callback the completion callback that gets notified of go away's send - * @see #goAway(GoAwayInfo) - */ - public void goAway(GoAwayInfo goAwayInfo, Callback callback); - - /** - * @return a snapshot of the streams currently active in this session - * @see #getStream(int) - */ - public Set<Stream> getStreams(); - - /** - * @param streamId the id of the stream to retrieve - * @return the stream with the given stream id - * @see #getStreams() - */ - public Stream getStream(int streamId); - - /** - * @param key the attribute key - * @return an arbitrary object associated with the given key to this session - * @see #setAttribute(String, Object) - */ - public Object getAttribute(String key); - - /** - * @param key the attribute key - * @param value an arbitrary object to associate with the given key to this session - * @see #getAttribute(String) - * @see #removeAttribute(String) - */ - public void setAttribute(String key, Object value); - - /** - * @param key the attribute key - * @return the arbitrary object associated with the given key to this session - * @see #setAttribute(String, Object) - */ - public Object removeAttribute(String key); - - /** - * @return the local address of the underlying endpoint - */ - public InetSocketAddress getLocalAddress(); - - /** - * @return the remote address of the underlying endpoint - */ - public InetSocketAddress getRemoteAddress(); - - /** - * <p>Super interface for listeners with callbacks that are invoked on specific session events.</p> - */ - public interface Listener extends EventListener - { - } - - /** - * <p>Specialized listener that is invoked upon creation and removal of streams.</p> - */ - public interface StreamListener extends Listener - { - /** - * <p>Callback invoked when a new SPDY stream is created.</p> - * - * @param stream the stream just created - */ - public void onStreamCreated(Stream stream); - - /** - * <p>Callback invoked when a SPDY stream is closed.</p> - * - * @param stream the stream just closed. - */ - public void onStreamClosed(Stream stream); - - /** - * <p>Empty implementation of {@link StreamListener}.</p> - */ - public static class Adapter implements StreamListener - { - @Override - public void onStreamCreated(Stream stream) - { - } - - @Override - public void onStreamClosed(Stream stream) - { - } - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java deleted file mode 100644 index 0291d74be8..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java +++ /dev/null @@ -1,163 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.EventListener; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * <p>A {@link SessionFrameListener} is the passive counterpart of a {@link Session} and receives events happening - * on a SPDY session.</p> - * - * @see Session - */ -public interface SessionFrameListener extends EventListener -{ - /** - * <p>Callback invoked when a request to create a stream has been received.</p> - * <p>Application code should implement this method and reply to the stream creation, eventually - * sending data:</p> - * <pre> - * public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - * { - * // Do something with the metadata contained in synInfo - * - * if (stream.isHalfClosed()) // The other peer will not send data - * { - * stream.reply(new ReplyInfo(false)); - * stream.data(new StringDataInfo("foo", true)); - * return null; // Not interested in further stream events - * } - * - * ... - * } - * </pre> - * <p>Alternatively, if the stream creation requires reading data sent from the other peer:</p> - * <pre> - * public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - * { - * // Do something with the metadata contained in synInfo - * - * if (!stream.isHalfClosed()) // The other peer will send data - * { - * stream.reply(new ReplyInfo(true)); - * return new Stream.FrameListener.Adapter() // Interested in stream events - * { - * public void onData(Stream stream, DataInfo dataInfo) - * { - * // Do something with the incoming data in dataInfo - * } - * }; - * } - * - * ... - * } - * </pre> - * - * @param stream the stream just created - * @param synInfo the metadata sent on stream creation - * @return a listener for stream events, or null if there is no interest in being notified of stream events - */ - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo); - - /** - * <p>Callback invoked when a stream error happens.</p> - * - * @param session the session - * @param rstInfo the metadata of the stream error - */ - public void onRst(Session session, RstInfo rstInfo); - - /** - * <p>Callback invoked when a request to configure the SPDY connection has been received.</p> - * - * @param session the session - * @param settingsInfo the metadata sent to configure - */ - public void onSettings(Session session, SettingsInfo settingsInfo); - - /** - * <p>Callback invoked when a ping request has completed its round-trip.</p> - * - * @param session the session - * @param pingResultInfo the metadata received - */ - public void onPing(Session session, PingResultInfo pingResultInfo); - - /** - * <p>Callback invoked when the other peer signals that it is closing the connection.</p> - * - * @param session the session - * @param goAwayResultInfo the metadata sent - */ - public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo); - - /** - * <p>Callback invoked when an exception is thrown during the processing of an event on a - * SPDY session.</p> - * <p>Examples of such conditions are invalid frames received, corrupted headers compression state, etc.</p> - * - * @param session the session - * @param x the exception that caused the event processing failure - */ - public void onFailure(Session session, Throwable x); - - - /** - * <p>Empty implementation of {@link SessionFrameListener}</p> - */ - public static class Adapter implements SessionFrameListener - { - private static final Logger logger = Log.getLogger(Adapter.class); - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - return null; - } - - @Override - public void onRst(Session session, RstInfo rstInfo) - { - } - - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - } - - @Override - public void onPing(Session session, PingResultInfo pingResultInfo) - { - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo) - { - } - - @Override - public void onFailure(Session session, Throwable x) - { - logger.info("", x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java deleted file mode 100644 index 09e2915dfb..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java +++ /dev/null @@ -1,68 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.HashMap; -import java.util.Map; - -/** - * <p>An enumeration of session statuses.</p> - */ -public enum SessionStatus -{ - /** - * <p>The session status indicating no errors</p> - */ - OK(0), - /** - * <p>The session status indicating a protocol error</p> - */ - PROTOCOL_ERROR(1); - - /** - * @param code the session status code - * @return a {@link SessionStatus} from the given code, - * or null if no status exists - */ - public static SessionStatus from(int code) - { - return Codes.codes.get(code); - } - - private final int code; - - private SessionStatus(int code) - { - this.code = code; - Codes.codes.put(code, this); - } - - /** - * @return the code of this {@link SessionStatus} - */ - public int getCode() - { - return code; - } - - private static class Codes - { - private static final Map<Integer, SessionStatus> codes = new HashMap<>(); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java deleted file mode 100644 index 1b09d32fa6..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java +++ /dev/null @@ -1,228 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -public class Settings implements Iterable<Settings.Setting> -{ - private final Map<ID, Settings.Setting> settings; - - public Settings() - { - settings = new HashMap<>(); - } - - public Settings(Settings original, boolean immutable) - { - Map<ID, Settings.Setting> copy = new HashMap<>(original.size()); - copy.putAll(original.settings); - settings = immutable ? Collections.unmodifiableMap(copy) : copy; - } - - public Setting get(ID id) - { - return settings.get(id); - } - - public void put(Setting setting) - { - settings.put(setting.id(), setting); - } - - public Setting remove(ID id) - { - return settings.remove(id); - } - - public int size() - { - return settings.size(); - } - - public void clear() - { - settings.clear(); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - Settings that = (Settings)obj; - return settings.equals(that.settings); - } - - @Override - public int hashCode() - { - return settings.hashCode(); - } - - @Override - public Iterator<Setting> iterator() - { - return settings.values().iterator(); - } - - @Override - public String toString() - { - return settings.toString(); - } - - public static final class ID - { - public static final ID UPLOAD_BANDWIDTH = new ID(1); - public static final ID DOWNLOAD_BANDWIDTH = new ID(2); - public static final ID ROUND_TRIP_TIME = new ID(3); - public static final ID MAX_CONCURRENT_STREAMS = new ID(4); - public static final ID CURRENT_CONGESTION_WINDOW = new ID(5); - public static final ID DOWNLOAD_RETRANSMISSION_RATE = new ID(6); - public static final ID INITIAL_WINDOW_SIZE = new ID(7); - - public synchronized static ID from(int code) - { - ID id = Codes.codes.get(code); - if (id == null) - id = new ID(code); - return id; - } - - private final int code; - - private ID(int code) - { - this.code = code; - Codes.codes.put(code, this); - } - - public int code() - { - return code; - } - - @Override - public String toString() - { - return String.valueOf(code); - } - - private static class Codes - { - private static final Map<Integer, ID> codes = new HashMap<>(); - } - } - - public static enum Flag - { - NONE((byte)0), - PERSIST((byte)1), - PERSISTED((byte)2); - - public static Flag from(byte code) - { - return Codes.codes.get(code); - } - - private final byte code; - - private Flag(byte code) - { - this.code = code; - Codes.codes.put(code, this); - } - - public byte code() - { - return code; - } - - private static class Codes - { - private static final Map<Byte, Flag> codes = new HashMap<>(); - } - } - - public static class Setting - { - private final ID id; - private final Flag flag; - private final int value; - - public Setting(ID id, int value) - { - this(id, Flag.NONE, value); - } - - public Setting(ID id, Flag flag, int value) - { - this.id = id; - this.flag = flag; - this.value = value; - } - - public ID id() - { - return id; - } - - public Flag flag() - { - return flag; - } - - public int value() - { - return value; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - Setting that = (Setting)obj; - return value == that.value && flag == that.flag && id == that.id; - } - - @Override - public int hashCode() - { - int result = id.hashCode(); - result = 31 * result + flag.hashCode(); - result = 31 * result + value; - return result; - } - - @Override - public String toString() - { - return String.format("[id=%s,flags=%s:value=%d]", id(), flag(), value()); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java deleted file mode 100644 index c607e1f940..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -public class SettingsInfo extends Info -{ - public static final byte CLEAR_PERSISTED = 1; - - private final Settings settings; - private final boolean clearPersisted; - - public SettingsInfo(Settings settings) - { - this(0, TimeUnit.SECONDS, settings, false); - } - - public SettingsInfo(long timeout, TimeUnit unit, Settings settings, boolean clearPersisted) - { - super(timeout, unit); - this.settings = settings; - this.clearPersisted = clearPersisted; - } - - public SettingsInfo(Settings settings, boolean clearPersisted) - { - this(0, TimeUnit.SECONDS, settings, clearPersisted); - } - - public boolean isClearPersisted() - { - return clearPersisted; - } - - public byte getFlags() - { - return isClearPersisted() ? CLEAR_PERSISTED : 0; - } - - public Settings getSettings() - { - return settings; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java deleted file mode 100644 index a75768bafd..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java +++ /dev/null @@ -1,237 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.channels.WritePendingException; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Promise; - -/** - * <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p> <p>Differently from - * socket streams, where the input and output streams are permanently associated with the socket (and hence with the - * connection that the socket represents), there can be multiple SPDY streams for a SPDY session.</p> <p>SPDY streams - * may terminate without this implying that the SPDY session is terminated.</p> <p>If SPDY is used to transport the HTTP - * protocol, then a SPDY stream maps to a HTTP request/response cycle, and after the request/response cycle is - * completed, the stream is closed, and other streams may be opened. Differently from HTTP, though, multiple SPDY - * streams may be opened concurrently on the same SPDY session.</p> <p>Like {@link Session}, {@link Stream} is the - * active part and by calling its API applications can generate events on the stream; conversely, {@link - * StreamFrameListener} is the passive part, and its callbacks are invoked when events happen on the stream.</p> <p>A - * {@link Stream} can send multiple data frames one after the other but implementations use a flow control mechanism - * that only sends the data frames if the other end has signalled that it can accept the frame.</p> <p>Data frames - * should be sent sequentially only when the previous frame has been completely sent. The reason for this requirement is - * to avoid potentially confusing code such as:</p> - * <pre> - * // WRONG CODE, DO NOT USE IT - * final Stream stream = ...; - * stream.data(StringDataInfo("chunk1", false), 5, TimeUnit.SECONDS, new Handler<Void>() { ... }); - * stream.data(StringDataInfo("chunk2", true), 1, TimeUnit.SECONDS, new Handler<Void>() { ... }); - * </pre> - * <p>where the second call to {@link #data(DataInfo, Callback)} has a timeout smaller than the previous call.</p> - * <p>The behavior of such style of invocations is unspecified (it may even throw an exception - similar to {@link - * WritePendingException}).</p> <p>The correct sending of data frames is the following:</p> - * <pre> - * final Stream stream = ...; - * ... - * // Blocking version - * stream.data(new StringDataInfo("chunk1", false)).get(1, TimeUnit.SECONDS); - * stream.data(new StringDataInfo("chunk2", true)).get(1, TimeUnit.SECONDS); - * - * // Asynchronous version - * stream.data(new StringDataInfo("chunk1", false), 1, TimeUnit.SECONDS, new Handler.Adapter<Void>() - * { - * public void completed(Void context) - * { - * stream.data(new StringDataInfo("chunk2", true)); - * } - * }); - * </pre> - * - * @see StreamFrameListener - */ -public interface Stream -{ - /** - * @return the id of this stream - */ - public int getId(); - - /** - * @return the priority of this stream - */ - public byte getPriority(); - - /** - * @return the session this stream is associated to - */ - public Session getSession(); - - /** - * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may use the - * returned future to get the pushstream once it got created</p> - * - * @param pushInfo the metadata to send on stream creation - * @return a future containing the stream once it got established - * @see #push(PushInfo, Promise) - */ - public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException; - - /** - * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may pass a - * non-null completion promise to be notified of when the pushstream has been established.</p> - * - * @param pushInfo the metadata to send on stream creation - * @param promise the completion promise that gets notified once the pushstream is established - * @see #push(PushInfo) - */ - public void push(PushInfo pushInfo, Promise<Stream> promise); - - /** - * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may use the returned - * future to wait for the reply to be actually sent.</p> - * - * @param replyInfo the metadata to send - * @see #reply(ReplyInfo, Callback) - * @see SessionFrameListener#onSyn(Stream, SynInfo) - */ - public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException; - - /** - * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may pass a non-null - * completion callback to be notified of when the reply has been actually sent.</p> - * - * @param replyInfo the metadata to send - * @param callback the completion callback that gets notified of reply sent - * @see #reply(ReplyInfo) - */ - public void reply(ReplyInfo replyInfo, Callback callback); - - /** - * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY - * frame.</p> <p>Callers may use the returned future to wait for the data to be actually sent.</p> - * - * @param dataInfo the metadata to send - * @see #data(DataInfo, Callback) - * @see #reply(ReplyInfo) - */ - public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException; - - /** - * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY - * frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the data has been actually - * sent.</p> - * - * @param dataInfo the metadata to send - * @param callback the completion callback that gets notified of data sent - * @see #data(DataInfo) - */ - public void data(DataInfo dataInfo, Callback callback); - - /** - * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a - * SYN_REPLY frame.</p> <p>Callers may use the returned future to wait for the headers to be actually sent.</p> - * - * @param headersInfo the metadata to send - * @see #headers(HeadersInfo, Callback) - * @see #reply(ReplyInfo) - */ - public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException; - - /** - * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a - * SYN_REPLY frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the headers have - * been actually sent.</p> - * - * @param headersInfo the metadata to send - * @param callback the completion callback that gets notified of headers sent - * @see #headers(HeadersInfo) - */ - public void headers(HeadersInfo headersInfo, Callback callback); - - /** - * @return whether this stream is unidirectional or not - */ - public boolean isUnidirectional(); - - /** - * @return whether this stream has been reset - */ - public boolean isReset(); - - /** - * @return whether this stream has been closed by both parties - * @see #isHalfClosed() - */ - public boolean isClosed(); - - /** - * @return whether this stream has been closed by one party only - * @see #isClosed() - */ - public boolean isHalfClosed(); - - /** - * @param key the attribute key - * @return an arbitrary object associated with the given key to this stream or null if no object can be found for - * the given key. - * @see #setAttribute(String, Object) - */ - public Object getAttribute(String key); - - /** - * @param key the attribute key - * @param value an arbitrary object to associate with the given key to this stream - * @see #getAttribute(String) - * @see #removeAttribute(String) - */ - public void setAttribute(String key, Object value); - - /** - * @param key the attribute key - * @return the arbitrary object associated with the given key to this stream - * @see #setAttribute(String, Object) - */ - public Object removeAttribute(String key); - - /** - * @return the associated parent stream or null if this is not an associated stream - */ - public Stream getAssociatedStream(); - - /** - * @return associated child streams or an empty set if no associated streams exist - */ - public Set<Stream> getPushedStreams(); - - /** - * Get the idle timeout set for this particular stream - * @return the idle timeout - */ - public long getIdleTimeout(); - - /** - * Set an idle timeout for this stream - * @param timeout - */ - public void setIdleTimeout(long timeout); - -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java deleted file mode 100644 index 08e41bce99..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java +++ /dev/null @@ -1,110 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.EventListener; - -/** - * <p>A {@link StreamFrameListener} is the passive counterpart of a {@link Stream} and receives - * events happening on a SPDY stream.</p> - * - * @see Stream - */ -public interface StreamFrameListener extends EventListener -{ - /** - * <p>Callback invoked when a reply to a stream creation has been received.</p> - * <p>Application code may implement this method to send more data to the other end:</p> - * <pre> - * public void onReply(Stream stream, ReplyInfo replyInfo) - * { - * stream.data(new StringDataInfo("content"), true); - * } - * </pre> - * @param stream the stream - * @param replyInfo the reply metadata - */ - public void onReply(Stream stream, ReplyInfo replyInfo); - - /** - * <p>Callback invoked when headers are received on a stream.</p> - * - * @param stream the stream - * @param headersInfo the headers metadata - */ - public void onHeaders(Stream stream, HeadersInfo headersInfo); - - /** - * <p>Callback invoked when a push syn has been received on a stream.</p> - * - * @param stream the push stream just created - * @param pushInfo the push metadata - * @return a listener for stream events or null if there is no interest in being notified of stream events - */ - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo); - - /** - * <p>Callback invoked when data bytes are received on a stream.</p> - * <p>Implementers should be read or consume the content of the - * {@link DataInfo} before this method returns.</p> - * - * @param stream the stream - * @param dataInfo the data metadata - */ - public void onData(Stream stream, DataInfo dataInfo); - - /** - * <p>Callback invoked on errors.</p> - * @param stream the stream - * @param x the failure - */ - public void onFailure(Stream stream, Throwable x); - - /** - * <p>Empty implementation of {@link StreamFrameListener}</p> - */ - public static class Adapter implements StreamFrameListener - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return null; - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - } - - @Override - public void onFailure(Stream stream, Throwable x) - { - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java deleted file mode 100644 index c18ab1fc3b..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java +++ /dev/null @@ -1,128 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.HashMap; -import java.util.Map; - -/** - * <p>An enumeration of stream statuses.</p> - */ -public enum StreamStatus -{ - /** - * <p>The stream status indicating a protocol error</p> - */ - PROTOCOL_ERROR(1, 1), - /** - * <p>The stream status indicating that the stream is not valid</p> - */ - INVALID_STREAM(2, 2), - /** - * <p>The stream status indicating that the stream has been refused</p> - */ - REFUSED_STREAM(3, 3), - /** - * <p>The stream status indicating that the implementation does not support the SPDY version of the stream</p> - */ - UNSUPPORTED_VERSION(4, 4), - /** - * <p>The stream status indicating that the stream is no longer needed</p> - */ - CANCEL_STREAM(5, 5), - /** - * <p>The stream status indicating an implementation error</p> - */ - INTERNAL_ERROR(6, 6), - /** - * <p>The stream status indicating a flow control error</p> - */ - FLOW_CONTROL_ERROR(7, 7), - /** - * <p>The stream status indicating a stream opened more than once</p> - */ - STREAM_IN_USE(-1, 8), - /** - * <p>The stream status indicating data on a stream already closed</p> - */ - STREAM_ALREADY_CLOSED(-1, 9), - /** - * <p>The stream status indicating credentials not valid</p> - */ - INVALID_CREDENTIALS(-1, 10), - /** - * <p>The stream status indicating that the implementation could not support a frame too large</p> - */ - FRAME_TOO_LARGE(-1, 11); - - /** - * @param version the SPDY protocol version - * @param code the stream status code - * @return a {@link StreamStatus} from the given version and code, - * or null if no such status exists - */ - public static StreamStatus from(short version, int code) - { - switch (version) - { - case SPDY.V2: - return Codes.v2Codes.get(code); - case SPDY.V3: - return Codes.v3Codes.get(code); - default: - throw new IllegalStateException(); - } - } - - private final int v2Code; - private final int v3Code; - - private StreamStatus(int v2Code, int v3Code) - { - this.v2Code = v2Code; - if (v2Code >= 0) - Codes.v2Codes.put(v2Code, this); - this.v3Code = v3Code; - if (v3Code >= 0) - Codes.v3Codes.put(v3Code, this); - } - - /** - * @param version the SPDY protocol version - * @return the stream status code - */ - public int getCode(short version) - { - switch (version) - { - case SPDY.V2: - return v2Code; - case SPDY.V3: - return v3Code; - default: - throw new IllegalStateException(); - } - } - - private static class Codes - { - private static final Map<Integer, StreamStatus> v2Codes = new HashMap<>(); - private static final Map<Integer, StreamStatus> v3Codes = new HashMap<>(); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java deleted file mode 100644 index 793c32a265..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.TimeUnit; - -/** - * <p>Specialized {@link DataInfo} for {@link String} content.</p> - */ -public class StringDataInfo extends BytesDataInfo -{ - public StringDataInfo(String string, boolean close) - { - super(string.getBytes(StandardCharsets.UTF_8), close); - } - - public StringDataInfo(long timeout, TimeUnit unit, String string, boolean close) - { - super(timeout, unit, string.getBytes(StandardCharsets.UTF_8), close); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java deleted file mode 100644 index 26424c3c60..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java +++ /dev/null @@ -1,128 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.Fields; - -/** - * <p>A container for SYN_STREAM frames metadata and data.</p> - */ -public class SynInfo extends Info -{ - /** - * <p>Flag that indicates that this {@link SynInfo} is the last frame in the stream.</p> - * - * @see #isClose() - * @see #getFlags() - */ - public static final byte FLAG_CLOSE = 1; - - private final boolean close; - private final byte priority; - private final Fields headers; - - /** - * <p>Creates a {@link SynInfo} instance with the given headers and the given close flag, - * not unidirectional, without associated stream, and with default priority.</p> - * - * @param headers the {@link Fields} - * @param close the value of the close flag - */ - public SynInfo(Fields headers, boolean close) - { - this(0, TimeUnit.SECONDS, headers, close, (byte)0); - // either builder or setters for timeout - } - - /** - * <p> - * Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority. - * </p> - * @param headers - * the {@link Fields} - * @param close - * the value of the close flag - * @param priority - */ - public SynInfo(Fields headers, boolean close, byte priority) - { - this(0, TimeUnit.SECONDS, headers, close, priority); - } - - /** - * <p> - * Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority. - * </p> - * @param timeout the timeout value - * @param unit the TimeUnit of the timeout - * @param headers - * the {@link Fields} - * @param close - * the value of the close flag - * @param priority - */ - public SynInfo(long timeout, TimeUnit unit, Fields headers, boolean close, byte priority) - { - super(timeout, unit); - this.close = close; - this.priority = priority; - this.headers = headers; - } - - /** - * @return the value of the close flag - */ - public boolean isClose() - { - return close; - } - - /** - * @return the priority - */ - public byte getPriority() - { - return priority; - } - - /** - * @return the {@link Fields} - */ - public Fields getHeaders() - { - return headers; - } - - /** - * @return the close flag as integer - * @see #FLAG_CLOSE - */ - public byte getFlags() - { - return isClose() ? FLAG_CLOSE : 0; - } - - @Override - public String toString() - { - return String.format("SYN close=%b headers=%s", close, headers); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java deleted file mode 100644 index 69824eaf31..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java +++ /dev/null @@ -1,50 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api.server; - -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; - -/** - * <p>Specific, server-side, {@link SessionFrameListener}.</p> - * <p>In addition to {@link SessionFrameListener}, this listener adds method - * {@link #onConnect(Session)} that is called when a client first connects to the - * server and may be used by a server-side application to send a SETTINGS frame - * to configure the connection before the client can open any stream.</p> - */ -public interface ServerSessionFrameListener extends SessionFrameListener -{ - /** - * <p>Callback invoked when a client opens a connection.</p> - * - * @param session the session - */ - public void onConnect(Session session); - - /** - * <p>Empty implementation of {@link ServerSessionFrameListener}</p> - */ - public static class Adapter extends SessionFrameListener.Adapter implements ServerSessionFrameListener - { - @Override - public void onConnect(Session session) - { - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java deleted file mode 100644 index 0ff4b6c9b6..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -public abstract class ControlFrame -{ - public static final int HEADER_LENGTH = 8; - - private final short version; - private final ControlFrameType type; - private final byte flags; - - public ControlFrame(short version, ControlFrameType type, byte flags) - { - this.version = version; - this.type = type; - this.flags = flags; - } - - public short getVersion() - { - return version; - } - - public ControlFrameType getType() - { - return type; - } - - public byte getFlags() - { - return flags; - } - - @Override - public String toString() - { - return String.format("%s frame v%s", getType(), getVersion()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java deleted file mode 100644 index 7ca6ec83db..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java +++ /dev/null @@ -1,59 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.util.HashMap; -import java.util.Map; - -public enum ControlFrameType -{ - SYN_STREAM((short)1), - SYN_REPLY((short)2), - RST_STREAM((short)3), - SETTINGS((short)4), - NOOP((short)5), - PING((short)6), - GO_AWAY((short)7), - HEADERS((short)8), - WINDOW_UPDATE((short)9), - CREDENTIAL((short)10); - - public static ControlFrameType from(short code) - { - return Codes.codes.get(code); - } - - private final short code; - - private ControlFrameType(short code) - { - this.code = code; - Codes.codes.put(code, this); - } - - public short getCode() - { - return code; - } - - private static class Codes - { - private static final Map<Short, ControlFrameType> codes = new HashMap<>(); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java deleted file mode 100644 index 9788bc2d43..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.security.cert.Certificate; - -public class CredentialFrame extends ControlFrame -{ - private final short slot; - private final byte[] proof; - private final Certificate[] certificateChain; - - public CredentialFrame(short version, short slot, byte[] proof, Certificate[] certificateChain) - { - super(version, ControlFrameType.CREDENTIAL, (byte)0); - this.slot = slot; - this.proof = proof; - this.certificateChain = certificateChain; - } - - public short getSlot() - { - return slot; - } - - public byte[] getProof() - { - return proof; - } - - public Certificate[] getCertificateChain() - { - return certificateChain; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java deleted file mode 100644 index d3689cd404..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java +++ /dev/null @@ -1,63 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.DataInfo; - -public class DataFrame -{ - public static final int HEADER_LENGTH = 8; - - private final int streamId; - private final byte flags; - private final int length; - - public DataFrame(int streamId, byte flags, int length) - { - this.streamId = streamId; - this.flags = flags; - this.length = length; - } - - public int getStreamId() - { - return streamId; - } - - public byte getFlags() - { - return flags; - } - - public int getLength() - { - return length; - } - - public boolean isClose() - { - return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE; - } - - @Override - public String toString() - { - return String.format("DATA frame stream=%d length=%d close=%b", getStreamId(), getLength(), isClose()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java deleted file mode 100644 index 0471f75fca..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.SessionStatus; - -public class GoAwayFrame extends ControlFrame -{ - private final int lastStreamId; - private final int statusCode; - - public GoAwayFrame(short version, int lastStreamId, int statusCode) - { - super(version, ControlFrameType.GO_AWAY, (byte)0); - this.lastStreamId = lastStreamId; - this.statusCode = statusCode; - } - - public int getLastStreamId() - { - return lastStreamId; - } - - public int getStatusCode() - { - return statusCode; - } - - @Override - public String toString() - { - SessionStatus sessionStatus = SessionStatus.from(getStatusCode()); - return String.format("%s last_stream=%d status=%s", super.toString(), getLastStreamId(), sessionStatus == null ? getStatusCode() : sessionStatus); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java deleted file mode 100644 index c1f9380168..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.util.Fields; - -public class HeadersFrame extends ControlFrame -{ - private final int streamId; - private final Fields headers; - - public HeadersFrame(short version, byte flags, int streamId, Fields headers) - { - super(version, ControlFrameType.HEADERS, flags); - this.streamId = streamId; - this.headers = headers; - } - - public int getStreamId() - { - return streamId; - } - - public Fields getHeaders() - { - return headers; - } - - public boolean isClose() - { - return (getFlags() & HeadersInfo.FLAG_CLOSE) == HeadersInfo.FLAG_CLOSE; - } - - public boolean isResetCompression() - { - return (getFlags() & HeadersInfo.FLAG_RESET_COMPRESSION) == HeadersInfo.FLAG_RESET_COMPRESSION; - } - - @Override - public String toString() - { - return String.format("%s stream=%d close=%b reset_compression=%b", super.toString(), getStreamId(), isClose(), isResetCompression()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java deleted file mode 100644 index 13881ba815..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java +++ /dev/null @@ -1,29 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.SPDY; - -public class NoOpFrame extends ControlFrame -{ - public NoOpFrame() - { - super(SPDY.V2, ControlFrameType.NOOP, (byte)0); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java deleted file mode 100644 index 0032301316..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -public class PingFrame extends ControlFrame -{ - private final int pingId; - - public PingFrame(short version, int pingId) - { - super(version, ControlFrameType.PING, (byte)0); - this.pingId = pingId; - } - - public int getPingId() - { - return pingId; - } - - @Override - public String toString() - { - return String.format("%s ping=%d", super.toString(), getPingId()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java deleted file mode 100644 index 3b6b9839d2..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.StreamStatus; - -public class RstStreamFrame extends ControlFrame -{ - private final int streamId; - private final int statusCode; - - public RstStreamFrame(short version, int streamId, int statusCode) - { - super(version, ControlFrameType.RST_STREAM, (byte)0); - this.streamId = streamId; - this.statusCode = statusCode; - } - - public int getStreamId() - { - return streamId; - } - - public int getStatusCode() - { - return statusCode; - } - - @Override - public String toString() - { - StreamStatus streamStatus = StreamStatus.from(getVersion(), getStatusCode()); - return String.format("%s stream=%d status=%s", super.toString(), getStreamId(), streamStatus == null ? getStatusCode() : streamStatus); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java deleted file mode 100644 index 240c684519..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java +++ /dev/null @@ -1,49 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; - -public class SettingsFrame extends ControlFrame -{ - private final Settings settings; - - public SettingsFrame(short version, byte flags, Settings settings) - { - super(version, ControlFrameType.SETTINGS, flags); - this.settings = settings; - } - - public boolean isClearPersisted() - { - return (getFlags() & SettingsInfo.CLEAR_PERSISTED) == SettingsInfo.CLEAR_PERSISTED; - } - - public Settings getSettings() - { - return settings; - } - - @Override - public String toString() - { - return String.format("%s clear_persisted=%b settings=%s", super.toString(), isClearPersisted(), getSettings()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java deleted file mode 100644 index 73cfb9c3b6..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.util.Fields; - -public class SynReplyFrame extends ControlFrame -{ - private final int streamId; - private final Fields headers; - - public SynReplyFrame(short version, byte flags, int streamId, Fields headers) - { - super(version, ControlFrameType.SYN_REPLY, flags); - this.streamId = streamId; - this.headers = headers; - } - - public int getStreamId() - { - return streamId; - } - - public Fields getHeaders() - { - return headers; - } - - public boolean isClose() - { - return (getFlags() & ReplyInfo.FLAG_CLOSE) == ReplyInfo.FLAG_CLOSE; - } - - @Override - public String toString() - { - return String.format("%s stream=%d close=%b", super.toString(), getStreamId(), isClose()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java deleted file mode 100644 index 98b65f3196..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java +++ /dev/null @@ -1,83 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import org.eclipse.jetty.spdy.PushSynInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.util.Fields; - -public class SynStreamFrame extends ControlFrame -{ - private final int streamId; - private final int associatedStreamId; - private final byte priority; - private final short slot; - private final Fields headers; - - public SynStreamFrame(short version, byte flags, int streamId, int associatedStreamId, byte priority, short slot, Fields headers) - { - super(version, ControlFrameType.SYN_STREAM, flags); - this.streamId = streamId; - this.associatedStreamId = associatedStreamId; - this.priority = priority; - this.slot = slot; - this.headers = headers; - } - - public int getStreamId() - { - return streamId; - } - - public int getAssociatedStreamId() - { - return associatedStreamId; - } - - public byte getPriority() - { - return priority; - } - - public short getSlot() - { - return slot; - } - - public Fields getHeaders() - { - return headers; - } - - public boolean isClose() - { - return (getFlags() & SynInfo.FLAG_CLOSE) == SynInfo.FLAG_CLOSE; - } - - public boolean isUnidirectional() - { - return (getFlags() & PushSynInfo.FLAG_UNIDIRECTIONAL) == PushSynInfo.FLAG_UNIDIRECTIONAL; - } - - @Override - public String toString() - { - return String.format("%s stream=%d close=%b", super.toString(), getStreamId(), isClose()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java deleted file mode 100644 index f07b5589fb..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -public class WindowUpdateFrame extends ControlFrame -{ - private final int streamId; - private final int windowDelta; - - public WindowUpdateFrame(short version, int streamId, int windowDelta) - { - super(version, ControlFrameType.WINDOW_UPDATE, (byte)0); - this.streamId = streamId; - this.windowDelta = windowDelta; - } - - public int getStreamId() - { - return streamId; - } - - public int getWindowDelta() - { - return windowDelta; - } - - @Override - public String toString() - { - return String.format("%s stream=%d delta=%d", super.toString(), getStreamId(), getWindowDelta()); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java deleted file mode 100644 index 57381bc9a4..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.frames.ControlFrame; - -public abstract class ControlFrameGenerator -{ - private final ByteBufferPool bufferPool; - - protected ControlFrameGenerator(ByteBufferPool bufferPool) - { - this.bufferPool = bufferPool; - } - - protected ByteBufferPool getByteBufferPool() - { - return bufferPool; - } - - public abstract ByteBuffer generate(ControlFrame frame); - - protected void generateControlFrameHeader(ControlFrame frame, int frameLength, ByteBuffer buffer) - { - buffer.putShort((short)(0x8000 + frame.getVersion())); - buffer.putShort(frame.getType().getCode()); - int flagsAndLength = frame.getFlags(); - flagsAndLength <<= 24; - flagsAndLength += frameLength; - buffer.putInt(flagsAndLength); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java deleted file mode 100644 index 2ed6e20d45..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java +++ /dev/null @@ -1,87 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.CredentialFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class CredentialGenerator extends ControlFrameGenerator -{ - public CredentialGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - CredentialFrame credential = (CredentialFrame)frame; - - byte[] proof = credential.getProof(); - - List<byte[]> certificates = serializeCertificates(credential.getCertificateChain()); - int certificatesLength = 0; - for (byte[] certificate : certificates) - certificatesLength += certificate.length; - - int frameBodyLength = 2 + 4 + proof.length + certificates.size() * 4 + certificatesLength; - - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(credential, frameBodyLength, buffer); - - buffer.putShort(credential.getSlot()); - buffer.putInt(proof.length); - buffer.put(proof); - for (byte[] certificate : certificates) - { - buffer.putInt(certificate.length); - buffer.put(certificate); - } - - buffer.flip(); - return buffer; - } - - private List<byte[]> serializeCertificates(Certificate[] certificates) - { - try - { - List<byte[]> result = new ArrayList<>(certificates.length); - for (Certificate certificate : certificates) - result.add(certificate.getEncoded()); - return result; - } - catch (CertificateEncodingException x) - { - throw new SessionException(SessionStatus.PROTOCOL_ERROR, x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java deleted file mode 100644 index 6a3304ffeb..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class DataFrameGenerator -{ - private final ByteBufferPool bufferPool; - - public DataFrameGenerator(ByteBufferPool bufferPool) - { - this.bufferPool = bufferPool; - } - - public ByteBuffer generate(int streamId, int length, DataInfo dataInfo) - { - ByteBuffer buffer = bufferPool.acquire(DataFrame.HEADER_LENGTH + length, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - buffer.limit(length + DataFrame.HEADER_LENGTH); - buffer.position(DataFrame.HEADER_LENGTH); - // Guaranteed to always be >= 0 - int read = dataInfo.readInto(buffer); - - buffer.putInt(0, streamId & 0x7F_FF_FF_FF); - buffer.putInt(4, read & 0x00_FF_FF_FF); - - byte flags = dataInfo.getFlags(); - if (dataInfo.available() > 0) - flags &= ~DataInfo.FLAG_CLOSE; - buffer.put(4, flags); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java deleted file mode 100644 index 0bc53829cd..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java +++ /dev/null @@ -1,63 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; -import java.util.EnumMap; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.ControlFrameType; - -public class Generator -{ - final static boolean useDirectBuffers=false; - private final EnumMap<ControlFrameType, ControlFrameGenerator> generators = new EnumMap<>(ControlFrameType.class); - private final DataFrameGenerator dataFrameGenerator; - - public Generator(ByteBufferPool bufferPool, CompressionFactory.Compressor compressor) - { - HeadersBlockGenerator headersBlockGenerator = new HeadersBlockGenerator(compressor); - generators.put(ControlFrameType.SYN_STREAM, new SynStreamGenerator(bufferPool, headersBlockGenerator)); - generators.put(ControlFrameType.SYN_REPLY, new SynReplyGenerator(bufferPool, headersBlockGenerator)); - generators.put(ControlFrameType.RST_STREAM, new RstStreamGenerator(bufferPool)); - generators.put(ControlFrameType.SETTINGS, new SettingsGenerator(bufferPool)); - generators.put(ControlFrameType.NOOP, new NoOpGenerator(bufferPool)); - generators.put(ControlFrameType.PING, new PingGenerator(bufferPool)); - generators.put(ControlFrameType.GO_AWAY, new GoAwayGenerator(bufferPool)); - generators.put(ControlFrameType.HEADERS, new HeadersGenerator(bufferPool, headersBlockGenerator)); - generators.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateGenerator(bufferPool)); - generators.put(ControlFrameType.CREDENTIAL, new CredentialGenerator(bufferPool)); - - dataFrameGenerator = new DataFrameGenerator(bufferPool); - } - - public ByteBuffer control(ControlFrame frame) - { - ControlFrameGenerator generator = generators.get(frame.getType()); - return generator.generate(frame); - } - - public ByteBuffer data(int streamId, int length, DataInfo dataInfo) - { - return dataFrameGenerator.generate(streamId, length, dataInfo); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java deleted file mode 100644 index 524862a327..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java +++ /dev/null @@ -1,67 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.GoAwayFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class GoAwayGenerator extends ControlFrameGenerator -{ - public GoAwayGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - GoAwayFrame goAway = (GoAwayFrame)frame; - - int frameBodyLength = 8; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(goAway, frameBodyLength, buffer); - - buffer.putInt(goAway.getLastStreamId() & 0x7F_FF_FF_FF); - writeStatusCode(goAway, buffer); - - buffer.flip(); - return buffer; - } - - private void writeStatusCode(GoAwayFrame goAway, ByteBuffer buffer) - { - switch (goAway.getVersion()) - { - case SPDY.V2: - break; - case SPDY.V3: - buffer.putInt(goAway.getStatusCode()); - break; - default: - throw new IllegalStateException(); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java deleted file mode 100644 index 9921f324ea..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java +++ /dev/null @@ -1,150 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import org.eclipse.jetty.spdy.CompressionDictionary; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.util.Fields; - -public class HeadersBlockGenerator -{ - private final CompressionFactory.Compressor compressor; - private boolean needsDictionary = true; - - public HeadersBlockGenerator(CompressionFactory.Compressor compressor) - { - this.compressor = compressor; - } - - public ByteBuffer generate(short version, Fields headers) - { - // TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using ByteBuffer ? - final Charset iso1 = StandardCharsets.ISO_8859_1; - ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.getSize() * 64); - writeCount(version, buffer, headers.getSize()); - for (Fields.Field header : headers) - { - String name = header.getName().toLowerCase(Locale.ENGLISH); - byte[] nameBytes = name.getBytes(iso1); - writeNameLength(version, buffer, nameBytes.length); - buffer.write(nameBytes, 0, nameBytes.length); - - // Most common path first - String value = header.getValue(); - byte[] valueBytes = value.getBytes(iso1); - if (header.hasMultipleValues()) - { - List<String> values = header.getValues(); - for (int i = 1; i < values.size(); ++i) - { - byte[] moreValueBytes = values.get(i).getBytes(iso1); - byte[] newValueBytes = Arrays.copyOf(valueBytes,valueBytes.length + 1 + moreValueBytes.length); - newValueBytes[valueBytes.length] = 0; - System.arraycopy(moreValueBytes, 0, newValueBytes, valueBytes.length + 1, moreValueBytes.length); - valueBytes = newValueBytes; - } - } - - writeValueLength(version, buffer, valueBytes.length); - buffer.write(valueBytes, 0, valueBytes.length); - } - - return compress(version, buffer.toByteArray()); - } - - private ByteBuffer compress(short version, byte[] bytes) - { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length); - - // The headers compression context is per-session, so we need to synchronize - synchronized (compressor) - { - if (needsDictionary) - { - compressor.setDictionary(CompressionDictionary.get(version)); - needsDictionary = false; - } - - compressor.setInput(bytes); - - // Compressed bytes may be bigger than input bytes, so we need to loop and accumulate them - // Beware that the minimum amount of bytes generated by the compressor is few bytes, so we - // need to use an output buffer that is big enough to exit the compress loop - buffer.reset(); - int compressed; - byte[] output = new byte[Math.max(256, bytes.length)]; - while (true) - { - // SPDY uses the SYNC_FLUSH mode - compressed = compressor.compress(output); - buffer.write(output, 0, compressed); - if (compressed < output.length) - break; - } - } - - return ByteBuffer.wrap(buffer.toByteArray()); - } - - private void writeCount(short version, ByteArrayOutputStream buffer, int value) - { - switch (version) - { - case SPDY.V2: - { - buffer.write((value & 0xFF_00) >>> 8); - buffer.write(value & 0x00_FF); - break; - } - case SPDY.V3: - { - buffer.write((value & 0xFF_00_00_00) >>> 24); - buffer.write((value & 0x00_FF_00_00) >>> 16); - buffer.write((value & 0x00_00_FF_00) >>> 8); - buffer.write(value & 0x00_00_00_FF); - break; - } - default: - { - // Here the version is trusted to be correct; if it's not - // then it's a bug rather than an application error - throw new IllegalStateException(); - } - } - } - - private void writeNameLength(short version, ByteArrayOutputStream buffer, int length) - { - writeCount(version, buffer, length); - } - - private void writeValueLength(short version, ByteArrayOutputStream buffer, int length) - { - writeCount(version, buffer, length); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java deleted file mode 100644 index afb9adb206..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java +++ /dev/null @@ -1,76 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.HeadersFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class HeadersGenerator extends ControlFrameGenerator -{ - private final HeadersBlockGenerator headersBlockGenerator; - - public HeadersGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator) - { - super(bufferPool); - this.headersBlockGenerator = headersBlockGenerator; - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - HeadersFrame headers = (HeadersFrame)frame; - short version = headers.getVersion(); - - ByteBuffer headersBuffer = headersBlockGenerator.generate(version, headers.getHeaders()); - - int frameBodyLength = 4; - if (frame.getVersion() == SPDY.V2) - frameBodyLength += 2; - - int frameLength = frameBodyLength + headersBuffer.remaining(); - if (frameLength > 0xFF_FF_FF) - { - // Too many headers, but unfortunately we have already modified the compression - // context, so we have no other choice than tear down the connection. - throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers"); - } - - int totalLength = ControlFrame.HEADER_LENGTH + frameLength; - - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(headers, frameLength, buffer); - - buffer.putInt(headers.getStreamId() & 0x7F_FF_FF_FF); - if (frame.getVersion() == SPDY.V2) - buffer.putShort((short)0); - - buffer.put(headersBuffer); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java deleted file mode 100644 index cbf029c55e..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java +++ /dev/null @@ -1,49 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.NoOpFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class NoOpGenerator extends ControlFrameGenerator -{ - public NoOpGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - NoOpFrame noOp = (NoOpFrame)frame; - - int frameBodyLength = 0; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(noOp, frameBodyLength, buffer); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java deleted file mode 100644 index c263a20f08..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.PingFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class PingGenerator extends ControlFrameGenerator -{ - public PingGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - PingFrame ping = (PingFrame)frame; - - int frameBodyLength = 4; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(ping, frameBodyLength, buffer); - - buffer.putInt(ping.getPingId()); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java deleted file mode 100644 index d26ac8ee91..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.RstStreamFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class RstStreamGenerator extends ControlFrameGenerator -{ - public RstStreamGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - RstStreamFrame rstStream = (RstStreamFrame)frame; - - int frameBodyLength = 8; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(rstStream, frameBodyLength, buffer); - - buffer.putInt(rstStream.getStreamId() & 0x7F_FF_FF_FF); - buffer.putInt(rstStream.getStatusCode()); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java deleted file mode 100644 index 4c00ddee1d..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java +++ /dev/null @@ -1,91 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.SettingsFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class SettingsGenerator extends ControlFrameGenerator -{ - public SettingsGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - SettingsFrame settingsFrame = (SettingsFrame)frame; - - Settings settings = settingsFrame.getSettings(); - int size = settings.size(); - int frameBodyLength = 4 + 8 * size; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(settingsFrame, frameBodyLength, buffer); - - buffer.putInt(size); - - for (Settings.Setting setting : settings) - { - int id = setting.id().code(); - byte flags = setting.flag().code(); - int idAndFlags = convertIdAndFlags(frame.getVersion(), id, flags); - buffer.putInt(idAndFlags); - buffer.putInt(setting.value()); - } - - buffer.flip(); - return buffer; - } - - private int convertIdAndFlags(short version, int id, byte flags) - { - switch (version) - { - case SPDY.V2: - { - // In v2 the format is 24 bits of ID + 8 bits of flag - int idAndFlags = (id << 8) + (flags & 0xFF); - // A bug in the Chromium implementation forces v2 to have - // the 3 ID bytes little endian, so we swap first and third - int result = idAndFlags & 0x00_FF_00_FF; - result += (idAndFlags & 0xFF_00_00_00) >>> 16; - result += (idAndFlags & 0x00_00_FF_00) << 16; - return result; - } - case SPDY.V3: - { - // In v3 the format is 8 bits of flags + 24 bits of ID - return (flags << 24) + (id & 0xFF_FF_FF); - } - default: - { - throw new IllegalStateException(); - } - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java deleted file mode 100644 index d9aaa79ca2..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java +++ /dev/null @@ -1,104 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class SynReplyGenerator extends ControlFrameGenerator -{ - private final HeadersBlockGenerator headersBlockGenerator; - - public SynReplyGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator) - { - super(bufferPool); - this.headersBlockGenerator = headersBlockGenerator; - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - SynReplyFrame synReply = (SynReplyFrame)frame; - short version = synReply.getVersion(); - - ByteBuffer headersBuffer = headersBlockGenerator.generate(version, synReply.getHeaders()); - - int frameBodyLength = getFrameDataLength(version); - - int frameLength = frameBodyLength + headersBuffer.remaining(); - if (frameLength > 0xFF_FF_FF) - { - // Too many headers, but unfortunately we have already modified the compression - // context, so we have no other choice than tear down the connection. - throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers"); - } - - int totalLength = ControlFrame.HEADER_LENGTH + frameLength; - - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(synReply, frameLength, buffer); - - buffer.putInt(synReply.getStreamId() & 0x7F_FF_FF_FF); - writeAdditional(version, buffer); - - buffer.put(headersBuffer); - - buffer.flip(); - return buffer; - } - - private int getFrameDataLength(short version) - { - switch (version) - { - case SPDY.V2: - return 6; - case SPDY.V3: - return 4; - default: - // Here the version is trusted to be correct; if it's not - // then it's a bug rather than an application error - throw new IllegalStateException(); - } - } - - private void writeAdditional(short version, ByteBuffer buffer) - { - switch (version) - { - case SPDY.V2: - buffer.putShort((short)0); - break; - case SPDY.V3: - break; - default: - // Here the version is trusted to be correct; if it's not - // then it's a bug rather than an application error - throw new IllegalStateException(); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java deleted file mode 100644 index 7a4e8ee618..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java +++ /dev/null @@ -1,94 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class SynStreamGenerator extends ControlFrameGenerator -{ - private final HeadersBlockGenerator headersBlockGenerator; - - public SynStreamGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator) - { - super(bufferPool); - this.headersBlockGenerator = headersBlockGenerator; - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - SynStreamFrame synStream = (SynStreamFrame)frame; - short version = synStream.getVersion(); - - ByteBuffer headersBuffer = headersBlockGenerator.generate(version, synStream.getHeaders()); - - int frameBodyLength = 10; - - int frameLength = frameBodyLength + headersBuffer.remaining(); - if (frameLength > 0xFF_FF_FF) - { - // Too many headers, but unfortunately we have already modified the compression - // context, so we have no other choice than tear down the connection. - throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers"); - } - - int totalLength = ControlFrame.HEADER_LENGTH + frameLength; - - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(synStream, frameLength, buffer); - - int streamId = synStream.getStreamId(); - buffer.putInt(streamId & 0x7F_FF_FF_FF); - buffer.putInt(synStream.getAssociatedStreamId() & 0x7F_FF_FF_FF); - writePriority(streamId, version, synStream.getPriority(), buffer); - buffer.put((byte)synStream.getSlot()); - - buffer.put(headersBuffer); - - buffer.flip(); - return buffer; - } - - private void writePriority(int streamId, short version, byte priority, ByteBuffer buffer) - { - switch (version) - { - case SPDY.V2: - priority <<= 6; - break; - case SPDY.V3: - priority <<= 5; - break; - default: - throw new StreamException(streamId, StreamStatus.UNSUPPORTED_VERSION); - } - buffer.put(priority); - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java deleted file mode 100644 index 5ce1699721..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.WindowUpdateFrame; -import org.eclipse.jetty.util.BufferUtil; - -public class WindowUpdateGenerator extends ControlFrameGenerator -{ - public WindowUpdateGenerator(ByteBufferPool bufferPool) - { - super(bufferPool); - } - - @Override - public ByteBuffer generate(ControlFrame frame) - { - WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame; - - int frameBodyLength = 8; - int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; - ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers); - BufferUtil.clearToFill(buffer); - generateControlFrameHeader(windowUpdate, frameBodyLength, buffer); - - buffer.putInt(windowUpdate.getStreamId() & 0x7F_FF_FF_FF); - buffer.putInt(windowUpdate.getWindowDelta() & 0x7F_FF_FF_FF); - - buffer.flip(); - return buffer; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java deleted file mode 100644 index 9dccfcd692..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java +++ /dev/null @@ -1,26 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -public abstract class ControlFrameBodyParser -{ - public abstract boolean parse(ByteBuffer buffer); -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java deleted file mode 100644 index cfaf14af26..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java +++ /dev/null @@ -1,213 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.util.EnumMap; - -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.ControlFrameType; - -public abstract class ControlFrameParser -{ - private final EnumMap<ControlFrameType, ControlFrameBodyParser> parsers = new EnumMap<>(ControlFrameType.class); - private final ControlFrameBodyParser unknownParser = new UnknownControlFrameBodyParser(this); - private State state = State.VERSION; - private int cursor; - private short version; - private short type; - private byte flags; - private int length; - private ControlFrameBodyParser bodyParser; - private int bytesToSkip = 0; - - public ControlFrameParser(CompressionFactory.Decompressor decompressor) - { - parsers.put(ControlFrameType.SYN_STREAM, new SynStreamBodyParser(decompressor, this)); - parsers.put(ControlFrameType.SYN_REPLY, new SynReplyBodyParser(decompressor, this)); - parsers.put(ControlFrameType.RST_STREAM, new RstStreamBodyParser(this)); - parsers.put(ControlFrameType.SETTINGS, new SettingsBodyParser(this)); - parsers.put(ControlFrameType.NOOP, new NoOpBodyParser(this)); - parsers.put(ControlFrameType.PING, new PingBodyParser(this)); - parsers.put(ControlFrameType.GO_AWAY, new GoAwayBodyParser(this)); - parsers.put(ControlFrameType.HEADERS, new HeadersBodyParser(decompressor, this)); - parsers.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateBodyParser(this)); - parsers.put(ControlFrameType.CREDENTIAL, new CredentialBodyParser(this)); - } - - public short getVersion() - { - return version; - } - - public byte getFlags() - { - return flags; - } - - public int getLength() - { - return length; - } - - public void skip(int bytesToSkip) - { - state = State.SKIP; - this.bytesToSkip = bytesToSkip; - } - - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case VERSION: - { - if (buffer.remaining() >= 2) - { - version = (short)(buffer.getShort() & 0x7F_FF); - state = State.TYPE; - } - else - { - state = State.VERSION_BYTES; - cursor = 2; - } - break; - } - case VERSION_BYTES: - { - byte currByte = buffer.get(); - --cursor; - version += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - version &= 0x7F_FF; - state = State.TYPE; - } - break; - } - case TYPE: - { - if (buffer.remaining() >= 2) - { - type = buffer.getShort(); - state = State.FLAGS; - } - else - { - state = State.TYPE_BYTES; - cursor = 2; - } - break; - } - case TYPE_BYTES: - { - byte currByte = buffer.get(); - --cursor; - type += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - state = State.FLAGS; - break; - } - case FLAGS: - { - flags = buffer.get(); - cursor = 3; - state = State.LENGTH; - break; - } - case LENGTH: - { - byte currByte = buffer.get(); - --cursor; - length += (currByte & 0xFF) << 8 * cursor; - if (cursor > 0) - break; - - ControlFrameType controlFrameType = ControlFrameType.from(type); - - // SPEC v3, 2.2.1: unrecognized control frames must be ignored - if (controlFrameType == null) - bodyParser = unknownParser; - else - bodyParser = parsers.get(controlFrameType); - - state = State.BODY; - - // We have to let it fall through the next switch: - // the NOOP frame has no body and we cannot break - // because the buffer may be consumed and we will - // never enter the BODY case. - } - case BODY: - { - if (bodyParser.parse(buffer)) - { - reset(); - return true; - } - break; - } - case SKIP: - { - int remaining = buffer.remaining(); - if (remaining >= bytesToSkip) - { - buffer.position(buffer.position() + bytesToSkip); - reset(); - return true; - } - else - { - buffer.position(buffer.limit()); - bytesToSkip = bytesToSkip - remaining; - return false; - } - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - void reset() - { - state = State.VERSION; - cursor = 0; - version = 0; - type = 0; - flags = 0; - length = 0; - bodyParser = null; - bytesToSkip = 0; - } - - protected abstract void onControlFrame(ControlFrame frame); - - private enum State - { - VERSION, VERSION_BYTES, TYPE, TYPE_BYTES, FLAGS, LENGTH, BODY, SKIP - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java deleted file mode 100644 index f511aed935..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java +++ /dev/null @@ -1,274 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.io.ByteArrayInputStream; -import java.nio.ByteBuffer; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.CredentialFrame; - -public class CredentialBodyParser extends ControlFrameBodyParser -{ - private final List<Certificate> certificates = new ArrayList<>(); - private final ControlFrameParser controlFrameParser; - private State state = State.SLOT; - private int totalLength; - private int cursor; - private short slot; - private int proofLength; - private byte[] proof; - private int certificateLength; - private byte[] certificate; - - public CredentialBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case SLOT: - { - if (buffer.remaining() >= 2) - { - slot = buffer.getShort(); - checkSlotValid(); - state = State.PROOF_LENGTH; - } - else - { - state = State.SLOT_BYTES; - cursor = 2; - } - break; - } - case SLOT_BYTES: - { - byte currByte = buffer.get(); - --cursor; - slot += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - checkSlotValid(); - state = State.PROOF_LENGTH; - } - break; - } - case PROOF_LENGTH: - { - if (buffer.remaining() >= 4) - { - proofLength = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.PROOF; - } - else - { - state = State.PROOF_LENGTH_BYTES; - cursor = 4; - } - break; - } - case PROOF_LENGTH_BYTES: - { - byte currByte = buffer.get(); - --cursor; - proofLength += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - proofLength &= 0x7F_FF_FF_FF; - state = State.PROOF; - } - break; - } - case PROOF: - { - totalLength = controlFrameParser.getLength() - 2 - 4 - proofLength; - proof = new byte[proofLength]; - if (buffer.remaining() >= proofLength) - { - buffer.get(proof); - state = State.CERTIFICATE_LENGTH; - if (totalLength == 0) - { - onCredential(); - return true; - } - } - else - { - state = State.PROOF_BYTES; - cursor = proofLength; - } - break; - } - case PROOF_BYTES: - { - proof[proofLength - cursor] = buffer.get(); - --cursor; - if (cursor == 0) - { - state = State.CERTIFICATE_LENGTH; - if (totalLength == 0) - { - onCredential(); - return true; - } - } - break; - } - case CERTIFICATE_LENGTH: - { - if (buffer.remaining() >= 4) - { - certificateLength = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.CERTIFICATE; - } - else - { - state = State.CERTIFICATE_LENGTH_BYTES; - cursor = 4; - } - break; - } - case CERTIFICATE_LENGTH_BYTES: - { - byte currByte = buffer.get(); - --cursor; - certificateLength += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - certificateLength &= 0x7F_FF_FF_FF; - state = State.CERTIFICATE; - } - break; - } - case CERTIFICATE: - { - totalLength -= 4 + certificateLength; - certificate = new byte[certificateLength]; - if (buffer.remaining() >= certificateLength) - { - buffer.get(certificate); - if (onCertificate()) - return true; - } - else - { - state = State.CERTIFICATE_BYTES; - cursor = certificateLength; - } - break; - } - case CERTIFICATE_BYTES: - { - certificate[certificateLength - cursor] = buffer.get(); - --cursor; - if (cursor == 0) - { - if (onCertificate()) - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void checkSlotValid() - { - if (slot <= 0) - throw new SessionException(SessionStatus.PROTOCOL_ERROR, - "Invalid slot " + slot + " for " + ControlFrameType.CREDENTIAL + " frame"); - } - - private boolean onCertificate() - { - certificates.add(deserializeCertificate(certificate)); - if (totalLength == 0) - { - onCredential(); - return true; - } - else - { - certificateLength = 0; - state = State.CERTIFICATE_LENGTH; - } - return false; - } - - private Certificate deserializeCertificate(byte[] bytes) - { - try - { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - return certificateFactory.generateCertificate(new ByteArrayInputStream(bytes)); - } - catch (CertificateException x) - { - throw new SessionException(SessionStatus.PROTOCOL_ERROR, x); - } - } - - private void onCredential() - { - CredentialFrame frame = new CredentialFrame(controlFrameParser.getVersion(), slot, - Arrays.copyOf(proof, proof.length), certificates.toArray(new Certificate[certificates.size()])); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - state = State.SLOT; - totalLength = 0; - cursor = 0; - slot = 0; - proofLength = 0; - proof = null; - certificateLength = 0; - certificate = null; - certificates.clear(); - } - - public enum State - { - SLOT, SLOT_BYTES, PROOF_LENGTH, PROOF_LENGTH_BYTES, PROOF, PROOF_BYTES, - CERTIFICATE_LENGTH, CERTIFICATE_LENGTH_BYTES, CERTIFICATE, CERTIFICATE_BYTES - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java deleted file mode 100644 index 4bc025c2df..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java +++ /dev/null @@ -1,155 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.frames.DataFrame; - -public abstract class DataFrameParser -{ - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - private byte flags; - private int length; - - /** - * <p>Parses the given {@link ByteBuffer} for a data frame.</p> - * - * @param buffer the {@link ByteBuffer} to parse - * @return true if the data frame has been fully parsed, false otherwise - */ - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.FLAGS; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - state = State.FLAGS; - break; - } - case FLAGS: - { - flags = buffer.get(); - cursor = 3; - state = State.LENGTH; - break; - } - case LENGTH: - { - byte currByte = buffer.get(); - --cursor; - length += (currByte & 0xFF) << 8 * cursor; - if (cursor > 0) - break; - state = State.DATA; - // Fall down if length == 0: we can't loop because the buffer - // may be empty but we need to invoke the application anyway - if (length > 0) - break; - } - case DATA: - { - // Length can only be at most 3 bytes, which is 16_777_215 i.e. 16 MiB. - // However, compliant clients should implement flow control, so it's - // unlikely that we will get that 16 MiB chunk. - // However, TCP may further split the flow control window, so we may - // only have part of the data at this point. - - int size = Math.min(length, buffer.remaining()); - int limit = buffer.limit(); - buffer.limit(buffer.position() + size); - ByteBuffer bytes = buffer.slice(); - buffer.limit(limit); - buffer.position(buffer.position() + size); - length -= size; - if (length == 0) - { - onDataFrame(bytes); - return true; - } - else - { - // We got only part of the frame data bytes, - // so we generate a synthetic data frame - onDataFragment(bytes); - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void onDataFrame(ByteBuffer bytes) - { - DataFrame frame = new DataFrame(streamId, flags, bytes.remaining()); - onDataFrame(frame, bytes); - reset(); - } - - private void onDataFragment(ByteBuffer bytes) - { - DataFrame frame = new DataFrame(streamId, (byte)(flags & ~DataInfo.FLAG_CLOSE), bytes.remaining()); - onDataFrame(frame, bytes); - // Do not reset, we're expecting more data - } - - protected abstract void onDataFrame(DataFrame frame, ByteBuffer data); - - private void reset() - { - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - flags = 0; - length = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, FLAGS, LENGTH, DATA - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java deleted file mode 100644 index 8ad18fb03d..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java +++ /dev/null @@ -1,159 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.frames.GoAwayFrame; - -public class GoAwayBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - private State state = State.LAST_GOOD_STREAM_ID; - private int cursor; - private int lastStreamId; - private int statusCode; - - public GoAwayBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case LAST_GOOD_STREAM_ID: - { - if (buffer.remaining() >= 4) - { - lastStreamId = buffer.getInt() & 0x7F_FF_FF_FF; - switch (controlFrameParser.getVersion()) - { - case SPDY.V2: - { - onGoAway(); - return true; - } - case SPDY.V3: - { - state = State.STATUS_CODE; - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - else - { - state = State.LAST_GOOD_STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case LAST_GOOD_STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - lastStreamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - lastStreamId &= 0x7F_FF_FF_FF; - switch (controlFrameParser.getVersion()) - { - case SPDY.V2: - { - onGoAway(); - return true; - } - case SPDY.V3: - { - state = State.STATUS_CODE; - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - break; - } - case STATUS_CODE: - { - if (buffer.remaining() >= 4) - { - statusCode = buffer.getInt(); - onGoAway(); - return true; - } - else - { - state = State.STATUS_CODE_BYTES; - cursor = 4; - } - break; - } - case STATUS_CODE_BYTES: - { - byte currByte = buffer.get(); - --cursor; - statusCode += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - onGoAway(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void onGoAway() - { - GoAwayFrame frame = new GoAwayFrame(controlFrameParser.getVersion(), lastStreamId, statusCode); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - state = State.LAST_GOOD_STREAM_ID; - cursor = 0; - lastStreamId = 0; - statusCode = 0; - } - - private enum State - { - LAST_GOOD_STREAM_ID, LAST_GOOD_STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java deleted file mode 100644 index 3c3d67f667..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java +++ /dev/null @@ -1,230 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.zip.ZipException; - -import org.eclipse.jetty.spdy.CompressionDictionary; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.StreamStatus; - -public abstract class HeadersBlockParser -{ - private final CompressionFactory.Decompressor decompressor; - private byte[] data; - private boolean needsDictionary = true; - - protected HeadersBlockParser(CompressionFactory.Decompressor decompressor) - { - this.decompressor = decompressor; - } - - public boolean parse(int streamId, short version, int length, ByteBuffer buffer) - { - // Need to be sure that all the compressed data has arrived - // Because SPDY uses SYNC_FLUSH mode, and the Java API - // does not expose when decompression is finished with this mode - // (but only when using NO_FLUSH), then we need to - // accumulate the compressed bytes until we have all of them - - boolean accumulated = accumulate(length, buffer); - if (!accumulated) - return false; - - byte[] compressedHeaders = data; - data = null; - ByteBuffer decompressedHeaders = decompress(version, compressedHeaders); - - Charset iso1 = StandardCharsets.ISO_8859_1; - // We know the decoded bytes contain the full headers, - // so optimize instead of looping byte by byte - int count = readCount(version, decompressedHeaders); - for (int i = 0; i < count; ++i) - { - int nameLength = readNameLength(version, decompressedHeaders); - if (nameLength == 0) - throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid header name length"); - byte[] nameBytes = new byte[nameLength]; - decompressedHeaders.get(nameBytes); - String name = new String(nameBytes, iso1); - - int valueLength = readValueLength(version, decompressedHeaders); - if (valueLength == 0) - throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid header value length"); - byte[] valueBytes = new byte[valueLength]; - decompressedHeaders.get(valueBytes); - String value = new String(valueBytes, iso1); - // Multi valued headers are separate by NUL - String[] values = value.split("\u0000"); - // Check if there are multiple NULs (section 2.6.9) - for (String v : values) - if (v.length() == 0) - throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid multi valued header"); - - onHeader(name, values); - } - - return true; - } - - private boolean accumulate(int length, ByteBuffer buffer) - { - int remaining = buffer.remaining(); - if (data == null) - { - if (remaining < length) - { - data = new byte[remaining]; - buffer.get(data); - return false; - } - else - { - data = new byte[length]; - buffer.get(data); - return true; - } - } - else - { - int accumulated = data.length; - int needed = length - accumulated; - if (remaining < needed) - { - byte[] local = Arrays.copyOf(data,accumulated + remaining); - buffer.get(local, accumulated, remaining); - data = local; - return false; - } - else - { - byte[] local = Arrays.copyOf(data,length); - buffer.get(local, accumulated, needed); - data = local; - return true; - } - } - } - - private int readCount(int version, ByteBuffer buffer) - { - switch (version) - { - case SPDY.V2: - return buffer.getShort(); - case SPDY.V3: - return buffer.getInt(); - default: - throw new IllegalStateException(); - } - } - - private int readNameLength(int version, ByteBuffer buffer) - { - return readCount(version, buffer); - } - - private int readValueLength(int version, ByteBuffer buffer) - { - return readCount(version, buffer); - } - - protected abstract void onHeader(String name, String[] values); - - private ByteBuffer decompress(short version, byte[] compressed) - { - // Differently from compression, decompression always happens - // non-concurrently because we read and parse with a single - // thread, and therefore there is no need for synchronization. - - try - { - byte[] decompressed = null; - byte[] buffer = new byte[compressed.length * 2]; - decompressor.setInput(compressed); - - while (true) - { - int count = decompressor.decompress(buffer); - if (count == 0) - { - if (decompressed != null) - { - return ByteBuffer.wrap(decompressed); - } - else if (needsDictionary) - { - decompressor.setDictionary(CompressionDictionary.get(version)); - needsDictionary = false; - } - else - { - throw new IllegalStateException(); - } - } - else - { - if (count < buffer.length) - { - if (decompressed == null) - { - // Only one pass was needed to decompress - return ByteBuffer.wrap(buffer, 0, count); - } - else - { - // Last pass needed to decompress, merge decompressed bytes - byte[] result = Arrays.copyOf(decompressed,decompressed.length+count); - System.arraycopy(buffer, 0, result, decompressed.length, count); - return ByteBuffer.wrap(result); - } - } - else - { - if (decompressed == null) - { - decompressed = buffer; - buffer = new byte[buffer.length]; - } - else - { - byte[] result = Arrays.copyOf(decompressed,decompressed.length+buffer.length); - System.arraycopy(buffer, 0, result, decompressed.length, buffer.length); - decompressed = result; - } - } - } - } - } - catch (ZipException x) - { - // We had a compression problem, and since the compression context - // is per-connection, we need to tear down the connection - throw new SessionException(SessionStatus.PROTOCOL_ERROR, x); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java deleted file mode 100644 index 47dfe2cea5..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java +++ /dev/null @@ -1,173 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.HeadersFrame; -import org.eclipse.jetty.util.Fields; - -public class HeadersBodyParser extends ControlFrameBodyParser -{ - private final Fields headers = new Fields(); - private final ControlFrameParser controlFrameParser; - private final HeadersBlockParser headersBlockParser; - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - - public HeadersBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - this.headersBlockParser = new HeadersHeadersBlockParser(decompressor); - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.ADDITIONAL; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - streamId &= 0x7F_FF_FF_FF; - state = State.ADDITIONAL; - } - break; - } - case ADDITIONAL: - { - switch (controlFrameParser.getVersion()) - { - case SPDY.V2: - { - if (buffer.remaining() >= 2) - { - buffer.getShort(); - state = State.HEADERS; - } - else - { - state = State.ADDITIONAL_BYTES; - cursor = 2; - } - break; - } - case SPDY.V3: - { - state = State.HEADERS; - break; - } - default: - { - throw new IllegalStateException(); - } - } - break; - } - case ADDITIONAL_BYTES: - { - assert controlFrameParser.getVersion() == SPDY.V2; - buffer.get(); - --cursor; - if (cursor == 0) - state = State.HEADERS; - break; - } - case HEADERS: - { - short version = controlFrameParser.getVersion(); - int length = controlFrameParser.getLength() - 4; - if (version == SPDY.V2) - length -= 2; - if (headersBlockParser.parse(streamId, version, length, buffer)) - { - byte flags = controlFrameParser.getFlags(); - if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION) - throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS); - - HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Fields(headers, true)); - controlFrameParser.onControlFrame(frame); - - reset(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void reset() - { - headers.clear(); - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS - } - - private class HeadersHeadersBlockParser extends HeadersBlockParser - { - public HeadersHeadersBlockParser(CompressionFactory.Decompressor decompressor) - { - super(decompressor); - } - - @Override - protected void onHeader(String name, String[] values) - { - for (String value : values) - headers.add(name, value); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java deleted file mode 100644 index 636ddc3fc2..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.frames.NoOpFrame; - -public class NoOpBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - - public NoOpBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - NoOpFrame frame = new NoOpFrame(); - controlFrameParser.onControlFrame(frame); - return true; - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java deleted file mode 100644 index 378f25689d..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java +++ /dev/null @@ -1,240 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.util.EventListener; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class Parser -{ - private static final Logger logger = Log.getLogger(Parser.class); - private final List<Listener> listeners = new CopyOnWriteArrayList<>(); - private final ControlFrameParser controlFrameParser; - private final DataFrameParser dataFrameParser; - private State state = State.CONTROL_BIT; - - public Parser(CompressionFactory.Decompressor decompressor) - { - // It is important to allocate one decompression context per - // SPDY session for the control frames (to decompress the headers) - controlFrameParser = new ControlFrameParser(decompressor) - { - @Override - protected void onControlFrame(ControlFrame frame) - { - logger.debug("Parsed {}", frame); - notifyControlFrame(frame); - } - }; - dataFrameParser = new DataFrameParser() - { - @Override - protected void onDataFrame(DataFrame frame, ByteBuffer data) - { - logger.debug("Parsed {}, {} data bytes", frame, data.remaining()); - notifyDataFrame(frame, data); - } - }; - } - - public void addListener(Listener listener) - { - listeners.add(listener); - } - - public void removeListener(Listener listener) - { - listeners.remove(listener); - } - - protected void notifyControlFrame(ControlFrame frame) - { - for (Listener listener : listeners) - { - try - { - listener.onControlFrame(frame); - } - catch (Exception x) - { - logger.info("Exception while notifying listener " + listener, x); - } - } - } - - protected void notifyDataFrame(DataFrame frame, ByteBuffer data) - { - for (Listener listener : listeners) - { - try - { - listener.onDataFrame(frame, data); - } - catch (Exception x) - { - logger.info("Exception while notifying listener " + listener, x); - } - } - } - - protected void notifyStreamException(StreamException x) - { - for (Listener listener : listeners) - { - try - { - listener.onStreamException(x); - } - catch (Exception xx) - { - logger.debug("Could not notify listener " + listener, xx); - } - } - } - - protected void notifySessionException(SessionException x) - { - logger.debug("SPDY session exception", x); - for (Listener listener : listeners) - { - try - { - listener.onSessionException(x); - } - catch (Exception xx) - { - logger.debug("Could not notify listener " + listener, xx); - } - } - } - - public void parse(ByteBuffer buffer) - { - logger.debug("Parsing {} bytes", buffer.remaining()); - try - { - while (buffer.hasRemaining()) - { - try - { - switch (state) - { - case CONTROL_BIT: - { - // We must only peek the first byte and not advance the buffer - // because the 7 least significant bits may be relevant in data frames - int currByte = buffer.get(buffer.position()); - boolean isControlFrame = (currByte & 0x80) == 0x80; - state = isControlFrame ? State.CONTROL_FRAME : State.DATA_FRAME; - break; - } - case CONTROL_FRAME: - { - if (controlFrameParser.parse(buffer)) - reset(); - break; - } - case DATA_FRAME: - { - if (dataFrameParser.parse(buffer)) - reset(); - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - catch (StreamException x) - { - notifyStreamException(x); - } - } - } - catch (SessionException x) - { - notifySessionException(x); - } - catch (Throwable x) - { - notifySessionException(new SessionException(SessionStatus.PROTOCOL_ERROR, x)); - } - finally - { - // Be sure to consume after exceptions - buffer.position(buffer.limit()); - } - } - - private void reset() - { - state = State.CONTROL_BIT; - } - - public interface Listener extends EventListener - { - public void onControlFrame(ControlFrame frame); - - public void onDataFrame(DataFrame frame, ByteBuffer data); - - public void onStreamException(StreamException x); - - public void onSessionException(SessionException x); - - public static class Adapter implements Listener - { - @Override - public void onControlFrame(ControlFrame frame) - { - } - - @Override - public void onDataFrame(DataFrame frame, ByteBuffer data) - { - } - - @Override - public void onStreamException(StreamException x) - { - } - - @Override - public void onSessionException(SessionException x) - { - } - } - } - - private enum State - { - CONTROL_BIT, CONTROL_FRAME, DATA_FRAME - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java deleted file mode 100644 index ad4a596f24..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java +++ /dev/null @@ -1,98 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.frames.PingFrame; - -public class PingBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - private State state = State.PING_ID; - private int cursor; - private int pingId; - - public PingBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case PING_ID: - { - if (buffer.remaining() >= 4) - { - pingId = buffer.getInt() & 0x7F_FF_FF_FF; - onPing(); - return true; - } - else - { - state = State.PING_ID_BYTES; - cursor = 4; - } - break; - } - case PING_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - pingId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - onPing(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void onPing() - { - PingFrame frame = new PingFrame(controlFrameParser.getVersion(), pingId); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - state = State.PING_ID; - cursor = 0; - pingId = 0; - } - - private enum State - { - PING_ID, PING_ID_BYTES - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java deleted file mode 100644 index 175fea3ea9..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java +++ /dev/null @@ -1,127 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.frames.RstStreamFrame; - -public class RstStreamBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - private int statusCode; - - public RstStreamBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.STATUS_CODE; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - streamId &= 0x7F_FF_FF_FF; - state = State.STATUS_CODE; - } - break; - } - case STATUS_CODE: - { - if (buffer.remaining() >= 4) - { - statusCode = buffer.getInt(); - onRstStream(); - return true; - } - else - { - state = State.STATUS_CODE_BYTES; - cursor = 4; - } - break; - } - case STATUS_CODE_BYTES: - { - byte currByte = buffer.get(); - --cursor; - statusCode += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - onRstStream(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void onRstStream() - { - // TODO: check that statusCode is not 0 - RstStreamFrame frame = new RstStreamFrame(controlFrameParser.getVersion(), streamId, statusCode); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - statusCode = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java deleted file mode 100644 index bb9623a702..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java +++ /dev/null @@ -1,200 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.frames.SettingsFrame; - -public class SettingsBodyParser extends ControlFrameBodyParser -{ - private final Settings settings = new Settings(); - private final ControlFrameParser controlFrameParser; - private State state = State.COUNT; - private int cursor; - private int count; - private int idAndFlags; - private int value; - - public SettingsBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case COUNT: - { - if (buffer.remaining() >= 4) - { - count = buffer.getInt(); - state = State.ID_FLAGS; - } - else - { - state = State.COUNT_BYTES; - cursor = 4; - } - break; - } - case COUNT_BYTES: - { - byte currByte = buffer.get(); - --cursor; - count += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - state = State.ID_FLAGS; - break; - } - case ID_FLAGS: - { - if (buffer.remaining() >= 4) - { - idAndFlags = convertIdAndFlags(controlFrameParser.getVersion(), buffer.getInt()); - state = State.VALUE; - } - else - { - state = State.ID_FLAGS_BYTES; - cursor = 4; - } - break; - } - case ID_FLAGS_BYTES: - { - byte currByte = buffer.get(); - --cursor; - value += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - idAndFlags = convertIdAndFlags(controlFrameParser.getVersion(), value); - state = State.VALUE; - } - break; - } - case VALUE: - { - if (buffer.remaining() >= 4) - { - value = buffer.getInt(); - if (onPair()) - return true; - } - else - { - state = State.VALUE_BYTES; - cursor = 4; - value = 0; - } - break; - } - case VALUE_BYTES: - { - byte currByte = buffer.get(); - --cursor; - value += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - if (onPair()) - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private int convertIdAndFlags(short version, int idAndFlags) - { - switch (version) - { - case SPDY.V2: - { - // A bug in the Chromium implementation forces v2 to have - // 3 ID bytes little endian + 1 byte of flags - // Here we normalize this to conform with v3, which is - // 1 bytes of flag + 3 ID bytes big endian - int result = (idAndFlags & 0x00_00_00_FF) << 24; - result += (idAndFlags & 0x00_00_FF_00) << 8; - result += (idAndFlags & 0x00_FF_00_00) >>> 8; - result += (idAndFlags & 0xFF_00_00_00) >>> 24; - return result; - } - case SPDY.V3: - { - return idAndFlags; - } - default: - { - throw new IllegalStateException(); - } - } - } - - private boolean onPair() - { - int id = idAndFlags & 0x00_FF_FF_FF; - byte flags = (byte)((idAndFlags & 0xFF_00_00_00) >>> 24); - settings.put(new Settings.Setting(Settings.ID.from(id), Settings.Flag.from(flags), value)); - state = State.ID_FLAGS; - idAndFlags = 0; - value = 0; - --count; - if (count == 0) - { - onSettings(); - return true; - } - return false; - } - - private void onSettings() - { - SettingsFrame frame = new SettingsFrame(controlFrameParser.getVersion(), controlFrameParser.getFlags(), new Settings(settings, true)); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - settings.clear(); - state = State.COUNT; - cursor = 0; - count = 0; - idAndFlags = 0; - value = 0; - } - - private enum State - { - COUNT, COUNT_BYTES, ID_FLAGS, ID_FLAGS_BYTES, VALUE, VALUE_BYTES - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java deleted file mode 100644 index 8b35f3019a..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java +++ /dev/null @@ -1,184 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.util.Fields; - -public class SynReplyBodyParser extends ControlFrameBodyParser -{ - private final Fields headers = new Fields(); - private final ControlFrameParser controlFrameParser; - private final HeadersBlockParser headersBlockParser; - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - - public SynReplyBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - this.headersBlockParser = new SynReplyHeadersBlockParser(decompressor); - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.ADDITIONAL; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - streamId &= 0x7F_FF_FF_FF; - state = State.ADDITIONAL; - } - break; - } - case ADDITIONAL: - { - switch (controlFrameParser.getVersion()) - { - case SPDY.V2: - { - if (buffer.remaining() >= 2) - { - buffer.getShort(); - state = State.HEADERS; - } - else - { - state = State.ADDITIONAL_BYTES; - cursor = 2; - } - break; - } - case SPDY.V3: - { - state = State.HEADERS; - break; - } - default: - { - throw new IllegalStateException(); - } - } - break; - } - case ADDITIONAL_BYTES: - { - assert controlFrameParser.getVersion() == SPDY.V2; - buffer.get(); - --cursor; - if (cursor == 0) - state = State.HEADERS; - break; - } - case HEADERS: - { - short version = controlFrameParser.getVersion(); - int length = controlFrameParser.getLength() - getSynReplyDataLength(version); - if (headersBlockParser.parse(streamId, version, length, buffer)) - { - byte flags = controlFrameParser.getFlags(); - if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE) - throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY); - - SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Fields(headers, true)); - controlFrameParser.onControlFrame(frame); - - reset(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private int getSynReplyDataLength(short version) - { - switch (version) - { - case 2: - return 6; - case 3: - return 4; - default: - throw new IllegalStateException(); - } - } - - private void reset() - { - headers.clear(); - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS - } - - private class SynReplyHeadersBlockParser extends HeadersBlockParser - { - public SynReplyHeadersBlockParser(CompressionFactory.Decompressor decompressor) - { - super(decompressor); - } - - @Override - protected void onHeader(String name, String[] values) - { - for (String value : values) - headers.add(name, value); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java deleted file mode 100644 index 6b28214ded..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java +++ /dev/null @@ -1,236 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.PushSynInfo; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.util.Fields; - -public class SynStreamBodyParser extends ControlFrameBodyParser -{ - private final Fields headers = new Fields(); - private final ControlFrameParser controlFrameParser; - private final HeadersBlockParser headersBlockParser; - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - private int associatedStreamId; - private byte priority; - private short slot; - - public SynStreamBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - this.headersBlockParser = new SynStreamHeadersBlockParser(decompressor); - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.ASSOCIATED_STREAM_ID; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - streamId &= 0x7F_FF_FF_FF; - state = State.ASSOCIATED_STREAM_ID; - } - break; - } - case ASSOCIATED_STREAM_ID: - { - // Now we know the streamId, we can do the version check - // and if it is wrong, issue a RST_STREAM - try - { - checkVersion(controlFrameParser.getVersion(), streamId); - } - catch (StreamException e) - { - // We've already read 4 bytes of the streamId which are part of controlFrameParser.getLength - // so we need to substract those from the bytesToSkip. - int bytesToSkip = controlFrameParser.getLength() - 4; - int remaining = buffer.remaining(); - if (remaining >= bytesToSkip) - { - buffer.position(buffer.position() + bytesToSkip); - controlFrameParser.reset(); - reset(); - } - else - { - int bytesToSkipInNextBuffer = bytesToSkip - remaining; - buffer.position(buffer.limit()); - controlFrameParser.skip(bytesToSkipInNextBuffer); - reset(); - } - throw e; - } - if (buffer.remaining() >= 4) - { - associatedStreamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.PRIORITY; - } - else - { - state = State.ASSOCIATED_STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case ASSOCIATED_STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - associatedStreamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - associatedStreamId &= 0x7F_FF_FF_FF; - state = State.PRIORITY; - } - break; - } - case PRIORITY: - { - byte currByte = buffer.get(); - ++cursor; - if (cursor == 1) - { - priority = readPriority(controlFrameParser.getVersion(), currByte); - } - else - { - slot = (short)(currByte & 0xFF); - cursor = 0; - state = State.HEADERS; - } - break; - } - case HEADERS: - { - short version = controlFrameParser.getVersion(); - int length = controlFrameParser.getLength() - 10; - if (headersBlockParser.parse(streamId, version, length, buffer)) - { - byte flags = controlFrameParser.getFlags(); - if (flags > (SynInfo.FLAG_CLOSE | PushSynInfo.FLAG_UNIDIRECTIONAL)) - throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + - ControlFrameType.SYN_STREAM); - - SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, - priority, slot, new Fields(headers, false)); - controlFrameParser.onControlFrame(frame); - - reset(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void checkVersion(short version, int streamId) - { - if (version != SPDY.V2 && version != SPDY.V3) - throw new StreamException(streamId, StreamStatus.UNSUPPORTED_VERSION); - } - - private byte readPriority(short version, byte currByte) - { - // Right shift retains the sign bit when operated on a byte, - // so we use an int to perform the shifts - switch (version) - { - case SPDY.V2: - int p2 = currByte & 0b1100_0000; - p2 >>>= 6; - return (byte)p2; - case SPDY.V3: - int p3 = currByte & 0b1110_0000; - p3 >>>= 5; - return (byte)p3; - default: - throw new IllegalStateException(); - } - } - - private void reset() - { - headers.clear(); - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - associatedStreamId = 0; - priority = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, ASSOCIATED_STREAM_ID, ASSOCIATED_STREAM_ID_BYTES, PRIORITY, HEADERS - } - - private class SynStreamHeadersBlockParser extends HeadersBlockParser - { - public SynStreamHeadersBlockParser(CompressionFactory.Decompressor decompressor) - { - super(decompressor); - } - - @Override - protected void onHeader(String name, String[] values) - { - for (String value : values) - headers.add(name, value); - } - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java deleted file mode 100644 index 2f7a008e2f..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -public class UnknownControlFrameBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - private State state = State.BODY; - private int remaining; - - public UnknownControlFrameBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - switch (state) - { - case BODY: - { - remaining = controlFrameParser.getLength(); - state = State.CONSUME; - // Fall down - } - case CONSUME: - { - int consume = Math.min(remaining, buffer.remaining()); - buffer.position(buffer.position() + consume); - remaining -= consume; - if (remaining > 0) - return false; - reset(); - return true; - } - default: - { - throw new IllegalStateException(); - } - } - } - - private void reset() - { - state = State.BODY; - remaining = 0; - } - - private enum State - { - BODY, CONSUME - } -} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java deleted file mode 100644 index f55ecd4d9d..0000000000 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java +++ /dev/null @@ -1,127 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.frames.WindowUpdateFrame; - -public class WindowUpdateBodyParser extends ControlFrameBodyParser -{ - private final ControlFrameParser controlFrameParser; - private State state = State.STREAM_ID; - private int cursor; - private int streamId; - private int windowDelta; - - public WindowUpdateBodyParser(ControlFrameParser controlFrameParser) - { - this.controlFrameParser = controlFrameParser; - } - - @Override - public boolean parse(ByteBuffer buffer) - { - while (buffer.hasRemaining()) - { - switch (state) - { - case STREAM_ID: - { - if (buffer.remaining() >= 4) - { - streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.WINDOW_DELTA; - } - else - { - state = State.STREAM_ID_BYTES; - cursor = 4; - } - break; - } - case STREAM_ID_BYTES: - { - byte currByte = buffer.get(); - --cursor; - streamId += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - streamId &= 0x7F_FF_FF_FF; - state = State.WINDOW_DELTA; - } - break; - } - case WINDOW_DELTA: - { - if (buffer.remaining() >= 4) - { - windowDelta = buffer.getInt() & 0x7F_FF_FF_FF; - onWindowUpdate(); - return true; - } - else - { - state = State.WINDOW_DELTA_BYTES; - cursor = 4; - } - break; - } - case WINDOW_DELTA_BYTES: - { - byte currByte = buffer.get(); - --cursor; - windowDelta += (currByte & 0xFF) << 8 * cursor; - if (cursor == 0) - { - windowDelta &= 0x7F_FF_FF_FF; - onWindowUpdate(); - return true; - } - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - return false; - } - - private void onWindowUpdate() - { - WindowUpdateFrame frame = new WindowUpdateFrame(controlFrameParser.getVersion(), streamId, windowDelta); - controlFrameParser.onControlFrame(frame); - reset(); - } - - private void reset() - { - state = State.STREAM_ID; - cursor = 0; - streamId = 0; - windowDelta = 0; - } - - private enum State - { - STREAM_ID, STREAM_ID_BYTES, WINDOW_DELTA, WINDOW_DELTA_BYTES; - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java deleted file mode 100644 index 969d72e790..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java +++ /dev/null @@ -1,159 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.ByteArrayEndPoint; -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SPDYException; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.toolchain.test.AdvancedRunner; -import org.eclipse.jetty.toolchain.test.annotation.Slow; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.thread.Scheduler; -import org.eclipse.jetty.util.thread.TimerScheduler; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AdvancedRunner.class) -//TODO: Uncomment comment lines and reimplement tests to fit new design -@Ignore("Doesn't work with new Flusher class, needs to be rewritten") -public class AsyncTimeoutTest -{ - EndPoint endPoint = new ByteArrayEndPoint(); - - @Slow - @Test - public void testAsyncTimeoutInControlFrames() throws Exception - { - final long timeout = 1000; - final TimeUnit unit = TimeUnit.MILLISECONDS; - - ByteBufferPool bufferPool = new MappedByteBufferPool(); - Executor threadPool = Executors.newCachedThreadPool(); - Scheduler scheduler = new TimerScheduler(); - scheduler.start(); // TODO need to use jetty lifecycles better here - Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor()); - Session session = new StandardSession(SPDY.V2, bufferPool, scheduler, new TestController(), - endPoint, null, 1, null, generator, new FlowControlStrategy.None()) - { -// @Override - public void flush() - { - try - { - unit.sleep(2 * timeout); -// super.flush(); - } - catch (InterruptedException x) - { - throw new SPDYException(x); - } - } - }; - - final CountDownLatch failedLatch = new CountDownLatch(1); - session.syn(new SynInfo(timeout, unit, new Fields(), true, (byte)0), null, new Promise.Adapter<Stream>() - { - @Override - public void failed(Throwable x) - { - failedLatch.countDown(); - } - }); - - Assert.assertTrue(failedLatch.await(2 * timeout, unit)); - } - - @Slow - @Test - public void testAsyncTimeoutInDataFrames() throws Exception - { - final long timeout = 1000; - final TimeUnit unit = TimeUnit.MILLISECONDS; - - ByteBufferPool bufferPool = new MappedByteBufferPool(); - Executor threadPool = Executors.newCachedThreadPool(); - Scheduler scheduler = new TimerScheduler(); - scheduler.start(); - Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor()); - Session session = new StandardSession(SPDY.V2, bufferPool, scheduler, new TestController(), - endPoint, null, 1, null, generator, new FlowControlStrategy.None()) - { -// @Override - protected void write(ByteBuffer buffer, Callback callback) - { - try - { - // Wait if we're writing the data frame (control frame's first byte is 0x80) - if (buffer.get(0) == 0) - unit.sleep(2 * timeout); -// super.write(buffer, callback); - } - catch (InterruptedException x) - { - throw new SPDYException(x); - } - } - }; - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - final CountDownLatch failedLatch = new CountDownLatch(1); - stream.data(new StringDataInfo(timeout, unit, "data", true), new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - failedLatch.countDown(); - } - }); - - Assert.assertTrue(failedLatch.await(2 * timeout, unit)); - } - - private static class TestController implements Controller - { - @Override - public void write(Callback callback, ByteBuffer... buffers) - { - callback.succeeded(); - } - - @Override - public void close(boolean onlyOutput) - { - } - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java deleted file mode 100644 index 80bd21c0b7..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java +++ /dev/null @@ -1,681 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.util.HashSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.spdy.frames.SettingsFrame; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; -import org.eclipse.jetty.util.thread.Scheduler; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; - -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class StandardSessionTest -{ - private static final Logger LOG = Log.getLogger(StandardSessionTest.class); - private static final short VERSION = SPDY.V2; - - @Mock - private Controller controller; - - @Mock - private EndPoint endPoint; - - private ExecutorService threadPool; - private StandardSession session; - private Scheduler scheduler; - private Fields headers; - private final ByteBufferPool bufferPool = new MappedByteBufferPool(); - private final Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor()); - - @Before - public void setUp() throws Exception - { - threadPool = Executors.newCachedThreadPool(); - scheduler = new ScheduledExecutorScheduler(); - scheduler.start(); - session = new StandardSession(VERSION, bufferPool, scheduler, controller, endPoint, null, 1, null, - generator, new FlowControlStrategy.None()); - when(endPoint.getIdleTimeout()).thenReturn(30000L); - headers = new Fields(); - } - - @After - public void after() throws Exception - { - scheduler.stop(); - threadPool.shutdownNow(); - } - - @SuppressWarnings("unchecked") - private void setControllerWriteExpectation(final boolean fail) - { - doAnswer(new Answer() - { - public Object answer(InvocationOnMock invocation) - { - Object[] args = invocation.getArguments(); - Callback callback = (Callback)args[0]; - if (fail) - callback.failed(new ClosedChannelException()); - else - callback.succeeded(); - return null; - } - }).when(controller).write(any(Callback.class), any(ByteBuffer.class)); - } - - @Test - public void testStreamIsRemovedFromSessionWhenReset() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - assertThatStreamIsInSession(stream); - assertThat("stream is not reset", stream.isReset(), is(false)); - session.rst(new RstInfo(stream.getId(), StreamStatus.STREAM_ALREADY_CLOSED)); - assertThatStreamIsNotInSession(stream); - assertThatStreamIsReset(stream); - } - - @Test - public void testStreamIsAddedAndRemovedFromSession() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - assertThatStreamIsInSession(stream); - stream.updateCloseState(true, true); - session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null)); - assertThatStreamIsClosed(stream); - assertThatStreamIsNotInSession(stream); - } - - @Test - public void testStreamIsRemovedWhenHeadersWithCloseFlagAreSent() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - assertThatStreamIsInSession(stream); - stream.updateCloseState(true, false); - stream.headers(new HeadersInfo(headers, true)); - assertThatStreamIsClosed(stream); - assertThatStreamIsNotInSession(stream); - } - - @Test - public void testStreamIsUnidirectional() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - assertThat("stream is not unidirectional", stream.isUnidirectional(), not(true)); - Stream pushStream = createPushStream(stream); - assertThat("pushStream is unidirectional", pushStream.isUnidirectional(), is(true)); - } - - @Test - public void testPushStreamCreation() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - Stream stream = createStream(); - IStream pushStream = createPushStream(stream); - assertThat("Push stream must be associated to the first stream created", pushStream.getAssociatedStream().getId(), is(stream.getId())); - assertThat("streamIds need to be monotonic", pushStream.getId(), greaterThan(stream.getId())); - } - - @Test - public void testPushStreamIsNotClosedWhenAssociatedStreamIsClosed() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - Stream pushStream = createPushStream(stream); - assertThatStreamIsNotHalfClosed(stream); - assertThatStreamIsNotClosed(stream); - assertThatPushStreamIsHalfClosed(pushStream); - assertThatPushStreamIsNotClosed(pushStream); - - stream.updateCloseState(true, true); - assertThatStreamIsHalfClosed(stream); - assertThatStreamIsNotClosed(stream); - assertThatPushStreamIsHalfClosed(pushStream); - assertThatPushStreamIsNotClosed(pushStream); - - session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null)); - assertThatStreamIsClosed(stream); - assertThatPushStreamIsNotClosed(pushStream); - } - - @Test - public void testCreatePushStreamOnClosedStream() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - stream.updateCloseState(true, true); - assertThatStreamIsHalfClosed(stream); - stream.updateCloseState(true, false); - assertThatStreamIsClosed(stream); - createPushStreamAndMakeSureItFails(stream); - } - - private void createPushStreamAndMakeSureItFails(IStream stream) throws InterruptedException - { - final CountDownLatch failedLatch = new CountDownLatch(1); - PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false); - stream.push(pushInfo, new Promise.Adapter<Stream>() - { - @Override - public void failed(Throwable x) - { - failedLatch.countDown(); - } - }); - assertThat("pushStream creation failed", failedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testPushStreamIsAddedAndRemovedFromParentAndSessionWhenClosed() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - IStream pushStream = createPushStream(stream); - assertThatPushStreamIsHalfClosed(pushStream); - assertThatPushStreamIsInSession(pushStream); - assertThatStreamIsAssociatedWithPushStream(stream, pushStream); - session.data(pushStream, new StringDataInfo("close", true), 5, TimeUnit.SECONDS, new Callback.Adapter()); - assertThatPushStreamIsClosed(pushStream); - assertThatPushStreamIsNotInSession(pushStream); - assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream); - } - - @Test - public void testPushStreamIsRemovedWhenReset() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - IStream pushStream = (IStream)stream.push(new PushInfo(new Fields(), false)); - assertThatPushStreamIsInSession(pushStream); - session.rst(new RstInfo(pushStream.getId(), StreamStatus.INVALID_STREAM)); - assertThatPushStreamIsNotInSession(pushStream); - assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream); - assertThatStreamIsReset(pushStream); - } - - @Test - public void testPushStreamWithSynInfoClosedTrue() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, true); - IStream pushStream = (IStream)stream.push(pushInfo); - assertThatPushStreamIsHalfClosed(pushStream); - assertThatPushStreamIsClosed(pushStream); - assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream); - assertThatStreamIsNotInSession(pushStream); - } - - @Test - public void testPushStreamSendHeadersWithCloseFlagIsRemovedFromSessionAndDisassociateFromParent() throws InterruptedException, ExecutionException, - TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = createStream(); - PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false); - IStream pushStream = (IStream)stream.push(pushInfo); - assertThatStreamIsAssociatedWithPushStream(stream, pushStream); - assertThatPushStreamIsInSession(pushStream); - pushStream.headers(new HeadersInfo(headers, true)); - assertThatPushStreamIsNotInSession(pushStream); - assertThatPushStreamIsHalfClosed(pushStream); - assertThatPushStreamIsClosed(pushStream); - assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream); - } - - @Test - public void testCreatedAndClosedListenersAreCalledForNewStream() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - final CountDownLatch createdListenerCalledLatch = new CountDownLatch(1); - final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1); - session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch)); - IStream stream = createStream(); - session.onControlFrame(new SynReplyFrame(VERSION, (byte)0, stream.getId(), new Fields())); - session.onDataFrame(new DataFrame(stream.getId(), SynInfo.FLAG_CLOSE, 128), ByteBuffer.allocate(128)); - stream.data(new StringDataInfo("close", true)); - assertThat("onStreamCreated listener has been called", createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch); - } - - @Test - public void testListenerIsCalledForResetStream() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1); - session.addListener(new TestStreamListener(null, closedListenerCalledLatch)); - IStream stream = createStream(); - session.rst(new RstInfo(stream.getId(), StreamStatus.CANCEL_STREAM)); - assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch); - } - - @Test - public void testCreatedAndClosedListenersAreCalledForNewPushStream() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - final CountDownLatch createdListenerCalledLatch = new CountDownLatch(2); - final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1); - session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch)); - IStream stream = createStream(); - IStream pushStream = createPushStream(stream); - session.data(pushStream, new StringDataInfo("close", true), 5, TimeUnit.SECONDS, new Callback.Adapter()); - assertThat("onStreamCreated listener has been called twice. Once for the stream and once for the pushStream", - createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch); - } - - @Test - public void testListenerIsCalledForResetPushStream() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1); - session.addListener(new TestStreamListener(null, closedListenerCalledLatch)); - IStream stream = createStream(); - IStream pushStream = createPushStream(stream); - session.rst(new RstInfo(pushStream.getId(), StreamStatus.CANCEL_STREAM)); - assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch); - } - - private class TestStreamListener extends Session.StreamListener.Adapter - { - private CountDownLatch createdListenerCalledLatch; - private CountDownLatch closedListenerCalledLatch; - - public TestStreamListener(CountDownLatch createdListenerCalledLatch, CountDownLatch closedListenerCalledLatch) - { - this.createdListenerCalledLatch = createdListenerCalledLatch; - this.closedListenerCalledLatch = closedListenerCalledLatch; - } - - @Override - public void onStreamCreated(Stream stream) - { - if (createdListenerCalledLatch != null) - createdListenerCalledLatch.countDown(); - super.onStreamCreated(stream); - } - - @Override - public void onStreamClosed(Stream stream) - { - if (closedListenerCalledLatch != null) - closedListenerCalledLatch.countDown(); - super.onStreamClosed(stream); - } - } - - @Test - @Ignore("In V3 we need to rst the stream if we receive data on a remotely half closed stream.") - public void receiveDataOnRemotelyHalfClosedStreamResetsStreamInV3() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - IStream stream = (IStream)session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()); - stream.updateCloseState(true, false); - assertThat("stream is half closed from remote side", stream.isHalfClosed(), is(true)); - stream.process(new ByteBufferDataInfo(ByteBuffer.allocate(256), true)); - } - - @Test - public void testReceiveDataOnRemotelyClosedStreamIsIgnored() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - final CountDownLatch onDataCalledLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - onDataCalledLatch.countDown(); - super.onData(stream, dataInfo); - } - }); - session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), headers)); - session.onDataFrame(new DataFrame(stream.getId(), (byte)0, 0), ByteBuffer.allocate(128)); - assertThat("onData is never called", onDataCalledLatch.await(1, TimeUnit.SECONDS), not(true)); - } - - @SuppressWarnings("unchecked") - @Test - public void testControllerWriteFails() throws Exception - { - final AtomicInteger writes = new AtomicInteger(); - final AtomicBoolean fail = new AtomicBoolean(); - Controller controller = new Controller() - { - @Override - public void write(Callback callback, ByteBuffer... buffers) - { - writes.incrementAndGet(); - if (fail.get()) - callback.failed(new ClosedChannelException()); - else - callback.succeeded(); - } - - @Override - public void close(boolean onlyOutput) - { - - } - }; - ISession session = new StandardSession(VERSION, bufferPool, scheduler, controller, endPoint, null, 1, null, generator, null); - IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null); - stream.updateWindowSize(8192); - - // Send a reply to comply with the API usage - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - - // Make the controller fail - fail.set(true); - final CountDownLatch failedCalledLatch = new CountDownLatch(1); - Callback.Adapter callback = new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - failedCalledLatch.countDown(); - } - }; - // Data frame should fail on controller.write() - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), callback); - - Assert.assertEquals(2, writes.get()); - Assert.assertTrue(failedCalledLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testControlFramesAreStillSentForResetStreams() throws InterruptedException, ExecutionException, TimeoutException - { - setControllerWriteExpectation(false); - - // This is necessary to keep the compression context of Headers valid - IStream stream = createStream(); - session.rst(new RstInfo(stream.getId(), StreamStatus.INVALID_STREAM)); - stream.headers(new HeadersInfo(headers, true)); - - verify(controller, times(3)).write(any(Callback.class), any(ByteBuffer.class)); - } - - @Test - public void testMaxConcurrentStreams() throws InterruptedException - { - final CountDownLatch failedBecauseMaxConcurrentStreamsExceeded = new CountDownLatch(1); - - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0)); - SettingsFrame settingsFrame = new SettingsFrame(VERSION, (byte)0, settings); - session.onControlFrame(settingsFrame); - - PushSynInfo pushSynInfo = new PushSynInfo(1, new PushInfo(new Fields(), false)); - session.syn(pushSynInfo, null, new Promise.Adapter<Stream>() - { - @Override - public void failed(Throwable x) - { - failedBecauseMaxConcurrentStreamsExceeded.countDown(); - } - }); - - assertThat("Opening push stream failed because maxConcurrentStream is exceeded", - failedBecauseMaxConcurrentStreamsExceeded.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testHeaderFramesAreSentInTheOrderTheyAreCreated() throws ExecutionException, - TimeoutException, InterruptedException - { - testHeaderFramesAreSentInOrder((byte)0, (byte)0, (byte)0); - } - - @Test - public void testHeaderFramesAreSentInTheOrderTheyAreCreatedWithPrioritization() throws ExecutionException, - TimeoutException, InterruptedException - { - testHeaderFramesAreSentInOrder((byte)0, (byte)1, (byte)2); - } - - private void testHeaderFramesAreSentInOrder(final byte priority0, final byte priority1, final byte priority2) throws InterruptedException, ExecutionException - { - final StandardSession testLocalSession = new StandardSession(VERSION, bufferPool, scheduler, - new ControllerMock(), endPoint, null, 1, null, generator, new FlowControlStrategy.None()); - HashSet<Future> tasks = new HashSet<>(); - - int numberOfTasksToRun = 128; - for (int i = 0; i < numberOfTasksToRun; i++) - { - tasks.add(threadPool.submit(new Runnable() - { - - @Override - public void run() - { - synStream(priority0); - synStream(priority1); - synStream(priority2); - } - - private void synStream(byte priority) - { - SynInfo synInfo = new SynInfo(headers, false, priority); - testLocalSession.syn(synInfo, new StreamFrameListener.Adapter(), new FuturePromise<Stream>()); - } - })); - } - - for (Future task : tasks) - { - task.get(); - } - - threadPool.shutdown(); - threadPool.awaitTermination(60, TimeUnit.SECONDS); - } - - private class ControllerMock implements Controller - { - long lastStreamId = 0; - - @Override - public void write(Callback callback, ByteBuffer... buffers) - { - StandardSession.FrameBytes frameBytes = (StandardSession.FrameBytes)callback; - - int streamId = frameBytes.getStream().getId(); - if (LOG.isDebugEnabled()) - LOG.debug("last: {}, current: {}", lastStreamId, streamId); - if (lastStreamId < streamId) - lastStreamId = streamId; - else - throw new IllegalStateException("Last streamId: " + lastStreamId + " is not smaller than current StreamId: " + - streamId); - frameBytes.succeeded(); - } - - @Override - public void close(boolean onlyOutput) - { - } - } - - private IStream createStream() throws InterruptedException, ExecutionException, TimeoutException - { - SynInfo synInfo = new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0); - return (IStream)session.syn(synInfo, new StreamFrameListener.Adapter()); - } - - private IStream createPushStream(Stream stream) throws InterruptedException, ExecutionException, TimeoutException - { - PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false); - return (IStream)stream.push(pushInfo); - } - - private void assertThatStreamIsClosed(IStream stream) - { - assertThat("stream is closed", stream.isClosed(), is(true)); - } - - private void assertThatStreamIsReset(IStream stream) - { - assertThat("stream is reset", stream.isReset(), is(true)); - } - - private void assertThatStreamIsNotInSession(IStream stream) - { - assertThat("stream is not in session", session.getStreams().contains(stream), not(true)); - } - - private void assertThatStreamIsInSession(IStream stream) - { - assertThat("stream is in session", session.getStreams().contains(stream), is(true)); - } - - private void assertThatStreamIsNotClosed(IStream stream) - { - assertThat("stream is not closed", stream.isClosed(), not(true)); - } - - private void assertThatStreamIsNotHalfClosed(IStream stream) - { - assertThat("stream is not halfClosed", stream.isHalfClosed(), not(true)); - } - - private void assertThatPushStreamIsNotClosed(Stream pushStream) - { - assertThat("pushStream is not closed", pushStream.isClosed(), not(true)); - } - - private void assertThatStreamIsHalfClosed(IStream stream) - { - assertThat("stream is halfClosed", stream.isHalfClosed(), is(true)); - } - - private void assertThatStreamIsNotAssociatedWithPushStream(IStream stream, IStream pushStream) - { - assertThat("pushStream is removed from parent", stream.getPushedStreams().contains(pushStream), not(true)); - } - - private void assertThatPushStreamIsNotInSession(Stream pushStream) - { - assertThat("pushStream is not in session", session.getStreams().contains(pushStream), not(true)); - } - - private void assertThatPushStreamIsInSession(Stream pushStream) - { - assertThat("pushStream is in session", session.getStreams().contains(pushStream), is(true)); - } - - private void assertThatStreamIsAssociatedWithPushStream(IStream stream, Stream pushStream) - { - assertThat("stream is associated with pushStream", stream.getPushedStreams().contains(pushStream), is(true)); - } - - private void assertThatPushStreamIsClosed(Stream pushStream) - { - assertThat("pushStream is closed", pushStream.isClosed(), is(true)); - } - - private void assertThatPushStreamIsHalfClosed(Stream pushStream) - { - assertThat("pushStream is half closed ", pushStream.isHalfClosed(), is(true)); - } - - private void assertThatOnStreamClosedListenerHasBeenCalled(final CountDownLatch closedListenerCalledLatch) throws InterruptedException - { - assertThat("onStreamClosed listener has been called", closedListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true)); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java deleted file mode 100644 index ee79f8138e..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java +++ /dev/null @@ -1,258 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy; - -import java.nio.channels.ClosedChannelException; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.toolchain.test.annotation.Slow; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class StandardStreamTest -{ - private final ScheduledExecutorScheduler scheduler = new ScheduledExecutorScheduler(); - @Mock - private ISession session; - @Mock - private SynStreamFrame synStreamFrame; - - @Before - public void setUp() throws Exception - { - scheduler.start(); - } - - @After - public void tearDown() throws Exception - { - scheduler.stop(); - } - - @SuppressWarnings("unchecked") - @Test - public void testSyn() - { - Stream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, null, null, null); - Set<Stream> streams = new HashSet<>(); - streams.add(stream); - when(synStreamFrame.isClose()).thenReturn(false); - PushInfo pushInfo = new PushInfo(new Fields(), false); - when(session.getStreams()).thenReturn(streams); - stream.push(pushInfo, new Promise.Adapter<Stream>()); - verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), pushInfo)), - any(StreamFrameListener.class), any(Promise.class)); - } - - private class PushSynInfoMatcher extends ArgumentMatcher<PushSynInfo> - { - private int associatedStreamId; - private PushInfo pushInfo; - - public PushSynInfoMatcher(int associatedStreamId, PushInfo pushInfo) - { - this.associatedStreamId = associatedStreamId; - this.pushInfo = pushInfo; - } - - @Override - public boolean matches(Object argument) - { - PushSynInfo pushSynInfo = (PushSynInfo)argument; - return pushSynInfo.getAssociatedStreamId() == associatedStreamId && pushSynInfo.isClose() == pushInfo.isClose(); - } - } - - @Test - public void testSynOnClosedStream() - { - IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, - null, null , null); - stream.updateCloseState(true, true); - stream.updateCloseState(true, false); - assertThat("stream expected to be closed", stream.isClosed(), is(true)); - final CountDownLatch failedLatch = new CountDownLatch(1); - stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false), new Promise.Adapter<Stream>() - { - @Override - public void failed(Throwable x) - { - failedLatch.countDown(); - } - }); - assertThat("PushStream creation failed", failedLatch.getCount(), equalTo(0L)); - } - - @SuppressWarnings("unchecked") - @Test(expected = IllegalStateException.class) - public void testSendDataOnHalfClosedStream() throws InterruptedException, ExecutionException, TimeoutException - { - SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null); - IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, - null, scheduler, null); - stream.updateWindowSize(8192); - stream.updateCloseState(synStreamFrame.isClose(), true); - assertThat("stream is half closed", stream.isHalfClosed(), is(true)); - stream.data(new StringDataInfo("data on half closed stream", true)); - verify(session, never()).data(any(IStream.class), any(DataInfo.class), anyInt(), any(TimeUnit.class), any(Callback.class)); - } - - @Test - @Slow - public void testIdleTimeout() throws Exception - { - IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null); - long idleTimeout = 500; - stream.setIdleTimeout(idleTimeout); - - final AtomicInteger failureCount = new AtomicInteger(); - final CountDownLatch failureLatch = new CountDownLatch(1); - stream.setStreamFrameListener(new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - assertThat("exception is a TimeoutException", x, is(instanceOf(TimeoutException.class))); - failureCount.incrementAndGet(); - failureLatch.countDown(); - } - }); - stream.process(new StringDataInfo("string", false)); - - // Wait more than (2 * idleTimeout) to be sure to trigger a failureCount > 1 - Thread.sleep(3 * idleTimeout); - - assertThat("onFailure has been called", failureLatch.await(5, TimeUnit.SECONDS), is(true)); - Assert.assertEquals(1, failureCount.get()); - } - - @Test - @Slow - public void testIdleTimeoutIsInterruptedWhenReceiving() throws Exception - { - final CountDownLatch failureLatch = new CountDownLatch(1); - IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null); - long idleTimeout = 1000; - stream.setIdleTimeout(idleTimeout); - stream.setStreamFrameListener(new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - assertThat("exception is a TimeoutException", x, is(instanceOf(TimeoutException.class))); - failureLatch.countDown(); - } - }); - stream.process(new SynStreamFrame(SPDY.V3, (byte)0, 1, 0, (byte)0, (short)0, null)); - stream.process(new StringDataInfo("string", false)); - Thread.sleep(idleTimeout / 2); - stream.process(new StringDataInfo("string", false)); - Thread.sleep(idleTimeout / 2); - stream.process(new StringDataInfo("string", false)); - Thread.sleep(idleTimeout / 2); - stream.process(new StringDataInfo("string", true)); - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - Thread.sleep(idleTimeout); - assertThat("onFailure has not been called", failureLatch.await(idleTimeout, TimeUnit.MILLISECONDS), is(false)); - } - - @Test - @Slow - public void testReplyFailureClosesStream() throws Exception - { - ISession session = new StandardSession(SPDY.V3, null, null, null, null, null, 1, null, null, null) - { - @Override - public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback) - { - callback.failed(new ClosedChannelException()); - } - }; - IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null); - final AtomicInteger failureCount = new AtomicInteger(); - stream.setStreamFrameListener(new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - failureCount.incrementAndGet(); - } - }); - long idleTimeout = 500; - stream.setIdleTimeout(idleTimeout); - - stream.process(new SynStreamFrame(SPDY.V3, (byte)0, 1, 0, (byte)0, (short)0, null)); - - final CountDownLatch failureLatch = new CountDownLatch(1); - stream.reply(new ReplyInfo(false), new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - failureLatch.countDown(); - } - }); - - Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS)); - - // Make sure that the idle timeout never fires, since the failure above should have closed the stream - Thread.sleep(3 * idleTimeout); - - Assert.assertEquals(0, failureCount.get()); - Assert.assertTrue(stream.isClosed()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java deleted file mode 100644 index bd1ea53757..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java +++ /dev/null @@ -1,260 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.spdy.StandardSession; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class ClientUsageTest -{ - @Test - public void testClientRequestResponseNoBody() throws Exception - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null); - - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - replyInfo.getHeaders().get("host"); - - // Then issue another similar request - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - }); - } - - @Test - public void testClientReceivesPush1() throws InterruptedException, ExecutionException, TimeoutException - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null); - - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return new Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - } - }; - }; - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - replyInfo.getHeaders().get("host"); - - // Then issue another similar request - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - }); - } - - @Test - public void testClientReceivesPush2() throws InterruptedException, ExecutionException, TimeoutException - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, new SessionFrameListener.Adapter() - { - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - } - }; - } - }, null, null); - - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - replyInfo.getHeaders().get("host"); - - // Then issue another similar request - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - }); - } - - @Test - public void testClientRequestWithBodyResponseNoBody() throws Exception - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - replyInfo.getHeaders().get("host"); - - // Then issue another similar request - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - }); - // Send-and-forget the data - stream.data(new StringDataInfo("data", true)); - } - - @Test - public void testAsyncClientRequestWithBodyResponseNoBody() throws Exception - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null); - - final String context = "context"; - session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - replyInfo.getHeaders().get("host"); - - // Then issue another similar request - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - }, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream stream) - { - // Differently from JDK 7 AIO, there is no need to - // have an explicit parameter for the context since - // that is captured while the handler is created anyway, - // and it is used only by the handler as parameter - - // The style below is fire-and-forget, since - // we do not pass the handler nor we call get() - // to wait for the data to be sent - stream.data(new StringDataInfo(context, true), new Callback.Adapter()); - } - } - ); - } - - @Test - public void testAsyncClientRequestWithBodyAndResponseWithBody() throws Exception - { - Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null); - - session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - // The good of passing the listener to push() is that applications can safely - // accumulate info from the reply headers to be used in the data callback, - // e.g. content-type, charset, etc. - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do something with the response - Fields headers = replyInfo.getHeaders(); - int contentLength = headers.get("content-length").getValueAsInt(); - stream.setAttribute("content-length", contentLength); - if (!replyInfo.isClose()) - stream.setAttribute("builder", new StringBuilder()); - - // May issue another similar request while waiting for data - try - { - stream.getSession().syn(new SynInfo(new Fields(), true), this); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - throw new IllegalStateException(e); - } - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - StringBuilder builder = (StringBuilder)stream.getAttribute("builder"); - builder.append(dataInfo.asString(StandardCharsets.UTF_8, true)); - - } - }, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream stream) - { - stream.data(new BytesDataInfo("wee".getBytes(StandardCharsets.UTF_8), false), new Callback.Adapter()); - stream.data(new StringDataInfo("foo", false), new Callback.Adapter()); - stream.data(new ByteBufferDataInfo(StandardCharsets.UTF_8.encode("bar"), true), new Callback.Adapter()); - } - } - ); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java deleted file mode 100644 index 88a94ac1d9..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java +++ /dev/null @@ -1,121 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.api; - -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class ServerUsageTest -{ - @Test - public void testServerSynAndReplyWithData() throws Exception - { - ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo) - { - Fields synHeaders = streamInfo.getHeaders(); - // Do something with headers, for example extract them and - // perform an http request via Jetty's LocalConnector - - // Get the http response, fill headers and data - Fields replyHeaders = new Fields(); - replyHeaders.put(synHeaders.get("host")); - // Sends a reply - stream.reply(new ReplyInfo(replyHeaders, false), new Callback.Adapter()); - - // Sends data - StringDataInfo dataInfo = new StringDataInfo("foo", false); - stream.data(dataInfo, new Callback.Adapter()); - // Stream is now closed - return null; - } - }; - Assert.assertNotNull(ssfl); - } - - @Test - public void testServerInitiatesStreamAndPushesData() throws Exception - { - ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - // SPDY does not allow the server to initiate a stream without an existing stream - // being opened by the client already. - // Correct SPDY sequence will be: - // C --- SYN_STREAM(id=1) --> S - // C <-- SYN_REPLY(id=1) --- S - // C <-- SYN_STREAM(id=2,uni,assId=1) --- S - // - // However, the API may allow to initiate the stream - - session.syn(new SynInfo(new Fields(), false), null, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream stream) - { - // The point here is that we have no idea if the client accepted our stream - // So we return a stream, we may be able to send the headers frame, but later - // the client sends a rst frame. - // We have to atomically set some flag on the stream to signal it's closed - // and any operation on it will throw - stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter()); - } - }); - } - }; - Assert.assertNotNull(ssfl); - } - - @Test - public void testServerPush() throws Exception - { - ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo) - { - // Need to send the reply first - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - - Session session = stream.getSession(); - // Since it's unidirectional, no need to pass the listener - session.syn(new SynInfo(new Fields(), false, (byte)0), null, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushStream.data(new StringDataInfo("foo", false), new Callback.Adapter()); - } - }); - return null; - } - }; - Assert.assertNotNull(ssfl); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java deleted file mode 100644 index e1c10ec0ea..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java +++ /dev/null @@ -1,104 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.security.KeyStore; -import java.security.cert.Certificate; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.resource.Resource; -import org.junit.Assert; -import org.junit.Test; - -public class CredentialGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - short slot = 1; - byte[] proof = new byte[]{0, 1, 2}; - Certificate[] temp = loadCertificates(); - Certificate[] certificates = new Certificate[temp.length * 2]; - System.arraycopy(temp, 0, certificates, 0, temp.length); - System.arraycopy(temp, 0, certificates, temp.length, temp.length); - CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType()); - CredentialFrame credential = (CredentialFrame)frame2; - Assert.assertEquals(SPDY.V3, credential.getVersion()); - Assert.assertEquals(0, credential.getFlags()); - Assert.assertEquals(slot, credential.getSlot()); - Assert.assertArrayEquals(proof, credential.getProof()); - Assert.assertArrayEquals(certificates, credential.getCertificateChain()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - short slot = 1; - byte[] proof = new byte[]{0, 1, 2}; - Certificate[] certificates = loadCertificates(); - CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType()); - CredentialFrame credential = (CredentialFrame)frame2; - Assert.assertEquals(SPDY.V3, credential.getVersion()); - Assert.assertEquals(0, credential.getFlags()); - Assert.assertEquals(slot, credential.getSlot()); - Assert.assertArrayEquals(proof, credential.getProof()); - Assert.assertArrayEquals(certificates, credential.getCertificateChain()); - } - - private Certificate[] loadCertificates() throws Exception - { - KeyStore keyStore = KeyStore.getInstance("JKS"); - InputStream keyStoreStream = Resource.newResource("src/test/resources/keystore.jks").getInputStream(); - keyStore.load(keyStoreStream, "storepwd".toCharArray()); - return keyStore.getCertificateChain("mykey"); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java deleted file mode 100644 index a209fe895b..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java +++ /dev/null @@ -1,144 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class DataGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - testGenerateParse("test1"); - } - - @Test - public void testGenerateParseZeroLength() throws Exception - { - testGenerateParse(""); - } - - private void testGenerateParse(String content) throws Exception - { - int length = content.length(); - DataInfo data = new StringDataInfo(content, true); - int streamId = 13; - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.data(streamId, 2 * length, data); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - DataFrame frame2 = listener.getDataFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(streamId, frame2.getStreamId()); - Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags()); - Assert.assertEquals(length, frame2.getLength()); - Assert.assertEquals(length, listener.getData().remaining()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - String content = "test2"; - int length = content.length(); - DataInfo data = new StringDataInfo(content, true); - int streamId = 13; - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.data(streamId, 2 * length, data); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - { - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - if (buffer.remaining() < length) - { - DataFrame frame2 = listener.getDataFrame(); - Assert.assertNotNull(frame2); - Assert.assertEquals(streamId, frame2.getStreamId()); - Assert.assertEquals(buffer.hasRemaining() ? 0 : DataInfo.FLAG_CLOSE, frame2.getFlags()); - Assert.assertEquals(1, frame2.getLength()); - Assert.assertEquals(1, listener.getData().remaining()); - } - } - } - - @Test - public void testGenerateParseWithSyntheticFrames() throws Exception - { - String content = "0123456789ABCDEF"; - int length = content.length(); - DataInfo data = new StringDataInfo(content, true); - int streamId = 13; - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.data(streamId, 2 * length, data); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - - // Split the buffer to simulate a split boundary in receiving the bytes - int split = 3; - ByteBuffer buffer1 = ByteBuffer.allocate(buffer.remaining() - split); - buffer.limit(buffer.limit() - split); - buffer1.put(buffer); - buffer1.flip(); - ByteBuffer buffer2 = ByteBuffer.allocate(split); - buffer.limit(buffer.limit() + split); - buffer2.put(buffer); - buffer2.flip(); - - parser.parse(buffer1); - DataFrame frame2 = listener.getDataFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(streamId, frame2.getStreamId()); - Assert.assertEquals(0, frame2.getFlags()); - Assert.assertEquals(length - split, frame2.getLength()); - Assert.assertEquals(length - split, listener.getData().remaining()); - - parser.parse(buffer2); - DataFrame frame3 = listener.getDataFrame(); - - Assert.assertNotNull(frame3); - Assert.assertEquals(streamId, frame3.getStreamId()); - Assert.assertEquals(DataInfo.FLAG_CLOSE, frame3.getFlags()); - Assert.assertEquals(split, frame3.getLength()); - Assert.assertEquals(split, listener.getData().remaining()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java deleted file mode 100644 index 11ce7ea7cc..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java +++ /dev/null @@ -1,85 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class GoAwayGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - int lastStreamId = 13; - int statusCode = 1; - GoAwayFrame frame1 = new GoAwayFrame(SPDY.V3, lastStreamId, statusCode); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.GO_AWAY, frame2.getType()); - GoAwayFrame goAway = (GoAwayFrame)frame2; - Assert.assertEquals(SPDY.V3, goAway.getVersion()); - Assert.assertEquals(lastStreamId, goAway.getLastStreamId()); - Assert.assertEquals(0, goAway.getFlags()); - Assert.assertEquals(statusCode, goAway.getStatusCode()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - int lastStreamId = 13; - int statusCode = 1; - GoAwayFrame frame1 = new GoAwayFrame(SPDY.V3, lastStreamId, statusCode); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.GO_AWAY, frame2.getType()); - GoAwayFrame goAway = (GoAwayFrame)frame2; - Assert.assertEquals(SPDY.V3, goAway.getVersion()); - Assert.assertEquals(lastStreamId, goAway.getLastStreamId()); - Assert.assertEquals(0, goAway.getFlags()); - Assert.assertEquals(statusCode, goAway.getStatusCode()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java deleted file mode 100644 index 03c3cd4cfb..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java +++ /dev/null @@ -1,103 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Fields; -import org.junit.Before; -import org.junit.Test; - -public class HeadersGenerateParseTest -{ - - private Fields headers = new Fields(); - private int streamId = 13; - private byte flags = HeadersInfo.FLAG_RESET_COMPRESSION; - private final TestSPDYParserListener listener = new TestSPDYParserListener(); - private final Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - private ByteBuffer buffer; - - @Before - public void setUp() - { - parser.addListener(listener); - headers.put("a", "b"); - buffer = createHeadersFrameBuffer(headers); - } - - private ByteBuffer createHeadersFrameBuffer(Fields headers) - { - HeadersFrame frame1 = new HeadersFrame(SPDY.V2, flags, streamId, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - assertThat("Buffer is not null", buffer, notNullValue()); - return buffer; - } - - @Test - public void testGenerateParse() throws Exception - { - parser.parse(buffer); - assertExpectationsAreMet(headers); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - - assertExpectationsAreMet(headers); - } - - @Test - public void testHeadersAreTranslatedToLowerCase() - { - Fields headers = new Fields(); - headers.put("Via","localhost"); - parser.parse(createHeadersFrameBuffer(headers)); - HeadersFrame parsedHeadersFrame = assertExpectationsAreMet(headers); - Fields.Field viaHeader = parsedHeadersFrame.getHeaders().get("via"); - assertThat("Via Header name is lowercase", viaHeader.getName(), is("via")); - } - - private HeadersFrame assertExpectationsAreMet(Fields headers) - { - ControlFrame parsedControlFrame = listener.getControlFrame(); - assertThat("listener received controlFrame", parsedControlFrame, notNullValue()); - assertThat("ControlFrame type is HEADERS", ControlFrameType.HEADERS, is(parsedControlFrame.getType())); - HeadersFrame headersFrame = (HeadersFrame)parsedControlFrame; - assertThat("Version matches", SPDY.V2, is(headersFrame.getVersion())); - assertThat("StreamId matches", streamId, is(headersFrame.getStreamId())); - assertThat("flags match", flags, is(headersFrame.getFlags())); - assertThat("headers match", headers, is(headersFrame.getHeaders())); - return headersFrame; - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java deleted file mode 100644 index 7795337fbc..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java +++ /dev/null @@ -1,74 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class NoOpGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - NoOpFrame frame1 = new NoOpFrame(); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.NOOP, frame2.getType()); - NoOpFrame noOp = (NoOpFrame)frame2; - Assert.assertEquals(0, noOp.getFlags()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - NoOpFrame frame1 = new NoOpFrame(); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.NOOP, frame2.getType()); - NoOpFrame noOp = (NoOpFrame)frame2; - Assert.assertEquals(0, noOp.getFlags()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java deleted file mode 100644 index f34ed5759d..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java +++ /dev/null @@ -1,81 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class PingGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - int pingId = 13; - PingFrame frame1 = new PingFrame(SPDY.V2, pingId); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.PING, frame2.getType()); - PingFrame ping = (PingFrame)frame2; - Assert.assertEquals(SPDY.V2, ping.getVersion()); - Assert.assertEquals(pingId, ping.getPingId()); - Assert.assertEquals(0, ping.getFlags()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - int pingId = 13; - PingFrame frame1 = new PingFrame(SPDY.V2, pingId); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.PING, frame2.getType()); - PingFrame ping = (PingFrame)frame2; - Assert.assertEquals(SPDY.V2, ping.getVersion()); - Assert.assertEquals(pingId, ping.getPingId()); - Assert.assertEquals(0, ping.getFlags()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java deleted file mode 100644 index 8bc8710e55..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java +++ /dev/null @@ -1,92 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class RstStreamGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - int streamId = 13; - int streamStatus = StreamStatus.UNSUPPORTED_VERSION.getCode(SPDY.V2); - RstStreamFrame frame1 = new RstStreamFrame(SPDY.V2, streamId, streamStatus); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - assertThat("buffer is not null", buffer, not(nullValue())); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - assertThat("frame2 is not null", frame2, not(nullValue())); - assertThat("frame2 is type RST_STREAM",ControlFrameType.RST_STREAM, equalTo(frame2.getType())); - RstStreamFrame rstStream = (RstStreamFrame)frame2; - assertThat("rstStream version is SPDY.V2",SPDY.V2, equalTo(rstStream.getVersion())); - assertThat("rstStream id is equal to streamId",streamId, equalTo(rstStream.getStreamId())); - assertThat("rstStream flags are 0",(byte)0, equalTo(rstStream.getFlags())); - assertThat("stream status is equal to rstStream statuscode",streamStatus, is(rstStream.getStatusCode())); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - int streamId = 13; - int streamStatus = StreamStatus.UNSUPPORTED_VERSION.getCode(SPDY.V2); - RstStreamFrame frame1 = new RstStreamFrame(SPDY.V2, streamId, streamStatus); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.RST_STREAM, frame2.getType()); - RstStreamFrame rstStream = (RstStreamFrame)frame2; - Assert.assertEquals(SPDY.V2, rstStream.getVersion()); - Assert.assertEquals(streamId, rstStream.getStreamId()); - Assert.assertEquals(0, rstStream.getFlags()); - Assert.assertEquals(streamStatus, rstStream.getStatusCode()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java deleted file mode 100644 index adf9760220..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java +++ /dev/null @@ -1,89 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class SettingsGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - byte flags = SettingsInfo.CLEAR_PERSISTED; - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, Settings.Flag.PERSIST, 100)); - settings.put(new Settings.Setting(Settings.ID.ROUND_TRIP_TIME, Settings.Flag.PERSISTED, 500)); - SettingsFrame frame1 = new SettingsFrame(SPDY.V2, flags, settings); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SETTINGS, frame2.getType()); - SettingsFrame settingsFrame = (SettingsFrame)frame2; - Assert.assertEquals(SPDY.V2, settingsFrame.getVersion()); - Assert.assertEquals(flags, settingsFrame.getFlags()); - Assert.assertEquals(settings, settingsFrame.getSettings()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - byte flags = SettingsInfo.CLEAR_PERSISTED; - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_RETRANSMISSION_RATE, 100)); - settings.put(new Settings.Setting(Settings.ID.ROUND_TRIP_TIME, 500)); - SettingsFrame frame1 = new SettingsFrame(SPDY.V2, flags, settings); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SETTINGS, frame2.getType()); - SettingsFrame settingsFrame = (SettingsFrame)frame2; - Assert.assertEquals(SPDY.V2, settingsFrame.getVersion()); - Assert.assertEquals(flags, settingsFrame.getFlags()); - Assert.assertEquals(settings, settingsFrame.getSettings()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java deleted file mode 100644 index 61c5cc5ec1..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java +++ /dev/null @@ -1,91 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class SynReplyGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - byte flags = ReplyInfo.FLAG_CLOSE; - int streamId = 13; - Fields headers = new Fields(); - headers.put("a", "b"); - SynReplyFrame frame1 = new SynReplyFrame(SPDY.V2, flags, streamId, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SYN_REPLY, frame2.getType()); - SynReplyFrame synReply = (SynReplyFrame)frame2; - Assert.assertEquals(SPDY.V2, synReply.getVersion()); - Assert.assertEquals(flags, synReply.getFlags()); - Assert.assertEquals(streamId, synReply.getStreamId()); - Assert.assertEquals(headers, synReply.getHeaders()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - byte flags = ReplyInfo.FLAG_CLOSE; - int streamId = 13; - Fields headers = new Fields(); - headers.put("a", "b"); - SynReplyFrame frame1 = new SynReplyFrame(SPDY.V2, flags, streamId, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SYN_REPLY, frame2.getType()); - SynReplyFrame synReply = (SynReplyFrame)frame2; - Assert.assertEquals(SPDY.V2, synReply.getVersion()); - Assert.assertEquals(flags, synReply.getFlags()); - Assert.assertEquals(streamId, synReply.getStreamId()); - Assert.assertEquals(headers, synReply.getHeaders()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java deleted file mode 100644 index 0eeb55cfd9..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java +++ /dev/null @@ -1,105 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class SynStreamGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - byte flags = SynInfo.FLAG_CLOSE; - int streamId = 13; - int associatedStreamId = 11; - byte priority = 3; - short slot = 5; - Fields headers = new Fields(); - headers.put("a", "b"); - headers.put("c", "d"); - SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SYN_STREAM, frame2.getType()); - SynStreamFrame synStream = (SynStreamFrame)frame2; - Assert.assertEquals(SPDY.V2, synStream.getVersion()); - Assert.assertEquals(streamId, synStream.getStreamId()); - Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId()); - Assert.assertEquals(flags, synStream.getFlags()); - Assert.assertEquals(priority, synStream.getPriority()); - Assert.assertEquals(slot, synStream.getSlot()); - Assert.assertEquals(headers, synStream.getHeaders()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - byte flags = SynInfo.FLAG_CLOSE; - int streamId = 13; - int associatedStreamId = 11; - byte priority = 3; - short slot = 5; - Fields headers = new Fields(); - headers.put("a", "b"); - headers.put("c", "d"); - SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.SYN_STREAM, frame2.getType()); - SynStreamFrame synStream = (SynStreamFrame)frame2; - Assert.assertEquals(SPDY.V2, synStream.getVersion()); - Assert.assertEquals(streamId, synStream.getStreamId()); - Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId()); - Assert.assertEquals(flags, synStream.getFlags()); - Assert.assertEquals(priority, synStream.getPriority()); - Assert.assertEquals(slot, synStream.getSlot()); - Assert.assertEquals(headers, synStream.getHeaders()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java deleted file mode 100644 index 3d6d5b3ece..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java +++ /dev/null @@ -1,70 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.parser.Parser; - -public class TestSPDYParserListener implements Parser.Listener -{ - private ControlFrame controlFrame; - private DataFrame dataFrame; - private ByteBuffer data; - - @Override - public void onControlFrame(ControlFrame frame) - { - this.controlFrame = frame; - } - - @Override - public void onDataFrame(DataFrame frame, ByteBuffer data) - { - this.dataFrame = frame; - this.data = data; - } - - @Override - public void onStreamException(StreamException x) - { - } - - @Override - public void onSessionException(SessionException x) - { - } - - public ControlFrame getControlFrame() - { - return controlFrame; - } - - public DataFrame getDataFrame() - { - return dataFrame; - } - - public ByteBuffer getData() - { - return data; - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java deleted file mode 100644 index 24689350f6..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java +++ /dev/null @@ -1,85 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.frames; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.junit.Assert; -import org.junit.Test; - -public class WindowUpdateGenerateParseTest -{ - @Test - public void testGenerateParse() throws Exception - { - int streamId = 13; - int windowDelta = 17; - WindowUpdateFrame frame1 = new WindowUpdateFrame(SPDY.V2, streamId, windowDelta); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - parser.parse(buffer); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.WINDOW_UPDATE, frame2.getType()); - WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame2; - Assert.assertEquals(SPDY.V2, windowUpdate.getVersion()); - Assert.assertEquals(streamId, windowUpdate.getStreamId()); - Assert.assertEquals(0, windowUpdate.getFlags()); - Assert.assertEquals(windowDelta, windowUpdate.getWindowDelta()); - } - - @Test - public void testGenerateParseOneByteAtATime() throws Exception - { - int streamId = 13; - int windowDelta = 17; - WindowUpdateFrame frame1 = new WindowUpdateFrame(SPDY.V2, streamId, windowDelta); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - ByteBuffer buffer = generator.control(frame1); - - Assert.assertNotNull(buffer); - - TestSPDYParserListener listener = new TestSPDYParserListener(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(listener); - while (buffer.hasRemaining()) - parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); - ControlFrame frame2 = listener.getControlFrame(); - - Assert.assertNotNull(frame2); - Assert.assertEquals(ControlFrameType.WINDOW_UPDATE, frame2.getType()); - WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame2; - Assert.assertEquals(SPDY.V2, windowUpdate.getVersion()); - Assert.assertEquals(streamId, windowUpdate.getStreamId()); - Assert.assertEquals(0, windowUpdate.getFlags()); - Assert.assertEquals(windowDelta, windowUpdate.getWindowDelta()); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java deleted file mode 100644 index b0c972c770..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java +++ /dev/null @@ -1,110 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.generator; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.nio.ByteBuffer; -import java.util.concurrent.ThreadLocalRandom; - -import org.eclipse.jetty.io.ArrayByteBufferPool; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.util.BufferUtil; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class DataFrameGeneratorTest -{ - private int increment = 1024; - private int streamId = 1; - private ArrayByteBufferPool bufferPool; - private DataFrameGenerator dataFrameGenerator; - private ByteBuffer headerBuffer = ByteBuffer.allocate(DataFrame.HEADER_LENGTH); - - @Before - public void setUp() - { - bufferPool = new ArrayByteBufferPool(64, increment, 8192); - dataFrameGenerator = new DataFrameGenerator(bufferPool); - headerBuffer.putInt(0, streamId & 0x7F_FF_FF_FF); - - } - - @Test - public void testGenerateSmallFrame() - { - int bufferSize = 256; - generateFrame(bufferSize); - } - - @Test - public void testGenerateFrameWithBufferThatEqualsBucketSize() - { - int bufferSize = increment; - generateFrame(bufferSize); - } - - @Test - public void testGenerateFrameWithBufferThatEqualsBucketSizeMinusHeaderLength() - { - int bufferSize = increment - DataFrame.HEADER_LENGTH; - generateFrame(bufferSize); - } - - private void generateFrame(int bufferSize) - { - ByteBuffer byteBuffer = createByteBuffer(bufferSize); - ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(byteBuffer, true); - fillHeaderBuffer(bufferSize); - ByteBuffer dataFrameBuffer = dataFrameGenerator.generate(streamId, bufferSize, dataInfo); - - assertThat("The content size in dataFrameBuffer matches the buffersize + header length", - dataFrameBuffer.limit(), - is(bufferSize + DataFrame.HEADER_LENGTH)); - - byte[] headerBytes = new byte[DataFrame.HEADER_LENGTH]; - dataFrameBuffer.get(headerBytes, 0, DataFrame.HEADER_LENGTH); - - assertThat("Header bytes are prepended", headerBytes, is(headerBuffer.array())); - } - - private ByteBuffer createByteBuffer(int bufferSize) - { - byte[] bytes = new byte[bufferSize]; - ThreadLocalRandom.current().nextBytes(bytes); - ByteBuffer byteBuffer = bufferPool.acquire(bufferSize, false); - BufferUtil.flipToFill(byteBuffer); - byteBuffer.put(bytes); - BufferUtil.flipToFlush(byteBuffer, 0); - return byteBuffer; - } - - private void fillHeaderBuffer(int bufferSize) - { - headerBuffer.putInt(4, bufferSize & 0x00_FF_FF_FF); - headerBuffer.put(4, DataInfo.FLAG_CLOSE); - } - -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java deleted file mode 100644 index 5d1a51d1b5..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java +++ /dev/null @@ -1,287 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.zip.ZipException; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Fields; -import org.junit.Test; - -public class BrokenFrameTest -{ - - @Test - public void testInvalidHeaderNameLength() throws Exception - { - Fields headers = new Fields(); - headers.add("broken", "header"); - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor()); - - ByteBuffer bufferWithBrokenHeaderNameLength = generator.control(frame); - // Break the header name length to provoke the Parser to throw a StreamException - bufferWithBrokenHeaderNameLength.put(21, (byte)0); - - ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(BufferUtil.toArray(bufferWithBrokenHeaderNameLength)); - outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame)); - - byte concatenatedFramesByteArray[] = outputStream.toByteArray(); - ByteBuffer concatenatedBuffer = BufferUtil.toBuffer(concatenatedFramesByteArray); - - final CountDownLatch latch = new CountDownLatch(2); - Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - latch.countDown(); - } - - @Override - public void onStreamException(StreamException x) - { - latch.countDown(); - } - }); - parser.parse(concatenatedBuffer); - - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testInvalidVersion() throws Exception - { - Fields headers = new Fields(); - headers.add("good", "header"); - headers.add("another","header"); - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor()); - - ByteBuffer bufferWithBrokenVersion = generator.control(frame); - // Break the header name length to provoke the Parser to throw a StreamException - bufferWithBrokenVersion.put(1, (byte)4); - - ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion)); - outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame)); - - byte concatenatedFramesByteArray[] = outputStream.toByteArray(); - ByteBuffer concatenatedBuffer = BufferUtil.toBuffer(concatenatedFramesByteArray); - - final CountDownLatch latch = new CountDownLatch(2); - Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - latch.countDown(); - } - - @Override - public void onStreamException(StreamException x) - { - latch.countDown(); - } - }); - parser.parse(concatenatedBuffer); - - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testInvalidVersionWithSplitBuffer() throws Exception - { - Fields headers = new Fields(); - headers.add("good", "header"); - headers.add("another","header"); - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor()); - - ByteBuffer bufferWithBrokenVersion = generator.control(frame); - // Break the header name length to provoke the Parser to throw a StreamException - bufferWithBrokenVersion.put(1, (byte)4); - - ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion)); - outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame)); - - byte concatenatedFramesByteArray[] = outputStream.toByteArray(); - ByteBuffer concatenatedBuffer1 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,0,20)); - ByteBuffer concatenatedBuffer2 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,20, - concatenatedFramesByteArray.length)); - - final CountDownLatch latch = new CountDownLatch(2); - Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - latch.countDown(); - } - - @Override - public void onStreamException(StreamException x) - { - latch.countDown(); - } - }); - parser.parse(concatenatedBuffer1); - parser.parse(concatenatedBuffer2); - - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testInvalidVersionAndGoodFrameSplitInThreeBuffers() throws Exception - { - Fields headers = new Fields(); - headers.add("good", "header"); - headers.add("another","header"); - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers); - Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor()); - - ByteBuffer bufferWithBrokenVersion = generator.control(frame); - // Break the header name length to provoke the Parser to throw a StreamException - bufferWithBrokenVersion.put(1, (byte)4); - - ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion)); - outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame)); - - byte concatenatedFramesByteArray[] = outputStream.toByteArray(); - ByteBuffer concatenatedBuffer1 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,0,20)); - ByteBuffer concatenatedBuffer2 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,20, 30)); - ByteBuffer concatenatedBuffer3 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,30, - concatenatedFramesByteArray.length)); - - final CountDownLatch latch = new CountDownLatch(2); - Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - latch.countDown(); - } - - @Override - public void onStreamException(StreamException x) - { - latch.countDown(); - } - }); - parser.parse(concatenatedBuffer1); - parser.parse(concatenatedBuffer2); - parser.parse(concatenatedBuffer3); - - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); - } - - private static class NoCompressionCompressionFactory implements CompressionFactory - { - - @Override - public Compressor newCompressor() - { - return null; - } - - @Override - public Decompressor newDecompressor() - { - return null; - } - - public static class NoCompressionCompressor implements Compressor - { - - private byte[] input; - - @Override - public void setInput(byte[] input) - { - this.input = input; - } - - @Override - public void setDictionary(byte[] dictionary) - { - } - - @Override - public int compress(byte[] output) - { - System.arraycopy(input, 0, output, 0, input.length); - return input.length; - } - } - - public static class NoCompressionDecompressor implements Decompressor - { - private byte[] input; - - @Override - public void setDictionary(byte[] dictionary) - { - } - - @Override - public void setInput(byte[] input) - { - this.input = input; - } - - @Override - public int decompress(byte[] output) throws ZipException - { - System.arraycopy(input, 0, output, 0, input.length); - return input.length; - } - } - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java deleted file mode 100644 index 2ad3a83d78..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java +++ /dev/null @@ -1,100 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.junit.Assert; -import org.junit.Test; - -public class LiveChromiumRequestParserTest -{ - @Test - public void testSynStream() throws Exception - { - // Bytes taken with wireshark from a live chromium request - byte[] bytes1 = toBytes("" + - "800200010100011a0000000100000000000038eadfa251b262e0626083a41706" + - "7bb80b75302cd6ae4017cdcdb12eb435d0b3d4d1d2d702b32c18f850732c036f" + - "68889bae850e44da94811f2d0b3308821ca80375a14e714a72065c0d2cd619f8" + - "52f37443837552f3a076b080b234033f28de73404c2b43630b135306b65c6059" + - "929fc2c0ecee1ac2c0560c4c7eb9a940b52525050ccc206f32ea337021f22643" + - "bb6f7e55664e4ea2bea99e81824684a1a135400a3e9979a5150a151666f16626" + - "9a0a8e40afa686a726796796e89b1a9bea992b68787b84f8fae828e46466a72a" + - "b8a72667e76b2a842695e69594ea1b0203d640c1390358e06496e6ea1b9ae901" + - "c3c5d048cfdc1c22988a22149c98965894093195811d1a150c1cb01802000000" + - "ffff"); - byte[] bytes2 = toBytes("" + - "800200010100002700000003000000008000428a106660d00ee640e5d14f4b2c" + - "cb0466313d203154c217000000ffff"); - - final AtomicReference<ControlFrame> frameRef = new AtomicReference<>(); - Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - frameRef.set(frame); - } - }); - parser.parse(ByteBuffer.wrap(bytes1)); - - ControlFrame frame = frameRef.get(); - Assert.assertNotNull(frame); - Assert.assertEquals(ControlFrameType.SYN_STREAM, frame.getType()); - SynStreamFrame synStream = (SynStreamFrame)frame; - Assert.assertEquals(2, synStream.getVersion()); - Assert.assertEquals(1, synStream.getStreamId()); - Assert.assertEquals(0, synStream.getAssociatedStreamId()); - Assert.assertEquals(0, synStream.getPriority()); - Assert.assertNotNull(synStream.getHeaders()); - Assert.assertFalse(synStream.getHeaders().isEmpty()); - - frameRef.set(null); - parser.parse(ByteBuffer.wrap(bytes2)); - - frame = frameRef.get(); - Assert.assertNotNull(frame); - Assert.assertEquals(ControlFrameType.SYN_STREAM, frame.getType()); - synStream = (SynStreamFrame)frame; - Assert.assertEquals(2, synStream.getVersion()); - Assert.assertEquals(3, synStream.getStreamId()); - Assert.assertEquals(0, synStream.getAssociatedStreamId()); - Assert.assertEquals(2, synStream.getPriority()); - Assert.assertNotNull(synStream.getHeaders()); - Assert.assertFalse(synStream.getHeaders().isEmpty()); - } - - private byte[] toBytes(String hexs) - { - byte[] bytes = new byte[hexs.length() / 2]; - for (int i = 0; i < hexs.length(); i += 2) - { - String hex = hexs.substring(i, i + 2); - bytes[i / 2] = (byte)Integer.parseInt(hex, 16); - } - return bytes; - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java deleted file mode 100644 index 4c5e5d68d9..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -public class ParseVersusCacheBenchmarkTest -{ - @Ignore - @Test - public void testParseVersusCache() throws Exception - { - // The parser knows the header name and value lengths, so it creates strings - // out of the bytes; however, this involves creating a byte[] copy the bytes, - // and creating a new String. - // The alternative is to use a cache<ByteBuffer, String>. Is that faster ? - // See also: http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html - - String name = "Content-Type"; - String value = "application/octect-stream"; - ByteBuffer buffer = ByteBuffer.wrap((name + value).getBytes(StandardCharsets.ISO_8859_1)); - int iterations = 100_000_000; - - long begin = System.nanoTime(); - for (int i = 0; i < iterations; ++i) - { - byte[] nameBytes = new byte[name.length()]; - buffer.get(nameBytes); - String name2 = new String(nameBytes, StandardCharsets.ISO_8859_1); - Assert.assertEquals(name2, name); - - byte[] valueBytes = new byte[value.length()]; - buffer.get(valueBytes); - String value2 = new String(valueBytes, StandardCharsets.ISO_8859_1); - Assert.assertEquals(value2, value); - - buffer.flip(); - } - long end = System.nanoTime(); - System.err.printf("parse time: %d%n", TimeUnit.NANOSECONDS.toMillis(end - begin)); - - Map<ByteBuffer, String> map = new HashMap<>(); - map.put(ByteBuffer.wrap(name.getBytes(StandardCharsets.ISO_8859_1)), name); - map.put(ByteBuffer.wrap(value.getBytes(StandardCharsets.ISO_8859_1)), value); - final Map<ByteBuffer, String> cache = Collections.unmodifiableMap(map); - - begin = System.nanoTime(); - for (int i = 0; i < iterations; ++i) - { - buffer.limit(buffer.position() + name.length()); - String name2 = cache.get(buffer); - Assert.assertEquals(name2, name); - - buffer.position(buffer.limit()); - buffer.limit(buffer.position() + value.length()); - String value2 = cache.get(buffer); - Assert.assertEquals(value2, value); - - buffer.position(buffer.limit()); - buffer.flip(); - } - end = System.nanoTime(); - System.err.printf("cache time: %d%n", TimeUnit.NANOSECONDS.toMillis(end - begin)); - } -} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java deleted file mode 100644 index 9bd9909493..0000000000 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.parser; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.SessionException; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class UnknownControlFrameTest -{ - @Test - public void testUnknownControlFrame() throws Exception - { - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Fields()); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - ByteBuffer buffer = generator.control(frame); - // Change the frame type to unknown - buffer.putShort(2, (short)0); - - final CountDownLatch latch = new CountDownLatch(1); - Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - latch.countDown(); - } - - @Override - public void onDataFrame(DataFrame frame, ByteBuffer data) - { - latch.countDown(); - } - - @Override - public void onStreamException(StreamException x) - { - latch.countDown(); - } - - @Override - public void onSessionException(SessionException x) - { - latch.countDown(); - } - }); - parser.parse(buffer); - - Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties deleted file mode 100644 index 5250a08562..0000000000 --- a/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.spdy.LEVEL=WARN diff --git a/jetty-spdy/spdy-core/src/test/resources/keystore.jks b/jetty-spdy/spdy-core/src/test/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-core/src/test/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-core/src/test/resources/truststore.jks b/jetty-spdy/spdy-core/src/test/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-core/src/test/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml deleted file mode 100644 index 0045fc1cfb..0000000000 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-example-webapp</artifactId> - <packaging>war</packaging> - <name>Jetty :: SPDY :: HTTP Web Application</name> - - <build> - <plugins> - <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>${project.version}</version> - <configuration> - <stopPort>8888</stopPort> - <stopKey>quit</stopKey> - <jvmArgs> - -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar - </jvmArgs> - <jettyXml>${basedir}/src/main/config/example-jetty-spdy.xml</jettyXml> - <contextPath>/</contextPath> - <excludedGoals> - <excludedGoal>run</excludedGoal> - <excludedGoal>run-war</excludedGoal> - <excludedGoal>deploy</excludedGoal> - <excludedGoal>start</excludedGoal> - <excludedGoal>stop</excludedGoal> - </excludedGoals> - </configuration> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - </plugin> - </plugins> - </build> - - <profiles> - <profile> - <id>proxy</id> - <build> - <plugins> - <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>${project.version}</version> - <configuration> - <stopPort>8888</stopPort> - <stopKey>quit</stopKey> - <jvmArgs> - -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar - </jvmArgs> - <jettyXml>${basedir}/src/main/config/example-jetty-spdy-proxy.xml</jettyXml> - <contextPath>/</contextPath> - <excludedGoals> - <excludedGoal>run</excludedGoal> - <excludedGoal>run-war</excludedGoal> - <excludedGoal>deploy</excludedGoal> - <excludedGoal>start</excludedGoal> - <excludedGoal>stop</excludedGoal> - </excludedGoals> - </configuration> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - </plugin> - </plugins> - </build> - </profile> - </profiles> - -</project> diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml deleted file mode 100644 index 7d3d360ac8..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml +++ /dev/null @@ -1,147 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="keyStorePath">src/main/resources/keystore.jks</Set> - <Set name="keyStorePassword">storepwd</Set> - <Set name="trustStorePath">src/main/resources/truststore.jks</Set> - <Set name="trustStorePassword">storepwd</Set> - <Set name="protocol">TLSv1</Set> - </New> - - <!-- - <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set> - --> - - <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Arg> - <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Set name="secureScheme">https</Set> - <Set name="securePort"> - <Property name="jetty.tls.port" default="8443"/> - </Set> - <Set name="outputBufferSize">32768</Set> - <Set name="requestHeaderSize">8192</Set> - <Set name="responseHeaderSize">8192</Set> - - <!-- Uncomment to enable handling of X-Forwarded- style headers - <Call name="addCustomizer"> - <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg> - </Call> - --> - </New> - </Arg> - <Call name="addCustomizer"> - <Arg> - <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/> - </Arg> - </Call> - </New> - - <!-- - This is the upstream server connector. It speaks non-SSL SPDY/3(HTTP) on port 9090. - --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <!-- SPDY/3 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="tlsHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="port">9090</Set> - </New> - </Arg> - </Call> - - <!-- - This ProxyEngine translates the incoming SPDY/x(HTTP) request to SPDY/2(HTTP) - --> - <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.server.proxy.SPDYProxyEngine"> - <Arg> - <New class="org.eclipse.jetty.spdy.client.SPDYClient$Factory"> - <Call name="start"/> - </New> - </Arg> - </New> - - <!-- - The ProxyEngineSelector receives SPDY/x(HTTP) requests from proxy connectors below - and is configured to process requests for host "localhost". - Such requests are converted from SPDY/x(HTTP) to SPDY/3(HTTP) by the configured ProxyEngine - and forwarded to 127.0.0.1:9090, where they are served by the upstream server above. - --> - <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector"> - <Call name="putProxyEngine"> - <Arg>spdy/3</Arg> - <Arg> - <Ref refid="spdyProxyEngine"/> - </Arg> - </Call> - <Set name="proxyServerInfos"> - <Map> - <Entry> - <Item>localhost</Item> - <Item> - <New class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector$ProxyServerInfo"> - <Arg type="String">spdy/3</Arg> - <Arg>127.0.0.1</Arg> - <Arg type="int">9090</Arg> - </New> - </Item> - </Entry> - </Map> - </Set> - </New> - - <!-- - These are the reverse proxy connectors accepting requests from clients. - They accept non-SSL (on port 8080) and SSL (on port 8443) HTTP, - SPDY/2(HTTP) and SPDY/3(HTTP). - Non-SPDY HTTP requests are converted to SPDY internally and passed to the - ProxyEngine above. - --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector"> - <Arg> - <Ref refid="Server"/> - </Arg> - <Arg> - <Ref refid="proxyEngineSelector"/> - </Arg> - <Set name="Port">8080</Set> - </New> - </Arg> - </Call> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector"> - <Arg> - <Ref refid="Server"/> - </Arg> - <Arg> - <Ref refid="sslContextFactory"/> - </Arg> - <Arg> - <Ref refid="proxyEngineSelector"/> - </Arg> - <Set name="Port">8443</Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml deleted file mode 100644 index 47f83be825..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml +++ /dev/null @@ -1,138 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="keyStorePath">src/main/resources/keystore.jks</Set> - <Set name="keyStorePassword">storepwd</Set> - <Set name="trustStorePath">src/main/resources/truststore.jks</Set> - <Set name="trustStorePassword">storepwd</Set> - <Set name="protocol">TLSv1</Set> - </New> - - <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Arg> - <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Set name="secureScheme">https</Set> - <Set name="securePort"> - <Property name="jetty.tls.port" default="8443"/> - </Set> - <Set name="outputBufferSize">32768</Set> - <Set name="requestHeaderSize">8192</Set> - <Set name="responseHeaderSize">8192</Set> - - <!-- Uncomment to enable handling of X-Forwarded- style headers - <Call name="addCustomizer"> - <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg> - </Call> - --> - </New> - </Arg> - <Call name="addCustomizer"> - <Arg> - <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/> - </Arg> - </Call> - </New> - - <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> - <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the - user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> - <!-- - <Set name="UserAgentBlacklist"> - <Array type="String"> - <Item>.*(?i)firefox/14.*</Item> - <Item>.*(?i)firefox/15.*</Item> - <Item>.*(?i)firefox/16.*</Item> - </Array> - </Set> - --> - - <!-- Uncomment to override default file extensions to push --> - <!-- - <Set name="PushRegexps"> - <Array type="String"> - <Item>.*\.css</Item> - <Item>.*\.js</Item> - <Item>.*\.png</Item> - <Item>.*\.jpg</Item> - <Item>.*\.gif</Item> - </Array> - </Set> - --> - <Set name="referrerPushPeriod">5000</Set> - <Set name="maxAssociatedResources">32</Set> - </New> - - <Call id="sslConnector" name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"><Ref refid="Server"/></Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - - <!-- SSL Connection factory with NPN as next protocol --> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next">npn</Arg> - <Arg name="sslContextFactory"> - <Ref refid="sslContextFactory"/> - </Arg> - </New> - </Item> - - <!-- NPN Connection factory with HTTP as default protocol --> - <Item> - <New class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - <Item>spdy/3</Item> - <Item>spdy/2</Item> - <Item>http/1.1</Item> - </Array> - </Arg> - <Set name="defaultProtocol">http/1.1</Set> - </New> - </Item> - - <!-- SPDY/3 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="tlsHttpConfig"/> - </Arg> - <Arg name="pushStrategy"> - <Ref refid="pushStrategy"/> - </Arg> - </New> - </Item> - - <!-- SPDY/2 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">2</Arg> - <Arg name="config"> - <Ref refid="tlsHttpConfig"/> - </Arg> - </New> - </Item> - - <!-- HTTP Connection factory --> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"> - <Ref refid="tlsHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - - <Set name="port">8443</Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties b/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties deleted file mode 100644 index 5250a08562..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.spdy.LEVEL=WARN diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks b/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks b/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index eb49319a3e..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<web-app xmlns="http://java.sun.com/xml/ns/javaee" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" - version="3.0"> -</web-app> diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp deleted file mode 100644 index 4e41a655ad..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<div> - <p>This paragraph has been retrieved via an AJAX call</p> -</div> diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp deleted file mode 100644 index d69cd4a729..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<div> - <p>This paragraph is an included content via <jsp:include></p> -</div> diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp deleted file mode 100644 index f190e572ab..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp +++ /dev/null @@ -1,37 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html> -<head> - <title>SPDY TEST PAGE</title> - <link rel="stylesheet" href="stylesheet.css" /> - <script type="text/javascript"> - function submit() - { - var xhr = new XMLHttpRequest(); - xhr.open("POST", "${pageContext.request.contextPath}/form.jsp", false); - xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); - xhr.send("param=1"); - window.document.getElementById("form").innerHTML = xhr.responseText; - } - </script> -</head> -<body> -<h2>SPDY TEST PAGE</h2> -<div> - <p><span id="css">This paragraph should have a colored background, meaning that the CSS has been loaded.</span></p> -</div> -<div id="image"> - <p>Below there should be an image</p> - <img src="${pageContext.request.contextPath}/logo.jpg" alt="logo" /> -</div> -<div> - <jsp:include page="included.jsp" /> -</div> -<div> - <p>Click on the button below to perform an AJAX call</p> - <button type="button" onclick="submit()"> - PERFORM AJAX CALL - </button> - <p id="form"></p> -</div> -</body> -</html> diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg b/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg Binary files differdeleted file mode 100644 index e8eb8c55fd..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg +++ /dev/null diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css b/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css deleted file mode 100644 index 169c339849..0000000000 --- a/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css +++ /dev/null @@ -1,9 +0,0 @@ -body -{ - font-family: Verdana, sans-serif; -} - -#css -{ - background: #0FF; -} diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml deleted file mode 100644 index 1cb3ae6970..0000000000 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-http-client-transport</artifactId> - <name>Jetty :: SPDY :: HTTP Client Transport</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.client.http</bundle-symbolic-name> - </properties> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.client.http;version="9.1"</Export-Package> - <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-common</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java deleted file mode 100644 index 0f32567e4a..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java +++ /dev/null @@ -1,78 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import org.eclipse.jetty.client.HttpChannel; -import org.eclipse.jetty.client.HttpDestination; -import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.spdy.api.Session; - -public class HttpChannelOverSPDY extends HttpChannel -{ - private final HttpConnectionOverSPDY connection; - private final Session session; - private final HttpSenderOverSPDY sender; - private final HttpReceiverOverSPDY receiver; - - public HttpChannelOverSPDY(HttpDestination destination, HttpConnectionOverSPDY connection, Session session) - { - super(destination); - this.connection = connection; - this.session = session; - this.sender = new HttpSenderOverSPDY(this); - this.receiver = new HttpReceiverOverSPDY(this); - } - - public Session getSession() - { - return session; - } - - public HttpSenderOverSPDY getHttpSender() - { - return sender; - } - - public HttpReceiverOverSPDY getHttpReceiver() - { - return receiver; - } - - @Override - public void send() - { - HttpExchange exchange = getHttpExchange(); - if (exchange != null) - sender.send(exchange); - } - - @Override - public void release() - { - connection.release(this); - } - - @Override - public void exchangeTerminated(HttpExchange exchange, Result result) - { - super.exchangeTerminated(exchange, result); - release(); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java deleted file mode 100644 index 2aef0a5db8..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java +++ /dev/null @@ -1,107 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.io.IOException; -import java.net.SocketAddress; -import java.util.Map; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpClientTransport; -import org.eclipse.jetty.client.HttpDestination; -import org.eclipse.jetty.client.Origin; -import org.eclipse.jetty.client.api.Connection; -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.Promise; - -public class HttpClientTransportOverSPDY implements HttpClientTransport -{ - private final SPDYClient client; - private final ClientConnectionFactory connectionFactory; - private HttpClient httpClient; - - public HttpClientTransportOverSPDY(SPDYClient client) - { - this.client = client; - this.connectionFactory = client.getClientConnectionFactory(); - client.setClientConnectionFactory(new ClientConnectionFactory() - { - @Override - public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException - { - HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY); - return destination.getClientConnectionFactory().newConnection(endPoint, context); - } - }); - } - - @Override - public void setHttpClient(HttpClient client) - { - httpClient = client; - } - - @Override - public HttpDestination newHttpDestination(Origin origin) - { - return new HttpDestinationOverSPDY(httpClient, origin); - } - - @Override - public void connect(SocketAddress address, Map<String, Object> context) - { - final HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY); - @SuppressWarnings("unchecked") - final Promise<Connection> promise = (Promise<Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY); - - SessionFrameListener.Adapter listener = new SessionFrameListener.Adapter() - { - @Override - public void onFailure(Session session, Throwable x) - { - destination.abort(x); - } - }; - - client.connect(address, listener, new Promise<Session>() - { - @Override - public void succeeded(Session session) - { - promise.succeeded(new HttpConnectionOverSPDY(destination, session)); - } - - @Override - public void failed(Throwable x) - { - promise.failed(x); - } - }, context); - } - - @Override - public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException - { - return connectionFactory.newConnection(endPoint, context); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java deleted file mode 100644 index f3055e9f13..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.nio.channels.AsynchronousCloseException; -import java.util.Set; - -import org.eclipse.jetty.client.HttpChannel; -import org.eclipse.jetty.client.HttpConnection; -import org.eclipse.jetty.client.HttpDestination; -import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.ConcurrentHashSet; - -public class HttpConnectionOverSPDY extends HttpConnection -{ - private final Set<HttpChannel> channels = new ConcurrentHashSet<>(); - private final Session session; - - public HttpConnectionOverSPDY(HttpDestination destination, Session session) - { - super(destination); - this.session = session; - } - - @Override - protected void send(HttpExchange exchange) - { - normalizeRequest(exchange.getRequest()); - // One connection maps to N channels, so for each exchange we create a new channel - HttpChannel channel = new HttpChannelOverSPDY(getHttpDestination(), this, session); - channels.add(channel); - if (channel.associate(exchange)) - channel.send(); - else - channel.release(); - } - - protected void release(HttpChannel channel) - { - channels.remove(channel); - } - - @Override - public void close() - { - // First close then abort, to be sure that the connection cannot be reused - // from an onFailure() handler or by blocking code waiting for completion. - getHttpDestination().close(this); - session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE); - abort(new AsynchronousCloseException()); - } - - private void abort(Throwable failure) - { - for (HttpChannel channel : channels) - { - HttpExchange exchange = channel.getHttpExchange(); - if (exchange != null) - exchange.getRequest().abort(failure); - } - channels.clear(); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java deleted file mode 100644 index c52e0c4e03..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.MultiplexHttpDestination; -import org.eclipse.jetty.client.Origin; - -public class HttpDestinationOverSPDY extends MultiplexHttpDestination<HttpConnectionOverSPDY> -{ - public HttpDestinationOverSPDY(HttpClient client, Origin origin) - { - super(client, origin); - } - - @Override - protected void send(HttpConnectionOverSPDY connection, HttpExchange exchange) - { - connection.send(exchange); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java deleted file mode 100644 index 51b315137d..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java +++ /dev/null @@ -1,152 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.HttpReceiver; -import org.eclipse.jetty.client.HttpResponse; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; - -public class HttpReceiverOverSPDY extends HttpReceiver implements StreamFrameListener -{ - public HttpReceiverOverSPDY(HttpChannelOverSPDY channel) - { - super(channel); - } - - @Override - public HttpChannelOverSPDY getHttpChannel() - { - return (HttpChannelOverSPDY)super.getHttpChannel(); - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - HttpExchange exchange = getHttpExchange(); - if (exchange == null) - return; - - try - { - HttpResponse response = exchange.getResponse(); - - Fields fields = replyInfo.getHeaders(); - short spdy = stream.getSession().getVersion(); - HttpVersion version = HttpVersion.fromString(fields.get(HTTPSPDYHeader.VERSION.name(spdy)).getValue()); - response.version(version); - String[] status = fields.get(HTTPSPDYHeader.STATUS.name(spdy)).getValue().split(" ", 2); - - Integer code = Integer.parseInt(status[0]); - response.status(code); - String reason = status.length < 2 ? HttpStatus.getMessage(code) : status[1]; - response.reason(reason); - - if (responseBegin(exchange)) - { - for (Fields.Field field : fields) - { - String name = field.getName(); - if (HTTPSPDYHeader.from(spdy, name) != null) - continue; - // TODO: handle multiple values properly - HttpField httpField = new HttpField(name, field.getValue()); - responseHeader(exchange, httpField); - } - - if (responseHeaders(exchange)) - { - if (replyInfo.isClose()) - { - responseSuccess(exchange); - } - } - } - } - catch (Exception x) - { - responseFailure(x); - } - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - // SPDY push not supported - getHttpChannel().getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), Callback.Adapter.INSTANCE); - return null; - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - // TODO: see above handling of headers - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - HttpExchange exchange = getHttpExchange(); - if (exchange == null) - return; - - try - { - int length = dataInfo.length(); - // TODO: avoid data copy here - // TODO: handle callback properly - boolean process = responseContent(exchange, dataInfo.asByteBuffer(false), new Callback.Adapter()); - dataInfo.consume(length); - - if (process) - { - if (dataInfo.isClose()) - { - responseSuccess(exchange); - } - } - } - catch (Exception x) - { - responseFailure(x); - } - } - - @Override - public void onFailure(Stream stream, Throwable x) - { - HttpExchange exchange = getHttpExchange(); - if (exchange == null) - return; - exchange.getRequest().abort(x); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java deleted file mode 100644 index 7429fcf3a0..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java +++ /dev/null @@ -1,118 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import org.eclipse.jetty.client.HttpContent; -import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.HttpSender; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; - -public class HttpSenderOverSPDY extends HttpSender -{ - private volatile Stream stream; - - public HttpSenderOverSPDY(HttpChannelOverSPDY channel) - { - super(channel); - } - - @Override - public HttpChannelOverSPDY getHttpChannel() - { - return (HttpChannelOverSPDY)super.getHttpChannel(); - } - - @Override - protected void sendHeaders(HttpExchange exchange, final HttpContent content, final Callback callback) - { - final Request request = exchange.getRequest(); - final long idleTimeout = request.getIdleTimeout(); - short spdyVersion = getHttpChannel().getSession().getVersion(); - Fields fields = new Fields(); - HttpField hostHeader = null; - for (HttpField header : request.getHeaders()) - { - String name = header.getName(); - // The host header needs a special treatment - if (HTTPSPDYHeader.from(spdyVersion, name) != HTTPSPDYHeader.HOST) - fields.add(name, header.getValue()); - else - hostHeader = header; - } - - // Add special SPDY headers - fields.put(HTTPSPDYHeader.METHOD.name(spdyVersion), request.getMethod()); - String path = request.getPath(); - String query = request.getQuery(); - if (query != null) - path += "?" + query; - fields.put(HTTPSPDYHeader.URI.name(spdyVersion), path); - fields.put(HTTPSPDYHeader.VERSION.name(spdyVersion), request.getVersion().asString()); - if (hostHeader != null) - fields.put(HTTPSPDYHeader.HOST.name(spdyVersion), hostHeader.getValue()); - - SynInfo synInfo = new SynInfo(fields, !content.hasContent()); - getHttpChannel().getSession().syn(synInfo, getHttpChannel().getHttpReceiver(), new Promise<Stream>() - { - @Override - public void succeeded(Stream stream) - { - stream.setIdleTimeout(idleTimeout); - if (content.hasContent()) - HttpSenderOverSPDY.this.stream = stream; - callback.succeeded(); - } - - @Override - public void failed(Throwable failure) - { - callback.failed(failure); - } - }); - } - - @Override - protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback) - { - if (content.isConsumed()) - { - callback.succeeded(); - } - else - { - ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(content.getByteBuffer(), content.isLast()); - stream.data(dataInfo, callback); - } - } - - @Override - protected void reset() - { - super.reset(); - stream = null; - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java deleted file mode 100644 index ab7a2a7b5b..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java +++ /dev/null @@ -1,107 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.util.Arrays; -import java.util.Collection; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Rule; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -@RunWith(Parameterized.class) -public abstract class AbstractHttpClientServerTest -{ - @Parameterized.Parameters - public static Collection<SslContextFactory[]> parameters() - { - return Arrays.asList(new SslContextFactory[]{null}, new SslContextFactory[]{new SslContextFactory()}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - - protected SslContextFactory sslContextFactory; - protected String scheme; - protected Server server; - protected ServerConnector connector; - protected SPDYClient.Factory factory; - protected HttpClient client; - - public AbstractHttpClientServerTest(SslContextFactory sslContextFactory) - { - this.sslContextFactory = sslContextFactory; - this.scheme = (sslContextFactory == null ? HttpScheme.HTTP : HttpScheme.HTTPS).asString(); - } - - public void start(Handler handler) throws Exception - { - short version = SPDY.V3; - - HTTPSPDYServerConnectionFactory httpSPDY = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration()); - if (sslContextFactory != null) - { - sslContextFactory.setEndpointIdentificationAlgorithm(""); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - } - - server = new Server(); - connector = new ServerConnector(server, AbstractConnectionFactory.getFactories(sslContextFactory, httpSPDY)); - server.addConnector(connector); - server.setHandler(handler); - server.start(); - - QueuedThreadPool executor = new QueuedThreadPool(); - executor.setName(executor.getName() + "-client"); - - factory = new SPDYClient.Factory(executor); - factory.start(); - client = new HttpClient(new HttpClientTransportOverSPDY(factory.newSPDYClient(version)), sslContextFactory); - client.setExecutor(executor); - client.start(); - } - - @After - public void dispose() throws Exception - { - if (client != null) - client.stop(); - if (factory != null) - factory.stop(); - if (server != null) - server.stop(); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java deleted file mode 100644 index 34743bf61c..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; - -public class EmptyServerHandler extends AbstractHandler -{ - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java deleted file mode 100644 index 7753ae4536..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java +++ /dev/null @@ -1,262 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpClientTransport; -import org.eclipse.jetty.client.HttpDestination; -import org.eclipse.jetty.client.Origin; -import org.eclipse.jetty.client.ProxyConfiguration; -import org.eclipse.jetty.client.api.Connection; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory; -import org.eclipse.jetty.spdy.server.http.PushStrategy; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -public class HttpClientCustomProxyTest -{ - public static final byte[] CAFE_BABE = new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}; - - private Server server; - private ServerConnector connector; - private SPDYClient.Factory factory; - private HttpClient httpClient; - - public void prepare(Handler handler) throws Exception - { - server = new Server(); - connector = new ServerConnector(server, new CAFEBABEServerConnectionFactory(new HTTPSPDYServerConnectionFactory(SPDY.V3, new HttpConfiguration(), new PushStrategy.None()))); - server.addConnector(connector); - server.setHandler(handler); - server.start(); - - QueuedThreadPool executor = new QueuedThreadPool(); - executor.setName(executor.getName() + "-client"); - - factory = new SPDYClient.Factory(executor); - factory.start(); - - httpClient = new HttpClient(new HttpClientTransportOverSPDY(factory.newSPDYClient(SPDY.V3)), null); - httpClient.setExecutor(executor); - httpClient.start(); - } - - @After - public void dispose() throws Exception - { - if (httpClient != null) - httpClient.stop(); - if (factory != null) - factory.stop(); - if (server != null) - server.stop(); - } - - @Test - public void testCustomProxy() throws Exception - { - final String serverHost = "server"; - final int status = HttpStatus.NO_CONTENT_204; - prepare(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - if (!URI.create(baseRequest.getUri().toString()).isAbsolute()) - response.setStatus(HttpServletResponse.SC_USE_PROXY); - else if (serverHost.equals(request.getServerName())) - response.setStatus(status); - else - response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE); - } - }); - - // Setup the custom proxy - int proxyPort = connector.getLocalPort(); - int serverPort = proxyPort + 1; // Any port will do for these tests - just not the same as the proxy - httpClient.getProxyConfiguration().getProxies().add(new CAFEBABEProxy(new Origin.Address("localhost", proxyPort), false)); - - ContentResponse response = httpClient.newRequest(serverHost, serverPort) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertEquals(status, response.getStatus()); - } - - private class CAFEBABEProxy extends ProxyConfiguration.Proxy - { - private CAFEBABEProxy(Origin.Address address, boolean secure) - { - super(address, secure); - } - - @Override - public ClientConnectionFactory newClientConnectionFactory(ClientConnectionFactory connectionFactory) - { - return new CAFEBABEClientConnectionFactory(connectionFactory); - } - } - - private static class CAFEBABEClientConnectionFactory implements ClientConnectionFactory - { - private final ClientConnectionFactory connectionFactory; - - private CAFEBABEClientConnectionFactory(ClientConnectionFactory connectionFactory) - { - this.connectionFactory = connectionFactory; - } - - @Override - public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException - { - HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY); - Executor executor = destination.getHttpClient().getExecutor(); - return new CAFEBABEConnection(endPoint, executor, connectionFactory, context); - } - } - - private static class CAFEBABEConnection extends AbstractConnection - { - private final ClientConnectionFactory connectionFactory; - private final Map<String, Object> context; - - public CAFEBABEConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, Map<String, Object> context) - { - super(endPoint, executor); - this.connectionFactory = connectionFactory; - this.context = context; - } - - @Override - public void onOpen() - { - super.onOpen(); - fillInterested(); - getEndPoint().write(new Callback.Adapter(), ByteBuffer.wrap(CAFE_BABE)); - } - - @Override - public void onFillable() - { - try - { - ByteBuffer buffer = BufferUtil.allocate(4); - int filled = getEndPoint().fill(buffer); - Assert.assertEquals(4, filled); - Assert.assertArrayEquals(CAFE_BABE, buffer.array()); - - // We are good, upgrade the connection - ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(getEndPoint(), context)); - } - catch (Throwable x) - { - close(); - @SuppressWarnings("unchecked") - Promise<Connection> promise = (Promise<Connection>)context.get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY); - promise.failed(x); - } - } - } - - private class CAFEBABEServerConnectionFactory extends AbstractConnectionFactory - { - private final org.eclipse.jetty.server.ConnectionFactory connectionFactory; - - private CAFEBABEServerConnectionFactory(org.eclipse.jetty.server.ConnectionFactory connectionFactory) - { - super("cafebabe"); - this.connectionFactory = connectionFactory; - } - - @Override - public org.eclipse.jetty.io.Connection newConnection(Connector connector, EndPoint endPoint) - { - return new CAFEBABEServerConnection(connector, endPoint, connectionFactory); - } - } - - private class CAFEBABEServerConnection extends AbstractConnection - { - private final org.eclipse.jetty.server.ConnectionFactory connectionFactory; - - public CAFEBABEServerConnection(Connector connector, EndPoint endPoint, org.eclipse.jetty.server.ConnectionFactory connectionFactory) - { - super(endPoint, connector.getExecutor()); - this.connectionFactory = connectionFactory; - } - - @Override - public void onOpen() - { - super.onOpen(); - fillInterested(); - } - - @Override - public void onFillable() - { - try - { - ByteBuffer buffer = BufferUtil.allocate(4); - int filled = getEndPoint().fill(buffer); - Assert.assertEquals(4, filled); - Assert.assertArrayEquals(CAFE_BABE, buffer.array()); - getEndPoint().write(new Callback.Adapter(), buffer); - - // We are good, upgrade the connection - ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(connector, getEndPoint())); - } - catch (Throwable x) - { - close(); - } - } - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java deleted file mode 100644 index 2fcf1e9555..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java +++ /dev/null @@ -1,467 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.client.http; - -import java.io.IOException; -import java.net.URI; -import java.net.URLEncoder; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPOutputStream; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.api.Response; -import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.client.util.BytesContentProvider; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.toolchain.test.annotation.Slow; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Test; - -public class HttpClientTest extends AbstractHttpClientServerTest -{ - public HttpClientTest(SslContextFactory sslContextFactory) - { - super(sslContextFactory); - } - - @Test - public void test_GET_ResponseWithoutContent() throws Exception - { - start(new EmptyServerHandler()); - - Response response = client.GET(scheme + "://localhost:" + connector.getLocalPort()); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - } - - @Test - public void test_GET_ResponseWithContent() throws Exception - { - final byte[] data = new byte[]{0, 1, 2, 3, 4, 5, 6, 7}; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - response.getOutputStream().write(data); - baseRequest.setHandled(true); - } - }); - - ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort()); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - byte[] content = response.getContent(); - Assert.assertArrayEquals(data, content); - } - - @Test - public void test_GET_WithParameters_ResponseWithContent() throws Exception - { - final String paramName1 = "a"; - final String paramName2 = "b"; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - response.setCharacterEncoding("UTF-8"); - ServletOutputStream output = response.getOutputStream(); - String paramValue1 = request.getParameter(paramName1); - output.write(paramValue1.getBytes("UTF-8")); - String paramValue2 = request.getParameter(paramName2); - Assert.assertEquals("", paramValue2); - output.write("empty".getBytes("UTF-8")); - baseRequest.setHandled(true); - } - }); - - String value1 = "\u20AC"; - String paramValue1 = URLEncoder.encode(value1, "UTF-8"); - String query = paramName1 + "=" + paramValue1 + "&" + paramName2; - ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - String content = new String(response.getContent(), "UTF-8"); - Assert.assertEquals(value1 + "empty", content); - } - - @Test - public void test_GET_WithParametersMultiValued_ResponseWithContent() throws Exception - { - final String paramName1 = "a"; - final String paramName2 = "b"; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - response.setCharacterEncoding("UTF-8"); - ServletOutputStream output = response.getOutputStream(); - String[] paramValues1 = request.getParameterValues(paramName1); - for (String paramValue : paramValues1) - output.write(paramValue.getBytes("UTF-8")); - String paramValue2 = request.getParameter(paramName2); - output.write(paramValue2.getBytes("UTF-8")); - baseRequest.setHandled(true); - } - }); - - String value11 = "\u20AC"; - String value12 = "\u20AA"; - String value2 = "&"; - String paramValue11 = URLEncoder.encode(value11, "UTF-8"); - String paramValue12 = URLEncoder.encode(value12, "UTF-8"); - String paramValue2 = URLEncoder.encode(value2, "UTF-8"); - String query = paramName1 + "=" + paramValue11 + "&" + paramName1 + "=" + paramValue12 + "&" + paramName2 + "=" + paramValue2; - ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - String content = new String(response.getContent(), "UTF-8"); - Assert.assertEquals(value11 + value12 + value2, content); - } - - @Test - public void test_POST_WithParameters() throws Exception - { - final String paramName = "a"; - final String paramValue = "\u20AC"; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - String value = request.getParameter(paramName); - if (paramValue.equals(value)) - { - response.setCharacterEncoding("UTF-8"); - response.setContentType("text/plain"); - response.getOutputStream().print(value); - } - } - }); - - ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .param(paramName, paramValue) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8")); - } - - @Test - public void test_PUT_WithParameters() throws Exception - { - final String paramName = "a"; - final String paramValue = "\u20AC"; - final String encodedParamValue = URLEncoder.encode(paramValue, "UTF-8"); - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - String value = request.getParameter(paramName); - if (paramValue.equals(value)) - { - response.setCharacterEncoding("UTF-8"); - response.setContentType("text/plain"); - response.getOutputStream().print(value); - } - } - }); - - URI uri = URI.create(scheme + "://localhost:" + connector.getLocalPort() + "/path?" + paramName + "=" + encodedParamValue); - ContentResponse response = client.newRequest(uri) - .method(HttpMethod.PUT) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8")); - } - - @Test - public void test_POST_WithParameters_WithContent() throws Exception - { - final byte[] content = {0, 1, 2, 3}; - final String paramName = "a"; - final String paramValue = "\u20AC"; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - String value = request.getParameter(paramName); - if (paramValue.equals(value)) - { - response.setCharacterEncoding("UTF-8"); - response.setContentType("application/octet-stream"); - response.getOutputStream().write(content); - } - } - }); - - ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort() + "/?b=1") - .param(paramName, paramValue) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertArrayEquals(content, response.getContent()); - } - - @Test - public void test_POST_WithContent_NotifiesRequestContentListener() throws Exception - { - final byte[] content = {0, 1, 2, 3}; - start(new EmptyServerHandler()); - - ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .onRequestContent(new Request.ContentListener() - { - @Override - public void onContent(Request request, ByteBuffer buffer) - { - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - if (!Arrays.equals(content, bytes)) - request.abort(new Exception()); - } - }) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - } - - @Test - public void test_POST_WithContent_TracksProgress() throws Exception - { - start(new EmptyServerHandler()); - - final AtomicInteger progress = new AtomicInteger(); - ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .onRequestContent(new Request.ContentListener() - { - @Override - public void onContent(Request request, ByteBuffer buffer) - { - byte[] bytes = new byte[buffer.remaining()]; - Assert.assertEquals(1, bytes.length); - buffer.get(bytes); - Assert.assertEquals(bytes[0], progress.getAndIncrement()); - } - }) - .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4})) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(5, progress.get()); - } - - @Test - public void test_GZIP_ContentEncoding() throws Exception - { - final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - response.setHeader("Content-Encoding", "gzip"); - GZIPOutputStream gzipOutput = new GZIPOutputStream(response.getOutputStream()); - gzipOutput.write(data); - gzipOutput.finish(); - } - }); - - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertEquals(200, response.getStatus()); - Assert.assertArrayEquals(data, response.getContent()); - } - - @Slow - @Test - public void test_Request_IdleTimeout() throws Exception - { - final long idleTimeout = 1000; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - try - { - baseRequest.setHandled(true); - TimeUnit.MILLISECONDS.sleep(2 * idleTimeout); - } - catch (InterruptedException x) - { - throw new ServletException(x); - } - } - }); - - final String host = "localhost"; - final int port = connector.getLocalPort(); - try - { - client.newRequest(host, port) - .scheme(scheme) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); - Assert.fail(); - } - catch (ExecutionException expected) - { - Assert.assertTrue(expected.getCause() instanceof TimeoutException); - } - - // Make another request without specifying the idle timeout, should not fail - ContentResponse response = client.newRequest(host, port) - .scheme(scheme) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - } - - @Test - public void testSendToIPv6Address() throws Exception - { - start(new EmptyServerHandler()); - - ContentResponse response = client.newRequest("[::1]", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - } - - @Test - public void test_HEAD_With_ResponseContentLength() throws Exception - { - final int length = 1024; - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - response.getOutputStream().write(new byte[length]); - } - }); - - // HEAD requests receive a Content-Length header, but do not - // receive the content so they must handle this case properly - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .method(HttpMethod.HEAD) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(0, response.getContent().length); - - // Perform a normal GET request to be sure the content is now read - response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); - - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(length, response.getContent().length); - } - - @Test - public void testLongPollIsAbortedWhenClientIsStopped() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - start(new AbstractHandler() - { - @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - request.startAsync(); - latch.countDown(); - } - }); - - final CountDownLatch completeLatch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .send(new Response.CompleteListener() - { - @Override - public void onComplete(Result result) - { - if (result.isFailed()) - completeLatch.countDown(); - } - }); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - - // Stop the client, the complete listener must be invoked. - client.stop(); - - Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties deleted file mode 100644 index 8163013d57..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.LEVEL=DEBUG -#org.eclipse.jetty.client.LEVEL=DEBUG -#org.eclipse.jetty.spdy.LEVEL=DEBUG diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/keystore.jks b/jetty-spdy/spdy-http-client-transport/src/test/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/truststore.jks b/jetty-spdy/spdy-http-client-transport/src/test/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-http-client-transport/src/test/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml deleted file mode 100644 index 769206b738..0000000000 --- a/jetty-spdy/spdy-http-common/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-http-common</artifactId> - <name>Jetty :: SPDY :: HTTP Common</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.http.common</bundle-symbolic-name> - </properties> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.http;version="9.1"</Export-Package> - <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-core</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java b/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java deleted file mode 100644 index 2959d6e09a..0000000000 --- a/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.http; - -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jetty.spdy.api.SPDY; - -/** - * <p>{@link HTTPSPDYHeader} defines the SPDY headers that are not also HTTP headers, - * such as <tt>method</tt>, <tt>version</tt>, etc. or that are treated differently - * by the SPDY protocol, such as <tt>host</tt>.</p> - */ -public enum HTTPSPDYHeader -{ - METHOD("method", ":method"), - URI("url", ":path"), - VERSION("version", ":version"), - SCHEME("scheme", ":scheme"), - HOST("host", ":host"), - STATUS("status", ":status"); - - public static HTTPSPDYHeader from(short version, String name) - { - switch (version) - { - case SPDY.V2: - return Names.v2Names.get(name); - case SPDY.V3: - return Names.v3Names.get(name); - default: - throw new IllegalStateException(); - } - } - - private final String v2Name; - private final String v3Name; - - private HTTPSPDYHeader(String v2Name, String v3Name) - { - this.v2Name = v2Name; - Names.v2Names.put(v2Name, this); - this.v3Name = v3Name; - Names.v3Names.put(v3Name, this); - } - - public String name(short version) - { - switch (version) - { - case SPDY.V2: - return v2Name; - case SPDY.V3: - return v3Name; - default: - throw new IllegalStateException(); - } - } - - private static class Names - { - private static final Map<String, HTTPSPDYHeader> v2Names = new HashMap<>(); - private static final Map<String, HTTPSPDYHeader> v3Names = new HashMap<>(); - } -} diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml deleted file mode 100644 index b20584099e..0000000000 --- a/jetty-spdy/spdy-http-server/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-http-server</artifactId> - <name>Jetty :: SPDY :: HTTP Server</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.http.server</bundle-symbolic-name> - </properties> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jars</id> - <goals> - <goal>jar</goal> - <goal>test-jar</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.server.http;version="9.1", - org.eclipse.jetty.spdy.server.proxy;version="9.1" - </Export-Package> - <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* - </Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-server</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${project.version}</version> - </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>jetty-servlets</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.npn</groupId> - <artifactId>npn-api</artifactId> - <version>${npn.api.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-continuation</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml deleted file mode 100644 index c525bd1797..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml +++ /dev/null @@ -1,158 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<!-- ============================================================= --> -<!-- Configure the Jetty Server instance with an ID "Server" --> -<!-- by adding a SPDY connector. --> -<!-- This configuration must be used in conjunction with jetty.xml --> -<!-- It should not be used with jetty-https.xml as this connector --> -<!-- can provide both HTTPS and SPDY connections --> -<!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Setup the SSL Context factory used to establish all TLS --> - <!-- Connections and session. --> - <!-- --> - <!-- Consult the javadoc of o.e.j.util.ssl.SslContextFactory --> - <!-- o.e.j.server.HttpConnectionFactory for all configuration --> - <!-- that may be set here. --> - <!-- =========================================================== --> - <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="KeyStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - </New> - - <!-- =========================================================== --> - <!-- Enables NPN debugging on System.err --> - <!-- =========================================================== - <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set> - --> - - <!-- =========================================================== --> - <!-- Create a TLS specific HttpConfiguration based on the --> - <!-- common HttpConfiguration defined in jetty.xml --> - <!-- Add a SecureRequestCustomizer to extract certificate and --> - <!-- session information --> - <!-- =========================================================== --> - <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Arg><Ref refid="httpConfig"/></Arg> - <Call name="addCustomizer"> - <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg> - </Call> - </New> - - <!-- =========================================================== --> - <!-- This is the upstream server connector. --> - <!-- It speaks non-SSL SPDY/3(HTTP) on port 9090. --> - <!-- =========================================================== --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <!-- SPDY/3 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="tlsHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="port">9090</Set> - </New> - </Arg> - </Call> - - <!-- =========================================================== --> - <!-- This ProxyEngine translates the incoming SPDY/x(HTTP) --> - <!-- requests to SPDY/2(HTTP) --> - <!-- =========================================================== --> - <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.server.proxy.SPDYProxyEngine"> - <Arg> - <New class="org.eclipse.jetty.spdy.client.SPDYClient$Factory"> - <Call name="start"/> - </New> - </Arg> - </New> - - <!-- =========================================================== --> - <!-- The ProxyEngineSelector receives SPDY/x(HTTP) requests --> - <!-- from proxy connectors below and is configured to process --> - <!-- requests for host "localhost". --> - <!-- Such requests are converted from SPDY/x(HTTP) to --> - <!-- SPDY/3(HTTP) by the configured ProxyEngine and forwarded --> - <!-- to 127.0.0.1:9090, where they are served by the upstream --> - <!-- server above. --> - <!-- =========================================================== --> - <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector"> - <Call name="putProxyEngine"> - <Arg>spdy/3</Arg> - <Arg> - <Ref refid="spdyProxyEngine"/> - </Arg> - </Call> - <Set name="proxyServerInfos"> - <Map> - <Entry> - <Item>localhost</Item> - <Item> - <New class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector$ProxyServerInfo"> - <Arg type="String">spdy/3</Arg> - <Arg>127.0.0.1</Arg> - <Arg type="int">9090</Arg> - </New> - </Item> - </Entry> - </Map> - </Set> - </New> - - <!-- =========================================================== --> - <!-- These are the reverse proxy connectors accepting requests --> - <!-- from clients. --> - <!-- They accept non-SSL (on port 8080) and SSL (on port 8443) --> - <!-- HTTP, SPDY/2(HTTP) and SPDY/3(HTTP). --> - <!-- Non-SPDY HTTP requests are converted to SPDY internally --> - <!-- and passed to the ProxyEngine above. --> - <!-- =========================================================== --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector"> - <Arg> - <Ref refid="Server"/> - </Arg> - <Arg> - <Ref refid="proxyEngineSelector"/> - </Arg> - <Set name="Port">8080</Set> - </New> - </Arg> - </Call> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector"> - <Arg> - <Ref refid="Server"/> - </Arg> - <Arg> - <Ref refid="sslContextFactory"/> - </Arg> - <Arg> - <Ref refid="proxyEngineSelector"/> - </Arg> - <Set name="Port">8443</Set> - </New> - </Arg> - </Call> - -</Configure> 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 deleted file mode 100644 index b094d7ce85..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml +++ /dev/null @@ -1,139 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<!-- ============================================================= --> -<!-- Configure a SPDY connector. --> -<!-- This configuration must be used in conjunction with jetty.xml --> -<!-- and jetty-ssl.xml --> -<!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Create a push strategy which can be used by reference by --> - <!-- individual connection factories below. --> - <!-- --> - <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy --> - <!-- for all configuration that may be set here. --> - <!-- =========================================================== --> - <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> - <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the - user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> - <!-- - <Set name="UserAgentBlacklist"> - <Array type="String"> - <Item>.*(?i)firefox/14.*</Item> - <Item>.*(?i)firefox/15.*</Item> - <Item>.*(?i)firefox/16.*</Item> - </Array> - </Set> - --> - - <!-- Uncomment to override default file extensions to push --> - <!-- - <Set name="PushRegexps"> - <Array type="String"> - <Item>.*\.css</Item> - <Item>.*\.js</Item> - <Item>.*\.png</Item> - <Item>.*\.jpg</Item> - <Item>.*\.gif</Item> - </Array> - </Set> - --> - <Set name="referrerPushPeriod">5000</Set> - <Set name="maxAssociatedResources">32</Set> - </New> - - <!-- =========================================================== --> - <!-- Add a SPDY/HTTPS Connector. --> - <!-- Configure an o.e.j.server.ServerConnector with connection --> - <!-- factories for TLS (aka SSL), ProtoNego, SPDY and HTTP to --> - <!-- provide a connector that can accept HTTPS or SPDY --> - <!-- connections. --> - <!-- --> - <!-- All accepted TLS connections are initially wired to a --> - <!-- Protonego connection, which attempts to use a TLS extension --> - <!-- to negotiation the protocol. If it is not supported by --> - <!-- the client, then the connection is replaced by a HTTP --> - <!-- connection. If a specific protocol version (eg spdy/3) is --> - <!-- negotiated, then the appropriate connection factory --> - <!-- is used to create a connection to replace the connection --> - <!-- --> - <!-- The final result is a SPDY or HTTP connection wired behind --> - <!-- a TLS (aka SSL) connection. --> - <!-- --> - <!-- Consult the javadoc of o.e.j.server.ServerConnector and the --> - <!-- specific connection factory types for all configuration --> - <!-- that may be set here. --> - <!-- =========================================================== --> - <Call id="spdyConnector" name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - - <!-- SSL Connection factory with Protonego as next protocol --> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next"><Property name="protonego"/></Arg> - <Arg name="sslContextFactory"> - <Ref refid="sslContextFactory"/> - </Arg> - </New> - </Item> - - <!-- NPN Connection factory with HTTP as default protocol --> - <Item> - <Ref refid="protonego"/> - </Item> - - <!-- SPDY/3 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> - <!-- Uncomment to enable ReferrerPushStrategy --> - <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>--> - </New> - </Item> - - <!-- SPDY/2 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">2</Arg> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> - </New> - </Item> - - <!-- HTTP Connection factory --> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - - <Set name="host"><Property name="jetty.host"/></Set> - <Set name="port"><Property name="spdy.port" default="443"/></Set> - <Set name="idleTimeout"><Property name="spdy.timeout" default="30000"/></Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml deleted file mode 100644 index 6e30f39ed6..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<Configure id="protonego" class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - <Item>spdy/3</Item> - <Item>spdy/2</Item> - <Item>http/1.1</Item> - </Array> - </Arg> - - <Set name="defaultProtocol">http/1.1</Set> - - <!-- =========================================================== --> - <!-- Enables NPN debugging on System.err --> - <!-- =========================================================== - <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set> - --> - -</Configure> diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod deleted file mode 100644 index 007570b675..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod deleted file mode 100644 index 007570b675..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod deleted file mode 100644 index 868a7a77fc..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod deleted file mode 100644 index 868a7a77fc..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod deleted file mode 100644 index 20c1db27bd..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod deleted file mode 100644 index 20c1db27bd..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod deleted file mode 100644 index 20c1db27bd..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod deleted file mode 100644 index 1645a52dba..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.4.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod deleted file mode 100644 index 73bc09007e..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod deleted file mode 100644 index 73bc09007e..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod deleted file mode 100644 index 73bc09007e..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod deleted file mode 100644 index 73bc09007e..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod deleted file mode 100644 index 465e6f034b..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod deleted file mode 100644 index 465e6f034b..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod deleted file mode 100644 index 465e6f034b..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod deleted file mode 100644 index 5f8704d68a..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod deleted file mode 100644 index 5f8704d68a..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod deleted file mode 100644 index 5f8704d68a..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod deleted file mode 100644 index 5f8704d68a..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod deleted file mode 100644 index 851aca8727..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod deleted file mode 100644 index 851aca8727..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod deleted file mode 100644 index a5fac1140c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod deleted file mode 100644 index a5fac1140c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod deleted file mode 100644 index a5fac1140c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod deleted file mode 100644 index 2cce5fab7c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.11.v20150415/npn-boot-1.1.11.v20150415.jar|lib/npn/npn-boot-1.1.11.v20150415.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.11.v20150415.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod deleted file mode 100644 index 1a2c71d721..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod +++ /dev/null @@ -1,37 +0,0 @@ -# NPN is provided via a -Xbootclasspath that modifies the secure connections -# in java to support the NPN layer needed for SPDY. -# -# This modification has a tight dependency on specific updates of Java 1.7. -# (No support for Java 8 exists for npn / npn-boot, use alpn instead) -# -# The npn module will use an appropriate npn-boot jar for your specific -# version of Java. -# -# IMPORTANT: Versions of Java that exist after this module was created are -# not guaranteed to work with existing npn-boot jars, and might -# need a new npn-boot to be created / tested / deployed by the -# Jetty project in order to provide support for these future -# Java versions. -# -# All versions of npn-boot can be found at -# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/ - - -[name] -protonego-impl - -[depend] -protonego-impl/npn-${java.version} - -[xml] -etc/protonego-npn.xml - -[files] -lib/ -lib/npn/ - -[license] -NPN is a hosted at github under the GPL v2 with ClassPath Exception. -NPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package. -http://github.com/jetty-project/jetty-npn -http://openjdk.java.net/legal/gplv2+ce.html diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod deleted file mode 100644 index cf79dfa0f2..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod +++ /dev/null @@ -1,26 +0,0 @@ -# -# SPDY Support Module -# - -[depend] -ssl -protonego - -[lib] -lib/spdy/*.jar - -[xml] -etc/jetty-ssl.xml -etc/jetty-spdy.xml - -[ini-template] -## SPDY Configuration - -# Port for SPDY connections -spdy.port=8443 - -# SPDY idle timeout in milliseconds -spdy.timeout=30000 - -# Initial Window Size for SPDY -#spdy.initialWindowSize=65536 diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java deleted file mode 100644 index 34eef7c66e..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java +++ /dev/null @@ -1,167 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.annotation.Name; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory implements HttpConfiguration.ConnectionFactory -{ - private static final String CHANNEL_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.HTTPChannelOverSPDY"; - private static final Logger LOG = Log.getLogger(HTTPSPDYServerConnectionFactory.class); - - private final PushStrategy pushStrategy; - private final HttpConfiguration httpConfiguration; - - public HTTPSPDYServerConnectionFactory( - @Name("version") int version, - @Name("config") HttpConfiguration config) - { - this(version,config,new PushStrategy.None()); - } - - public HTTPSPDYServerConnectionFactory( - @Name("version") int version, - @Name("config") HttpConfiguration config, - @Name("pushStrategy") PushStrategy pushStrategy) - { - super(version); - this.pushStrategy = pushStrategy; - httpConfiguration = config; - addBean(httpConfiguration); - } - - @Override - public HttpConfiguration getHttpConfiguration() - { - return httpConfiguration; - } - - @Override - protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint) - { - return new HTTPServerFrameListener(connector,endPoint); - } - - private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener - { - private final Connector connector; - private final EndPoint endPoint; - - public HTTPServerFrameListener(Connector connector,EndPoint endPoint) - { - this.endPoint = endPoint; - this.connector=connector; - } - - @Override - public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo) - { - // Every time we have a SYN, it maps to a HTTP request. - // We can have multiple concurrent SYNs on the same connection, - // and this is very different from HTTP, where only one request - // can arrive on the same connection, so we need to create an - // HttpChannel for each SYN in order to run concurrently. - - if (LOG.isDebugEnabled()) - LOG.debug("Received {} on {}", synInfo, stream); - - Fields headers = synInfo.getHeaders(); - // According to SPDY/3 spec section 3.2.1 user-agents MUST support gzip compression. Firefox omits the - // accept-encoding header as it is redundant to negotiate gzip compression support with the server, - // if clients have to accept it. - // So we inject the accept-encoding header here, even if not set by the client. This will enforce SPDY - // clients to follow the spec and enable gzip compression if GzipFilter or the like is enabled. - if (!(headers.get("accept-encoding") != null && headers.get("accept-encoding").getValue().contains - ("gzip"))) - headers.add("accept-encoding", "gzip"); - HttpTransportOverSPDY transport = new HttpTransportOverSPDY(connector, httpConfiguration, endPoint, - pushStrategy, stream, headers); - HttpInputOverSPDY input = new HttpInputOverSPDY(); - HttpChannelOverSPDY channel = new HttpChannelOverSPDY(connector, httpConfiguration, endPoint, transport, input, stream); - stream.setAttribute(CHANNEL_ATTRIBUTE, channel); - - channel.requestStart(headers, synInfo.isClose()); - - if (headers.isEmpty()) - { - // If the SYN has no headers, they may come later in a HEADERS frame - return this; - } - else - { - if (synInfo.isClose()) - return null; - else - return this; - } - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Do nothing, servers cannot get replies - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("Received {} on {}", headersInfo, stream); - HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE); - channel.requestHeaders(headersInfo.getHeaders(), headersInfo.isClose()); - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return null; - } - - @Override - public void onData(Stream stream, final DataInfo dataInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("Received {} on {}", dataInfo, stream); - HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE); - channel.requestContent(dataInfo, dataInfo.isClose()); - } - - @Override - public void onFailure(Stream stream, Throwable x) - { - LOG.debug(x); - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java deleted file mode 100644 index 25d1e39797..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.util.Collections; -import java.util.Map; - -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class HTTPSPDYServerConnector extends ServerConnector -{ - public HTTPSPDYServerConnector(Server server) - { - this(server, Collections.<Short, PushStrategy>emptyMap()); - } - - public HTTPSPDYServerConnector(Server server, SslContextFactory sslContextFactory) - { - this(server, sslContextFactory, Collections.<Short, PushStrategy>emptyMap()); - } - - public HTTPSPDYServerConnector(Server server, Map<Short, PushStrategy> pushStrategies) - { - this(server, null, pushStrategies); - } - - public HTTPSPDYServerConnector(Server server, SslContextFactory sslContextFactory, Map<Short, PushStrategy> pushStrategies) - { - this(server, new HttpConfiguration(), sslContextFactory, pushStrategies); - } - - public HTTPSPDYServerConnector(Server server, short version, HttpConfiguration httpConfiguration, PushStrategy push) - { - super(server, new HTTPSPDYServerConnectionFactory(version, httpConfiguration, push)); - } - - public HTTPSPDYServerConnector(Server server, HttpConfiguration config, SslContextFactory sslContextFactory, Map<Short, PushStrategy> pushStrategies) - { - super(server, AbstractConnectionFactory.getFactories(sslContextFactory, - sslContextFactory == null - ? new ConnectionFactory[]{new HttpConnectionFactory(config)} - : new ConnectionFactory[]{new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"), - new HttpConnectionFactory(config), - new HTTPSPDYServerConnectionFactory(SPDY.V3, config, getPushStrategy(SPDY.V3, pushStrategies)), - new HTTPSPDYServerConnectionFactory(SPDY.V2, config, getPushStrategy(SPDY.V2, pushStrategies))})); - NPNServerConnectionFactory npnConnectionFactory = getConnectionFactory(NPNServerConnectionFactory.class); - if (npnConnectionFactory != null) - npnConnectionFactory.setDefaultProtocol("http/1.1"); - } - - private static PushStrategy getPushStrategy(short version, Map<Short, PushStrategy> pushStrategies) - { - PushStrategy pushStrategy = pushStrategies.get(version); - if (pushStrategy == null) - pushStrategy = new PushStrategy.None(); - return pushStrategy; - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java deleted file mode 100644 index f336f4f47c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ /dev/null @@ -1,246 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpChannel; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpTransport; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class HttpChannelOverSPDY extends HttpChannel<DataInfo> -{ - private static final Logger LOG = Log.getLogger(HttpChannelOverSPDY.class); - - private final Stream stream; - private boolean dispatched; // Guarded by synchronization on tasks - private boolean redispatch; // Guarded by synchronization on tasks - private boolean headersComplete; - - public HttpChannelOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInputOverSPDY input, Stream stream) - { - super(connector, configuration, endPoint, transport, input); - this.stream = stream; - } - - @Override - public long getIdleTimeout() - { - return stream.getIdleTimeout(); - } - - @Override - public boolean headerComplete() - { - headersComplete = true; - return super.headerComplete(); - } - - private void dispatch() - { - synchronized (this) - { - if (dispatched) - redispatch=true; - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Dispatch {}", this); - dispatched=true; - execute(this); - } - } - } - - @Override - public void run() - { - boolean execute=true; - - while(execute) - { - try - { - if (LOG.isDebugEnabled()) - LOG.debug("Executing {}",this); - super.run(); - } - finally - { - if (LOG.isDebugEnabled()) - LOG.debug("Completing {}", this); - synchronized (this) - { - dispatched = redispatch; - redispatch=false; - execute=dispatched; - } - } - } - } - - - public void requestStart(final Fields headers, final boolean endRequest) - { - if (!headers.isEmpty()) - requestHeaders(headers, endRequest); - } - - public void requestHeaders(Fields headers, boolean endRequest) - { - boolean proceed = performBeginRequest(headers); - if (!proceed) - return; - - performHeaders(headers); - - if (endRequest) - { - boolean dispatch = headerComplete(); - if (messageComplete()) - dispatch=true; - if (dispatch) - dispatch(); - } - } - - public void requestContent(final DataInfo dataInfo, boolean endRequest) - { - boolean dispatch=false; - if (!headersComplete && headerComplete()) - dispatch=true; - - if (LOG.isDebugEnabled()) - LOG.debug("HTTP > {} bytes of content", dataInfo.length()); - - // We need to copy the dataInfo since we do not know when its bytes - // will be consumed. When the copy is consumed, we consume also the - // original, so the implementation can send a window update. - ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false); - ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - dataInfo.consume(delta); - } - }; - if (LOG.isDebugEnabled()) - LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo); - - if (content(copyDataInfo)) - dispatch=true; - - if (endRequest && messageComplete()) - dispatch=true; - - if (dispatch) - dispatch(); - } - - @Override - public boolean messageComplete() - { - super.messageComplete(); - return false; - } - - private boolean performBeginRequest(Fields headers) - { - short version = stream.getSession().getVersion(); - Fields.Field methodHeader = headers.get(HTTPSPDYHeader.METHOD.name(version)); - Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version)); - Fields.Field versionHeader = headers.get(HTTPSPDYHeader.VERSION.name(version)); - - if (methodHeader == null || uriHeader == null || versionHeader == null) - { - badMessage(400, "Missing required request line elements"); - return false; - } - - HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue()); - HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue()); - - // TODO should handle URI as byte buffer as some bad clients send WRONG encodings in query string - // that we have to deal with - ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue()); - - if (LOG.isDebugEnabled()) - LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); - startRequest(httpMethod, httpMethod.asString(), uri, httpVersion); - - Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); - if (schemeHeader != null) - getRequest().setScheme(schemeHeader.getValue()); - return true; - } - - private void performHeaders(Fields headers) - { - for (Fields.Field header : headers) - { - String name = header.getName(); - - // Skip special SPDY headers, unless it's the "host" header - HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(stream.getSession().getVersion(), name); - if (specialHeader != null) - { - if (specialHeader == HTTPSPDYHeader.HOST) - name = "host"; - else - continue; - } - - switch (name) - { - case "connection": - case "keep-alive": - case "proxy-connection": - case "transfer-encoding": - { - // Spec says to ignore these headers - continue; - } - default: - { - // Spec says headers must be single valued - String value = header.getValue(); - if (LOG.isDebugEnabled()) - LOG.debug("HTTP > {}: {}", name, value); - parsedHeader(new HttpField(name,value)); - break; - } - } - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java deleted file mode 100644 index 08bb592d3a..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java +++ /dev/null @@ -1,49 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import org.eclipse.jetty.server.QueuedHttpInput; -import org.eclipse.jetty.spdy.api.DataInfo; - -public class HttpInputOverSPDY extends QueuedHttpInput<DataInfo> -{ - @Override - protected int remaining(DataInfo item) - { - return item.available(); - } - - @Override - protected int get(DataInfo item, byte[] buffer, int offset, int length) - { - return item.readInto(buffer, offset, length); - } - - @Override - protected void consume(DataInfo item, int length) - { - item.consume(length); - } - - @Override - protected void onContentConsumed(DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - } -} 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 deleted file mode 100644 index aa46cd3f42..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ /dev/null @@ -1,423 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.nio.ByteBuffer; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpTransport; -import org.eclipse.jetty.spdy.StreamException; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.ConcurrentArrayQueue; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class HttpTransportOverSPDY implements HttpTransport -{ - private static final Logger LOG = Log.getLogger(HttpTransportOverSPDY.class); - - private final Connector connector; - private final HttpConfiguration configuration; - private final EndPoint endPoint; - private final PushStrategy pushStrategy; - private final Stream stream; - private final short version; - private final Fields requestHeaders; - private final AtomicBoolean committed = new AtomicBoolean(); - - public HttpTransportOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, PushStrategy pushStrategy, Stream stream, Fields requestHeaders) - { - this.connector = connector; - this.configuration = configuration; - this.endPoint = endPoint; - this.pushStrategy = pushStrategy == null ? new PushStrategy.None() : pushStrategy; - this.stream = stream; - this.requestHeaders = requestHeaders; - Session session = stream.getSession(); - this.version = session.getVersion(); - } - - protected Stream getStream() - { - return stream; - } - - protected Fields getRequestHeaders() - { - return requestHeaders; - } - - - @Override - public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) - { - // TODO can this be more efficient? - send(null, responseBodyContent, lastContent, callback); - } - - @Override - public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, final Callback callback) - { - if (LOG.isDebugEnabled()) - LOG.debug("Sending {} {} {} {} last={}", this, stream, info, BufferUtil.toDetailString(content), lastContent); - - if (stream.isClosed() || stream.isReset()) - { - EofException exception = new EofException("stream closed"); - callback.failed(exception); - return; - } - - // info==null content==null lastContent==false should not happen - // info==null content==null lastContent==true signals no more content - complete - // info==null content!=null lastContent==false send data on committed response - // info==null content!=null lastContent==true send last data on committed response - complete - // info!=null content==null lastContent==false reply, commit - // info!=null content==null lastContent==true reply, commit and complete - // info!=null content!=null lastContent==false reply, commit with content - // info!=null content!=null lastContent==true reply, commit with content and complete - - boolean isHeadRequest = HttpMethod.HEAD.name().equalsIgnoreCase(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).getValue()); - boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest; - boolean close = !hasContent && lastContent; - - if (info != null) - { - if (!committed.compareAndSet(false, true)) - { - StreamException exception = new StreamException(stream.getId(), StreamStatus.PROTOCOL_ERROR, - "Stream already committed!"); - callback.failed(exception); - if (LOG.isDebugEnabled()) - LOG.debug("Committed response twice.", exception); - return; - } - sendReply(info, !hasContent ? callback : new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - callback.failed(x); - } - }, close); - } - - // Do we have some content to send as well - if (hasContent) - { - // send the data and let it call the callback - if (LOG.isDebugEnabled()) - LOG.debug("Send content: {} on stream: {} lastContent={}", BufferUtil.toDetailString(content), stream, - lastContent); - stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS, content, lastContent - ), callback); - } - // else do we need to close - else if (lastContent && info == null) - { - // send empty data to close and let the send call the callback - if (LOG.isDebugEnabled()) - LOG.debug("No content and lastContent=true. Sending empty ByteBuffer to close stream: {}", stream); - stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS, - BufferUtil.EMPTY_BUFFER, lastContent), callback); - } - else if (!lastContent && !hasContent && info == null) - throw new IllegalStateException("not lastContent, no content and no responseInfo!"); - - } - - private void sendReply(HttpGenerator.ResponseInfo info, Callback callback, boolean close) - { - Fields headers = new Fields(); - - HttpVersion httpVersion = HttpVersion.HTTP_1_1; - headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString()); - - int status = info.getStatus(); - StringBuilder httpStatus = new StringBuilder().append(status); - String reason = info.getReason(); - if (reason == null) - reason = HttpStatus.getMessage(status); - if (reason != null) - httpStatus.append(" ").append(reason); - headers.put(HTTPSPDYHeader.STATUS.name(version), httpStatus.toString()); - if (LOG.isDebugEnabled()) - LOG.debug("HTTP < {} {}", httpVersion, httpStatus); - - // TODO merge the two Field classes into one - HttpFields fields = info.getHttpFields(); - if (fields != null) - { - for (int i = 0; i < fields.size(); ++i) - { - HttpField field = fields.getField(i); - String name = field.getName(); - String value = field.getValue(); - headers.add(name, value); - if (LOG.isDebugEnabled()) - LOG.debug("HTTP < {}: {}", name, value); - } - } - - if (configuration.getSendServerVersion()) - headers.add(HttpHeader.SERVER.asString(), HttpConfiguration.SERVER_VERSION); - if (configuration.getSendXPoweredBy()) - headers.add(HttpHeader.X_POWERED_BY.asString(), HttpConfiguration.SERVER_VERSION); - - ReplyInfo reply = new ReplyInfo(headers, close); - if (LOG.isDebugEnabled()) - LOG.debug("Sending reply: {} on stream: {}", reply, stream); - reply(stream, reply, callback); - } - - @Override - public void completed() - { - if (LOG.isDebugEnabled()) - LOG.debug("Completed {}", this); - } - - private void reply(Stream stream, ReplyInfo replyInfo, Callback callback) - { - if (!stream.isUnidirectional()) - stream.reply(replyInfo, callback); - else - stream.headers(new HeadersInfo(replyInfo.getHeaders(), replyInfo.isClose()), callback); - - Fields responseHeaders = replyInfo.getHeaders(); - if (responseHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().startsWith("200") && !stream.isClosed()) - { - Set<String> pushResources = pushStrategy.apply(stream, requestHeaders, responseHeaders); - if (pushResources.size() > 0) - { - PushResourceCoordinator pushResourceCoordinator = new PushResourceCoordinator(pushResources); - pushResourceCoordinator.coordinate(); - } - } - } - - private static class PushHttpTransportOverSPDY extends HttpTransportOverSPDY - { - private final PushResourceCoordinator coordinator; - private final short version; - - private PushHttpTransportOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, - PushStrategy pushStrategy, Stream stream, Fields requestHeaders, - PushResourceCoordinator coordinator, short version) - { - super(connector, configuration, endPoint, pushStrategy, stream, requestHeaders); - this.coordinator = coordinator; - this.version = version; - } - - @Override - public void completed() - { - Stream stream = getStream(); - if (LOG.isDebugEnabled()) - LOG.debug("Resource pushed for {} on {}", - getRequestHeaders().get(HTTPSPDYHeader.URI.name(version)), stream); - coordinator.complete(); - } - } - - private class PushResourceCoordinator - { - private final Queue<PushResource> queue = new ConcurrentArrayQueue<>(); - private final Set<String> resources; - private AtomicBoolean active = new AtomicBoolean(false); - - private PushResourceCoordinator(Set<String> resources) - { - this.resources = resources; - } - - private void coordinate() - { - if (LOG.isDebugEnabled()) - LOG.debug("Pushing resources: {}", resources); - // Must send all push frames to the client at once before we - // return from this method and send the main resource data - for (String pushResource : resources) - pushResource(pushResource); - } - - private void sendNextResourceData() - { - if (LOG.isDebugEnabled()) - LOG.debug("{} sendNextResourceData active: {}", hashCode(), active.get()); - if (active.compareAndSet(false, true)) - { - PushResource resource = queue.poll(); - if (resource != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Opening new push channel for: {}", resource); - HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(resource.getPushStream(), resource.getPushRequestHeaders()); - pushChannel.requestStart(resource.getPushRequestHeaders(), true); - return; - } - - if (active.compareAndSet(true, false)) - { - if (queue.peek() != null) - sendNextResourceData(); - } - else - { - throw new IllegalStateException("active must not be false here! Concurrency bug!"); - } - } - } - - private HttpChannelOverSPDY newHttpChannelOverSPDY(Stream pushStream, Fields pushRequestHeaders) - { - HttpTransport transport = new PushHttpTransportOverSPDY(connector, configuration, endPoint, pushStrategy, - pushStream, pushRequestHeaders, this, version); - HttpInputOverSPDY input = new HttpInputOverSPDY(); - return new HttpChannelOverSPDY(connector, configuration, endPoint, transport, input, pushStream); - } - - private void pushResource(String pushResource) - { - Fields.Field scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)); - Fields.Field host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)); - Fields.Field uri = requestHeaders.get(HTTPSPDYHeader.URI.name(version)); - final Fields pushHeaders = createPushHeaders(scheme, host, pushResource); - final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource); - - stream.push(new PushInfo(pushHeaders, false), new Promise<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - if (LOG.isDebugEnabled()) - LOG.debug("Headers pushed for {} on {}", pushHeaders.get(HTTPSPDYHeader.URI.name(version)), pushStream); - queue.offer(new PushResource(pushStream, pushRequestHeaders)); - sendNextResourceData(); - } - - @Override - public void failed(Throwable x) - { - LOG.debug("Creating push stream failed.", x); - sendNextResourceData(); - } - }); - } - - private void complete() - { - if (!active.compareAndSet(true, false)) - throw new IllegalStateException(); - sendNextResourceData(); - } - - private Fields createRequestHeaders(Fields.Field scheme, Fields.Field host, Fields.Field uri, String pushResourcePath) - { - final Fields newRequestHeaders = new Fields(requestHeaders, false); - newRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - newRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - newRequestHeaders.put(scheme); - newRequestHeaders.put(host); - newRequestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath); - String referrer = scheme.getValue() + "://" + host.getValue() + uri.getValue(); - newRequestHeaders.put("referer", referrer); - newRequestHeaders.put("x-spdy-push", "true"); - return newRequestHeaders; - } - - private Fields createPushHeaders(Fields.Field scheme, Fields.Field host, String pushResourcePath) - { - final Fields pushHeaders = new Fields(); - if (version == SPDY.V2) - pushHeaders.put(HTTPSPDYHeader.URI.name(version), scheme.getValue() + "://" + host.getValue() + pushResourcePath); - else - { - pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath); - pushHeaders.put(scheme); - pushHeaders.put(host); - } - return pushHeaders; - } - } - - private static class PushResource - { - private final Stream pushStream; - private final Fields pushRequestHeaders; - - public PushResource(Stream pushStream, Fields pushRequestHeaders) - { - this.pushStream = pushStream; - this.pushRequestHeaders = pushRequestHeaders; - } - - public Stream getPushStream() - { - return pushStream; - } - - public Fields getPushRequestHeaders() - { - return pushRequestHeaders; - } - - @Override - public String toString() - { - return "PushResource{" + - "pushStream=" + pushStream + - ", pushRequestHeaders=" + pushRequestHeaders + - '}'; - } - } - - @Override - public void abort() - { - // TODO close the stream in a way to indicate an incomplete response? - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java deleted file mode 100644 index 2c553c95eb..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java +++ /dev/null @@ -1,55 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import java.util.Collections; -import java.util.Set; - -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.util.Fields; - -/** - * <p>{@link PushStrategy} encapsulates the decisions about performing - * SPDY pushes of secondary resources associated with a primary resource.</p> - */ -public interface PushStrategy -{ - /** - * <p>Applies the SPDY push logic for the primary resource.</p> - * - * @param stream the primary resource stream - * @param requestHeaders the primary resource request headers - * @param responseHeaders the primary resource response headers - * @return a list of secondary resource URIs to push - */ - public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders); - - /** - * An implementation that returns an empty list of secondary resources - */ - public static class None implements PushStrategy - { - @Override - public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders) - { - return Collections.emptySet(); - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java deleted file mode 100644 index f2beb38d4c..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java +++ /dev/null @@ -1,342 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.regex.Pattern; - -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.<p>A typical request for a main - * resource such as {@code index.html} is immediately followed by a number of requests for associated resources. - * Associated resource requests will have a {@code Referer} HTTP header that points to {@code index.html}, which is used - * to link the associated resource to the main resource.<p>However, also following a hyperlink generates a HTTP request - * with a {@code Referer} HTTP header that points to {@code index.html}; therefore a proper value for {@link - * #setReferrerPushPeriod(int)} has to be set. If the referrerPushPeriod for a main resource has elapsed, no more - * associated resources will be added for that main resource.<p>This class distinguishes associated main resources by - * their URL path suffix and content type. CSS stylesheets, images and JavaScript files have recognizable URL path - * suffixes that are classified as associated resources. The suffix regexs can be configured by constructor argument</p> - * <p>When CSS stylesheets refer to images, the CSS image request will have the CSS stylesheet as referrer. This - * implementation will push also the CSS image.<p>The push metadata built by this implementation is limited by the - * number of pages of the application itself, and by the {@link #setMaxAssociatedResources(int)} max associated - * resources} parameter. This parameter limits the number of associated resources per each main resource, so that if a - * main resource has hundreds of associated resources, only up to the number specified by this parameter will be - * pushed. - */ -public class ReferrerPushStrategy implements PushStrategy -{ - private static final Logger LOG = Log.getLogger(ReferrerPushStrategy.class); - private final ConcurrentMap<String, MainResource> mainResources = new ConcurrentHashMap<>(); - private final Set<Pattern> pushRegexps = new HashSet<>(); - private final Set<String> pushContentTypes = new HashSet<>(); - private final Set<Pattern> allowedPushOrigins = new HashSet<>(); - private final Set<Pattern> userAgentBlacklist = new HashSet<>(); - private volatile int maxAssociatedResources = 32; - private volatile int referrerPushPeriod = 5000; - - public ReferrerPushStrategy() - { - List<String> defaultPushRegexps = Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg", - ".*\\.gif", ".*\\.ico"); - addPushRegexps(defaultPushRegexps); - - List<String> defaultPushContentTypes = Arrays.asList( - "text/css", - "text/javascript", "application/javascript", "application/x-javascript", - "image/png", "image/x-png", - "image/jpeg", - "image/gif", - "image/x-icon", "image/vnd.microsoft.icon"); - this.pushContentTypes.addAll(defaultPushContentTypes); - } - - public void setPushRegexps(List<String> pushRegexps) - { - pushRegexps.clear(); - addPushRegexps(pushRegexps); - } - - private void addPushRegexps(List<String> pushRegexps) - { - for (String pushRegexp : pushRegexps) - this.pushRegexps.add(Pattern.compile(pushRegexp)); - } - - public void setPushContentTypes(List<String> pushContentTypes) - { - pushContentTypes.clear(); - pushContentTypes.addAll(pushContentTypes); - } - - public void setAllowedPushOrigins(List<String> allowedPushOrigins) - { - allowedPushOrigins.clear(); - for (String allowedPushOrigin : allowedPushOrigins) - this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*"))); - } - - public void setUserAgentBlacklist(List<String> userAgentPatterns) - { - userAgentBlacklist.clear(); - for (String userAgentPattern : userAgentPatterns) - userAgentBlacklist.add(Pattern.compile(userAgentPattern)); - } - - public void setMaxAssociatedResources(int maxAssociatedResources) - { - this.maxAssociatedResources = maxAssociatedResources; - } - - public void setReferrerPushPeriod(int referrerPushPeriod) - { - this.referrerPushPeriod = referrerPushPeriod; - } - - public Set<Pattern> getPushRegexps() - { - return pushRegexps; - } - - public Set<String> getPushContentTypes() - { - return pushContentTypes; - } - - public Set<Pattern> getAllowedPushOrigins() - { - return allowedPushOrigins; - } - - public Set<Pattern> getUserAgentBlacklist() - { - return userAgentBlacklist; - } - - public int getMaxAssociatedResources() - { - return maxAssociatedResources; - } - - public int getReferrerPushPeriod() - { - return referrerPushPeriod; - } - - @Override - public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders) - { - Set<String> result = Collections.<String>emptySet(); - short version = stream.getSession().getVersion(); - if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD - .name(version)).getValue()) && !isUserAgentBlacklisted(requestHeaders)) - { - String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).getValue(); - String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).getValue(); - String origin = scheme + "://" + host; - String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).getValue(); - String absoluteURL = origin + url; - if (LOG.isDebugEnabled()) - LOG.debug("Applying push strategy for {}", absoluteURL); - if (isMainResource(url, responseHeaders)) - { - MainResource mainResource = getOrCreateMainResource(absoluteURL); - result = mainResource.getResources(); - } - else if (isPushResource(url, responseHeaders)) - { - Fields.Field referrerHeader = requestHeaders.get("referer"); - if (referrerHeader != null) - { - String referrer = referrerHeader.getValue(); - MainResource mainResource = mainResources.get(referrer); - if (mainResource == null) - mainResource = getOrCreateMainResource(referrer); - - Set<String> pushResources = mainResource.getResources(); - if (!pushResources.contains(url)) - mainResource.addResource(url, origin, referrer); - else - result = getPushResources(absoluteURL); - } - } - if (LOG.isDebugEnabled()) - LOG.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result); - } - return result; - } - - private Set<String> getPushResources(String absoluteURL) - { - Set<String> result = Collections.emptySet(); - if (mainResources.get(absoluteURL) != null) - result = mainResources.get(absoluteURL).getResources(); - return result; - } - - private MainResource getOrCreateMainResource(String absoluteURL) - { - MainResource mainResource = mainResources.get(absoluteURL); - if (mainResource == null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Creating new main resource for {}", absoluteURL); - MainResource value = new MainResource(absoluteURL); - mainResource = mainResources.putIfAbsent(absoluteURL, value); - if (mainResource == null) - mainResource = value; - } - return mainResource; - } - - private boolean isIfModifiedSinceHeaderPresent(Fields headers) - { - return headers.get("if-modified-since") != null; - } - - private boolean isValidMethod(String method) - { - return "GET".equalsIgnoreCase(method); - } - - private boolean isMainResource(String url, Fields responseHeaders) - { - return !isPushResource(url, responseHeaders); - } - - public boolean isUserAgentBlacklisted(Fields headers) - { - Fields.Field userAgentHeader = headers.get("user-agent"); - if (userAgentHeader != null) - for (Pattern userAgentPattern : userAgentBlacklist) - if (userAgentPattern.matcher(userAgentHeader.getValue()).matches()) - return true; - return false; - } - - private boolean isPushResource(String url, Fields responseHeaders) - { - for (Pattern pushRegexp : pushRegexps) - { - if (pushRegexp.matcher(url).matches()) - { - Fields.Field header = responseHeaders.get("content-type"); - if (header == null) - return true; - - String contentType = header.getValue().toLowerCase(Locale.ENGLISH); - for (String pushContentType : pushContentTypes) - if (contentType.startsWith(pushContentType)) - return true; - } - } - return false; - } - - private class MainResource - { - private final String name; - private final CopyOnWriteArraySet<String> resources = new CopyOnWriteArraySet<>(); - private final AtomicLong firstResourceAdded = new AtomicLong(-1); - - private MainResource(String name) - { - this.name = name; - } - - public boolean addResource(String url, String origin, String referrer) - { - // We start the push period here and not when initializing the main resource, because a browser with a - // prefilled cache won't request the subresources. If the browser with warmed up cache now hits the main - // resource after a server restart, the push period shouldn't start until the first subresource is - // being requested. - firstResourceAdded.compareAndSet(-1, System.nanoTime()); - - long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - firstResourceAdded.get()); - if (!referrer.startsWith(origin) && !isPushOriginAllowed(origin)) - { - if (LOG.isDebugEnabled()) - LOG.debug("Skipped store of push metadata {} for {}: Origin: {} doesn't match or origin not allowed", - url, name, origin); - return false; - } - - // This check is not strictly concurrent-safe, but limiting - // the number of associated resources is achieved anyway - // although in rare cases few more resources will be stored - if (resources.size() >= maxAssociatedResources) - { - if (LOG.isDebugEnabled()) - LOG.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached", - url, name, maxAssociatedResources); - return false; - } - if (delay > referrerPushPeriod) - { - if (LOG.isDebugEnabled()) - LOG.debug("Delay: {}ms longer than referrerPushPeriod ({}ms). Not adding resource: {} for: {}", - delay, referrerPushPeriod, url, name); - return false; - } - - if (LOG.isDebugEnabled()) - LOG.debug("Adding: {} to: {} with delay: {}ms.", url, this, delay); - resources.add(url); - return true; - } - - public Set<String> getResources() - { - return Collections.unmodifiableSet(resources); - } - - public String toString() - { - return String.format("%s@%x{name=%s,resources=%s}", - getClass().getSimpleName(), - hashCode(), - name, - resources - ); - } - - private boolean isPushOriginAllowed(String origin) - { - for (Pattern allowedPushOrigin : allowedPushOrigins) - if (allowedPushOrigin.matcher(origin).matches()) - return true; - return false; - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java deleted file mode 100644 index 5906f22ac7..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java +++ /dev/null @@ -1,276 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.proxy; - -import java.nio.ByteBuffer; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.api.Response; -import org.eclipse.jetty.client.util.DeferredContentProvider; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.HttpCookieStore; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * <p>{@link HTTPProxyEngine} implements a SPDY to HTTP proxy, that is, converts SPDY events received by clients into - * HTTP events for the servers.</p> - */ -public class HTTPProxyEngine extends ProxyEngine -{ - private static final Logger LOG = Log.getLogger(HTTPProxyEngine.class); - private static final Callback LOGGING_CALLBACK = new LoggingCallback(); - - private final HttpClient httpClient; - - public HTTPProxyEngine(HttpClient httpClient) - { - this.httpClient = httpClient; - configureHttpClient(httpClient); - } - - private void configureHttpClient(HttpClient httpClient) - { - // Redirects must be proxied as is, not followed - httpClient.setFollowRedirects(false); - // Must not store cookies, otherwise cookies of different clients will mix - httpClient.setCookieStore(new HttpCookieStore.Empty()); - } - - public StreamFrameListener proxy(final Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo) - { - short version = clientStream.getSession().getVersion(); - String method = clientSynInfo.getHeaders().get(HTTPSPDYHeader.METHOD.name(version)).getValue(); - String path = clientSynInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue(); - - Fields headers = new Fields(clientSynInfo.getHeaders(), false); - - removeHopHeaders(headers); - addRequestProxyHeaders(clientStream, headers); - customizeRequestHeaders(clientStream, headers); - - String host = proxyServerInfo.getHost(); - int port = proxyServerInfo.getAddress().getPort(); - - if (LOG.isDebugEnabled()) - LOG.debug("Sending HTTP request to: {}", host + ":" + port); - final Request request = httpClient.newRequest(host, port) - .path(path) - .method(HttpMethod.fromString(method)); - addNonSpdyHeadersToRequest(version, headers, request); - - if (!clientSynInfo.isClose()) - { - request.content(new DeferredContentProvider()); - } - - sendRequest(clientStream, request); - - return new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // We proxy to HTTP so we do not receive replies - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - @Override - public void onData(Stream clientStream, final DataInfo clientDataInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("received clientDataInfo: {} for stream: {}", clientDataInfo, clientStream); - - DeferredContentProvider contentProvider = (DeferredContentProvider)request.getContent(); - contentProvider.offer(clientDataInfo.asByteBuffer(true)); - - if (clientDataInfo.isClose()) - contentProvider.close(); - } - }; - } - - private void sendRequest(final Stream clientStream, Request request) - { - request.send(new Response.Listener.Adapter() - { - private volatile boolean committed; - - @Override - public void onHeaders(final Response response) - { - if (LOG.isDebugEnabled()) - LOG.debug("onHeaders called with response: {}. Sending replyInfo to client.", response); - Fields responseHeaders = createResponseHeaders(clientStream, response); - removeHopHeaders(responseHeaders); - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false); - clientStream.reply(replyInfo, new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - LOG.debug("failed: ", x); - response.abort(x); - } - - @Override - public void succeeded() - { - committed = true; - } - }); - } - - @Override - public void onContent(final Response response, ByteBuffer content) - { - if (LOG.isDebugEnabled()) - LOG.debug("onContent called with response: {} and content: {}. Sending response content to client.", - response, content); - final ByteBuffer contentCopy = httpClient.getByteBufferPool().acquire(content.remaining(), true); - BufferUtil.flipPutFlip(content, contentCopy); - ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(contentCopy, false); - clientStream.data(dataInfo, new Callback() - { - @Override - public void failed(Throwable x) - { - LOG.debug("failed: ", x); - releaseBuffer(); - response.abort(x); - } - - @Override - public void succeeded() - { - releaseBuffer(); - } - - private void releaseBuffer() - { - httpClient.getByteBufferPool().release(contentCopy); - } - }); - } - - @Override - public void onSuccess(Response response) - { - if (LOG.isDebugEnabled()) - LOG.debug("onSuccess called. Closing client stream."); - clientStream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true), LOGGING_CALLBACK); - } - - @Override - public void onFailure(Response response, Throwable failure) - { - LOG.debug("onFailure called: ", failure); - if (committed) - { - LOG.debug("clientStream already committed. Resetting stream."); - try - { - clientStream.getSession().rst(new RstInfo(clientStream.getId(), StreamStatus.INTERNAL_ERROR)); - } - catch (InterruptedException | ExecutionException | TimeoutException e) - { - LOG.debug(e); - } - } - else - { - if (clientStream.isClosed()) - return; - Fields responseHeaders = createResponseHeaders(clientStream, response); - if (failure instanceof TimeoutException) - responseHeaders.add(HTTPSPDYHeader.STATUS.name(clientStream.getSession().getVersion()), - String.valueOf(HttpStatus.GATEWAY_TIMEOUT_504)); - else - responseHeaders.add(HTTPSPDYHeader.STATUS.name(clientStream.getSession().getVersion()), - String.valueOf(HttpStatus.BAD_GATEWAY_502)); - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true); - clientStream.reply(replyInfo, LOGGING_CALLBACK); - } - } - }); - } - - private Fields createResponseHeaders(Stream clientStream, Response response) - { - Fields responseHeaders = new Fields(); - for (HttpField header : response.getHeaders()) - responseHeaders.add(header.getName(), header.getValue()); - short version = clientStream.getSession().getVersion(); - if (response.getStatus() > 0) - responseHeaders.add(HTTPSPDYHeader.STATUS.name(version), - String.valueOf(response.getStatus())); - responseHeaders.add(HTTPSPDYHeader.VERSION.name(version), HttpVersion.HTTP_1_1.asString()); - addResponseProxyHeaders(clientStream, responseHeaders); - return responseHeaders; - } - - private void addNonSpdyHeadersToRequest(short version, Fields headers, Request request) - { - for (Fields.Field header : headers) - if (HTTPSPDYHeader.from(version, header.getName()) == null) - request.header(header.getName(), header.getValue()); - } - - static class LoggingCallback extends Callback.Adapter - { - @Override - public void failed(Throwable x) - { - LOG.debug(x); - } - - @Override - public void succeeded() - { - if (LOG.isDebugEnabled()) - LOG.debug("succeeded"); - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java deleted file mode 100644 index c29b0e86d9..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java +++ /dev/null @@ -1,63 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.proxy; - -import java.util.Objects; - -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class HTTPSPDYProxyServerConnector extends ServerConnector -{ - public HTTPSPDYProxyServerConnector(Server server, ProxyEngineSelector proxyEngineSelector) - { - this(server, new HttpConfiguration(), proxyEngineSelector); - } - - public HTTPSPDYProxyServerConnector(Server server, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector) - { - super(server, (SslContextFactory)null, new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)); - } - - public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, ProxyEngineSelector proxyEngineSelector) - { - this(server, sslContextFactory, new HttpConfiguration(), proxyEngineSelector); - } - - public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector) - { - this(server, sslContextFactory, config, proxyEngineSelector, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); - } - - public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector, NegotiatingServerConnectionFactory negotiatingFactory) - { - super(server, Objects.requireNonNull(sslContextFactory), negotiatingFactory, - new SPDYServerConnectionFactory(SPDY.V3, proxyEngineSelector), - new SPDYServerConnectionFactory(SPDY.V2, proxyEngineSelector), - new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)); - negotiatingFactory.setDefaultProtocol("http/1.1"); - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java deleted file mode 100644 index ffa968f4f9..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java +++ /dev/null @@ -1,129 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.proxy; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; - -/** - * <p>{@link ProxyEngine} is the class for SPDY proxy functionalities that receives a SPDY request and converts it to - * any protocol to its server side.</p> - * <p>This class listens for SPDY events sent by clients; subclasses are responsible for translating - * these SPDY client events into appropriate events to forward to the server, in the appropriate - * protocol that is understood by the server.</p> - */ -public abstract class ProxyEngine -{ - private static final Set<String> HOP_HEADERS = new HashSet<>(); - static - { - HOP_HEADERS.add("proxy-connection"); - HOP_HEADERS.add("connection"); - HOP_HEADERS.add("keep-alive"); - HOP_HEADERS.add("transfer-encoding"); - HOP_HEADERS.add("te"); - HOP_HEADERS.add("trailer"); - HOP_HEADERS.add("proxy-authorization"); - HOP_HEADERS.add("proxy-authenticate"); - HOP_HEADERS.add("upgrade"); - } - - private final String name; - - protected ProxyEngine() - { - this(name()); - } - - private static String name() - { - try - { - return InetAddress.getLocalHost().getHostName(); - } - catch (UnknownHostException x) - { - return "localhost"; - } - } - - public abstract StreamFrameListener proxy(Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo); - - protected ProxyEngine(String name) - { - this.name = name; - } - - public String getName() - { - return name; - } - - protected void removeHopHeaders(Fields headers) - { - // Header names are case-insensitive (RFC2616) and oej.util.Fields.add converts the names to lowercase. So we - // need to compare with the lowercase values only - for (String hopHeader : HOP_HEADERS) - headers.remove(hopHeader); - } - - protected void addRequestProxyHeaders(Stream stream, Fields headers) - { - addViaHeader(headers); - Fields.Field schemeField = headers.get(HTTPSPDYHeader.SCHEME.name(stream.getSession().getVersion())); - if(schemeField != null) - headers.add("X-Forwarded-Proto", schemeField.getValue()); - InetSocketAddress address = stream.getSession().getRemoteAddress(); - if (address != null) - { - headers.add("X-Forwarded-Host", address.getHostName()); - headers.add("X-Forwarded-For", address.toString()); - } - headers.add("X-Forwarded-Server", name()); - } - - protected void addResponseProxyHeaders(Stream stream, Fields headers) - { - addViaHeader(headers); - } - - private void addViaHeader(Fields headers) - { - headers.add("Via", "http/1.1 " + getName()); - } - - protected void customizeRequestHeaders(Stream stream, Fields headers) - { - } - - protected void customizeResponseHeaders(Stream stream, Fields headers) - { - } - -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java deleted file mode 100644 index 176122a975..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java +++ /dev/null @@ -1,203 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.PingResultInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * <p>{@link ProxyEngineSelector} is the main entry point for push stream events of a jetty SPDY proxy. It receives the - * push stream frames from the clients, checks if there's an appropriate {@link ProxyServerInfo} for the given target - * host and forwards the push to a {@link ProxyEngine} for the protocol defined in {@link ProxyServerInfo}.</p> - * - * <p>If no {@link ProxyServerInfo} can be found for the given target host or no {@link ProxyEngine} can be found for - * the given protocol, it resets the client stream.</p> - * - * <p>This class also provides configuration for the proxy rules.</p> - */ -public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter -{ - protected final Logger LOG = Log.getLogger(getClass()); - private final Map<String, ProxyServerInfo> proxyInfos = new ConcurrentHashMap<>(); - private final Map<String, ProxyEngine> proxyEngines = new ConcurrentHashMap<>(); - - @Override - public final StreamFrameListener onSyn(final Stream clientStream, SynInfo clientSynInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("C -> P {} on {}", clientSynInfo, clientStream); - - final Session clientSession = clientStream.getSession(); - short clientVersion = clientSession.getVersion(); - Fields headers = new Fields(clientSynInfo.getHeaders(), false); - - Fields.Field hostHeader = headers.get(HTTPSPDYHeader.HOST.name(clientVersion)); - if (hostHeader == null) - { - if (LOG.isDebugEnabled()) - LOG.debug("No host header found: " + headers); - rst(clientStream); - return null; - } - - String host = hostHeader.getValue(); - int colon = host.indexOf(':'); - if (colon >= 0) - host = host.substring(0, colon); - - ProxyServerInfo proxyServerInfo = getProxyServerInfo(host); - if (proxyServerInfo == null) - { - if (LOG.isDebugEnabled()) - LOG.debug("No matching ProxyServerInfo found for: " + host); - rst(clientStream); - return null; - } - - String protocol = proxyServerInfo.getProtocol(); - ProxyEngine proxyEngine = proxyEngines.get(protocol); - if (proxyEngine == null) - { - if (LOG.isDebugEnabled()) - LOG.debug("No matching ProxyEngine found for: " + protocol); - rst(clientStream); - return null; - } - if (LOG.isDebugEnabled()) - LOG.debug("Forwarding request: {} -> {}", clientSynInfo, proxyServerInfo); - return proxyEngine.proxy(clientStream, clientSynInfo, proxyServerInfo); - } - - @Override - public void onPing(Session clientSession, PingResultInfo pingResultInfo) - { - // We do not know to which upstream server - // to send the PING so we just ignore it - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo) - { - // TODO: - } - - public Map<String, ProxyEngine> getProxyEngines() - { - return new HashMap<>(proxyEngines); - } - - public void setProxyEngines(Map<String, ProxyEngine> proxyEngines) - { - this.proxyEngines.clear(); - this.proxyEngines.putAll(proxyEngines); - } - - public ProxyEngine getProxyEngine(String protocol) - { - return proxyEngines.get(protocol); - } - - public void putProxyEngine(String protocol, ProxyEngine proxyEngine) - { - proxyEngines.put(protocol, proxyEngine); - } - - public Map<String, ProxyServerInfo> getProxyServerInfos() - { - return new HashMap<>(proxyInfos); - } - - protected ProxyServerInfo getProxyServerInfo(String host) - { - return proxyInfos.get(host); - } - - public void setProxyServerInfos(Map<String, ProxyServerInfo> proxyServerInfos) - { - this.proxyInfos.clear(); - this.proxyInfos.putAll(proxyServerInfos); - } - - public void putProxyServerInfo(String host, ProxyServerInfo proxyServerInfo) - { - proxyInfos.put(host, proxyServerInfo); - } - - private void rst(Stream stream) - { - RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM); - stream.getSession().rst(rstInfo, Callback.Adapter.INSTANCE); - } - - public static class ProxyServerInfo - { - private final String protocol; - private final String host; - private final InetSocketAddress address; - - public ProxyServerInfo(String protocol, String host, int port) - { - this.protocol = protocol; - this.host = host; - this.address = new InetSocketAddress(host, port); - } - - public String getProtocol() - { - return protocol; - } - - public String getHost() - { - return host; - } - - public InetSocketAddress getAddress() - { - return address; - } - - @Override - public String toString() - { - return "ProxyServerInfo{" + - "protocol='" + protocol + '\'' + - ", host='" + host + '\'' + - ", address=" + address + - '}'; - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java deleted file mode 100644 index e64b1d905b..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.proxy; - - -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; - -public class ProxyHTTPConnectionFactory extends AbstractConnectionFactory implements HttpConfiguration.ConnectionFactory -{ - private final short version; - private final ProxyEngineSelector proxyEngineSelector; - private final HttpConfiguration httpConfiguration; - - public ProxyHTTPConnectionFactory(HttpConfiguration httpConfiguration,short version, ProxyEngineSelector proxyEngineSelector) - { - // replaces http/1.1 - super(HttpVersion.HTTP_1_1.asString()); - this.version = version; - this.proxyEngineSelector = proxyEngineSelector; - this.httpConfiguration=httpConfiguration; - } - - @Override - public Connection newConnection(Connector connector, EndPoint endPoint) - { - return configure(new ProxyHTTPSPDYConnection(connector, httpConfiguration, endPoint, version, proxyEngineSelector),connector,endPoint); - } - - @Override - public HttpConfiguration getHttpConfiguration() - { - return httpConfiguration; - } - -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java deleted file mode 100644 index 040068c0e9..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java +++ /dev/null @@ -1,385 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.nio.ByteBuffer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnection; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.spdy.ISession; -import org.eclipse.jetty.spdy.IStream; -import org.eclipse.jetty.spdy.StandardSession; -import org.eclipse.jetty.spdy.StandardStream; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; - -public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParser.RequestHandler<ByteBuffer> -{ - private final short version; - private final Fields headers = new Fields(); - private final ProxyEngineSelector proxyEngineSelector; - private final ISession session; - private HTTPStream stream; - private ByteBuffer content; - - public ProxyHTTPSPDYConnection(Connector connector, HttpConfiguration config, EndPoint endPoint, short version, ProxyEngineSelector proxyEngineSelector) - { - super(config, connector, endPoint); - this.version = version; - this.proxyEngineSelector = proxyEngineSelector; - this.session = new HTTPSession(version, connector); - } - - @Override - protected HttpParser.RequestHandler<ByteBuffer> newRequestHandler() - { - return this; - } - - @Override - public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion) - { - Connector connector = getConnector(); - String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http"; - headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme); - headers.put(HTTPSPDYHeader.METHOD.name(version), methodString); - headers.put(HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings - headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString()); - return false; - } - - @Override - public boolean parsedHeader(HttpField field) - { - if (field.getHeader() == HttpHeader.HOST) - headers.put(HTTPSPDYHeader.HOST.name(version), field.getValue()); - else - headers.put(field.getName(), field.getValue()); - return false; - } - - @Override - public boolean parsedHostHeader(String host, int port) - { - return false; - } - - @Override - public boolean headerComplete() - { - return false; - } - - @Override - public boolean content(ByteBuffer item) - { - if (content == null) - { - stream = syn(false); - content = item; - } - else - { - stream.getStreamFrameListener().onData(stream, toDataInfo(item, false)); - } - return false; - } - - @Override - public boolean messageComplete() - { - if (stream == null) - { - assert content == null; - if (headers.isEmpty()) - proxyEngineSelector.onGoAway(session, new GoAwayResultInfo(0, SessionStatus.OK)); - else - syn(true); - } - else - { - stream.getStreamFrameListener().onData(stream, toDataInfo(content, true)); - } - return false; - } - - @Override - public void completed() - { - headers.clear(); - stream = null; - content = null; - super.completed(); - } - - @Override - public int getHeaderCacheSize() - { - // TODO get from configuration - return 256; - } - - @Override - public void earlyEOF() - { - // TODO - } - - @Override - public void badMessage(int status, String reason) - { - // TODO - } - - private HTTPStream syn(boolean close) - { - HTTPStream stream = new HTTPStream(1, (byte)0, session, null); - StreamFrameListener streamFrameListener = proxyEngineSelector.onSyn(stream, new SynInfo(headers, close)); - stream.setStreamFrameListener(streamFrameListener); - return stream; - } - - private DataInfo toDataInfo(ByteBuffer buffer, boolean close) - { - return new ByteBufferDataInfo(buffer, close); - } - - private class HTTPSession extends StandardSession - { - private HTTPSession(short version, Connector connector) - { - super(version, connector.getByteBufferPool(), connector.getScheduler(), null, - getEndPoint(), null, 1, proxyEngineSelector, null, null); - } - - @Override - public void rst(RstInfo rstInfo, Callback handler) - { - HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(HttpVersion.fromString(headers.get - ("version").getValue()), null, 0, 502, "SPDY reset received from upstream server", false); - send(info, null, true, Callback.Adapter.INSTANCE); - } - - @Override - public void goAway(GoAwayInfo goAwayInfo, Callback handler) - { - ProxyHTTPSPDYConnection.this.close(); - handler.succeeded(); - } - } - - /** - * <p>This stream will convert the SPDY invocations performed by the proxy into HTTP to be sent to the client.</p> - */ - private class HTTPStream extends StandardStream - { - private final Pattern statusRegexp = Pattern.compile("(\\d{3})\\s+(.*)"); - - private HTTPStream(int id, byte priority, ISession session, IStream associatedStream) - { - super(id, priority, session, associatedStream, getHttpChannel().getScheduler(), null); - } - - @Override - public void push(PushInfo pushInfo, Promise<Stream> handler) - { - // HTTP does not support pushed streams - handler.succeeded(new HTTPPushStream(2, getPriority(), getSession(), this)); - } - - @Override - public void headers(HeadersInfo headersInfo, Callback handler) - { - // TODO - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - @Override - public void reply(ReplyInfo replyInfo, final Callback handler) - { - Fields headers = new Fields(replyInfo.getHeaders(), false); - - addPersistenceHeader(headers); - - headers.remove(HTTPSPDYHeader.SCHEME.name(version)); - - String status = headers.remove(HTTPSPDYHeader.STATUS.name(version)).getValue(); - Matcher matcher = statusRegexp.matcher(status); - matcher.matches(); - int code = Integer.parseInt(matcher.group(1)); - String reason = matcher.group(2).trim(); - - HttpVersion httpVersion = HttpVersion.fromString(headers.remove(HTTPSPDYHeader.VERSION.name(version)).getValue()); - - // Convert the Host header from a SPDY special header to a normal header - Fields.Field host = headers.remove(HTTPSPDYHeader.HOST.name(version)); - if (host != null) - headers.put("host", host.getValue()); - - HttpFields fields = new HttpFields(); - for (Fields.Field header : headers) - { - String name = camelize(header.getName()); - fields.put(name, header.getValue()); - } - - // TODO: handle better the HEAD last parameter - long contentLength = fields.getLongField(HttpHeader.CONTENT_LENGTH.asString()); - HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(httpVersion, fields, contentLength, code, - reason, false); - - send(info, null, replyInfo.isClose(), new Adapter() - { - @Override - public void failed(Throwable x) - { - handler.failed(x); - } - }); - - if (replyInfo.isClose()) - completed(); - - handler.succeeded(); - } - - private String camelize(String name) - { - char[] chars = name.toCharArray(); - chars[0] = Character.toUpperCase(chars[0]); - - for (int i = 0; i < chars.length; ++i) - { - char c = chars[i]; - int j = i + 1; - if (c == '-' && j < chars.length) - chars[j] = Character.toUpperCase(chars[j]); - } - return new String(chars); - } - - @Override - public void data(DataInfo dataInfo, final Callback handler) - { - // Data buffer must be copied, as the ByteBuffer is pooled - ByteBuffer byteBuffer = dataInfo.asByteBuffer(false); - - send(null, byteBuffer, dataInfo.isClose(), new Adapter() - { - @Override - public void failed(Throwable x) - { - handler.failed(x); - } - }); - - if (dataInfo.isClose()) - completed(); - - handler.succeeded(); - } - } - - private void addPersistenceHeader(Fields headersToAddTo) - { - HttpVersion httpVersion = HttpVersion.fromString(headers.get("version").getValue()); - boolean persistent = false; - switch (httpVersion) - { - case HTTP_1_0: - { - Fields.Field keepAliveHeader = headers.get(HttpHeader.KEEP_ALIVE.asString()); - if(keepAliveHeader!=null) - persistent = HttpHeaderValue.KEEP_ALIVE.asString().equals(keepAliveHeader.getValue()); - if (!persistent) - persistent = HttpMethod.CONNECT.is(headers.get("method").getValue()); - if (persistent) - headersToAddTo.add(HttpHeader.CONNECTION.asString(), HttpHeaderValue.KEEP_ALIVE.asString()); - break; - } - case HTTP_1_1: - { - Fields.Field connectionHeader = headers.get(HttpHeader.CONNECTION.asString()); - if(connectionHeader != null) - persistent = !HttpHeaderValue.CLOSE.asString().equals(connectionHeader.getValue()); - else - persistent = true; - if (!persistent) - persistent = HttpMethod.CONNECT.is(headers.get("method").getValue()); - if (!persistent) - headersToAddTo.add(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString()); - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - - private class HTTPPushStream extends StandardStream - { - private HTTPPushStream(int id, byte priority, ISession session, IStream associatedStream) - { - super(id, priority, session, associatedStream, getHttpChannel().getScheduler(), null); - } - - @Override - public void headers(HeadersInfo headersInfo, Callback handler) - { - // Ignore pushed headers - handler.succeeded(); - } - - @Override - public void data(DataInfo dataInfo, Callback handler) - { - // Ignore pushed data - handler.succeeded(); - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java deleted file mode 100644 index 349672abde..0000000000 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java +++ /dev/null @@ -1,631 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.proxy; - -import java.net.InetSocketAddress; -import java.util.LinkedList; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.Info; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * <p>{@link SPDYProxyEngine} implements a SPDY to SPDY proxy, that is, converts SPDY events received by clients into - * SPDY events for the servers.</p> - */ -public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener -{ - private static final Logger LOG = Log.getLogger(SPDYProxyEngine.class); - - private static final String STREAM_PROMISE_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.proxy.streamPromise"; - private static final String CLIENT_STREAM_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.proxy.clientStream"; - - private final ConcurrentMap<String, Session> serverSessions = new ConcurrentHashMap<>(); - private final SessionFrameListener sessionListener = new ProxySessionFrameListener(); - private final SPDYClient.Factory factory; - private volatile long connectTimeout = 15000; - private volatile long timeout = 60000; - - public SPDYProxyEngine(SPDYClient.Factory factory) - { - this.factory = factory; - } - - public long getConnectTimeout() - { - return connectTimeout; - } - - public void setConnectTimeout(long connectTimeout) - { - this.connectTimeout = connectTimeout; - } - - public long getTimeout() - { - return timeout; - } - - public void setTimeout(long timeout) - { - this.timeout = timeout; - } - - public StreamFrameListener proxy(final Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo) - { - Fields headers = new Fields(clientSynInfo.getHeaders(), false); - - short serverVersion = getVersion(proxyServerInfo.getProtocol()); - InetSocketAddress address = proxyServerInfo.getAddress(); - Session serverSession = produceSession(proxyServerInfo.getHost(), serverVersion, address); - if (serverSession == null) - { - rst(clientStream); - return null; - } - - final Session clientSession = clientStream.getSession(); - - addRequestProxyHeaders(clientStream, headers); - customizeRequestHeaders(clientStream, headers); - convert(clientSession.getVersion(), serverVersion, headers); - - SynInfo serverSynInfo = new SynInfo(headers, clientSynInfo.isClose()); - StreamFrameListener listener = new ProxyStreamFrameListener(clientStream); - StreamPromise promise = new StreamPromise(clientStream, serverSynInfo); - clientStream.setAttribute(STREAM_PROMISE_ATTRIBUTE, promise); - serverSession.syn(serverSynInfo, listener, promise); - return this; - } - - private static short getVersion(String protocol) - { - switch (protocol) - { - case "spdy/2": - return SPDY.V2; - case "spdy/3": - return SPDY.V3; - default: - throw new IllegalArgumentException("Procotol: " + protocol + " is not a known SPDY protocol"); - } - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - throw new IllegalStateException("We shouldn't receive pushes from clients"); - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - throw new IllegalStateException("Servers do not receive replies"); - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - // TODO - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - @Override - public void onData(Stream clientStream, final DataInfo clientDataInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("C -> P {} on {}", clientDataInfo, clientStream); - - ByteBufferDataInfo serverDataInfo = new ByteBufferDataInfo(clientDataInfo.asByteBuffer(false), clientDataInfo.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - clientDataInfo.consume(delta); - } - }; - - StreamPromise streamPromise = (StreamPromise)clientStream.getAttribute(STREAM_PROMISE_ATTRIBUTE); - streamPromise.data(serverDataInfo); - } - - @Override - public void onFailure(Stream stream, Throwable x) - { - LOG.debug(x); - } - - private Session produceSession(String host, short version, InetSocketAddress address) - { - try - { - Session session = serverSessions.get(host); - if (session == null) - { - SPDYClient client = factory.newSPDYClient(version); - session = client.connect(address, sessionListener); - if (LOG.isDebugEnabled()) - LOG.debug("Proxy session connected to {}", address); - Session existing = serverSessions.putIfAbsent(host, session); - if (existing != null) - { - session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE); - session = existing; - } - } - return session; - } - catch (Exception x) - { - LOG.debug(x); - return null; - } - } - - private void convert(short fromVersion, short toVersion, Fields headers) - { - if (fromVersion != toVersion) - { - for (HTTPSPDYHeader httpHeader : HTTPSPDYHeader.values()) - { - Fields.Field header = headers.remove(httpHeader.name(fromVersion)); - if (header != null) - { - String toName = httpHeader.name(toVersion); - for (String value : header.getValues()) - headers.add(toName, value); - } - } - } - } - - private void rst(Stream stream) - { - RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM); - stream.getSession().rst(rstInfo, Callback.Adapter.INSTANCE); - } - - private class ProxyPushStreamFrameListener implements StreamFrameListener - { - private PushStreamPromise pushStreamPromise; - - private ProxyPushStreamFrameListener(PushStreamPromise pushStreamPromise) - { - this.pushStreamPromise = pushStreamPromise; - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("S -> P pushed {} on {}. Opening new PushStream P -> C now.", pushInfo, stream); - PushStreamPromise newPushStreamPromise = new PushStreamPromise(stream, pushInfo); - this.pushStreamPromise.push(newPushStreamPromise); - return new ProxyPushStreamFrameListener(newPushStreamPromise); - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - // Push streams never send a reply - throw new UnsupportedOperationException(); - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - throw new UnsupportedOperationException(); - } - - @Override - public void onData(Stream serverStream, final DataInfo serverDataInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("S -> P pushed {} on {}", serverDataInfo, serverStream); - - ByteBufferDataInfo clientDataInfo = new ByteBufferDataInfo(serverDataInfo.asByteBuffer(false), serverDataInfo.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - serverDataInfo.consume(delta); - } - }; - - pushStreamPromise.data(clientDataInfo); - } - - @Override - public void onFailure(Stream stream, Throwable x) - { - LOG.debug(x); - } - } - - private class ProxyStreamFrameListener extends StreamFrameListener.Adapter - { - private final Stream receiverStream; - - public ProxyStreamFrameListener(Stream receiverStream) - { - this.receiverStream = receiverStream; - } - - @Override - public StreamFrameListener onPush(Stream senderStream, PushInfo pushInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("S -> P {} on {}"); - PushInfo newPushInfo = convertPushInfo(pushInfo, senderStream, receiverStream); - PushStreamPromise pushStreamPromise = new PushStreamPromise(senderStream, newPushInfo); - receiverStream.push(newPushInfo, pushStreamPromise); - return new ProxyPushStreamFrameListener(pushStreamPromise); - } - - @Override - public void onReply(final Stream stream, ReplyInfo replyInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("S -> P {} on {}", replyInfo, stream); - final ReplyInfo clientReplyInfo = new ReplyInfo(convertHeaders(stream, receiverStream, replyInfo.getHeaders()), - replyInfo.isClose()); - reply(stream, clientReplyInfo); - } - - private void reply(final Stream stream, final ReplyInfo clientReplyInfo) - { - receiverStream.reply(clientReplyInfo, new Callback() - { - @Override - public void succeeded() - { - if (LOG.isDebugEnabled()) - LOG.debug("P -> C {} from {} to {}", clientReplyInfo, stream, receiverStream); - } - - @Override - public void failed(Throwable x) - { - LOG.debug(x); - rst(receiverStream); - } - }); - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - // TODO - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - @Override - public void onData(final Stream stream, final DataInfo dataInfo) - { - if (LOG.isDebugEnabled()) - LOG.debug("S -> P {} on {}", dataInfo, stream); - data(stream, dataInfo); - } - - private void data(final Stream stream, final DataInfo serverDataInfo) - { - final ByteBufferDataInfo clientDataInfo = new ByteBufferDataInfo(serverDataInfo.asByteBuffer(false), serverDataInfo.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - serverDataInfo.consume(delta); - } - }; - - receiverStream.data(clientDataInfo, new Callback() //TODO: timeout??? - { - @Override - public void succeeded() - { - if (LOG.isDebugEnabled()) - LOG.debug("P -> C {} from {} to {}", clientDataInfo, stream, receiverStream); - } - - @Override - public void failed(Throwable x) - { - LOG.debug(x); - rst(receiverStream); - } - }); - } - } - - /** - * <p>{@link StreamPromise} implements the forwarding of DATA frames from the client to the server and vice - * versa.</p> <p>Instances of this class buffer DATA frames sent by clients and send them to the server. The - * buffering happens between the send of the SYN_STREAM to the server (where DATA frames may arrive from the client - * before the SYN_STREAM has been fully sent), and between DATA frames, if the client is a fast producer and the - * server a slow consumer, or if the client is a SPDY v2 client (and hence without flow control) while the server is - * a SPDY v3 server (and hence with flow control).</p> - */ - private class StreamPromise implements Promise<Stream> - { - private final Queue<DataInfoCallback> queue = new LinkedList<>(); - private final Stream senderStream; - private final Info info; - private Stream receiverStream; - - private StreamPromise(Stream senderStream, Info info) - { - this.senderStream = senderStream; - this.info = info; - } - - @Override - public void succeeded(Stream stream) - { - if (LOG.isDebugEnabled()) - LOG.debug("P -> S {} from {} to {}", info, senderStream, stream); - - stream.setAttribute(CLIENT_STREAM_ATTRIBUTE, senderStream); - - DataInfoCallback dataInfoCallback; - synchronized (queue) - { - this.receiverStream = stream; - dataInfoCallback = queue.peek(); - if (dataInfoCallback != null) - { - if (dataInfoCallback.flushing) - { - if (LOG.isDebugEnabled()) - LOG.debug("SYN completed, flushing {}, queue size {}", dataInfoCallback.dataInfo, queue.size()); - dataInfoCallback = null; - } - else - { - dataInfoCallback.flushing = true; - if (LOG.isDebugEnabled()) - LOG.debug("SYN completed, queue size {}", queue.size()); - } - } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("SYN completed, queue empty"); - } - } - if (dataInfoCallback != null) - flush(stream, dataInfoCallback); - } - - @Override - public void failed(Throwable x) - { - LOG.debug(x); - rst(senderStream); - } - - public void data(DataInfo dataInfo) - { - Stream receiverStream; - DataInfoCallback dataInfoCallbackToFlush = null; - DataInfoCallback dataInfoCallBackToQueue = new DataInfoCallback(dataInfo); - synchronized (queue) - { - queue.offer(dataInfoCallBackToQueue); - receiverStream = this.receiverStream; - if (receiverStream != null) - { - dataInfoCallbackToFlush = queue.peek(); - if (dataInfoCallbackToFlush.flushing) - { - if (LOG.isDebugEnabled()) - LOG.debug("Queued {}, flushing {}, queue size {}", dataInfo, dataInfoCallbackToFlush.dataInfo, queue.size()); - receiverStream = null; - } - else - { - dataInfoCallbackToFlush.flushing = true; - if (LOG.isDebugEnabled()) - LOG.debug("Queued {}, queue size {}", dataInfo, queue.size()); - } - } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Queued {}, SYN incomplete, queue size {}", dataInfo, queue.size()); - } - } - if (receiverStream != null) - flush(receiverStream, dataInfoCallbackToFlush); - } - - private void flush(Stream receiverStream, DataInfoCallback dataInfoCallback) - { - if (LOG.isDebugEnabled()) - LOG.debug("P -> S {} on {}", dataInfoCallback.dataInfo, receiverStream); - receiverStream.data(dataInfoCallback.dataInfo, dataInfoCallback); //TODO: timeout??? - } - - private class DataInfoCallback implements Callback - { - private final DataInfo dataInfo; - private boolean flushing; - - private DataInfoCallback(DataInfo dataInfo) - { - this.dataInfo = dataInfo; - } - - @Override - public void succeeded() - { - Stream serverStream; - DataInfoCallback dataInfoCallback; - synchronized (queue) - { - serverStream = StreamPromise.this.receiverStream; - assert serverStream != null; - dataInfoCallback = queue.poll(); - assert dataInfoCallback == this; - dataInfoCallback = queue.peek(); - if (dataInfoCallback != null) - { - assert !dataInfoCallback.flushing; - dataInfoCallback.flushing = true; - if (LOG.isDebugEnabled()) - LOG.debug("Completed {}, queue size {}", dataInfo, queue.size()); - } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Completed {}, queue empty", dataInfo); - } - } - if (dataInfoCallback != null) - flush(serverStream, dataInfoCallback); - } - - @Override - public void failed(Throwable x) - { - LOG.debug(x); - rst(senderStream); - } - } - - public Stream getSenderStream() - { - return senderStream; - } - - public Info getInfo() - { - return info; - } - - public Stream getReceiverStream() - { - synchronized (queue) - { - return receiverStream; - } - } - } - - private class PushStreamPromise extends StreamPromise - { - private volatile PushStreamPromise pushStreamPromise; - - private PushStreamPromise(Stream senderStream, PushInfo pushInfo) - { - super(senderStream, pushInfo); - } - - @Override - public void succeeded(Stream receiverStream) - { - super.succeeded(receiverStream); - - if (LOG.isDebugEnabled()) - LOG.debug("P -> C PushStreamPromise.succeeded() called with pushStreamPromise: {}", pushStreamPromise); - - PushStreamPromise promise = pushStreamPromise; - if (promise != null) - receiverStream.push(convertPushInfo((PushInfo)getInfo(), getSenderStream(), receiverStream), pushStreamPromise); - } - - public void push(PushStreamPromise pushStreamPromise) - { - Stream receiverStream = getReceiverStream(); - - if (receiverStream != null) - receiverStream.push(convertPushInfo((PushInfo)getInfo(), getSenderStream(), receiverStream), pushStreamPromise); - else - this.pushStreamPromise = pushStreamPromise; - } - } - - private class ProxySessionFrameListener extends SessionFrameListener.Adapter - { - @Override - public void onRst(Session serverSession, RstInfo serverRstInfo) - { - Stream serverStream = serverSession.getStream(serverRstInfo.getStreamId()); - if (serverStream != null) - { - Stream clientStream = (Stream)serverStream.getAttribute(CLIENT_STREAM_ATTRIBUTE); - if (clientStream != null) - { - Session clientSession = clientStream.getSession(); - RstInfo clientRstInfo = new RstInfo(clientStream.getId(), serverRstInfo.getStreamStatus()); - clientSession.rst(clientRstInfo, Callback.Adapter.INSTANCE); - } - } - } - - @Override - public void onGoAway(Session serverSession, GoAwayResultInfo goAwayResultInfo) - { - serverSessions.values().remove(serverSession); - } - } - - private PushInfo convertPushInfo(PushInfo pushInfo, Stream from, Stream to) - { - Fields headersToConvert = pushInfo.getHeaders(); - Fields headers = convertHeaders(from, to, headersToConvert); - return new PushInfo(getTimeout(), TimeUnit.MILLISECONDS, headers, pushInfo.isClose()); - } - - private Fields convertHeaders(Stream from, Stream to, Fields headersToConvert) - { - Fields headers = new Fields(headersToConvert, false); - addResponseProxyHeaders(from, headers); - customizeResponseHeaders(from, headers); - convert(from.getSession().getVersion(), to.getSession().getVersion(), headers); - return headers; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java deleted file mode 100644 index 200c8f01fe..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java +++ /dev/null @@ -1,136 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.net.InetSocketAddress; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.Executor; - -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.StdErrLog; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Rule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -@RunWith(Parameterized.class) -public abstract class AbstractHTTPSPDYTest -{ - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - protected final short version; - protected Server server; - protected SPDYClient.Factory clientFactory; - protected HTTPSPDYServerConnector connector; - - protected AbstractHTTPSPDYTest(short version) - { - this.version = version; - } - - protected InetSocketAddress startHTTPServer(short version, Handler handler, long idleTimeout) throws Exception - { - QueuedThreadPool threadPool = new QueuedThreadPool(256); - threadPool.setName("serverQTP"); - server = new Server(threadPool); - connector = newHTTPSPDYServerConnector(version); - connector.setPort(0); - connector.setIdleTimeout(idleTimeout); - server.addConnector(connector); - server.setHandler(handler); - server.start(); - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected Server getServer() - { - return server; - } - - protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version) - { - // For these tests, we need the connector to speak HTTP over SPDY even in non-SSL - HttpConfiguration httpConfiguration = new HttpConfiguration(); - httpConfiguration.setSendServerVersion(true); - httpConfiguration.setSendXPoweredBy(true); - return new HTTPSPDYServerConnector(server, version, httpConfiguration, new PushStrategy.None()); - } - - protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception - { - if (clientFactory == null) - { - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = newSPDYClientFactory(threadPool); - clientFactory.start(); - } - return clientFactory.newSPDYClient(version).connect(socketAddress, listener); - } - - protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) - { - return new SPDYClient.Factory(threadPool, null, null, connector.getIdleTimeout()); - } - - @After - public void destroy() throws Exception - { - ((StdErrLog)Log.getLogger(HTTPSPDYServerConnector.class)).setHideStacks(true); - if (clientFactory != null) - { - clientFactory.stop(); - } - if (server != null) - { - server.stop(); - server.join(); - } - ((StdErrLog)Log.getLogger(HTTPSPDYServerConnector.class)).setHideStacks(false); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java deleted file mode 100644 index b86517aadc..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java +++ /dev/null @@ -1,128 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class ConcurrentStreamsTest extends AbstractHTTPSPDYTest -{ - public ConcurrentStreamsTest(short version) - { - super(version); - } - - @Test - public void testSlowStreamDoesNotBlockOtherStreams() throws Exception - { - final CountDownLatch slowServerLatch = new CountDownLatch(1); - final CountDownLatch fastServerLatch = new CountDownLatch(1); - final String fastPath = "/fast"; - final String slowPath = "/slow"; - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - try - { - request.setHandled(true); - switch (target) - { - case slowPath: - Assert.assertTrue(fastServerLatch.await(10, TimeUnit.SECONDS)); - slowServerLatch.countDown(); - break; - case fastPath: - fastServerLatch.countDown(); - break; - default: - Assert.fail(); - break; - } - } - catch (InterruptedException x) - { - throw new ServletException(x); - } - } - }, 30000), null); - - // Perform slow request. This will wait on server side until the fast request wakes it up - Fields headers = createHeaders(slowPath); - final CountDownLatch slowClientLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - slowClientLatch.countDown(); - } - }); - - // Perform the fast request. This will wake up the slow request - headers = createHeaders(fastPath); - final CountDownLatch fastClientLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - fastClientLatch.countDown(); - } - }); - - Assert.assertTrue(fastServerLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(slowServerLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(fastClientLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(slowClientLatch.await(5, TimeUnit.SECONDS)); - } - - private Fields createHeaders(String path) - { - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - headers.put(HTTPSPDYHeader.URI.name(version), path); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort()); - return headers; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java deleted file mode 100644 index 1656fd5da1..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java +++ /dev/null @@ -1,288 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class HttpTransportOverSPDYTest -{ - @Mock - Connector connector; - @Mock - HttpConfiguration httpConfiguration; - @Mock - EndPoint endPoint; - @Mock - PushStrategy pushStrategy; - @Mock - Stream stream; - @Mock - Callback callback; - @Mock - Session session; - @Mock - HttpGenerator.ResponseInfo responseInfo; - - Random random = new Random(); - short version = SPDY.V3; - - HttpTransportOverSPDY httpTransportOverSPDY; - - @Before - public void setUp() throws Exception - { - Fields requestHeaders = new Fields(); - requestHeaders.add(HTTPSPDYHeader.METHOD.name(version), "GET"); - when(responseInfo.getStatus()).thenReturn(HttpStatus.OK_200); - when(stream.getSession()).thenReturn(session); - when(session.getVersion()).thenReturn(SPDY.V3); - when(stream.isClosed()).thenReturn(false); - httpTransportOverSPDY = new HttpTransportOverSPDY(connector, httpConfiguration, endPoint, pushStrategy, - stream, requestHeaders); - } - - @Test - public void testSendWithResponseInfoNullAndContentNullAndLastContentTrue() throws Exception - { - ByteBuffer content = null; - boolean lastContent = true; - - httpTransportOverSPDY.send(null, content, lastContent, callback); - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - verify(callback, times(1)).succeeded(); - assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); - assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0)); - } - - @Test - public void testSendWithResponseInfoNullAndContentAndLastContentTrue() throws Exception - { - ByteBuffer content = createRandomByteBuffer(); - - boolean lastContent = true; - - httpTransportOverSPDY.send(null, content, lastContent, callback); - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - verify(callback, times(1)).succeeded(); - assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); - assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); - } - - @Test - public void testSendWithResponseInfoNullAndEmptyContentAndLastContentTrue() throws Exception - { - ByteBuffer content = BufferUtil.EMPTY_BUFFER; - boolean lastContent = true; - - httpTransportOverSPDY.send(null, content, lastContent, callback); - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - verify(callback, times(1)).succeeded(); - assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); - assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0)); - } - - @Test - public void testSendWithResponseInfoNullAndContentAndLastContentFalse() throws Exception - { - ByteBuffer content = createRandomByteBuffer(); - boolean lastContent = false; - - httpTransportOverSPDY.send(null, content, lastContent, callback); - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - verify(callback, times(1)).succeeded(); - assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false)); - assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(4096)); - } - - @Test(expected = IllegalStateException.class) - public void testSendWithResponseInfoNullAndContentNullAndLastContentFalse() throws Exception - { - ByteBuffer content = null; - boolean lastContent = false; - httpTransportOverSPDY.send(null, content, lastContent, callback); - } - - @Test(expected = IllegalStateException.class) - public void testSendWithResponseInfoNullAndEmptyContentAndLastContentFalse() throws Exception - { - ByteBuffer content = BufferUtil.EMPTY_BUFFER; - boolean lastContent = false; - httpTransportOverSPDY.send(null, content, lastContent, callback); - } - - @Test - public void testSendWithResponseInfoAndContentNullAndLastContentFalse() throws Exception - { - ByteBuffer content = null; - boolean lastContent = false; - - httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); - ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(false)); - - verify(stream, times(0)).data(any(ByteBufferDataInfo.class), any(Callback.class)); - verify(callback, times(1)).succeeded(); - } - - @Test - public void testSendWithResponseInfoAndContentNullAndLastContentTrue() throws Exception - { - ByteBuffer content = null; - boolean lastContent = true; - - // when stream.isClosed() is called a 2nd time, the reply has closed the stream already - when(stream.isClosed()).thenReturn(false).thenReturn(true); - - httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); - ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(true)); - - verify(callback, times(1)).succeeded(); - } - - @Test - public void testSendWithResponseInfoAndContentAndLastContentTrue() throws Exception - { - ByteBuffer content = createRandomByteBuffer(); - boolean lastContent = true; - - httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); - ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); - assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); - verify(callback, times(1)).succeeded(); - } - - @Test - public void testSendWithResponseInfoAndContentAndLastContentFalse() throws Exception - { - ByteBuffer content = createRandomByteBuffer(); - boolean lastContent = false; - - httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); - ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); - ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class); - verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); - - ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); - verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture()); - callbackCaptor.getValue().succeeded(); - assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false)); - assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); - - verify(callback, times(1)).succeeded(); - } - - @Test - public void testVerifyThatAStreamIsNotCommittedTwice() throws IOException, InterruptedException - { - final CountDownLatch failedCalledLatch = new CountDownLatch(1); - ByteBuffer content = createRandomByteBuffer(); - boolean lastContent = false; - - httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); - ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); - verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class)); - assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); - - httpTransportOverSPDY.send(HttpGenerator.RESPONSE_500_INFO, null, true, new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - failedCalledLatch.countDown(); - } - }); - - verify(stream, times(1)).data(any(DataInfo.class), any(Callback.class)); - - assertThat("callback.failed has been called", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private ByteBuffer createRandomByteBuffer() - { - ByteBuffer content = BufferUtil.allocate(8192); - BufferUtil.flipToFill(content); - byte[] randomBytes = new byte[4096]; - random.nextBytes(randomBytes); - content.put(randomBytes); - return content; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java deleted file mode 100644 index 39dd32f433..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java +++ /dev/null @@ -1,397 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Response; -import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore("make this test pass") // TODO -public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest -{ - // Sample resources size from webtide.com home page - private final int[] htmlResources = new int[] - {8 * 1024}; - private final int[] cssResources = new int[] - {12 * 1024, 2 * 1024}; - private final int[] jsResources = new int[] - {75 * 1024, 24 * 1024, 36 * 1024}; - private final int[] pngResources = new int[] - {1024, 45 * 1024, 6 * 1024, 2 * 1024, 2 * 1024, 2 * 1024, 3 * 1024, 512, 512, 19 * 1024, 512, 128, 32}; - private final Set<String> pushedResources = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); - private final AtomicReference<CountDownLatch> latch = new AtomicReference<>(); - private final long roundtrip = 100; - private final int runs = 10; - - public PushStrategyBenchmarkTest(short version) - { - super(version); - } - - @Test - public void benchmarkPushStrategy() throws Exception - { - InetSocketAddress address = startHTTPServer(version, new PushStrategyBenchmarkHandler(), 30000); - - // Plain HTTP - ConnectionFactory factory = new HttpConnectionFactory(new HttpConfiguration()); - connector.setDefaultProtocol(factory.getProtocol()); - HttpClient httpClient = new HttpClient(); - // Simulate browsers, that open 6 connection per origin - httpClient.setMaxConnectionsPerDestination(6); - httpClient.start(); - benchmarkHTTP(httpClient); - httpClient.stop(); - - // First push strategy - PushStrategy pushStrategy = new PushStrategy.None(); - factory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy); - connector.setDefaultProtocol(factory.getProtocol()); - Session session = startClient(version, address, new ClientSessionFrameListener()); - benchmarkSPDY(pushStrategy, session); - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - // Second push strategy - pushStrategy = new ReferrerPushStrategy(); - factory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy); - connector.setDefaultProtocol(factory.getProtocol()); - session = startClient(version, address, new ClientSessionFrameListener()); - benchmarkSPDY(pushStrategy, session); - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } - - private void benchmarkHTTP(HttpClient httpClient) throws Exception - { - // Warm up - performHTTPRequests(httpClient); - performHTTPRequests(httpClient); - - long total = 0; - for (int i = 0; i < runs; ++i) - { - long begin = System.nanoTime(); - int requests = performHTTPRequests(httpClient); - long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - begin); - total += elapsed; - System.err.printf("HTTP: run %d, %d request(s), roundtrip delay %d ms, elapsed = %d%n", - i, requests, roundtrip, elapsed); - } - System.err.printf("HTTP: roundtrip delay %d ms, average = %d%n%n", - roundtrip, total / runs); - } - - private int performHTTPRequests(HttpClient httpClient) throws Exception - { - int result = 0; - - for (int j = 0; j < htmlResources.length; ++j) - { - latch.set(new CountDownLatch(cssResources.length + jsResources.length + pngResources.length)); - - String primaryPath = "/" + j + ".html"; - String referrer = "http://localhost:" + connector.getLocalPort() + primaryPath; - ++result; - ContentResponse response = httpClient.newRequest("localhost", connector.getLocalPort()) - .path(primaryPath) - .timeout(5, TimeUnit.SECONDS) - .send(); - Assert.assertEquals(200, response.getStatus()); - - for (int i = 0; i < cssResources.length; ++i) - { - String path = "/" + i + ".css"; - ++result; - httpClient.newRequest("localhost", connector.getLocalPort()) - .path(path) - .header(HttpHeader.REFERER, referrer) - .send(new TestListener()); - } - for (int i = 0; i < jsResources.length; ++i) - { - String path = "/" + i + ".js"; - ++result; - httpClient.newRequest("localhost", connector.getLocalPort()) - .path(path) - .header(HttpHeader.REFERER, referrer) - .send(new TestListener()); - } - for (int i = 0; i < pngResources.length; ++i) - { - String path = "/" + i + ".png"; - ++result; - httpClient.newRequest("localhost", connector.getLocalPort()) - .path(path) - .header(HttpHeader.REFERER, referrer) - .send(new TestListener()); - } - - Assert.assertTrue(latch.get().await(5, TimeUnit.SECONDS)); - } - - return result; - } - - private void benchmarkSPDY(PushStrategy pushStrategy, Session session) throws Exception - { - // Warm up PushStrategy - performRequests(session); - performRequests(session); - - long total = 0; - for (int i = 0; i < runs; ++i) - { - long begin = System.nanoTime(); - int requests = performRequests(session); - long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - begin); - total += elapsed; - System.err.printf("SPDY(%s): run %d, %d request(s), roundtrip delay %d ms, elapsed = %d%n", - pushStrategy.getClass().getSimpleName(), i, requests, roundtrip, elapsed); - } - System.err.printf("SPDY(%s): roundtrip delay %d ms, average = %d%n%n", - pushStrategy.getClass().getSimpleName(), roundtrip, total / runs); - } - - private int performRequests(Session session) throws Exception - { - int result = 0; - - for (int j = 0; j < htmlResources.length; ++j) - { - latch.set(new CountDownLatch(cssResources.length + jsResources.length + pngResources.length)); - pushedResources.clear(); - - String primaryPath = "/" + j + ".html"; - String referrer = "http://localhost:" + connector.getLocalPort() + primaryPath; - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - headers.put(HTTPSPDYHeader.URI.name(version), primaryPath); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - headers.put(HTTPSPDYHeader.SCHEME.name(version), "http"); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort()); - // Wait for the HTML to simulate browser's behavior - ++result; - final CountDownLatch htmlLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - htmlLatch.countDown(); - } - }); - Assert.assertTrue(htmlLatch.await(5, TimeUnit.SECONDS)); - - for (int i = 0; i < cssResources.length; ++i) - { - String path = "/" + i + ".css"; - if (pushedResources.contains(path)) - continue; - headers = createRequestHeaders(referrer, path); - ++result; - session.syn(new SynInfo(headers, true), new DataListener()); - } - for (int i = 0; i < jsResources.length; ++i) - { - String path = "/" + i + ".js"; - if (pushedResources.contains(path)) - continue; - headers = createRequestHeaders(referrer, path); - ++result; - session.syn(new SynInfo(headers, true), new DataListener()); - } - for (int i = 0; i < pngResources.length; ++i) - { - String path = "/" + i + ".png"; - if (pushedResources.contains(path)) - continue; - headers = createRequestHeaders(referrer, path); - ++result; - session.syn(new SynInfo(headers, true), new DataListener()); - } - - Assert.assertTrue(latch.get().await(5, TimeUnit.SECONDS)); - } - - return result; - } - - private Fields createRequestHeaders(String referrer, String path) - { - Fields headers; - headers = new Fields(); - headers.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - headers.put(HTTPSPDYHeader.URI.name(version), path); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - headers.put(HTTPSPDYHeader.SCHEME.name(version), "http"); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort()); - headers.put("referer", referrer); - return headers; - } - - private void sleep(long delay) throws ServletException - { - try - { - TimeUnit.MILLISECONDS.sleep(delay); - } - catch (InterruptedException x) - { - throw new ServletException(x); - } - } - - private class PushStrategyBenchmarkHandler extends AbstractHandler - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - - // Sleep half of the roundtrip time, to simulate the delay of responses, even for pushed resources - sleep(roundtrip / 2); - // If it's not a pushed resource, sleep half of the roundtrip time, to simulate the delay of requests - if (request.getHeader("x-spdy-push") == null) - sleep(roundtrip / 2); - - String suffix = target.substring(target.indexOf('.') + 1); - int index = Integer.parseInt(target.substring(1, target.length() - suffix.length() - 1)); - - int contentLength; - String contentType; - switch (suffix) - { - case "html": - contentLength = htmlResources[index]; - contentType = "text/html"; - break; - case "css": - contentLength = cssResources[index]; - contentType = "text/css"; - break; - case "js": - contentLength = jsResources[index]; - contentType = "text/javascript"; - break; - case "png": - contentLength = pngResources[index]; - contentType = "image/png"; - break; - default: - throw new ServletException(); - } - - response.setContentType(contentType); - response.setContentLength(contentLength); - response.getOutputStream().write(new byte[contentLength]); - } - } - - private void addPushedResource(String pushedURI) - { - switch (version) - { - case SPDY.V2: - { - Matcher matcher = Pattern.compile("https?://[^:]+:\\d+(/.*)").matcher(pushedURI); - Assert.assertTrue(matcher.matches()); - pushedResources.add(matcher.group(1)); - break; - } - case SPDY.V3: - { - pushedResources.add(pushedURI); - break; - } - default: - { - throw new IllegalStateException(); - } - } - } - - private class ClientSessionFrameListener extends SessionFrameListener.Adapter - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - String path = synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue(); - addPushedResource(path); - return new DataListener(); - } - } - - private class DataListener extends StreamFrameListener.Adapter - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.get().countDown(); - } - } - - private class TestListener extends Response.Listener.Adapter - { - @Override - public void onComplete(Result result) - { - if (!result.isFailed()) - latch.get().countDown(); - } - } -} 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 deleted file mode 100644 index 159e742a39..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java +++ /dev/null @@ -1,1138 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetSocketAddress; -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.servlets.gzip.GzipHandler; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.log.StdErrLog; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest -{ - private static final Logger LOG = Log.getLogger(ReferrerPushStrategyTest.class); - - private final int referrerPushPeriod = 1000; - private final String mainResource = "/index.html"; - private final String cssResource = "/style.css"; - private InetSocketAddress serverAddress; - private ReferrerPushStrategy pushStrategy; - private ConnectionFactory defaultFactory; - private Fields mainRequestHeaders; - private Fields associatedCSSRequestHeaders; - private Fields associatedJSRequestHeaders; - - public ReferrerPushStrategyTest(short version) - { - super(version); - } - - @Override - protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version) - { - return new HTTPSPDYServerConnector(server, version, new HttpConfiguration(), new ReferrerPushStrategy()); - } - - @Before - public void setUp() throws Exception - { - serverAddress = createServer(); - pushStrategy = new ReferrerPushStrategy(); - pushStrategy.setReferrerPushPeriod(referrerPushPeriod); - defaultFactory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy); - connector.addConnectionFactory(defaultFactory); - if (connector.getConnectionFactory(NPNServerConnectionFactory.class) != null) - connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol()); - else - connector.setDefaultProtocol(defaultFactory.getProtocol()); - mainRequestHeaders = createHeadersWithoutReferrer(mainResource); - associatedCSSRequestHeaders = createHeaders(cssResource); - associatedJSRequestHeaders = createHeaders("/application.js"); - } - - @Test - public void testPushHeadersAreValid() throws Exception - { - sendMainRequestAndCSSRequest(null, false); - run2ndClientRequests(true, true); - } - - @Test - public void testClientResetsPushStreams() throws Exception - { - ((StdErrLog)Log.getLogger("org.eclipse.jetty.server.HttpChannel")).setHideStacks(true); - sendMainRequestAndCSSRequest(null, false); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - final CountDownLatch pushSynHeadersValid = new CountDownLatch(1); - Session session = startClient(version, serverAddress, null); - // Send main request. That should initiate the push push's which get reset by the client - sendRequest(session, mainRequestHeaders, pushSynHeadersValid, pushDataLatch, true); - - assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false)); - assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true)); - - sendRequest(session, associatedCSSRequestHeaders, pushSynHeadersValid, pushDataLatch, true); - ((StdErrLog)Log.getLogger("org.eclipse.jetty.server.HttpChannel")).setHideStacks(false); - } - - @Test - public void testUserAgentBlackList() throws Exception - { - pushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*")); - sendMainRequestAndCSSRequest(null, false); - run2ndClientRequests(false, false); - } - - @Test - public void testReferrerPushPeriod() throws Exception - { - Session session = sendMainRequestAndCSSRequest(null, false); - - // Sleep for pushPeriod This should prevent application.js from being mapped as pushResource - Thread.sleep(referrerPushPeriod + 1); - sendRequest(session, associatedJSRequestHeaders, null, null, false); - - run2ndClientRequests(false, true); - } - - @Test - public void testMaxAssociatedResources() throws Exception - { - pushStrategy.setMaxAssociatedResources(1); - Session session = sendMainRequestAndCSSRequest(null, false); - sendRequest(session, associatedJSRequestHeaders, null, null, false); - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(2); - final CountDownLatch pushSynHeadersValid = new CountDownLatch(1); - final CountDownLatch pushResponseHeaders = new CountDownLatch(1); - Session session2 = startClient(version, serverAddress, null); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid); - - assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true)); - assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)) - .getValue().endsWith - ("" + - ".css"), - is(true)); - return new StreamFrameListener.Adapter() - { - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - Fields headers = headersInfo.getHeaders(); - if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200 OK") - && validateHeader(headers, HTTPSPDYHeader.VERSION.name(version), - "HTTP/1.1") && validateHeader(headers, "content-encoding", "gzip")) - pushResponseHeaders.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false)); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - assertThat("Main request reply and/or data received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("Not more than one push is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false)); - assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true)); - assertThat("Push response headers are valid", pushResponseHeaders.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testMaxConcurrentStreamsToDisablePush() throws Exception - { - final CountDownLatch pushReceivedLatch = new CountDownLatch(1); - - Session pushCacheBuildSession = startClient(version, serverAddress, null); - - pushCacheBuildSession.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()); - pushCacheBuildSession.syn(new SynInfo(associatedCSSRequestHeaders, true), new StreamFrameListener.Adapter()); - - Session session = startClient(version, serverAddress, null); - - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0)); - SettingsInfo settingsInfo = new SettingsInfo(settings); - session.settings(settingsInfo); - - ((StdErrLog)Log.getLogger("org.eclipse.jetty.spdy.server.http" + - ".HttpTransportOverSPDY$PushResourceCoordinator$1")).setHideStacks(true); - session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushReceivedLatch.countDown(); - return super.onPush(stream, pushInfo); - } - }); - - assertThat("No push stream is received", pushReceivedLatch.await(1, TimeUnit.SECONDS), is(false)); - ((StdErrLog)Log.getLogger("org.eclipse.jetty.spdy.server.http" + - ".HttpTransportOverSPDY$PushResourceCoordinator$1")).setHideStacks(false); - } - - @Test - public void testPushResourceOrder() throws Exception - { - final CountDownLatch allExpectedPushesReceivedLatch = new CountDownLatch(4); - final CountDownLatch allPushDataReceivedLatch = new CountDownLatch(4); - - Session pushCacheBuildSession = startClient(version, serverAddress, null); - - sendRequest(pushCacheBuildSession, mainRequestHeaders, null, null, false); - sendRequest(pushCacheBuildSession, associatedCSSRequestHeaders, null, null, false); - sendRequest(pushCacheBuildSession, associatedJSRequestHeaders, null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/image1.jpg", mainResource), null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/image2.jpg", mainResource), null, null, false); - - Session session = startClient(version, serverAddress, null); - - session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - LOG.info("onPush: stream: {}, pushInfo: {}", stream, pushInfo); - String uriHeader = pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue(); - switch ((int)allExpectedPushesReceivedLatch.getCount()) - { - case 4: - assertThat("1st pushed resource is the css", uriHeader.endsWith("css"), is(true)); - break; - case 3: - assertThat("2nd pushed resource is the js", uriHeader.endsWith("js"), is(true)); - break; - case 2: - assertThat("3rd pushed resource is image1", uriHeader.endsWith("image1.jpg"), - is(true)); - break; - case 1: - assertThat("4th pushed resource is image2", uriHeader.endsWith("image2.jpg"), - is(true)); - break; - } - allExpectedPushesReceivedLatch.countDown(); - 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 - public void testThatPushResourcesAreUnique() throws Exception - { - final CountDownLatch pushReceivedLatch = new CountDownLatch(2); - sendMainRequestAndCSSRequest(null, false); - sendMainRequestAndCSSRequest(null, false); - - Session session = startClient(version, serverAddress, null); - - session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushReceivedLatch.countDown(); - LOG.info("Push received: {}", pushInfo); - return null; - } - }); - - assertThat("style.css has been pushed only once", pushReceivedLatch.await(1, TimeUnit.SECONDS), is(false)); - } - - @Test - public void testPushResourceAreSentNonInterleaved() throws Exception - { - final CountDownLatch allExpectedPushesReceivedLatch = new CountDownLatch(4); - final CountDownLatch allPushDataReceivedLatch = new CountDownLatch(4); - final CopyOnWriteArrayList<Integer> dataReceivedOrder = new CopyOnWriteArrayList<>(); - - InetSocketAddress bigResponseServerAddress = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - byte[] bytes = new byte[32768]; - new Random().nextBytes(bytes); - ServletOutputStream outputStream = response.getOutputStream(); - outputStream.write(bytes); - baseRequest.setHandled(true); - } - }, 30000); - Session pushCacheBuildSession = startClient(version, bigResponseServerAddress, null); - - Fields mainResourceHeaders = createHeadersWithoutReferrer(mainResource); - sendRequest(pushCacheBuildSession, mainResourceHeaders, null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/style.css", mainResource), null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/javascript.js", mainResource), null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/image1.jpg", mainResource), null, null, false); - sendRequest(pushCacheBuildSession, createHeaders("/image2.jpg", mainResource), null, null, false); - - Session session = startClient(version, bigResponseServerAddress, null); - - session.syn(new SynInfo(mainResourceHeaders, true), new StreamFrameListener.Adapter() - { - AtomicInteger currentStreamId = new AtomicInteger(2); - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - LOG.info("Received push for stream: {} {}", stream.getId(), pushInfo); - String uriHeader = pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue(); - switch ((int)allExpectedPushesReceivedLatch.getCount()) - { - case 4: - assertThat("1st pushed resource is the css", uriHeader.endsWith("css"), is(true)); - break; - case 3: - assertThat("2nd pushed resource is the js", uriHeader.endsWith("js"), is(true)); - break; - case 2: - assertThat("3rd pushed resource is image1", uriHeader.endsWith("image1.jpg"), - is(true)); - break; - case 1: - assertThat("4th pushed resource is image2", uriHeader.endsWith("image2.jpg"), - is(true)); - break; - } - allExpectedPushesReceivedLatch.countDown(); - return new Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - if (stream.getId() != currentStreamId.get()) - throw new IllegalStateException("Streams interleaved. Expected StreamId: " + - currentStreamId + " but was: " + stream.getId()); - dataInfo.consume(dataInfo.available()); - if (dataInfo.isClose()) - { - currentStreamId.compareAndSet(currentStreamId.get(), currentStreamId.get() + 2); - dataReceivedOrder.add(stream.getId()); - allPushDataReceivedLatch.countDown(); - } - LOG.info(stream.getId() + ":" + dataInfo); - } - }; - } - }); - - assertThat("All push resources received", allExpectedPushesReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("All pushData received", allPushDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("The data for different push streams has not been interleaved", - dataReceivedOrder.toString(), equalTo("[2, 4, 6, 8]")); - LOG.info(dataReceivedOrder.toString()); - } - - private InetSocketAddress createServer() throws Exception - { - GzipHandler gzipHandler = new GzipHandler(); - gzipHandler.setHandler(new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - output.print("<html><head/><body>HELLO</body></html>"); - else if (url.endsWith(".css")) - output.print("body { background: #FFF; }"); - else if (url.endsWith(".js")) - output.print("function(){}();"); - baseRequest.setHandled(true); - } - }); - return startHTTPServer(version, gzipHandler, 30000); - } - - private Session sendMainRequestAndCSSRequest(SessionFrameListener sessionFrameListener, boolean awaitPush) throws Exception - { - Session session = startClient(version, serverAddress, sessionFrameListener); - - CountDownLatch pushDataLatch = new CountDownLatch(2); - sendRequest(session, mainRequestHeaders, null, pushDataLatch, false); - sendRequest(session, associatedCSSRequestHeaders, null, pushDataLatch, false); - if (awaitPush) - assertThat("pushes have been received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true)); - - return session; - } - - 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() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - if (pushSynHeadersValid != null) - validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid); - - assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true)); - assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)) - .getValue().endsWith - ("" + - ".css"), - is(true)); - if (resetPush) - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertThat(replyInfo.getHeaders().get(HTTPSPDYHeader.STATUS.name(version)).getValue(), is("200 OK")); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - dataReceivedLatch.countDown(); - } - }, new Promise.Adapter<Stream>()); - assertThat(dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private void run2ndClientRequests(final boolean validateHeaders, - boolean expectPushResource) throws Exception - { - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - final CountDownLatch pushSynHeadersValid = new CountDownLatch(1); - final CountDownLatch pushResponseHeaders = new CountDownLatch(1); - Session session2 = startClient(version, serverAddress, null); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - if (validateHeaders) - validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid); - - assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true)); - assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)) - .getValue().endsWith - ("" + - ".css"), - is(true)); - return new StreamFrameListener.Adapter() - { - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - Fields headers = headersInfo.getHeaders(); - if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200 OK") - && validateHeader(headers, HTTPSPDYHeader.VERSION.name(version), - "HTTP/1.1") && validateHeader(headers, "content-encoding", "gzip")) - pushResponseHeaders.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false)); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - assertThat("Main request reply and/or data received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true)); - if (expectPushResource) - assertThat("Pushed data received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true)); - else - assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false)); - if (validateHeaders) - { - assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true)); - assertThat("Push response headers are valid", pushResponseHeaders.await(5, TimeUnit.SECONDS), is(true)); - } - } - - @Test - public void testAssociatedResourceIsPushed() throws Exception - { - InetSocketAddress address = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - output.print("<html><head/><body>HELLO</body></html>"); - else if (url.endsWith(".css")) - output.print("body { background: #FFF; }"); - baseRequest.setHandled(true); - } - }, 30000); - Session session1 = startClient(version, address, null); - - final CountDownLatch mainResourceLatch = new CountDownLatch(1); - Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource); - - session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainResourceLatch.countDown(); - } - }); - Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS)); - - sendRequest(session1, createHeaders(cssResource), null, null, false); - - // Create another client, and perform the same request for the main resource, we expect the css being pushed - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - Session session2 = startClient(version, address, null); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - Assert.assertTrue(stream.isUnidirectional()); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testAssociatedResourceWithWrongContentTypeIsNotPushed() throws Exception - { - final String fakeResource = "/fake.png"; - InetSocketAddress address = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - { - response.setContentType("text/html"); - output.print("<html><head/><body>HELLO</body></html>"); - } - else if (url.equals(fakeResource)) - { - response.setContentType("text/html"); - output.print("<html><head/><body>IMAGE</body></html>"); - } - else if (url.endsWith(".css")) - { - response.setContentType("text/css"); - output.print("body { background: #FFF; }"); - } - baseRequest.setHandled(true); - } - }, 30000); - Session session1 = startClient(version, address, null); - - final CountDownLatch mainResourceLatch = new CountDownLatch(1); - Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource); - - session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainResourceLatch.countDown(); - } - }); - Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch associatedResourceLatch = new CountDownLatch(1); - String cssResource = "/stylesheet.css"; - Fields associatedRequestHeaders = createHeaders(cssResource); - session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - associatedResourceLatch.countDown(); - } - }); - Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch fakeAssociatedResourceLatch = new CountDownLatch(1); - Fields fakeAssociatedRequestHeaders = createHeaders(fakeResource); - session1.syn(new SynInfo(fakeAssociatedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - fakeAssociatedResourceLatch.countDown(); - } - }); - Assert.assertTrue(fakeAssociatedResourceLatch.await(5, TimeUnit.SECONDS)); - - // Create another client, and perform the same request for the main resource, - // we expect the css being pushed but not the fake PNG - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - Session session2 = startClient(version, address, null); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - Assert.assertTrue(stream.isUnidirectional()); - Assert.assertTrue(pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue().endsWith("" + - ".css")); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testNestedAssociatedResourceIsPushed() throws Exception - { - InetSocketAddress address = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - output.print("<html><head/><body>HELLO</body></html>"); - else if (url.endsWith(".css")) - output.print("body { background: #FFF; }"); - else if (url.endsWith(".gif")) - output.print("\u0000"); - baseRequest.setHandled(true); - } - }, 30000); - Session session1 = startClient(version, address, null); - - final CountDownLatch mainResourceLatch = new CountDownLatch(1); - Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource); - - session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainResourceLatch.countDown(); - } - }); - Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch associatedResourceLatch = new CountDownLatch(1); - Fields associatedRequestHeaders = createHeaders(cssResource); - session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - associatedResourceLatch.countDown(); - } - }); - Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch nestedResourceLatch = new CountDownLatch(1); - String imageUrl = "/image.gif"; - Fields nestedRequestHeaders = createHeaders(imageUrl, cssResource); - - session1.syn(new SynInfo(nestedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - nestedResourceLatch.countDown(); - } - }); - Assert.assertTrue(nestedResourceLatch.await(5, TimeUnit.SECONDS)); - - // Create another client, and perform the same request for the main resource, we expect the css and the image being pushed - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(2); - Session session2 = startClient(version, address, null); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - Assert.assertTrue(stream.isUnidirectional()); - return new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return new Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testMainResourceWithReferrerIsNotPushed() throws Exception - { - InetSocketAddress address = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - output.print("<html><head/><body>HELLO</body></html>"); - baseRequest.setHandled(true); - } - }, 30000); - Session session1 = startClient(version, address, null); - - final CountDownLatch mainResourceLatch = new CountDownLatch(1); - Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource); - - session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainResourceLatch.countDown(); - } - }); - Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch associatedResourceLatch = new CountDownLatch(1); - String associatedResource = "/home.html"; - Fields associatedRequestHeaders = createHeaders(associatedResource); - - session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - associatedResourceLatch.countDown(); - } - }); - Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS)); - - // Create another client, and perform the same request for the main resource, we expect nothing being pushed - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushLatch = new CountDownLatch(1); - Session session2 = startClient(version, address, new SessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - pushLatch.countDown(); - return null; - } - }); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS)); - Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS)); - } - - @Test - public void testRequestWithIfModifiedSinceHeaderPreventsPush() throws Exception - { - InetSocketAddress address = startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - String url = request.getRequestURI(); - PrintWriter output = response.getWriter(); - if (url.endsWith(".html")) - output.print("<html><head/><body>HELLO</body></html>"); - else if (url.endsWith(".css")) - output.print("body { background: #FFF; }"); - baseRequest.setHandled(true); - } - }, 30000); - Session session1 = startClient(version, address, null); - - final CountDownLatch mainResourceLatch = new CountDownLatch(1); - Fields mainRequestHeaders = createHeaders(mainResource); - mainRequestHeaders.put("If-Modified-Since", "Tue, 27 Mar 2012 16:36:52 GMT"); - session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainResourceLatch.countDown(); - } - }); - Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch associatedResourceLatch = new CountDownLatch(1); - Fields associatedRequestHeaders = createHeaders(cssResource); - session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - associatedResourceLatch.countDown(); - } - }); - Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS)); - - // Create another client, and perform the same request for the main resource, we expect the css NOT being pushed as the main request contains an - // if-modified-since header - - final CountDownLatch mainStreamLatch = new CountDownLatch(2); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - Session session2 = startClient(version, address, new SessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(stream.isUnidirectional()); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - }); - session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - mainStreamLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - mainStreamLatch.countDown(); - } - }); - - Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS)); - Assert.assertFalse("We don't expect data to be pushed as the main request contained an if-modified-since header", pushDataLatch.await(1, TimeUnit.SECONDS)); - } - - private void validateHeaders(Fields headers, CountDownLatch pushSynHeadersValid) - { - if (validateUriHeader(headers)) - pushSynHeadersValid.countDown(); - } - - private boolean validateHeader(Fields headers, String name, String expectedValue) - { - Fields.Field header = headers.get(name); - if (header != null && expectedValue.equals(header.getValue())) - return true; - System.out.println(name + " not valid! Expected: " + expectedValue + " headers received:" + headers); - return false; - } - - private boolean validateUriHeader(Fields headers) - { - Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version)); - if (uriHeader != null) - if (version == SPDY.V2 && uriHeader.getValue().startsWith("http://")) - return true; - else if (version == SPDY.V3 && uriHeader.getValue().startsWith("/") - && headers.get(HTTPSPDYHeader.HOST.name(version)) != null && headers.get(HTTPSPDYHeader.SCHEME.name(version)) != null) - return true; - System.out.println(HTTPSPDYHeader.URI.name(version) + " not valid!"); - return false; - } - - private Fields createHeaders(String resource) - { - return createHeaders(resource, mainResource); - } - - private Fields createHeaders(String resource, String referrer) - { - Fields associatedRequestHeaders = createHeadersWithoutReferrer(resource); - associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + referrer); - return associatedRequestHeaders; - } - - private Fields createHeadersWithoutReferrer(String resource) - { - Fields requestHeaders = new Fields(); - requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) " + - "Gecko/20100101 Firefox/16.0"); - requestHeaders.put("accept-encoding", "gzip"); - requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - requestHeaders.put(HTTPSPDYHeader.URI.name(version), resource); - requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), "http"); - requestHeaders.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort()); - return requestHeaders; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java deleted file mode 100644 index 3a427cefe3..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java +++ /dev/null @@ -1,149 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Set; - -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class ReferrerPushStrategyUnitTest -{ - public static final short VERSION = SPDY.V3; - public static final String SCHEME = "http"; - public static final String HOST = "localhost"; - public static final String MAIN_URI = "/index.html"; - public static final String METHOD = "GET"; - - // class under test - private ReferrerPushStrategy referrerPushStrategy = new ReferrerPushStrategy(); - - @Mock - Stream stream; - @Mock - Session session; - - - @Before - public void setup() - { - referrerPushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*")); - } - - @Test - public void testReferrerCallsAfterTimeoutAreNotAddedAsPushResources() throws InterruptedException - { - Fields requestHeaders = getBaseHeaders(VERSION); - int referrerCallTimeout = 1000; - referrerPushStrategy.setReferrerPushPeriod(referrerCallTimeout); - setMockExpectations(); - - String referrerUrl = fillPushStrategyCache(requestHeaders); - - // sleep to pretend that the user manually clicked on a linked resource instead the browser requesting sub - // resources immediately - Thread.sleep(referrerCallTimeout + 1); - - requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image2.jpg"); - requestHeaders.put("referer", referrerUrl); - Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources is empty", pushResources.size(), is(0)); - - requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - // as the image2.jpg request has been a link and not a sub resource, we expect that pushResources.size() is - // still 2 - assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2)); - } - - @Test - public void testUserAgentFilter() throws InterruptedException - { - Fields requestHeaders = getBaseHeaders(VERSION); - setMockExpectations(); - - fillPushStrategyCache(requestHeaders); - - Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources contains two elements image.jpg and style.css as no user-agent header is present", - pushResources.size(), is(2)); - - requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4"); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources contains two elements image.jpg and style.css as chrome is not blacklisted", - pushResources.size(), is(2)); - - requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0"); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("no resources are returned as we want to filter firefox", pushResources.size(), is(0)); - } - - private Fields getBaseHeaders(short version) - { - Fields requestHeaders = new Fields(); - requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), SCHEME); - requestHeaders.put(HTTPSPDYHeader.HOST.name(version), HOST); - requestHeaders.put(HTTPSPDYHeader.URI.name(version), MAIN_URI); - requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), METHOD); - return requestHeaders; - } - - private void setMockExpectations() - { - when(stream.getSession()).thenReturn(session); - when(session.getVersion()).thenReturn(VERSION); - } - - private String fillPushStrategyCache(Fields requestHeaders) - { - Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources is empty", pushResources.size(), is(0)); - - String origin = SCHEME + "://" + HOST; - String referrerUrl = origin + MAIN_URI; - - requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image.jpg"); - requestHeaders.put("referer", referrerUrl); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources is empty", pushResources.size(), is(0)); - - requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "style.css"); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources is empty", pushResources.size(), is(0)); - - requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI); - pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields()); - assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2)); - return referrerUrl; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java deleted file mode 100644 index e0a6983b1c..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class SPDYTestUtils -{ - public static Fields createHeaders(String host, int port, short version, String httpMethod, String path) - { - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.METHOD.name(version), httpMethod); - headers.put(HTTPSPDYHeader.URI.name(version), path); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - headers.put(HTTPSPDYHeader.SCHEME.name(version), "http"); - headers.put(HTTPSPDYHeader.HOST.name(version), host + ":" + port); - return headers; - } - - public static SslContextFactory newSslContextFactory() - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslContextFactory.setProtocol("TLSv1"); - sslContextFactory.setIncludeProtocols("TLSv1"); - return sslContextFactory; - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java deleted file mode 100644 index 4756e1a182..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java +++ /dev/null @@ -1,108 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Ignore; -import org.junit.Test; - -public class SSLExternalServerTest extends AbstractHTTPSPDYTest -{ - public SSLExternalServerTest(short version) - { - // Google Servers do not support SPDY/2 anymore - super(SPDY.V3); - } - - @Override - protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) - { - SslContextFactory sslContextFactory = new SslContextFactory(); - // Force TLSv1 - sslContextFactory.setIncludeProtocols("TLSv1"); - sslContextFactory.setEndpointIdentificationAlgorithm(""); - return new SPDYClient.Factory(threadPool, null, sslContextFactory, 30000); - } - - @Test - @Ignore("Relies on an external server") - public void testExternalServer() throws Exception - { - String host = "encrypted.google.com"; - int port = 443; - InetSocketAddress address = new InetSocketAddress(host, port); - - try - { - // Test whether there is connectivity to avoid fail the test when offline - Socket socket = new Socket(); - socket.connect(address, 5000); - socket.close(); - } - catch (IOException x) - { - Assume.assumeNoException(x); - } - - Session session = startClient(version, address, null); - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.SCHEME.name(version), "https"); - headers.put(HTTPSPDYHeader.HOST.name(version), host + ":" + port); - headers.put(HTTPSPDYHeader.METHOD.name(version), "GET"); - headers.put(HTTPSPDYHeader.URI.name(version), "/"); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - final CountDownLatch latch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - Fields.Field versionHeader = headers.get(HTTPSPDYHeader.STATUS.name(version)); - if (versionHeader != null) - { - Matcher matcher = Pattern.compile("(\\d{3}).*").matcher(versionHeader.getValue()); - if (matcher.matches() && Integer.parseInt(matcher.group(1)) < 400) - latch.countDown(); - } - } - }); - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java deleted file mode 100644 index 8012510f3f..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java +++ /dev/null @@ -1,1625 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import javax.servlet.AsyncContext; -import javax.servlet.AsyncEvent; -import javax.servlet.AsyncListener; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.server.HttpChannel; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.StdErrLog; -import org.junit.Assert; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest -{ - public static final String SUSPENDED_ATTRIBUTE = ServerHTTPSPDYTest.class.getName() + ".SUSPENDED"; - - public ServerHTTPSPDYTest(short version) - { - super(version); - } - - @Test - public void testSimpleGET() throws Exception - { - final String path = "/foo"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("GET", httpRequest.getMethod()); - assertEquals(path, target); - assertEquals(path, httpRequest.getRequestURI()); - assertThat("accept-encoding is set to gzip, even if client didn't set it", - httpRequest.getHeader("accept-encoding"), containsString("gzip")); - assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort())); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), is(true)); - assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), is(notNullValue())); - assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), is(notNullValue())); - replyLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithQueryString() throws Exception - { - final String path = "/foo"; - final String query = "p=1"; - final String uri = path + "?" + query; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("GET", httpRequest.getMethod()); - assertEquals(path, target); - assertEquals(path, httpRequest.getRequestURI()); - assertEquals(query, httpRequest.getQueryString()); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithCookies() throws Exception - { - final String path = "/foo"; - final String uri = path; - final String cookie1 = "cookie1"; - final String cookie2 = "cookie2"; - final String cookie1Value = "cookie 1 value"; - final String cookie2Value = "cookie 2 value"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.addCookie(new Cookie(cookie1, cookie1Value)); - httpResponse.addCookie(new Cookie(cookie2, cookie2Value)); - assertThat("method is GET", httpRequest.getMethod(), is("GET")); - assertThat("target is /foo", target, is(path)); - assertThat("requestUri is /foo", httpRequest.getRequestURI(), is(path)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertThat("isClose is true", replyInfo.isClose(), is(true)); - Fields replyHeaders = replyInfo.getHeaders(); - assertThat("response code is 200 OK", replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue() - .contains("200"), is(true)); - assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(0), is(cookie1 + "=\"" + cookie1Value + - "\";Version=1")); - assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(1), is(cookie2 + "=\"" + cookie2Value + - "\";Version=1")); - replyLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testHEAD() throws Exception - { - final String path = "/foo"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("HEAD", httpRequest.getMethod()); - assertEquals(path, target); - assertEquals(path, httpRequest.getRequestURI()); - httpResponse.getWriter().write("body that shouldn't be sent on a HEAD request"); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "HEAD", path); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - fail("HEAD request shouldn't send any data"); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTWithDelayedContentBody() throws Exception - { - final String path = "/foo"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - // don't read the request body, reply immediately - request.setHandled(true); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); - headers.put("content-type", "application/x-www-form-urlencoded"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - stream.data(new StringDataInfo("a", false)); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - stream.data(new StringDataInfo("b", true)); - } - - @Test - public void testPOSTWithParameters() throws Exception - { - final String path = "/foo"; - final String data = "a=1&b=2"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("POST", httpRequest.getMethod()); - assertEquals("1", httpRequest.getParameter("a")); - assertEquals("2", httpRequest.getParameter("b")); - assertNotNull(httpRequest.getRemoteHost()); - assertNotNull(httpRequest.getRemotePort()); - assertNotNull(httpRequest.getRemoteAddr()); - assertNotNull(httpRequest.getLocalPort()); - assertNotNull(httpRequest.getLocalName()); - assertNotNull(httpRequest.getLocalAddr()); - assertNotNull(httpRequest.getServerPort()); - assertNotNull(httpRequest.getServerName()); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); - headers.put("content-type", "application/x-www-form-urlencoded"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - stream.data(new StringDataInfo(data, true)); - - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTWithParametersInTwoFramesTwoReads() throws Exception - { - final String path = "/foo"; - final String data1 = "a=1&"; - final String data2 = "b=2"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("POST", httpRequest.getMethod()); - assertEquals("1", httpRequest.getParameter("a")); - assertEquals("2", httpRequest.getParameter("b")); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); - headers.put("content-type", "application/x-www-form-urlencoded"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - // Sleep between the data frames so that they will be read in 2 reads - stream.data(new StringDataInfo(data1, false)); - Thread.sleep(1000); - stream.data(new StringDataInfo(data2, true)); - - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTWithParametersInTwoFramesOneRead() throws Exception - { - final String path = "/foo"; - final String data1 = "a=1&"; - final String data2 = "b=2"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("POST", httpRequest.getMethod()); - assertEquals("1", httpRequest.getParameter("a")); - assertEquals("2", httpRequest.getParameter("b")); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); - headers.put("content-type", "application/x-www-form-urlencoded"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - - // Send the data frames consecutively, so the server reads both frames in one read - stream.data(new StringDataInfo(data1, false)); - stream.data(new StringDataInfo(data2, true)); - - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithSmallResponseContent() throws Exception - { - final String data = "0123456789ABCDEF"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data.getBytes(StandardCharsets.UTF_8)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - assertTrue(dataInfo.isClose()); - assertEquals(data, dataInfo.asString(StandardCharsets.UTF_8, true)); - dataLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithOneByteResponseContent() throws Exception - { - final char data = 'x'; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - assertTrue(dataInfo.isClose()); - byte[] bytes = dataInfo.asBytes(true); - assertEquals(1, bytes.length); - assertEquals(data, bytes[0]); - dataLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithSmallResponseContentInTwoChunks() throws Exception - { - final String data1 = "0123456789ABCDEF"; - final String data2 = "FEDCBA9876543210"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data1.getBytes(StandardCharsets.UTF_8)); - output.flush(); - output.write(data2.getBytes(StandardCharsets.UTF_8)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(2); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replyFrames = new AtomicInteger(); - private final AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replyFrames.incrementAndGet()); - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int data = dataFrames.incrementAndGet(); - assertTrue(data >= 1 && data <= 2); - if (data == 1) - assertEquals(data1, dataInfo.asString(StandardCharsets.UTF_8, true)); - else - assertEquals(data2, dataInfo.asString(StandardCharsets.UTF_8, true)); - dataLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithBigResponseContentInOneWrite() throws Exception - { - final byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'x'); - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger contentBytes = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); - if (dataInfo.isClose()) - { - assertEquals(data.length, contentBytes.get()); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithBigResponseContentInMultipleWrites() throws Exception - { - final byte[] data = new byte[4 * 1024]; - Arrays.fill(data, (byte)'x'); - final int writeTimes = 16; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - for (int i = 0; i < writeTimes; i++) - { - output.write(data); - } - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger contentBytes = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); - if (dataInfo.isClose()) - { - assertEquals(data.length * writeTimes, contentBytes.get()); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithBigResponseContentInTwoWrites() throws Exception - { - final byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'y'); - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data); - output.write(data); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger contentBytes = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); - if (dataInfo.isClose()) - { - assertEquals(2 * data.length, contentBytes.get()); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithOutputStreamFlushedAndClosed() throws Exception - { - final String data = "0123456789ABCDEF"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.flush(); - output.close(); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - ByteBuffer byteBuffer = dataInfo.asByteBuffer(true); - while (byteBuffer.hasRemaining()) - buffer.write(byteBuffer.get()); - if (dataInfo.isClose()) - { - assertEquals(data, new String(buffer.toByteArray(), StandardCharsets.UTF_8)); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithResponseResetBuffer() throws Exception - { - final String data1 = "0123456789ABCDEF"; - final String data2 = "FEDCBA9876543210"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setStatus(HttpServletResponse.SC_OK); - ServletOutputStream output = httpResponse.getOutputStream(); - // Write some - output.write(data1.getBytes(StandardCharsets.UTF_8)); - // But then change your mind and reset the buffer - httpResponse.resetBuffer(); - output.write(data2.getBytes(StandardCharsets.UTF_8)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - ByteBuffer byteBuffer = dataInfo.asByteBuffer(true); - while (byteBuffer.hasRemaining()) - buffer.write(byteBuffer.get()); - if (dataInfo.isClose()) - { - assertEquals(data2, new String(buffer.toByteArray(), StandardCharsets.UTF_8)); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithRedirect() throws Exception - { - final String suffix = "/redirect"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - String location = httpResponse.encodeRedirectURL(String.format("%s://%s:%d%s", - request.getScheme(), request.getLocalAddr(), request.getLocalPort(), target + suffix)); - httpResponse.sendRedirect(location); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replies = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replies.incrementAndGet()); - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("302")); - assertTrue(replyHeaders.get("location").getValue().endsWith(suffix)); - replyLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithSendError() throws Exception - { - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replies = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replies.incrementAndGet()); - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("404")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - if (dataInfo.isClose()) - dataLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithException() throws Exception - { - StdErrLog log = StdErrLog.getLogger(HttpChannel.class); - log.setHideStacks(true); - - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - throw new NullPointerException("thrown_explicitly_by_the_test"); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch latch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replies = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replies.incrementAndGet()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("500")); - replyLatch.countDown(); - if (replyInfo.isClose()) - latch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - if (dataInfo.isClose()) - latch.countDown(); - } - }); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(latch.await(5, TimeUnit.SECONDS)); - - log.setHideStacks(false); - } - - @Test - public void testGETWithSmallResponseContentChunked() throws Exception - { - final String pangram1 = "the quick brown fox jumps over the lazy dog"; - final String pangram2 = "qualche vago ione tipo zolfo, bromo, sodio"; - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - httpResponse.setHeader("Transfer-Encoding", "chunked"); - ServletOutputStream output = httpResponse.getOutputStream(); - output.write(pangram1.getBytes(StandardCharsets.UTF_8)); - httpResponse.setHeader("EXTRA", "X"); - output.flush(); - output.write(pangram2.getBytes(StandardCharsets.UTF_8)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(2); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replyFrames = new AtomicInteger(); - private final AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replyFrames.incrementAndGet()); - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - assertTrue(replyHeaders.get("extra").getValue().contains("X")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int count = dataFrames.incrementAndGet(); - if (count == 1) - { - Assert.assertFalse(dataInfo.isClose()); - assertEquals(pangram1, dataInfo.asString(StandardCharsets.UTF_8, true)); - } - else if (count == 2) - { - assertTrue(dataInfo.isClose()); - assertEquals(pangram2, dataInfo.asString(StandardCharsets.UTF_8, true)); - } - dataLatch.countDown(); - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithMediumContentAsBufferByPassed() throws Exception - { - final byte[] data = new byte[2048]; - - final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - request.getResponse().getHttpOutput().sendContent(ByteBuffer.wrap(data)); - handlerLatch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final AtomicInteger replyFrames = new AtomicInteger(); - private final AtomicInteger contentLength = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertEquals(1, replyFrames.incrementAndGet()); - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - contentLength.addAndGet(dataInfo.asBytes(true).length); - if (dataInfo.isClose()) - { - Assert.assertEquals(data.length, contentLength.get()); - dataLatch.countDown(); - } - } - }); - assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testGETWithMultipleMediumContentByPassed() throws Exception - { - final byte[] data = new byte[2048]; - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - // The sequence of write/flush/write/write below triggers a condition where - // HttpGenerator._bypass is set to true on the second write(), and the - // third write causes an infinite spin loop on the third write(). - request.setHandled(true); - OutputStream output = httpResponse.getOutputStream(); - output.write(data); - output.flush(); - output.write(data); - output.write(data); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - final AtomicInteger contentLength = new AtomicInteger(); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.available()); - contentLength.addAndGet(dataInfo.length()); - if (dataInfo.isClose()) - dataLatch.countDown(); - } - }); - assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - assertEquals(3 * data.length, contentLength.get()); - } - - @Test - public void testPOSTThenSuspendRequestThenReadOneChunkThenComplete() throws Exception - { - final byte[] data = new byte[2000]; - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - final AsyncContext asyncContext = request.startAsync(); - new Thread() - { - @Override - public void run() - { - try - { - readRequestData(request, data.length); - asyncContext.complete(); - latch.countDown(); - } - catch (IOException x) - { - x.printStackTrace(); - } - } - }.start(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(data, true)); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTThenSuspendExpire() throws Exception - { - final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) - { - dispatchedAgainAfterExpire.countDown(); - } - else - { - AsyncContext asyncContext = request.startAsync(); - asyncContext.setTimeout(1000); - asyncContext.addListener(new AsyncListenerAdapter()); - request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); - } - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - - assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, - TimeUnit.SECONDS)); - assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTThenSuspendExpireWithRequestData() throws Exception - { - final byte[] data = new byte[2000]; - final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) - { - dispatchedAgainAfterExpire.countDown(); - } - else - { - readRequestData(request, data.length); - AsyncContext asyncContext = request.startAsync(); - asyncContext.setTimeout(1000); - asyncContext.addListener(new AsyncListenerAdapter()); - request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); - } - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(data, true)); - - assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, - TimeUnit.SECONDS)); - assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS)); - } - - private void readRequestData(Request request, int expectedDataLength) throws IOException - { - InputStream input = request.getInputStream(); - byte[] buffer = new byte[512]; - int read = 0; - while (read < expectedDataLength) - read += input.read(buffer); - } - - @Test - public void testPOSTThenSuspendRequestThenReadTwoChunksThenComplete() throws Exception - { - final byte[] data = new byte[2000]; - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - final AsyncContext asyncContext = request.startAsync(); - new Thread() - { - @Override - public void run() - { - try - { - InputStream input = request.getInputStream(); - byte[] buffer = new byte[512]; - int read = 0; - while (read < 2 * data.length) - read += input.read(buffer); - asyncContext.complete(); - latch.countDown(); - } - catch (IOException x) - { - x.printStackTrace(); - } - } - }.start(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - replyLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(data, false)); - stream.data(new BytesDataInfo(data, true)); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTThenSuspendRequestThenResumeThenRespond() throws Exception - { - final byte[] data = new byte[1000]; - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) - { - OutputStream output = httpResponse.getOutputStream(); - output.write(data); - } - else - { - final AsyncContext asyncContext = request.startAsync(); - request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); - InputStream input = request.getInputStream(); - byte[] buffer = new byte[256]; - int read = 0; - while (read < data.length) - read += input.read(buffer); - new Thread() - { - @Override - public void run() - { - try - { - TimeUnit.SECONDS.sleep(1); - asyncContext.dispatch(); - latch.countDown(); - } - catch (InterruptedException x) - { - x.printStackTrace(); - } - } - }.start(); - } - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch responseLatch = new CountDownLatch(2); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - responseLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - if (dataInfo.isClose()) - responseLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(data, true)); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testPOSTThenResponseWithoutReadingContent() throws Exception - { - final byte[] data = new byte[1000]; - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - latch.countDown(); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); - final CountDownLatch responseLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); - responseLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(data, false)); - stream.data(new BytesDataInfo(5, TimeUnit.SECONDS, data, true)); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testIdleTimeout() throws Exception - { - final int idleTimeout = 500; - final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); - - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - try - { - Thread.sleep(2 * idleTimeout); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - request.setHandled(true); - } - }, 30000), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); - timeoutReceivedLatch.countDown(); - } - }); - stream.setIdleTimeout(idleTimeout); - - assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testIdleTimeoutSetOnConnectionOnly() throws Exception - { - final int idleTimeout = 500; - final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - try - { - Thread.sleep(2 * idleTimeout); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - request.setHandled(true); - } - }, idleTimeout), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); - session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); - timeoutReceivedLatch.countDown(); - } - }); - - assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSingleStreamIdleTimeout() throws Exception - { - final int idleTimeout = 500; - final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); - final CountDownLatch replyReceivedLatch = new CountDownLatch(3); - Session session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - if ("true".equals(request.getHeader("slow"))) - { - try - { - Thread.sleep(2 * idleTimeout); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - } - request.setHandled(true); - } - }, idleTimeout), null); - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); - Fields slowHeaders = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); - slowHeaders.add("slow", "true"); - sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); - session.syn(new SynInfo(5, TimeUnit.SECONDS, slowHeaders, true, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onFailure(Stream stream, Throwable x) - { - assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); - timeoutReceivedLatch.countDown(); - } - }); - Thread.sleep(idleTimeout / 2); - sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); - Thread.sleep(idleTimeout / 2); - sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); - assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("received replies on 3 non idle requests", replyReceivedLatch.await(5, TimeUnit.SECONDS), - is(true)); - } - - private void sendSingleRequestThatIsNotExpectedToTimeout(final CountDownLatch replyReceivedLatch, Session session, Fields headers) throws ExecutionException, InterruptedException, TimeoutException - { - session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyReceivedLatch.countDown(); - } - }); - } - - private class AsyncListenerAdapter implements AsyncListener - { - @Override - public void onStartAsync(AsyncEvent event) throws IOException - { - } - - @Override - public void onComplete(AsyncEvent event) throws IOException - { - } - - @Override - public void onTimeout(AsyncEvent event) throws IOException - { - event.getAsyncContext().dispatch(); - } - - @Override - public void onError(AsyncEvent event) throws IOException - { - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java deleted file mode 100644 index 76740d6afc..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java +++ /dev/null @@ -1,160 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.http; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.hamcrest.CoreMatchers; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore("So far only used for testing performance tweaks. So no need to run it in a build") -public class SimpleHTTPBenchmarkTest extends AbstractHTTPSPDYTest -{ - private static final Logger LOG = Log.getLogger(SimpleHTTPBenchmarkTest.class); - private final int dataSize = 4096 * 100; - private Session session; - private int requestCount = 100; - - public SimpleHTTPBenchmarkTest(short version) - { - super(version); - } - - @Before - public void setUp() throws Exception - { - final byte[] data = new byte[dataSize]; - new Random().nextBytes(data); - session = startClient(version, startHTTPServer(version, new AbstractHandler() - { - @Override - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException - { - request.setHandled(true); - assertEquals("GET", httpRequest.getMethod()); - assertThat("accept-encoding is set to gzip, even if client didn't set it", - httpRequest.getHeader("accept-encoding"), containsString("gzip")); - assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort())); - httpResponse.getOutputStream().write(data); - } - }, 0), null); - } - - @Test - public void testRunBenchmark() throws Exception - { - long overallStart = System.nanoTime(); - int iterations = 20; - for (int j = 0; j < iterations; j++) - { - long start = System.nanoTime(); - for (int i = 0; i < requestCount; i++) - sendGetRequestWithData(); - long timeElapsed = System.nanoTime() - start; - LOG.info("Requests with {}b response took: {}ms", dataSize, timeElapsed / 1000 / 1000); - } - long timeElapsedOverall = (System.nanoTime() - overallStart) / 1000 / 1000; - LOG.info("Time elapsed overall: {}ms avg: {}ms", timeElapsedOverall, timeElapsedOverall / iterations); - } - - private void sendGetRequest() throws Exception - { - final CountDownLatch replyLatch = new CountDownLatch(1); - final String path = "/foo"; - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertTrue(replyInfo.isClose()); - Fields replyHeaders = replyInfo.getHeaders(); - assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), CoreMatchers.is(true)); - assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue())); - assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue())); - replyLatch.countDown(); - } - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private void sendGetRequestWithData() throws Exception - { - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - final String path = "/foo"; - - Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path); - session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields replyHeaders = replyInfo.getHeaders(); - assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), CoreMatchers.is(true)); - assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue())); - assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue())); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.available()); - if (dataInfo.isClose()) - dataLatch.countDown(); - } - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true)); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java deleted file mode 100644 index c1a3fa7084..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java +++ /dev/null @@ -1,408 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.util.StringContentProvider; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnector; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(Parameterized.class) -public class ProxyHTTPToSPDYTest -{ - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - private final short version; - private HttpClient httpClient; - private HttpClient httpClient2; - private SPDYClient.Factory factory; - private Server server; - private Server proxy; - private ServerConnector proxyConnector; - - public ProxyHTTPToSPDYTest(short version) - { - this.version = version; - } - - protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception - { - server = new Server(); - SPDYServerConnector serverConnector = new SPDYServerConnector(server, listener); - serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener)); - serverConnector.setPort(0); - server.addConnector(serverConnector); - server.start(); - return new InetSocketAddress("localhost", serverConnector.getLocalPort()); - } - - protected InetSocketAddress startProxy(InetSocketAddress address) throws Exception - { - proxy = new Server(); - ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector(); - SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory); - proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine); - proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, address.getHostName(), address.getPort())); - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, proxyEngineSelector); - proxyConnector.setPort(9999); - proxy.addConnector(proxyConnector); - proxy.start(); - return new InetSocketAddress("localhost", proxyConnector.getLocalPort()); - } - - @Before - public void init() throws Exception - { - factory = new SPDYClient.Factory(); - factory.start(); - httpClient = new HttpClient(); - httpClient.start(); - httpClient2 = new HttpClient(); - httpClient2.start(); - } - - @After - public void destroy() throws Exception - { - httpClient.stop(); - httpClient2.stop(); - if (server != null) - { - server.stop(); - server.join(); - } - if (proxy != null) - { - proxy.stop(); - proxy.join(); - } - factory.stop(); - } - - @Test - public void testClosingClientDoesNotCloseServer() throws Exception - { - final CountDownLatch closeLatch = new CountDownLatch(1); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter()); - return null; - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - closeLatch.countDown(); - } - })); - - Request request = httpClient.newRequest("localhost", proxyAddress.getPort()).method("GET"); - request.header("Connection", "close"); - ContentResponse response = request.send(); - - assertThat("response status is 200 OK", response.getStatus(), is(200)); - - // Must not close, other clients may still be connected - Assert.assertFalse(closeLatch.await(1, TimeUnit.SECONDS)); - } - - @Test - public void testGETThenNoContentFromTwoClients() throws Exception - { - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(synInfo.isClose()); - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true); - stream.reply(replyInfo, new Callback.Adapter()); - return null; - } - })); - - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET) - .send(); - assertThat("response code is 200 OK", response.getStatus(), is(200)); - - // Perform another request with another client - ContentResponse response2 = httpClient2.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET) - .send(); - assertThat("response2 code is 200 OK", response2.getStatus(), is(200)); - } - - @Test - public void testHEADRequest() throws Exception - { - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(synInfo.isClose()); - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true); - stream.reply(replyInfo, new Callback.Adapter()); - - return null; - } - })); - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.HEAD).send(); - assertThat("response code is 200 OK", response.getStatus(), is(200)); - } - - @Test - public void testGETThenSmallResponseContent() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(synInfo.isClose()); - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - responseHeaders.put("content-length", String.valueOf(data.length)); - - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false); - stream.reply(replyInfo, new Callback.Adapter()); - stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - - return null; - } - })); - - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET) - .send(); - assertThat("response code is 200 OK", response.getStatus(), is(200)); - assertThat(Arrays.equals(response.getContent(), data), is(true)); - - // Perform another request so that we are sure we reset the states of parsers and generators - ContentResponse response2 = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET) - .send(); - assertThat("response2 code is 200 OK", response2.getStatus(), is(200)); - assertThat(Arrays.equals(response2.getContent(), data), is(true)); - } - - @Test - public void testPOSTWithSmallRequestContentThenRedirect() throws Exception - { - final String data = "0123456789ABCDEF"; - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - { - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - headers.put(HTTPSPDYHeader.STATUS.name(version), "303 See Other"); - headers.put(HttpHeader.LOCATION.asString(),"http://other.location"); - stream.reply(new ReplyInfo(headers, true), new Callback.Adapter()); - } - } - }; - } - })); - - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.POST).content(new - StringContentProvider(data)).followRedirects(false).send(); - assertThat("response code is 303", response.getStatus(), is(303)); - - // Perform another request so that we are sure we reset the states of parsers and generators - ContentResponse response2 = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod - .POST).content(new StringContentProvider(data)).followRedirects(false).send(); - assertThat("response2 code is 303", response2.getStatus(), is(303)); - } - - @Test - public void testPOSTWithSmallRequestContentThenSmallResponseContent() throws Exception - { - String dataString = "0123456789ABCDEF"; - final byte[] data = dataString.getBytes(StandardCharsets.UTF_8); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - { - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - responseHeaders.put("content-length", String.valueOf(data.length)); - ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false); - stream.reply(replyInfo, new Callback.Adapter()); - stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - } - }; - } - })); - - ContentResponse response = httpClient.POST("http://localhost:" + proxyAddress.getPort() + "/").content(new - StringContentProvider(dataString)).send(); - assertThat("response status is 200 OK", response.getStatus(), is(200)); - assertThat("response content matches expected dataString", response.getContentAsString(), is(dataString)); - - // Perform another request so that we are sure we reset the states of parsers and generators - response = httpClient.POST("http://localhost:" + proxyAddress.getPort() + "/").content(new - StringContentProvider(dataString)).send(); - assertThat("response status is 200 OK", response.getStatus(), is(200)); - assertThat("response content matches expected dataString", response.getContentAsString(), is(dataString)); - } - - @Test - public void testGETThenSPDYPushIsIgnored() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - - Fields pushHeaders = new Fields(); - pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); - stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - }); - - stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter()); - return null; - } - })); - - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET).send(); - assertThat("response code is 200 OK", response.getStatus(), is(200)); - } - - @Test - public void testGETThenReset() throws Exception - { - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(synInfo.isClose()); - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter()); - - return null; - } - })); - - ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET).send(); - assertThat("response code is 502 Gateway Error", response.getStatus(), is(502)); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java deleted file mode 100644 index a50f1607d9..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java +++ /dev/null @@ -1,319 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - -@Ignore -@RunWith(value = Parameterized.class) -public abstract class ProxySPDYToHTTPLoadTest -{ - private static final Logger LOG = Log.getLogger(ProxySPDYToHTTPLoadTest.class); - - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - private final short version; - private final NegotiatingServerConnectionFactory negotiator; - private final String server1String = "server1"; - private final String server2String = "server2"; - private SPDYClient.Factory factory; - private Server server1; - private Server server2; - private Server proxy; - private ServerConnector proxyConnector; - private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory(); - - public ProxySPDYToHTTPLoadTest(short version, NegotiatingServerConnectionFactory negotiator) - { - this.version = version; - this.negotiator = negotiator; - } - - @Before - public void init() throws Exception - { - // change the ports if you want to trace the network traffic - server1 = startServer(new TestServerHandler(server1String, null), 0); - server2 = startServer(new TestServerHandler(server2String, null), 0); - factory = new SPDYClient.Factory(sslContextFactory); - factory.start(); - } - - @After - public void destroy() throws Exception - { - stopServer(server1); - stopServer(server2); - if (proxy != null) - { - proxy.stop(); - proxy.join(); - } - factory.stop(); - } - - private void stopServer(Server server) throws Exception - { - if (server != null) - { - server.stop(); - server.join(); - } - } - - protected Server startServer(Handler handler, int port) throws Exception - { - QueuedThreadPool threadPool = new QueuedThreadPool(256); - threadPool.setName("upstreamServerQTP"); - Server server = new Server(threadPool); - ServerConnector connector = new ServerConnector(server); - connector.setPort(port); - server.setHandler(handler); - server.addConnector(connector); - server.start(); - return server; - } - - private InetSocketAddress getServerAddress(Server server) - { - return new InetSocketAddress("localhost", ((ServerConnector)server.getConnectors()[0]).getLocalPort()); - } - - protected InetSocketAddress startProxy(InetSocketAddress server1, InetSocketAddress server2, - long proxyConnectorTimeout, long proxyEngineTimeout) throws Exception - { - QueuedThreadPool threadPool = new QueuedThreadPool(256); - threadPool.setName("proxyQTP"); - proxy = new Server(threadPool); - ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector(); - HttpClient httpClient = new HttpClient(); - httpClient.start(); - httpClient.setIdleTimeout(proxyEngineTimeout); - HTTPProxyEngine httpProxyEngine = new HTTPProxyEngine(httpClient); - proxyEngineSelector.putProxyEngine("http/1.1", httpProxyEngine); - - proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("http/1.1", - server1.getHostName(), server1.getPort())); - // server2 will be available at two different ProxyServerInfos with different hosts - proxyEngineSelector.putProxyServerInfo("127.0.0.1", new ProxyEngineSelector.ProxyServerInfo("http/1.1", - server2.getHostName(), server2.getPort())); - proxyEngineSelector.putProxyServerInfo("127.0.0.2", new ProxyEngineSelector.ProxyServerInfo("http/1.1", - server2.getHostName(), server2.getPort())); - - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, new HttpConfiguration(), proxyEngineSelector, negotiator); - proxyConnector.setPort(0); - proxyConnector.setIdleTimeout(proxyConnectorTimeout); - proxy.addConnector(proxyConnector); - proxy.start(); - return new InetSocketAddress("localhost", proxyConnector.getLocalPort()); - } - - @Test - public void testSimpleLoadTest() throws Exception - { - final InetSocketAddress proxyAddress = startProxy(getServerAddress(server1), getServerAddress(server2), 30000, - 30000); - - final int requestsPerClient = 50; - - ExecutorService executorService = Executors.newFixedThreadPool(3); - - Runnable client1 = createClientRunnable(proxyAddress, requestsPerClient, server1String, "localhost"); - Runnable client2 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.1"); - Runnable client3 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.2"); - - List<Future> futures = new ArrayList<>(); - - futures.add(executorService.submit(client1)); - futures.add(executorService.submit(client2)); - futures.add(executorService.submit(client3)); - - for (Future future : futures) - { - future.get(60, TimeUnit.SECONDS); - } - } - - private Runnable createClientRunnable(final InetSocketAddress proxyAddress, final int requestsPerClient, - final String serverIdentificationString, final String serverHost) - { - Runnable client = new Runnable() - { - @Override - public void run() - { - try - { - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - for (int i = 0; i < requestsPerClient; i++) - { - sendSingleClientRequest(proxyAddress, client, serverIdentificationString, serverHost); - } - } - catch (InterruptedException | ExecutionException | TimeoutException e) - { - e.printStackTrace(); - fail(); - } - } - }; - return client; - } - - private void sendSingleClientRequest(InetSocketAddress proxyAddress, Session client, final String serverIdentificationString, String serverHost) throws ExecutionException, InterruptedException, TimeoutException - { - final String data = UUID.randomUUID().toString(); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders(serverHost, proxyAddress.getPort(), version, "POST", "/"); - - Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - LOG.debug("Got reply: {}", replyInfo); - Fields headers = replyInfo.getHeaders(); - assertThat("response comes from the given server", headers.get(serverIdentificationString), - is(notNullValue())); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - LOG.debug("Got last dataFrame: {}", dataInfo); - assertThat("received data matches send data", result.toString(), is(data)); - dataLatch.countDown(); - } - } - }); - - stream.data(new StringDataInfo(data, true), new Callback.Adapter()); - - assertThat("reply has been received", replyLatch.await(15, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(15, TimeUnit.SECONDS), is(true)); - LOG.debug("Successfully received response"); - } - - private class TestServerHandler extends DefaultHandler - { - private final String responseHeader; - private final byte[] responseData; - - private TestServerHandler(String responseHeader, byte[] responseData) - { - this.responseHeader = responseHeader; - this.responseData = responseData; - } - - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException - { - assertThat("Via Header is set", baseRequest.getHeader("X-Forwarded-For"), is(notNullValue())); - assertThat("X-Forwarded-For Header is set", baseRequest.getHeader("X-Forwarded-For"), - is(notNullValue())); - assertThat("X-Forwarded-Host Header is set", baseRequest.getHeader("X-Forwarded-Host"), - is(notNullValue())); - assertThat("X-Forwarded-Proto Header is set", baseRequest.getHeader("X-Forwarded-Proto"), - is(notNullValue())); - assertThat("X-Forwarded-Server Header is set", baseRequest.getHeader("X-Forwarded-Server"), - is(notNullValue())); - baseRequest.setHandled(true); - - IO.copy(request.getInputStream(), response.getOutputStream()); - - if (responseHeader != null) - response.addHeader(responseHeader, "bar"); - if (responseData != null) - response.getOutputStream().write(responseData); - } - } - -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java deleted file mode 100644 index d12938309d..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java +++ /dev/null @@ -1,545 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpChannel; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.PingInfo; -import org.eclipse.jetty.spdy.api.PingResultInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.StdErrLog; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -@RunWith(value = Parameterized.class) -public abstract class ProxySPDYToHTTPTest -{ - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - private final short version; - private SPDYClient.Factory factory; - private Server server; - private Server proxy; - private ServerConnector proxyConnector; - private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory(); - - public ProxySPDYToHTTPTest(short version) - { - this.version = version; - } - - protected InetSocketAddress startServer(Handler handler) throws Exception - { - server = new Server(); - ServerConnector connector = new ServerConnector(server); - server.setHandler(handler); - server.addConnector(connector); - server.start(); - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected InetSocketAddress startProxy(InetSocketAddress address, long proxyConnectorTimeout, long proxyEngineTimeout) throws Exception - { - proxy = new Server(); - ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector(); - HttpClient httpClient = new HttpClient(); - httpClient.start(); - httpClient.setIdleTimeout(proxyEngineTimeout); - HTTPProxyEngine httpProxyEngine = new HTTPProxyEngine(httpClient); - proxyEngineSelector.putProxyEngine("http/1.1", httpProxyEngine); - proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("http/1.1", address.getHostName(), address.getPort())); - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector); - proxyConnector.setPort(0); - proxyConnector.setIdleTimeout(proxyConnectorTimeout); - proxy.addConnector(proxyConnector); - proxy.start(); - return new InetSocketAddress("localhost", proxyConnector.getLocalPort()); - } - - @Before - public void init() throws Exception - { - factory = new SPDYClient.Factory(sslContextFactory); - factory.start(); - } - - @After - public void destroy() throws Exception - { - if (server != null) - { - server.stop(); - server.join(); - } - if (proxy != null) - { - proxy.stop(); - proxy.join(); - } - factory.stop(); - ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false); - } - - @Test - public void testSYNThenREPLY() throws Exception - { - final String header = "foo"; - - InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - headers.put(header, "bar"); - headers.put("connection", "close"); - - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("Version header is set", headers.get(HTTPSPDYHeader.VERSION.name(version)), is(notNullValue())); - assertThat("Custom set header foo is set on response", headers.get(header), is(notNullValue())); - assertThat("HOP headers like connection are removed before forwarding", - headers.get("connection"), is(nullValue())); - replyLatch.countDown(); - } - }); - - assertThat("Reply is send to SPDY client", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSYNThenREPLYAndDATA() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - final String header = "foo"; - - InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, data)), 30000, 30000); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - headers.put(header, "bar"); - headers.put("connection", "close"); - - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("Trailer header has been filtered by proxy", headers.get("trailer"), - is(nullValue())); - assertThat("custom header exists in response", headers.get(header), is(notNullValue())); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - assertThat("received data matches send data", result.toByteArray(), is(data)); - dataLatch.countDown(); - } - } - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testHttpServerCommitsResponseTwice() throws Exception - { - final long timeout = 1000; - - InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - response.addHeader("some response", "header"); - response.flushBuffer(); - try - { - Thread.sleep(timeout * 2); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - - } - }), 30000, timeout); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch resetLatch = new CountDownLatch(1); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, new ServerSessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - resetLatch.countDown(); - } - }); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - headers.put("connection", "close"); - - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("stream is reset", resetLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testHttpServerSendsRedirect() throws Exception - { - InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - response.setStatus(HttpServletResponse.SC_FOUND); - response.setHeader("Location", "http://doesnot.exist"); - } - }), 30000, 30000); - - final CountDownLatch replyLatch = new CountDownLatch(1); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - assertThat("Status code is 302", replyInfo.getHeaders().get(HTTPSPDYHeader.STATUS.name(version)).getValue(), - is("302")); - assertThat("Location header has been received", replyInfo.getHeaders().get("Location"), is(notNullValue())); - replyLatch.countDown(); - } - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSYNWithRequestContentThenREPLYAndDATA() throws Exception - { - final String data = "0123456789ABCDEF"; - final String header = "foo"; - - InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/"); - headers.put(header, "bar"); - headers.put("connection", "close"); - - Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("custom header exists in response", headers.get(header), is(notNullValue())); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - assertThat("received data matches send data", data, is(result.toString())); - dataLatch.countDown(); - } - } - }); - - stream.data(new StringDataInfo(data, true), new Callback.Adapter()); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSYNWithSplitRequestContentThenREPLYAndDATA() throws Exception - { - final String data = "0123456789ABCDEF"; - final String data2 = "ABCDEF"; - final String header = "foo"; - - InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/"); - headers.put(header, "bar"); - headers.put("connection", "close"); - - Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("custom header exists in response", headers.get(header), is(notNullValue())); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - assertThat("received data matches send data", result.toString(), is(data + data2)); - dataLatch.countDown(); - } - } - }); - - stream.data(new StringDataInfo(data, false), new Callback.Adapter()); - stream.data(new StringDataInfo(data2, true), new Callback.Adapter()); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testClientTimeout() throws Exception - { - long timeout = 1000; - - InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(null, null)), timeout, 30000); - - final CountDownLatch goAwayLatch = new CountDownLatch(1); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayReceivedInfo) - { - goAwayLatch.countDown(); - } - }); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/"); - ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true); - client.syn(new SynInfo(headers, false), null); - assertThat("goAway has been received by proxy", goAwayLatch.await(2 * timeout, TimeUnit.MILLISECONDS), - is(true)); - } - - @Test - public void testServerTimeout() throws Exception - { - final int timeout = 1000; - final String header = "foo"; - - InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - try - { - Thread.sleep(2 * timeout); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - }), 30000, timeout); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/"); - headers.put(header, "bar"); - headers.put("connection", "close"); - - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("status is 504", headers.get(HTTPSPDYHeader.STATUS.name(version)).getValue(), is("504")); - replyLatch.countDown(); - } - - }); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testPING() throws Exception - { - // PING is per hop, and it does not carry the information to which server to ping to - // We just verify that it works - - InetSocketAddress proxyAddress = startProxy(startServer(null), 30000, 30000); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch pingLatch = new CountDownLatch(1); - Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() - { - @Override - public void onPing(Session session, PingResultInfo pingInfo) - { - pingLatch.countDown(); - } - }); - - client.ping(new PingInfo(5, TimeUnit.SECONDS)); - - Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS)); - } - - private class TestServerHandler extends DefaultHandler - { - private final String responseHeader; - private final byte[] responseData; - - private TestServerHandler(String responseHeader, byte[] responseData) - { - this.responseHeader = responseHeader; - this.responseData = responseData; - } - - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException - { - assertThat("Via Header is set", baseRequest.getHeader("X-Forwarded-For"), is(notNullValue())); - assertThat("X-Forwarded-For Header is set", baseRequest.getHeader("X-Forwarded-For"), - is(notNullValue())); - assertThat("X-Forwarded-Host Header is set", baseRequest.getHeader("X-Forwarded-Host"), - is(notNullValue())); - assertThat("X-Forwarded-Proto Header is set", baseRequest.getHeader("X-Forwarded-Proto"), - is(notNullValue())); - assertThat("X-Forwarded-Server Header is set", baseRequest.getHeader("X-Forwarded-Server"), - is(notNullValue())); - baseRequest.setHandled(true); - BufferedReader bufferedReader = request.getReader(); - int read; - while ((read = bufferedReader.read()) != -1) - response.getOutputStream().write(read); - - // add some hop header to be removed on the proxy - response.addHeader("Trailer", "bla"); - if (responseHeader != null) - response.addHeader(responseHeader, "bar"); - if (responseData != null) - response.getOutputStream().write(responseData); - } - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java deleted file mode 100644 index 6f1a596342..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java +++ /dev/null @@ -1,275 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.io.ByteArrayOutputStream; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnector; -import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(value = Parameterized.class) -public abstract class ProxySPDYToSPDYLoadTest -{ - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - private final short version; - private static final String UUID_HEADER_NAME = "uuidHeader"; - private static final String SERVER_ID_HEADER = "serverId"; - private SPDYClient.Factory factory; - private Server server; - private Server proxy; - private ServerConnector proxyConnector; - private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory(); - - public ProxySPDYToSPDYLoadTest(short version) - { - this.version = version; - } - - protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception - { - server = new Server(); - SPDYServerConnector serverConnector = new SPDYServerConnector(server, sslContextFactory, listener); - serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener)); - serverConnector.setPort(0); - server.addConnector(serverConnector); - server.start(); - return new InetSocketAddress("localhost", serverConnector.getLocalPort()); - } - - protected InetSocketAddress startProxy(InetSocketAddress server1, InetSocketAddress server2) throws Exception - { - proxy = new Server(); - ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector(); - - SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory); - proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine); - - proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, - "localhost", server1.getPort())); - // server2 will be available at two different ProxyServerInfos with different hosts - proxyEngineSelector.putProxyServerInfo("127.0.0.1", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, - "127.0.0.1", server2.getPort())); - // ProxyServerInfo is mapped to 127.0.0.2 in the proxyEngineSelector. However to be able to connect the - // ProxyServerInfo contains 127.0.0.1 as target host - proxyEngineSelector.putProxyServerInfo("127.0.0.2", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, - "127.0.0.1", server2.getPort())); - - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector); - proxyConnector.setPort(0); - proxy.addConnector(proxyConnector); - proxy.start(); - return new InetSocketAddress("localhost", proxyConnector.getLocalPort()); - } - - @Before - public void init() throws Exception - { - factory = new SPDYClient.Factory(sslContextFactory); - factory.start(); - } - - @After - public void destroy() throws Exception - { - server.stop(); - server.join(); - proxy.stop(); - proxy.join(); - factory.stop(); - } - - @Test - public void testSimpleLoadTest() throws Exception - { - String server1String = "server1"; - String server2String = "server2"; - - InetSocketAddress server1 = startServer(new TestServerFrameListener(server1String)); - InetSocketAddress server2 = startServer(new TestServerFrameListener(server2String)); - final InetSocketAddress proxyAddress = startProxy(server1, server2); - - final int requestsPerClient = 50; - - ExecutorService executorService = Executors.newFixedThreadPool(3); - - Runnable client1 = createClientRunnable(proxyAddress, requestsPerClient, server1String, "localhost"); - Runnable client2 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.1"); - Runnable client3 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.2"); - - List<Future> futures = new ArrayList<>(); - - futures.add(executorService.submit(client1)); - futures.add(executorService.submit(client2)); - futures.add(executorService.submit(client3)); - - for (Future future : futures) - { - future.get(60, TimeUnit.SECONDS); - } - } - - private Runnable createClientRunnable(final InetSocketAddress proxyAddress, final int requestsPerClient, - final String serverIdentificationString, final String serverHost) - { - Runnable client = new Runnable() - { - @Override - public void run() - { - try - { - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - for (int i = 0; i < requestsPerClient; i++) - { - sendSingleClientRequest(proxyAddress, client, serverIdentificationString, serverHost); - } - } - catch (InterruptedException | ExecutionException | TimeoutException e) - { - fail(); - e.printStackTrace(); - } - } - }; - return client; - } - - private void sendSingleClientRequest(InetSocketAddress proxyAddress, Session client, final String serverIdentificationString, String serverHost) throws ExecutionException, InterruptedException, TimeoutException - { - final String uuid = UUID.randomUUID().toString(); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - - Fields headers = SPDYTestUtils.createHeaders(serverHost, proxyAddress.getPort(), version, "POST", "/"); - headers.add(UUID_HEADER_NAME, uuid); - - Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - assertThat("uuid matches expected uuid", headers.get(UUID_HEADER_NAME).getValue(), is(uuid)); - assertThat("response comes from the given server", headers.get(SERVER_ID_HEADER).getValue(), - is(serverIdentificationString)); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - assertThat("received data matches send data", uuid, is(result.toString())); - dataLatch.countDown(); - } - } - }); - - stream.data(new StringDataInfo(uuid, true), new Callback.Adapter()); - - assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private class TestServerFrameListener extends ServerSessionFrameListener.Adapter - { - private String serverId; - - private TestServerFrameListener(String serverId) - { - this.serverId = serverId; - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - Fields.Field uuidHeader = requestHeaders.get(UUID_HEADER_NAME); - Assert.assertNotNull(uuidHeader); - - Fields responseHeaders = new Fields(); - responseHeaders.put(UUID_HEADER_NAME, uuidHeader.getValue()); - responseHeaders.put(SERVER_ID_HEADER, serverId); - stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - stream.data(dataInfo, new Callback.Adapter()); - } - }; - } - } - -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java deleted file mode 100644 index a74d54b7f6..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java +++ /dev/null @@ -1,553 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import java.io.ByteArrayOutputStream; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.PingInfo; -import org.eclipse.jetty.spdy.api.PingResultInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnector; -import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -@RunWith(value = Parameterized.class) -public abstract class ProxySPDYToSPDYTest -{ - @Parameterized.Parameters - public static Collection<Short[]> parameters() - { - return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); - } - - @Rule - public final TestTracker tracker = new TestTracker(); - private final short version; - private SPDYClient.Factory factory; - private Server server; - private Server proxy; - private ServerConnector proxyConnector; - private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory(); - - public ProxySPDYToSPDYTest(short version) - { - this.version = version; - } - - protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception - { - server = new Server(); - SPDYServerConnector serverConnector = new SPDYServerConnector(server, sslContextFactory, listener); - serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener)); - serverConnector.setPort(0); - server.addConnector(serverConnector); - server.start(); - return new InetSocketAddress("localhost", serverConnector.getLocalPort()); - } - - protected InetSocketAddress startProxy(InetSocketAddress address) throws Exception - { - proxy = new Server(); - ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector(); - SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory); - proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine); - proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, address.getHostName(), address.getPort())); - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector); - proxyConnector.setPort(0); - proxy.addConnector(proxyConnector); - proxy.start(); - return new InetSocketAddress("localhost", proxyConnector.getLocalPort()); - } - - @Before - public void init() throws Exception - { - factory = new SPDYClient.Factory(sslContextFactory); - factory.start(); - } - - @After - public void destroy() throws Exception - { - if (server != null) - { - server.stop(); - server.join(); - } - if (proxy != null) - { - proxy.stop(); - proxy.join(); - } - factory.stop(); - } - - @Test - public void testSYNThenREPLY() throws Exception - { - final String header = "foo"; - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - Assert.assertNotNull(requestHeaders.get(header)); - - Fields responseHeaders = new Fields(); - responseHeaders.put(header, "baz"); - stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter()); - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - headers.put(header, "bar"); - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - Assert.assertNotNull(headers.get(header)); - replyLatch.countDown(); - } - }); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } -@Test - public void testSYNThenRSTFromUpstreamServer() throws Exception - { - final String header = "foo"; - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - Assert.assertNotNull(requestHeaders.get(header)); - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter()); - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch resetLatch = new CountDownLatch(1); - Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - resetLatch.countDown(); - } - }); - - Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/"); - headers.put(header, "bar"); - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()); - - assertThat("reset is received by client", resetLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSYNThenREPLYAndDATA() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - final String header = "foo"; - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - Assert.assertNotNull(requestHeaders.get(header)); - - Fields responseHeaders = new Fields(); - responseHeaders.put(header, "baz"); - stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); - stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); - headers.put(header, "bar"); - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - private final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = replyInfo.getHeaders(); - Assert.assertNotNull(headers.get(header)); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - result.write(dataInfo.asBytes(true), 0, dataInfo.length()); - if (dataInfo.isClose()) - { - Assert.assertArrayEquals(data, result.toByteArray()); - dataLatch.countDown(); - } - } - }); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } - - @Test - public void testSYNThenSPDYPushIsReceived() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); - - Fields pushHeaders = new Fields(); - pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); - stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - }); - - stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch pushSynLatch = new CountDownLatch(1); - final CountDownLatch pushDataLatch = new CountDownLatch(1); - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushSynLatch.countDown(); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - dataLatch.countDown(); - } - }); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushSynLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } - - @Test - public void testSYNThenSPDYNestedPushIsReceived() throws Exception - { - final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8); - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Fields responseHeaders = new Fields(); - responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); - responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); - stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); - - final Fields pushHeaders = new Fields(); - pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); - stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/nestedpush"); - pushStream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/anothernestedpush"); - pushStream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>() - { - @Override - public void succeeded(Stream pushStream) - { - pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - }); - pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - }); - pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - } - }); - - stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); - - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch pushSynLatch = new CountDownLatch(3); - final CountDownLatch pushDataLatch = new CountDownLatch(3); - Session client = factory.newSPDYClient(version).connect(proxyAddress, null); - - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() - { - // onPush for 1st push stream - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushSynLatch.countDown(); - return new StreamFrameListener.Adapter() - { - // onPush for 2nd nested push stream - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushSynLatch.countDown(); - return new Adapter() - { - // onPush for 3rd nested push stream - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushSynLatch.countDown(); - return new Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - pushDataLatch.countDown(); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - dataLatch.countDown(); - } - }); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushSynLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } - - @Test - public void testPING() throws Exception - { - // PING is per hop, and it does not carry the information to which server to ping to - // We just verify that it works - - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter())); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch pingLatch = new CountDownLatch(1); - Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() - { - @Override - public void onPing(Session session, PingResultInfo pingInfo) - { - pingLatch.countDown(); - } - }); - - client.ping(new PingInfo(5, TimeUnit.SECONDS)); - - Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } - - @Test - public void testSYNThenReset() throws Exception - { - InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(synInfo.isClose()); - Fields requestHeaders = synInfo.getHeaders(); - Assert.assertNotNull(requestHeaders.get("via")); - - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter()); - - return null; - } - })); - proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); - - final CountDownLatch resetLatch = new CountDownLatch(1); - Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - resetLatch.countDown(); - } - }); - - Fields headers = new Fields(); - headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); - client.syn(new SynInfo(headers, true), null); - - Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); - - client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/resources/big_script.js b/jetty-spdy/spdy-http-server/src/test/resources/big_script.js deleted file mode 100644 index 37202fd211..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/resources/big_script.js +++ /dev/null @@ -1,791 +0,0 @@ -//---------------------------------------------------------------------- -// -// Silly / Pointless Javascript to test GZIP compression. -// -//---------------------------------------------------------------------- - -var LOGO = { - dat: [ - 0x50, 0x89, 0x47, 0x4e, 0x0a, 0x0d, 0x0a, 0x1a, 0x00, 0x00, 0x0d, 0x00, 0x48, 0x49, 0x52, 0x44, - 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x78, 0x00, 0x06, 0x08, 0x00, 0x00, 0x2a, 0x00, 0x21, 0x96, - 0x00, 0x0f, 0x00, 0x00, 0x73, 0x04, 0x49, 0x42, 0x08, 0x54, 0x08, 0x08, 0x7c, 0x08, 0x64, 0x08, - 0x00, 0x88, 0x00, 0x00, 0x70, 0x09, 0x59, 0x48, 0x00, 0x73, 0x04, 0x00, 0x00, 0x27, 0x04, 0x00, - 0x01, 0x27, 0x4f, 0xd9, 0x80, 0x1d, 0x00, 0x00, 0x19, 0x00, 0x45, 0x74, 0x74, 0x58, 0x6f, 0x53, - 0x74, 0x66, 0x61, 0x77, 0x65, 0x72, 0x77, 0x00, 0x77, 0x77, 0x69, 0x2e, 0x6b, 0x6e, 0x63, 0x73, - 0x70, 0x61, 0x2e, 0x65, 0x72, 0x6f, 0x9b, 0x67, 0x3c, 0xee, 0x00, 0x1a, 0x20, 0x00, 0x49, 0x00, - 0x41, 0x44, 0x78, 0x54, 0xed, 0x9c, 0x79, 0x9d, 0x1c, 0xd8, 0x95, 0x55, 0x3f, 0xff, 0xfb, 0xa7, - 0xb2, 0xdd, 0x24, 0xef, 0x24, 0x81, 0x81, 0x2c, 0x20, 0x40, 0xd5, 0x91, 0x8b, 0xb0, 0x3f, 0xbb, - 0x1d, 0x04, 0x54, 0x1c, 0x46, 0x74, 0x17, 0x18, 0xd1, 0x98, 0x19, 0xd1, 0x05, 0x11, 0x37, 0xf4, - 0xe2, 0x8f, 0xcc, 0xb8, 0x28, 0x8c, 0x82, 0x02, 0x22, 0x8c, 0xe0, 0xe8, 0xe2, 0x86, 0x02, 0x88, - 0x8e, 0xa2, 0x08, 0xe8, 0x42, 0x42, 0x4b, 0x08, 0xc2, 0xc8, 0x12, 0x12, 0xf6, 0x42, 0x7d, 0x90, - 0xf7, 0x7d, 0x3e, 0xee, 0x47, 0xf3, 0x77, 0x75, 0xeb, 0x6a, 0xdf, 0x7e, 0xee, 0xea, 0xab, 0x7b, - 0xdc, 0x93, 0xf3, 0xcf, 0xd0, 0xf0, 0xa9, 0x55, 0x53, 0xae, 0x6f, 0x5d, 0x3d, 0xd5, 0x9e, 0xf7, - 0xee, 0x7b, 0x8a, 0xf9, 0xe2, 0xaa, 0x38, 0x70, 0x0e, 0x1c, 0xc3, 0x87, 0x99, 0x2e, 0x2f, 0xb4, - 0xe1, 0xc0, 0x38, 0x70, 0x8e, 0x1c, 0x11, 0x83, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, - 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, - 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d, - 0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7, - 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, - 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, - 0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0x96, 0x81, 0x2f, 0xb4, 0x44, 0x40, - 0x2c, 0x3a, 0xe9, 0x98, 0xa7, 0x55, 0xe1, 0x3a, 0x38, 0x70, 0x8e, 0x1c, 0x42, 0x26, 0xf0, 0xd2, - 0x22, 0x4b, 0x16, 0x32, 0x0c, 0xb8, 0x02, 0xb8, 0xde, 0x38, 0xc9, 0x82, 0xe0, 0x4e, 0x80, 0xbf, - 0xa9, 0x4f, 0xbf, 0x6a, 0x7b, 0x05, 0x88, 0xb1, 0x6c, 0xc8, 0xc3, 0xe0, 0xfb, 0xc0, 0xd1, 0x81, - 0xcd, 0x86, 0x81, 0xe5, 0xc0, 0xe5, 0xab, 0xdf, 0x02, 0xea, 0xb6, 0xc3, 0x0e, 0x1c, 0xa3, 0x87, - 0x44, 0x6e, 0x12, 0x64, 0x29, 0x70, 0x41, 0xf0, 0x7a, 0x60, 0xaf, 0xc2, 0x01, 0x77, 0x80, 0xf3, - 0x55, 0x9b, 0x21, 0xf5, 0xf6, 0x0b, 0x81, 0xba, 0x81, 0xc7, 0x54, 0x5b, 0x77, 0xf5, 0xbf, 0x09, - 0xd9, 0xeb, 0xed, 0xb7, 0x45, 0x80, 0x0b, 0x24, 0x04, 0x2c, 0x5b, 0x66, 0xec, 0x35, 0x28, 0xf1, - 0xd7, 0xf0, 0xba, 0xaa, 0xb6, 0xd5, 0x11, 0x61, 0x23, 0x79, 0x27, 0xf0, 0x76, 0xdb, 0x5e, 0x81, - 0x27, 0x3c, 0xc3, 0xfc, 0x6c, 0x14, 0x1c, 0x3b, 0xc7, 0x0e, 0x10, 0xa0, 0x23, 0x91, 0x67, 0x81, - 0x91, 0x81, 0x9e, 0x75, 0x13, 0xaa, 0x4b, 0x38, 0x17, 0x55, 0xb2, 0x5b, 0x05, 0xd7, 0xa3, 0x9c, - 0x0b, 0xaa, 0x7e, 0x93, 0x8d, 0x31, 0xe0, 0x39, 0x48, 0x2b, 0xf9, 0xc7, 0x9c, 0x02, 0xbc, 0x0b, - 0xb6, 0xdb, 0x62, 0xd1, 0xe3, 0xa7, 0xdb, 0x66, 0x8b, 0x76, 0x03, 0xb4, 0xa5, 0x37, 0xdb, 0x64, - 0x70, 0xe1, 0x06, 0x38, 0x2d, 0xcb, 0xef, 0xd4, 0x01, 0x0c, 0x01, 0x86, 0x8b, 0xf7, 0xab, 0x48, - 0x7b, 0x25, 0x81, 0x43, 0x0d, 0x5f, 0x5e, 0xc2, 0x34, 0x84, 0x80, 0xe6, 0x50, 0x3f, 0x20, 0xfa, - 0x98, 0x19, 0xfa, 0xfd, 0xd7, 0xc4, 0x0c, 0x9c, 0x96, 0x55, 0x92, 0x3c, 0x0b, 0x43, 0x3d, 0xe5, - 0xcc, 0x33, 0x8c, 0x1a, 0x0e, 0x65, 0xab, 0x30, 0x31, 0xb4, 0x4d, 0xb9, 0xd6, 0x98, 0xb6, 0x6e, - 0xf3, 0xef, 0x9f, 0x6a, 0xba, 0xb2, 0xfc, 0xb7, 0xc7, 0xa3, 0xc8, 0x88, 0x55, 0x04, 0x62, 0xdd, - 0xa8, 0xd4, 0xe1, 0xc3, 0xd4, 0x70, 0x71, 0x40, 0xee, 0x7a, 0xd2, 0x82, 0xb0, 0xf6, 0x30, 0x8c, - 0x58, 0x6b, 0x36, 0xb2, 0x55, 0x72, 0x81, 0x4f, 0xfd, 0x4d, 0x88, 0xe5, 0x34, 0xee, 0x69, 0xbc, - 0x63, 0x38, 0xd6, 0xf6, 0x16, 0xf4, 0xd8, 0xd8, 0xb6, 0x57, 0x38, 0x77, 0xa8, 0x50, 0x78, 0x72, - 0x56, 0x2c, 0xb0, 0x1d, 0xb4, 0x88, 0xa7, 0x03, 0xb6, 0x95, 0x1e, 0xa7, 0xe5, 0x97, 0x9f, 0x9a, - 0x33, 0x0f, 0x73, 0x6a, 0xba, 0xdb, 0x9f, 0x02, 0x79, 0x3c, 0x7f, 0xb7, 0x34, 0xd7, 0x06, 0xa3, - 0x39, 0xe3, 0xbf, 0xdb, 0xdd, 0x71, 0x76, 0x94, 0x9f, 0x2e, 0x66, 0xd8, 0xe0, 0xd4, 0xaf, 0x95, - 0x70, 0xf4, 0xab, 0xeb, 0xfe, 0x7d, 0x87, 0x5d, 0xce, 0x03, 0x3b, 0x01, 0x8e, 0x1c, 0xe4, 0x66, - 0xff, 0x5a, 0xa7, 0xc6, 0x6d, 0x0e, 0x8b, 0xe3, 0xdb, 0x53, 0xfd, 0x07, 0x02, 0xe5, 0xfc, 0x70, - 0xbd, 0xc2, 0x07, 0x7e, 0x53, 0xbc, 0xab, 0x55, 0xc4, 0x39, 0xea, 0x6b, 0xa7, 0xb1, 0x89, 0xc0, - 0xf6, 0x8b, 0x1d, 0xfa, 0xa7, 0x70, 0x56, 0xaa, 0xf8, 0x74, 0xb0, 0x95, 0x82, 0x1d, 0x15, 0x3e, - 0x24, 0x2f, 0xc0, 0x0a, 0x73, 0x31, 0xfb, 0xcc, 0x65, 0xff, 0xe4, 0x4f, 0xbb, 0xc2, 0x1a, 0x96, - 0x1a, 0x37, 0xe0, 0x25, 0xcf, 0x80, 0x69, 0x1a, 0x77, 0xfe, 0xdd, 0xcf, 0x78, 0x13, 0xf2, 0x16, - 0x32, 0xc0, 0x46, 0xe3, 0x0e, 0x1d, 0x23, 0x87, 0x22, 0x21, 0x38, 0x72, 0x49, 0x70, 0x7b, 0x69, - 0x46, 0x68, 0xc4, 0xf8, 0x64, 0xe4, 0x94, 0x03, 0xb7, 0x7b, 0xb3, 0xf5, 0x27, 0xa2, 0x6f, 0xe0, - 0xb6, 0x2b, 0x45, 0x77, 0xef, 0x7b, 0xc7, 0xab, 0x83, 0xde, 0x72, 0x3b, 0xdf, 0x3c, 0xb0, 0x15, - 0x3c, 0xb7, 0x09, 0xd1, 0xd8, 0x8a, 0xc0, 0x76, 0x47, 0x01, 0x63, 0x34, 0xd6, 0x4e, 0xc1, 0xb8, - 0x16, 0x97, 0x3a, 0x44, 0x8f, 0x25, 0x37, 0x19, 0xe5, 0x1a, 0xd2, 0xac, 0xb1, 0x87, 0xc2, 0x2d, - 0x21, 0xcc, 0x6f, 0x66, 0xde, 0xfb, 0xb2, 0xbc, 0x2b, 0xb8, 0xbb, 0xf0, 0xa8, 0x97, 0x1e, 0xea, - 0x46, 0xa3, 0x0e, 0x1d, 0xa3, 0x87, 0x3e, 0x36, 0x2f, 0x8d, 0xfb, 0x1a, 0x43, 0xa1, 0x19, 0x5a, - 0x22, 0xdf, 0x4e, 0x89, 0xfd, 0x70, 0xbe, 0xfa, 0xae, 0xf0, 0xcd, 0x1b, 0xeb, 0xda, 0xef, 0x0d, - 0x66, 0xfa, 0x13, 0xa2, 0xb1, 0x14, 0x07, 0x3d, 0x74, 0x1c, 0xa7, 0xc0, 0x37, 0x9b, 0xd2, 0xff, - 0xc0, 0xfc, 0x38, 0x08, 0xcc, 0x0f, 0x6e, 0x37, 0x87, 0xd4, 0x1c, 0x88, 0x1c, 0x03, 0xda, 0x52, - 0x63, 0x3e, 0x96, 0x44, 0x7f, 0x64, 0xe4, 0xea, 0xd8, 0x2c, 0x27, 0x9b, 0x4c, 0x1f, 0x9f, 0x6e, - 0xd8, 0x6b, 0x01, 0xe4, 0x88, 0x83, 0x0d, 0x1c, 0x0e, 0x5c, 0x07, 0x9c, 0xff, 0x46, 0x0a, 0x54, - 0xc2, 0x6c, 0x32, 0x5b, 0x67, 0xf1, 0x46, 0x53, 0x64, 0x44, 0x5e, 0x08, 0xe1, 0xe2, 0x62, 0xdf, - 0xe9, 0x7e, 0x37, 0x5b, 0x08, 0xf0, 0x15, 0xf0, 0x8d, 0x55, 0x9e, 0x84, 0x8e, 0x1c, 0x22, 0x30, - 0x1e, 0x32, 0x48, 0xf8, 0xbb, 0x69, 0xe0, 0x45, 0x43, 0xaa, 0x8d, 0x93, 0xff, 0x46, 0x57, 0x77, - 0x67, 0x8e, 0x03, 0x3a, 0x8e, 0x03, 0xc0, 0x15, 0x9b, 0x7f, 0x37, 0xb2, 0x4f, 0x77, 0x79, 0x9e, - 0x08, 0xc1, 0x1a, 0xe3, 0xee, 0xe0, 0x27, 0x44, 0xd9, 0x29, 0xe5, 0xaf, 0x75, 0x4b, 0x1e, 0x50, - 0x8e, 0x09, 0x98, 0x9e, 0xc2, 0x61, 0xb3, 0x34, 0xc1, 0x23, 0xdd, 0xae, 0xda, 0xca, 0x03, 0x17, - 0x6a, 0x37, 0xaa, 0x91, 0x35, 0xee, 0x34, 0x6a, 0x30, 0x4a, 0x3c, 0xfc, 0xfc, 0xc2, 0x3f, 0xa8, - 0x7e, 0x14, 0xe7, 0x06, 0x07, 0x80, 0x88, 0x85, 0x1b, 0xfc, 0x59, 0xf0, 0x3a, 0xcc, 0x30, 0xde, - 0x88, 0x17, 0xa7, 0xc8, 0xf5, 0x55, 0x8d, 0x5b, 0xb1, 0x3e, 0xcc, 0x88, 0x8b, 0xc2, 0x8c, 0xf8, - 0xf4, 0x6a, 0xab, 0xb9, 0x7a, 0xf0, 0xf5, 0xe0, 0xf2, 0x22, 0x55, 0x5e, 0x6c, 0xdd, 0xae, 0xd1, - 0xff, 0x63, 0x9f, 0xe4, 0xb2, 0xf0, 0x01, 0x88, 0xef, 0x78, 0x56, 0xb8, 0x4f, 0x0e, 0xa0, 0x98, - 0xb5, 0xfa, 0xe8, 0xe8, 0x1b, 0xf7, 0xe6, 0x55, 0xeb, 0x7f, 0x17, 0xb6, 0xfa, 0x37, 0xb5, 0xad, - 0x69, 0xc3, 0x04, 0x2d, 0x22, 0x2d, 0x80, 0x33, 0xa5, 0x09, 0x1b, 0x6d, 0xe7, 0xe1, 0x4f, 0x15, - 0xb2, 0x05, 0x21, 0x9f, 0x47, 0x1d, 0x70, 0x14, 0x67, 0xc0, 0x30, 0x8f, 0xe7, 0xdf, 0xe7, 0x99, - 0x70, 0x1c, 0x44, 0x62, 0x38, 0xe4, 0x6a, 0xe0, 0x3a, 0xec, 0xf0, 0x5f, 0xc1, 0x3a, 0x8b, 0x37, - 0x39, 0xc8, 0xce, 0x06, 0x13, 0x7d, 0x9d, 0x76, 0x89, 0x6f, 0x80, 0xf3, 0x52, 0xdb, 0xeb, 0xb0, - 0x8f, 0xd8, 0x91, 0x10, 0xc0, 0x61, 0xfc, 0x27, 0xae, 0xfb, 0x6c, 0x39, 0x89, 0xf0, 0x00, 0x50, - 0x74, 0xcf, 0xf9, 0xe6, 0xae, 0xd3, 0xef, 0x80, 0x04, 0xdb, 0x65, 0xdc, 0xde, 0xca, 0x5d, 0x73, - 0x7e, 0x05, 0x23, 0xbb, 0x6f, 0x60, 0x70, 0x1b, 0xa2, 0x47, 0xf8, 0x93, 0x39, 0xb0, 0xb6, 0x02, - 0x7e, 0x1f, 0xa2, 0x7e, 0xe6, 0x29, 0xcb, 0x7f, 0xbb, 0xbf, 0xe0, 0x55, 0xe1, 0xb4, 0x3b, 0x66, - 0x05, 0x1e, 0x7e, 0x60, 0x01, 0xd0, 0x53, 0xaf, 0x35, 0xd5, 0x8d, 0x46, 0x18, 0x1e, 0x13, 0xfc, - 0xf7, 0xbe, 0x3d, 0xa1, 0x3e, 0x63, 0xdc, 0xfe, 0xec, 0x1b, 0xce, 0x1c, 0x81, 0xa4, 0x67, 0xcf, - 0x99, 0x71, 0x9b, 0xc5, 0xdb, 0x4a, 0xf1, 0x59, 0x3f, 0x9e, 0xf4, 0x93, 0x02, 0x15, 0x30, 0xeb, - 0x9a, 0x66, 0xe6, 0xb5, 0x00, 0x38, 0x02, 0xb8, 0x5b, 0x18, 0x38, 0xda, 0x4c, 0x7f, 0xb3, 0x0b, - 0x26, 0x86, 0x8d, 0x1d, 0x46, 0x46, 0x37, 0xbf, 0x6a, 0xa9, 0x85, 0x4f, 0x2f, 0xc3, 0xd7, 0xaf, - 0xd7, 0xde, 0xf4, 0x37, 0x2a, 0x12, 0x75, 0x5d, 0xaa, 0xab, 0x26, 0x76, 0x89, 0x3a, 0xf4, 0x8f, - 0x70, 0x1c, 0x19, 0x3a, 0x56, 0xd0, 0x82, 0x47, 0x32, 0x22, 0x38, 0x0e, 0xb4, 0xae, 0xca, 0x7d, - 0x2c, 0xf0, 0xf3, 0x86, 0x58, 0xaf, 0x99, 0xd2, 0x4f, 0x67, 0x02, 0x70, 0x8d, 0xd8, 0x07, 0x7e, - 0x79, 0x47, 0xda, 0x04, 0x81, 0x9e, 0xaf, 0xed, 0x89, 0x1d, 0xa5, 0xc9, 0x8b, 0xda, 0xf3, 0x3b, - 0xb2, 0x9c, 0xf0, 0x38, 0x1e, 0xde, 0x60, 0xd3, 0x81, 0x13, 0xf5, 0x11, 0x87, 0xf5, 0xf0, 0x77, - 0x84, 0xc9, 0x9e, 0x99, 0x79, 0x49, 0x73, 0xd3, 0x3c, 0x5d, 0xbb, 0xb2, 0xce, 0xfc, 0x17, 0x4d, - 0x71, 0x11, 0xd8, 0x35, 0x71, 0x1d, 0x8b, 0x14, 0x5c, 0x56, 0xdf, 0xe5, 0xed, 0x77, 0xc9, 0xa1, - 0xa3, 0x46, 0x7a, 0x2b, 0xdc, 0x0a, 0x2d, 0xbb, 0x59, 0x50, 0x37, 0x78, 0x9f, 0xf0, 0xec, 0x55, - 0xba, 0x7d, 0x7b, 0x1e, 0x7a, 0x6b, 0xfc, 0x0b, 0x6b, 0x6c, 0x5e, 0xc0, 0x5e, 0x17, 0x8f, 0x31, - 0xb1, 0x9a, 0x05, 0x99, 0x76, 0x5d, 0x6d, 0xc0, 0x84, 0x43, 0x67, 0xc3, 0x1d, 0x9b, 0xe6, 0x09, - 0xe1, 0xfb, 0x67, 0xe5, 0x23, 0x02, 0x55, 0xc1, 0xba, 0xaa, 0xa8, 0xde, 0x28, 0xd1, 0xe2, 0x67, - 0x48, 0x1b, 0x9d, 0x9d, 0xfc, 0xce, 0x3c, 0xef, 0x46, 0xe3, 0x73, 0xf7, 0x64, 0x44, 0xbe, 0x14, - 0x29, 0x42, 0x0c, 0xa7, 0x1a, 0xcb, 0xbe, 0x75, 0xfb, 0x10, 0x6a, 0x77, 0xb3, 0xf4, 0x70, 0x19, - 0xa6, 0xc0, 0xbd, 0x9f, 0xc2, 0x9c, 0x7b, 0x93, 0xbf, 0x03, 0xa3, 0x69, 0xbe, 0x73, 0x2a, 0x8e, - 0x0d, 0xfc, 0xb5, 0x30, 0x71, 0xb4, 0x88, 0xc6, 0xe7, 0x2c, 0x4c, 0x8c, 0x8c, 0xf6, 0x73, 0x7e, - 0x5f, 0x43, 0xf2, 0xb8, 0x77, 0xc5, 0x75, 0x55, 0x85, 0x57, 0xdf, 0xc3, 0xaf, 0x5f, 0x1b, 0xbd, - 0xf6, 0x37, 0x0b, 0x91, 0xd1, 0x3e, 0xa8, 0x77, 0xb6, 0xea, 0x27, 0x44, 0x61, 0x09, 0x01, 0xc5, - 0x47, 0x17, 0xc7, 0x82, 0xb6, 0x96, 0x9f, 0xa7, 0x25, 0x92, 0x78, 0x6b, 0xbc, 0x00, 0x49, 0x6a, - 0xbe, 0x9e, 0xc0, 0xee, 0x4a, 0xdd, 0xfc, 0x23, 0x68, 0x1c, 0xcf, 0x04, 0xf3, 0x72, 0xcd, 0xbf, - 0x59, 0xca, 0xde, 0xf8, 0x1b, 0x05, 0x25, 0x1d, 0x7f, 0x0b, 0xf2, 0xa7, 0x37, 0xb3, 0x23, 0x34, - 0x34, 0x9c, 0xec, 0xcc, 0x7a, 0x6f, 0x33, 0xb6, 0x57, 0x4f, 0x45, 0xc1, 0x1c, 0x5e, 0x23, 0x03, - 0x42, 0x22, 0x10, 0xa8, 0xb5, 0xc6, 0xe7, 0x09, 0x5f, 0x62, 0x57, 0xed, 0xda, 0xee, 0x08, 0x12, - 0xf7, 0x3f, 0x61, 0x52, 0x51, 0xe9, 0xec, 0x23, 0xcb, 0x6d, 0x77, 0x29, 0x0a, 0x6e, 0x7e, 0x8c, - 0xc0, 0x73, 0x89, 0x0d, 0x12, 0x4e, 0xad, 0x83, 0xf0, 0x11, 0xf8, 0x59, 0x82, 0x46, 0xc2, 0x36, - 0x2f, 0xcf, 0x48, 0x2d, 0xfc, 0x37, 0x24, 0x5c, 0x76, 0x10, 0xd3, 0x3f, 0xc3, 0x7e, 0x89, 0xde, - 0x6c, 0x57, 0x51, 0xdc, 0x50, 0x9d, 0xba, 0xa6, 0x8e, 0xf5, 0x17, 0x52, 0xfc, 0x0d, 0x89, 0x3b, - 0x14, 0xc8, 0x15, 0x7c, 0x5e, 0xdf, 0x3c, 0x3b, 0xc2, 0x4b, 0x8e, 0x65, 0x71, 0x89, 0xf7, 0x99, - 0x04, 0x8e, 0x03, 0xbc, 0x0a, 0x9f, 0xf1, 0xde, 0x32, 0x43, 0x38, 0x5c, 0xd9, 0x26, 0x77, 0x3b, - 0xc6, 0xcb, 0x70, 0xbe, 0xc5, 0x0e, 0x54, 0x8f, 0x63, 0x75, 0xc3, 0x85, 0x04, 0x2f, 0xa8, 0x4e, - 0xde, 0xc7, 0x37, 0xb7, 0x85, 0xf6, 0x98, 0x3b, 0x37, 0x77, 0xb7, 0x22, 0x96, 0xc6, 0x0e, 0x03, - 0x60, 0x25, 0x28, 0x59, 0x11, 0xc0, 0xff, 0x9d, 0x3a, 0xb5, 0x16, 0x02, 0x36, 0x91, 0x65, 0x7c, - 0x8f, 0x37, 0xc8, 0xee, 0xd1, 0x30, 0x16, 0x70, 0xba, 0xcc, 0x02, 0xbe, 0x82, 0x6b, 0xe5, 0x4f, - 0xb5, 0x13, 0x47, 0x94, 0x08, 0x3b, 0x44, 0x09, 0x4c, 0x2a, 0x94, 0x77, 0x07, 0xd6, 0x74, 0xeb, - 0xf7, 0x83, 0x6a, 0x77, 0xba, 0xe4, 0xab, 0x59, 0x67, 0xe1, 0x91, 0x70, 0x47, 0x17, 0x02, 0x22, - 0x27, 0x65, 0x73, 0x3f, 0x7b, 0x58, 0x84, 0xa2, 0xdd, 0xc7, 0xe5, 0x79, 0xc1, 0x3b, 0xbb, 0x32, - 0xe0, 0x05, 0xa6, 0xeb, 0x75, 0xec, 0x94, 0x16, 0x07, 0x6f, 0x29, 0xed, 0x7d, 0x70, 0x53, 0x82, - 0xc4, 0x54, 0x03, 0x96, 0x27, 0x2e, 0x88, 0x98, 0x31, 0xc0, 0xd9, 0xa7, 0x80, 0xc8, 0xb4, 0x0e, - 0x3b, 0x67, 0xe7, 0x81, 0x1b, 0x8c, 0x32, 0x0d, 0xe8, 0x0d, 0x6d, 0x28, 0x58, 0xd8, 0xeb, 0xff, - 0xc1, 0x1a, 0x14, 0xe4, 0x33, 0x93, 0x94, 0xe6, 0x67, 0xb6, 0x64, 0x74, 0x60, 0x98, 0xa3, 0xb8, - 0x6f, 0x34, 0xf1, 0x8f, 0x4c, 0xe8, 0xf4, 0xa8, 0x8d, 0xa9, 0x2f, 0x67, 0x9b, 0xf0, 0x93, 0x76, - 0xc9, 0x4e, 0x47, 0x57, 0x53, 0x93, 0x6e, 0x5c, 0xae, 0x57, 0x31, 0x07, 0x2d, 0xb5, 0xfb, 0xc3, - 0x27, 0xc7, 0xe4, 0x13, 0xee, 0xf9, 0x7e, 0xa6, 0x05, 0x76, 0x4d, 0x13, 0xa5, 0x7f, 0x2f, 0xaa, - 0xb0, 0x55, 0x36, 0x77, 0xf7, 0xbe, 0x16, 0xa1, 0x77, 0x7b, 0xea, 0x6e, 0x5b, 0x67, 0xf2, 0x70, - 0x41, 0xf7, 0x6d, 0x55, 0xf3, 0xc8, 0x2b, 0x6d, 0xba, 0x0b, 0x54, 0x3c, 0x0c, 0x97, 0xf1, 0x7c, - 0xb3, 0x7c, 0x30, 0xb5, 0x05, 0x0a, 0xd7, 0x65, 0xc0, 0x96, 0x9b, 0x0d, 0x42, 0x97, 0xc8, 0x42, - 0xbc, 0x5a, 0x59, 0x9e, 0xe0, 0x06, 0x3b, 0x0f, 0x9c, 0x73, 0xb8, 0xba, 0x6c, 0xe6, 0x41, 0xf5, - 0xb9, 0xb1, 0xb2, 0x3f, 0x7c, 0xf6, 0x86, 0xc0, 0x58, 0xbd, 0x75, 0x17, 0xe9, 0x22, 0x53, 0x48, - 0x16, 0x0e, 0xf6, 0x05, 0xad, 0xe0, 0xdb, 0xf1, 0xcb, 0x5e, 0x52, 0xdf, 0x0e, 0x44, 0x5e, 0x25, - 0x63, 0x88, 0x30, 0x06, 0xb4, 0xa4, 0xc7, 0x61, 0x45, 0x59, 0x4a, 0x3a, 0x45, 0xbb, 0x8c, 0xe4, - 0x9a, 0x06, 0x43, 0x78, 0x43, 0xe9, 0x38, 0x06, 0xf0, 0xc3, 0xb7, 0xd2, 0x82, 0x57, 0x30, 0xaa, - 0x55, 0xe0, 0x9a, 0x22, 0x4d, 0xe3, 0xd5, 0xbd, 0x3f, 0x44, 0x52, 0xb0, 0x77, 0x55, 0x48, 0x88, - 0x38, 0x06, 0x5f, 0x11, 0x79, 0x0d, 0xf4, 0x43, 0x2b, 0x00, 0x16, 0x92, 0x11, 0xea, 0xc3, 0x91, - 0x25, 0xf0, 0x18, 0xf7, 0x7c, 0xa2, 0xaa, 0x3f, 0x47, 0x5c, 0x70, 0x2b, 0x60, 0x12, 0x01, 0xfa, - 0x01, 0xee, 0xd7, 0x96, 0xf4, 0xb1, 0xb3, 0xe6, 0x8d, 0xfe, 0x0f, 0x2b, 0x4b, 0x6d, 0x3c, 0xb4, - 0xb7, 0xae, 0xdf, 0x00, 0x18, 0xda, 0x84, 0x29, 0x35, 0xf1, 0xf6, 0x53, 0x15, 0xfa, 0xdc, 0x6e, - 0x59, 0x10, 0x54, 0xea, 0x5e, 0xcd, 0x6c, 0x22, 0xe0, 0x39, 0x1f, 0xf2, 0x90, 0xab, 0x0d, 0x87, - 0xad, 0xcb, 0x45, 0x47, 0x6b, 0xbf, 0x20, 0xdb, 0xdb, 0x5e, 0x03, 0xb7, 0x07, 0x18, 0xd2, 0x5e, - 0xab, 0xc0, 0x56, 0xfd, 0xf7, 0x7f, 0x40, 0xcb, 0xc4, 0xa4, 0xb1, 0x61, 0xc4, 0xe0, 0xc0, 0x25, - 0x78, 0x19, 0xf2, 0x21, 0x36, 0xf1, 0xaa, 0x2f, 0xf4, 0x01, 0xc8, 0x8b, 0xc0, 0xab, 0xe0, 0x02, - 0xc0, 0xd7, 0x55, 0x03, 0x1f, 0x32, 0x91, 0x11, 0x00, 0xb7, 0x0c, 0xff, 0xcf, 0x9c, 0x1a, 0x20, - 0x1b, 0x27, 0xbf, 0xf3, 0x77, 0x73, 0x9e, 0x47, 0x86, 0x83, 0xb3, 0x84, 0x98, 0xe2, 0x34, 0x39, - 0x68, 0xc3, 0x13, 0xc3, 0xf3, 0xc0, 0xbf, 0xa2, 0x14, 0xe7, 0xf1, 0xe0, 0x4f, 0x3a, 0x2d, 0xdb, - 0x77, 0x22, 0xef, 0x00, 0x53, 0xc4, 0xb2, 0xf2, 0x16, 0xc1, 0x79, 0x11, 0xaa, 0x8f, 0x32, 0x3e, - 0x81, 0xd0, 0xf2, 0x22, 0xe0, 0x0e, 0xc0, 0xe3, 0xb0, 0x5b, 0x79, 0xd3, 0x16, 0xed, 0x2b, 0x91, - 0xf5, 0x54, 0xa1, 0x27, 0x98, 0xeb, 0x5c, 0x02, 0x5c, 0x09, 0xaf, 0x86, 0x91, 0xd0, 0x36, 0x61, - 0xc8, 0x89, 0x55, 0xbb, 0xd1, 0x35, 0x5e, 0xb4, 0x32, 0xb1, 0xdb, 0xdb, 0xdb, 0x4b, 0x5b, 0x63, - 0xcb, 0x84, 0x26, 0x27, 0x8d, 0x1b, 0x68, 0xfe, 0x5f, 0x4b, 0xb3, 0xb8, 0x67, 0xf7, 0x7d, 0x55, - 0x82, 0xb2, 0x13, 0xbd, 0x49, 0xf0, 0xd6, 0x0e, 0xef, 0x62, 0x5b, 0x67, 0x59, 0xfb, 0x17, 0xdb, - 0xd8, 0x18, 0x4d, 0xcc, 0xbb, 0xfa, 0x61, 0xab, 0xb5, 0xbc, 0xf6, 0x29, 0xaf, 0x10, 0x6d, 0x34, - 0x0a, 0xa7, 0x50, 0x7f, 0xfb, 0xd5, 0xb0, 0x53, 0x59, 0xfb, 0xce, 0x8a, 0x25, 0x37, 0xad, 0x3e, - 0xe5, 0xaa, 0x9b, 0xae, 0x4c, 0x88, 0xbe, 0x04, 0x4f, 0x81, 0x79, 0x8f, 0xa5, 0x3f, 0x6f, 0x15, - 0x31, 0xc4, 0xb8, 0x15, 0xe8, 0x18, 0x91, 0x13, 0x80, 0x07, 0x54, 0xeb, 0x30, 0x35, 0x20, 0xcd, - 0x33, 0x22, 0x07, 0x81, 0xdf, 0x8b, 0x14, 0x19, 0xe7, 0xa6, 0x3b, 0x4b, 0xca, 0x0b, 0x2e, 0xa2, - 0x1d, 0x7b, 0x73, 0xb1, 0x74, 0x6c, 0xa2, 0x28, 0xfa, 0x23, 0x30, 0x46, 0xaf, 0x04, 0x8a, 0x38, - 0x26, 0x4d, 0x7f, 0x00, 0x91, 0x14, 0x86, 0x0f, 0x9d, 0x1d, 0x11, 0x1f, 0x15, 0x39, 0x0f, 0xb8, - 0x55, 0xbb, 0x86, 0xd3, 0x3f, 0x00, 0x91, 0x16, 0xaa, 0xe9, 0x25, 0xfa, 0xfe, 0xdf, 0x00, 0x9f, - 0xb3, 0xaf, 0x1d, 0x78, 0x45, 0xe0, 0xfe, 0xcc, 0x78, 0xb7, 0x7e, 0x9f, 0xe0, 0x9a, 0xd7, 0x7b, - 0xbb, 0xe2, 0x1f, 0x67, 0xd4, 0x9f, 0xb0, 0xc6, 0xe0, 0xcc, 0x61, 0x6f, 0x6f, 0x01, 0x51, 0xe9, - 0xff, 0x88, 0xf2, 0xa8, 0x6b, 0x95, 0xb1, 0xea, 0x78, 0xa7, 0x37, 0x85, 0x34, 0x42, 0xf4, 0x6c, - 0x76, 0x0b, 0x6e, 0x7a, 0x01, 0x5f, 0x8a, 0xcc, 0x56, 0xfe, 0xfa, 0xc7, 0x57, 0xe8, 0x26, 0x44, - 0x95, 0xe3, 0x4c, 0x35, 0x35, 0x8b, 0x7a, 0xaa, 0xf1, 0x5f, 0x32, 0x5a, 0xf2, 0x22, 0xc0, 0x8f, - 0xec, 0x8b, 0xce, 0xff, 0x8e, 0x37, 0x3c, 0x36, 0xbc, 0x47, 0x44, 0x50, 0x26, 0xbe, 0x43, 0x22, - 0xff, 0x7d, 0x4d, 0xf6, 0x38, 0x12, 0xf1, 0xdf, 0xc2, 0x2d, 0x86, 0xb1, 0xa5, 0x2b, 0xb1, 0x3c, - 0x22, 0x27, 0x61, 0x94, 0x3b, 0x14, 0xc7, 0xb5, 0x28, 0x0f, 0x85, 0xdd, 0xe0, 0x16, 0x01, 0xd2, - 0xb9, 0x8e, 0xfb, 0x01, 0x4b, 0x25, 0x7c, 0x4b, 0xf4, 0xb8, 0x44, 0x41, 0xc2, 0x2e, 0xf3, 0xbe, - 0xd1, 0x2d, 0x27, 0x8a, 0x31, 0xf0, 0xe2, 0x28, 0x00, 0x24, 0x9e, 0x3f, 0x30, 0xb0, 0xaf, 0xcc, - 0xf5, 0xb7, 0x52, 0xf3, 0x72, 0x50, 0xa1, 0x70, 0xfe, 0xaa, 0x82, 0xa1, 0x69, 0xbd, 0x6b, 0x78, - 0x6b, 0x7f, 0x17, 0xb6, 0x39, 0x23, 0x1c, 0xf8, 0x9b, 0xf0, 0x27, 0x44, 0x00, 0x19, 0x21, 0x1b, - 0x0b, 0xe8, 0x1f, 0x4b, 0x8f, 0x86, 0xde, 0x15, 0xb9, 0x7a, 0xa9, 0xd9, 0xae, 0x9c, 0xca, 0x5d, - 0xbf, 0xef, 0xe8, 0x1b, 0xcc, 0xb5, 0x6a, 0x30, 0x9e, 0x30, 0xe1, 0xb7, 0x57, 0x9b, 0xcb, 0x7c, - 0x16, 0xe8, 0x31, 0x4e, 0x0e, 0xbc, 0x4f, 0xf3, 0x72, 0xbb, 0xb5, 0x3c, 0x10, 0xaf, 0x54, 0xc2, - 0xe9, 0x11, 0x53, 0xc0, 0xfa, 0x7f, 0xf0, 0x39, 0xb8, 0xae, 0x4c, 0xef, 0x13, 0x6e, 0x19, 0x4e, - 0xe5, 0x96, 0x21, 0xb8, 0x5a, 0x19, 0x9f, 0x6a, 0x33, 0xaf, 0x02, 0x8e, 0x72, 0xbb, 0x86, 0xca, - 0x02, 0xbe, 0xfa, 0x1b, 0x95, 0x95, 0x05, 0x3d, 0xe4, 0x76, 0x5e, 0x22, 0x15, 0xac, 0xc7, 0xaf, - 0x57, 0xfb, 0x72, 0x22, 0xb0, 0x3e, 0x2f, 0x05, 0x08, 0x3c, 0x94, 0xc0, 0x0c, 0xb6, 0x3b, 0x7f, - 0xba, 0xa1, 0x3e, 0x2f, 0xdd, 0xb2, 0x3d, 0xfc, 0xc8, 0xe8, 0xe2, 0x48, 0x88, 0x35, 0xf0, 0xf5, - 0x51, 0xc6, 0x5f, 0x66, 0x02, 0xf1, 0xce, 0xf0, 0xad, 0x31, 0x38, 0x5c, 0x71, 0xa6, 0x0c, 0xe7, - 0xcb, 0x3d, 0x7b, 0xbc, 0x2b, 0x5c, 0x3b, 0xd3, 0x76, 0xcc, 0x7e, 0x8c, 0xad, 0xb1, 0x95, 0x9f, - 0x1a, 0xfb, 0x8a, 0xf7, 0x86, 0x6d, 0x8c, 0x88, 0xe7, 0xc1, 0x8e, 0xf4, 0xcf, 0x68, 0x49, 0x70, - 0xa4, 0xc2, 0xa4, 0x9e, 0xbd, 0xc4, 0xc5, 0xdb, 0x8b, 0x72, 0xf9, 0x17, 0xfb, 0x8f, 0x21, 0xc8, - 0x8c, 0xad, 0xb5, 0x6f, 0x9f, 0x7a, 0x4e, 0x8e, 0xd5, 0xf0, 0xf0, 0xab, 0x9b, 0xf9, 0xd7, 0x0f, - 0x01, 0x22, 0x1d, 0x18, 0x56, 0xfd, 0xba, 0x9b, 0x0a, 0xb9, 0xe7, 0x5f, 0x16, 0xbb, 0x5f, 0x7b, - 0x8a, 0x8b, 0x5c, 0x2e, 0xe8, 0xdf, 0x22, 0x5c, 0x6f, 0xa3, 0x31, 0x67, 0x58, 0x04, 0x63, 0x9e, - 0xfe, 0x3c, 0x16, 0xec, 0xfa, 0xfe, 0x8e, 0xea, 0xdf, 0x2a, 0x9f, 0xa8, 0x1f, 0x67, 0x0f, 0xea, - 0xe0, 0x3b, 0x36, 0x06, 0x83, 0x0d, 0x90, 0x26, 0xfa, 0x85, 0x0f, 0xff, 0xe7, 0x6b, 0xc3, 0x5c, - 0x3d, 0xc9, 0xbc, 0xcf, 0x08, 0x10, 0x0a, 0x03, 0xcd, 0x5e, 0x2f, 0xd3, 0x72, 0x11, 0xad, 0xbe, - 0x57, 0x02, 0xda, 0x1d, 0x27, 0xce, 0xb5, 0x26, 0xb9, 0x31, 0x79, 0xad, 0x6e, 0x9d, 0xf2, 0x35, - 0x8f, 0x0a, 0xce, 0xec, 0xef, 0x71, 0x1c, 0xb6, 0x6f, 0x77, 0x64, 0x8d, 0x1e, 0x44, 0x3c, 0x0b, - 0x17, 0x8a, 0x2a, 0x2a, 0xf4, 0xdf, 0xc6, 0x0b, 0xf0, 0xb4, 0x69, 0xd5, 0x1c, 0xf6, 0x25, 0x5f, - 0x1a, 0xce, 0xb5, 0x91, 0x2a, 0x32, 0x45, 0xb5, 0xf8, 0x06, 0x83, 0x72, 0xeb, 0xef, 0xe0, 0xc2, - 0xcc, 0xb3, 0x87, 0xf5, 0x33, 0xb7, 0x70, 0xcd, 0xb2, 0x69, 0x83, 0xbb, 0x06, 0x25, 0x4d, 0xab, - 0x05, 0x1d, 0x1a, 0x6a, 0x34, 0x5c, 0xfc, 0xd6, 0x15, 0x73, 0xb7, 0x7a, 0x78, 0x33, 0xda, 0x6d, - 0x7c, 0x46, 0x4c, 0xed, 0x06, 0x47, 0x39, 0x6e, 0x08, 0x6a, 0x5f, 0xa6, 0xd0, 0xe9, 0x1a, 0x7d, - 0xdb, 0x54, 0x2c, 0x5a, 0x74, 0xc4, 0x69, 0x79, 0x45, 0xbb, 0x53, 0xe0, 0x25, 0x09, 0xff, 0x00, - 0xea, 0x1c, 0x01, 0x94, 0x81, 0x2b, 0x98, 0x5f, 0x37, 0xb2, 0x4f, 0x77, 0xc7, 0x9e, 0x24, 0x1b, - 0x58, 0x39, 0xd3, 0x0d, 0xe8, 0x21, 0x7a, 0xc0, 0x63, 0xc4, 0xb0, 0xcf, 0x80, 0x51, 0x32, 0x23, - 0xb5, 0x1f, 0xb8, 0xc0, 0x28, 0xd1, 0x05, 0xd6, 0x9e, 0x18, 0x3e, 0x08, 0x1b, 0x2c, 0xf7, 0x81, - 0xd3, 0xe2, 0x04, 0xbd, 0x6f, 0x38, 0x0b, 0x64, 0x9c, 0xcf, 0x9c, 0x38, 0x4e, 0xaf, 0xdf, 0x6b, - 0x9d, 0x6f, 0x78, 0x2f, 0x02, 0xc2, 0x1c, 0x6f, 0xc2, 0xd5, 0x47, 0xad, 0xf0, 0x75, 0xc9, 0xc2, - 0xb9, 0xc3, 0x42, 0x6c, 0x38, 0x6b, 0x78, 0x1e, 0x10, 0x18, 0xf7, 0x90, 0x90, 0x3b, 0xde, 0x9c, - 0x4c, 0x81, 0x4c, 0x58, 0x4a, 0x64, 0xc6, 0x5b, 0xf3, 0xb8, 0x59, 0x8d, 0xff, 0x3f, 0x95, 0x54, - 0xad, 0xc3, 0x8b, 0xca, 0xbc, 0xc6, 0x1b, 0xdb, 0x75, 0x54, 0x31, 0x63, 0xa3, 0xa7, 0x02, 0x3c, - 0x75, 0x3d, 0xd6, 0x58, 0xf3, 0xb8, 0xb9, 0x8d, 0xb1, 0x4f, 0x4f, 0xc9, 0x04, 0x31, 0x00, 0x24, - 0x19, 0x2f, 0x83, 0x5f, 0x60, 0x04, 0xf4, 0x74, 0x8d, 0xfb, 0x35, 0x2a, 0x3e, 0x0e, 0x6f, 0x81, - 0xb3, 0xda, 0x7b, 0x16, 0xa3, 0x31, 0x6f, 0xdf, 0x6a, 0xaa, 0xdc, 0x7f, 0xf5, 0xb1, 0xd5, 0x60, - 0xdb, 0x01, 0x40, 0x51, 0x5d, 0x4a, 0x61, 0x80, 0x3e, 0x2c, 0x86, 0x01, 0x87, 0x93, 0x17, 0x99, - 0x58, 0x60, 0x99, 0xda, 0x77, 0x67, 0x14, 0x70, 0xc1, 0x98, 0xb8, 0x4b, 0x73, 0x2a, 0xc4, 0xc5, - 0xfe, 0x36, 0xc2, 0x74, 0x66, 0x50, 0xbe, 0x9a, 0xcb, 0x18, 0xd2, 0x1c, 0x7c, 0x2a, 0xe8, 0xff, - 0xfc, 0x21, 0xd8, 0xe2, 0x55, 0xa1, 0x37, 0xeb, 0x58, 0xdb, 0xe4, 0x5e, 0x9f, 0xa8, 0xba, 0xe7, - 0xcf, 0x82, 0x13, 0x72, 0x9f, 0xae, 0x96, 0x0f, 0x1d, 0x97, 0xb6, 0x69, 0x8b, 0x4d, 0xb7, 0x79, - 0xd7, 0x4b, 0x96, 0x76, 0xe7, 0x7f, 0x86, 0xd9, 0x03, 0xaf, 0xab, 0x6a, 0x10, 0x33, 0x01, 0x27, - 0x75, 0x78, 0x11, 0x42, 0x67, 0x84, 0xf3, 0x3b, 0xb4, 0x3c, 0xd0, 0x33, 0x6f, 0xae, 0x7e, 0x06, - 0xc1, 0x50, 0xd0, 0xde, 0xed, 0x7a, 0xd7, 0x3d, 0xe0, 0x55, 0x0d, 0x77, 0x1c, 0x94, 0x86, 0xac, - 0x07, 0x35, 0x31, 0xdc, 0x38, 0x4c, 0x96, 0x7c, 0x01, 0x79, 0x95, 0x86, 0x83, 0x0b, 0x0a, 0x61, - 0x7d, 0x55, 0xa8, 0xd5, 0x28, 0xd1, 0x10, 0x81, 0x4a, 0x55, 0x0c, 0x02, 0xf1, 0x13, 0x5f, 0x85, - 0x3f, 0x5f, 0x85, 0xaa, 0x1d, 0x6f, 0x36, 0x69, 0x9f, 0xf4, 0x17, 0x36, 0x6d, 0x8d, 0xbe, 0xe1, - 0x86, 0xe3, 0x96, 0xc6, 0x9c, 0x5c, 0x26, 0xdc, 0x69, 0x1c, 0x5d, 0x5a, 0xd1, 0xc1, 0xc2, 0x10, - 0xb2, 0xcf, 0x75, 0x95, 0xd1, 0xd9, 0x54, 0x65, 0x8e, 0xb1, 0x58, 0xa5, 0xee, 0xdd, 0xa5, 0xb5, - 0xa3, 0xed, 0x32, 0x3a, 0x32, 0x4c, 0xb4, 0x5c, 0x4a, 0xa5, 0x4f, 0x89, 0xd5, 0xeb, 0x62, 0xce, - 0xcf, 0x96, 0x46, 0x0d, 0xe5, 0xe8, 0x7c, 0x72, 0xfd, 0x21, 0x49, 0x06, 0xde, 0x0e, 0x45, 0x5c, - 0xf0, 0x72, 0xf8, 0x23, 0x3d, 0xa6, 0x41, 0x9b, 0xb0, 0x72, 0xc6, 0x1a, 0xa5, 0x5a, 0xe1, 0x62, - 0xa3, 0x83, 0xdb, 0x4a, 0x9f, 0x47, 0x25, 0x96, 0xf8, 0x63, 0x59, 0x19, 0x38, 0xb5, 0x5f, 0x4f, - 0xea, 0x4f, 0xe1, 0x05, 0xa8, 0x53, 0x54, 0x42, 0x19, 0x79, 0xd1, 0xc8, 0x19, 0x1d, 0x99, 0xee, - 0xc4, 0x31, 0x16, 0xb8, 0x33, 0x6c, 0xe6, 0xf0, 0x2d, 0x51, 0x74, 0x7c, 0x74, 0x62, 0xe7, 0xae, - 0x0b, 0x4c, 0x71, 0x4b, 0x8d, 0x1c, 0x34, 0x21, 0xc6, 0xef, 0x16, 0x39, 0xcb, 0x1c, 0x41, 0x63, - 0x05, 0x9b, 0xaf, 0x2a, 0x3e, 0x61, 0x5f, 0x05, 0xbb, 0x75, 0x4b, 0x94, 0x96, 0x7c, 0x19, 0xdb, - 0x4e, 0xc1, 0xf9, 0x9d, 0x67, 0x50, 0xc7, 0x20, 0xd3, 0x00, 0x8d, 0x7b, 0x1c, 0x90, 0xb9, 0x7c, - 0xc0, 0xa7, 0xb7, 0x2f, 0x22, 0x07, 0x7b, 0xbf, 0xdb, 0x80, 0xd8, 0x2a, 0xa1, 0x6b, 0xc9, 0x4e, - 0xd5, 0xc1, 0x24, 0x06, 0xab, 0x07, 0x72, 0x61, 0x90, 0x58, 0xfc, 0xc2, 0xf3, 0x6f, 0x30, 0x09, - 0xa4, 0xa4, 0x54, 0x80, 0xc6, 0xe6, 0x3a, 0x23, 0x6b, 0x18, 0x12, 0xba, 0x13, 0x7f, 0xdd, 0x71, - 0xf6, 0xd4, 0xb6, 0x48, 0x9b, 0xa3, 0xdd, 0xff, 0xf0, 0x7f, 0x46, 0x8f, 0x67, 0x87, 0xd9, 0x85, - 0xcd, 0x43, 0xed, 0xfe, 0xe6, 0xf6, 0x25, 0x95, 0x75, 0xc1, 0x4b, 0xd9, 0x75, 0x54, 0x85, 0x77, - 0xad, 0xc3, 0xff, 0xce, 0xbc, 0x42, 0x8a, 0xb8, 0x0c, 0x88, 0xeb, 0xc1, 0x00, 0x0c, 0xdc, 0x70, - 0x8c, 0x90, 0x77, 0xf1, 0x4f, 0x7c, 0x3e, 0xf4, 0x54, 0x2d, 0xae, 0xd5, 0xbe, 0x01, 0x7e, 0xf6, - 0xd5, 0x7c, 0x6a, 0xe7, 0x1c, 0x95, 0x2d, 0x0c, 0xbb, 0xdb, 0x55, 0x5d, 0x56, 0x77, 0xfc, 0x38, - 0xf8, 0x7d, 0xb6, 0x8a, 0x62, 0xd4, 0x26, 0xef, 0x92, 0x03, 0xd5, 0x83, 0xe7, 0xb0, 0x6d, 0x80, - 0xff, 0xcc, 0xec, 0xa6, 0xc3, 0x80, 0x2a, 0x21, 0x02, 0x5b, 0xa1, 0x0c, 0xfe, 0xc2, 0x26, 0x65, - 0x0a, 0xb5, 0x1d, 0x6f, 0x70, 0x7d, 0xfe, 0x8d, 0xb4, 0xc6, 0xff, 0x08, 0xca, 0x1a, 0xb5, 0x4a, - 0x52, 0x31, 0xd4, 0x71, 0xc6, 0xcf, 0xe5, 0x3e, 0xdf, 0x15, 0x7c, 0xb3, 0xf0, 0xfa, 0x59, 0x2c, - 0x7d, 0xc3, 0x27, 0xc7, 0x46, 0xf6, 0x65, 0xd6, 0x7a, 0x0f, 0xf7, 0xfe, 0xc3, 0x6c, 0xeb, 0x9d, - 0xa2, 0x2a, 0x73, 0x1d, 0x2d, 0xf0, 0xb1, 0xb1, 0xff, 0x31, 0xf0, 0x9b, 0x35, 0x3e, 0x02, 0x44, - 0x53, 0x70, 0x72, 0x54, 0x8f, 0xb0, 0x92, 0x0a, 0x45, 0x83, 0xb2, 0xea, 0x35, 0xb7, 0x72, 0x5e, - 0x9b, 0xf0, 0x4e, 0x89, 0x10, 0x92, 0x0e, 0x93, 0xdc, 0xf8, 0x87, 0xd2, 0x0b, 0x6c, 0x3f, 0x4c, - 0x82, 0xd5, 0x52, 0x02, 0x03, 0x30, 0x0d, 0x3a, 0x86, 0x01, 0x88, 0x40, 0xa5, 0x2a, 0x92, 0x04, - 0x7f, 0x32, 0xa1, 0x33, 0x78, 0xd5, 0xd6, 0x03, 0xbc, 0x8c, 0xec, 0x6b, 0x75, 0xbe, 0x43, 0x99, - 0x18, 0x32, 0xc2, 0xd7, 0x34, 0x75, 0xb0, 0x86, 0x45, 0x48, 0xf9, 0x4a, 0xd5, 0x13, 0x4b, 0x1c, - 0xf1, 0x39, 0x4c, 0x69, 0x30, 0x8b, 0xe1, 0x33, 0x62, 0xdc, 0x62, 0x52, 0x9c, 0x0a, 0xc2, 0x44, - 0x60, 0xcf, 0x9d, 0xa9, 0xe4, 0x19, 0xb9, 0x3c, 0xba, 0x8f, 0x00, 0x25, 0xd9, 0x6f, 0x47, 0xd8, - 0xee, 0xb0, 0x3f, 0x06, 0xd5, 0x56, 0x71, 0xf5, 0x8a, 0xc7, 0x05, 0xc8, 0xec, 0xc0, 0xec, 0x7a, - 0x16, 0xdd, 0x1c, 0x95, 0x99, 0xfc, 0xae, 0xaa, 0x74, 0x4e, 0x84, 0x92, 0x79, 0x18, 0x44, 0x82, - 0x24, 0x64, 0x9a, 0xf0, 0xf6, 0xd2, 0xb3, 0xe1, 0xb4, 0xb3, 0x35, 0x0f, 0x09, 0xeb, 0xad, 0x36, - 0xb0, 0x2a, 0x73, 0x6b, 0xaf, 0xe0, 0x78, 0xf5, 0x02, 0x0a, 0xcd, 0x0c, 0x62, 0xf0, 0xb9, 0x94, - 0x42, 0x6c, 0xb5, 0xb2, 0x07, 0x6f, 0x87, 0x0a, 0x0a, 0xb4, 0x8a, 0x63, 0xb9, 0x21, 0x86, 0xd3, - 0x0f, 0x67, 0xf9, 0x8a, 0x03, 0xef, 0xf0, 0x81, 0x6f, 0xfc, 0x25, 0x93, 0x1d, 0x60, 0x1c, 0x03, - 0xda, 0x52, 0x63, 0x3e, 0xd6, 0x44, 0x29, 0x78, 0x2a, 0xac, 0x66, 0xd7, 0x9d, 0xbd, 0x41, 0xa9, - 0xb9, 0xef, 0x09, 0x2e, 0x3d, 0xc0, 0xe5, 0x79, 0x9b, 0x3b, 0x12, 0x22, 0x46, 0x80, 0x07, 0x25, - 0x8d, 0x6f, 0x0e, 0x4a, 0xb4, 0x36, 0x64, 0xec, 0xa6, 0x1c, 0x17, 0x62, 0xe2, 0x67, 0xee, 0x73, - 0xc2, 0x36, 0xcb, 0xcf, 0x5e, 0x53, 0x54, 0x7e, 0x94, 0x24, 0x95, 0x80, 0x1d, 0x5e, 0xe9, 0xde, - 0x99, 0x1d, 0xd9, 0xc4, 0xf5, 0x7f, 0x6c, 0xf0, 0x9e, 0x67, 0x6d, 0xef, 0x67, 0xea, 0x4f, 0x45, - 0x97, 0x81, 0x0a, 0x7b, 0x30, 0x28, 0x4d, 0xa5, 0xd6, 0x98, 0xe1, 0x9e, 0xa3, 0x6d, 0xf8, 0x5b, - 0x00, 0xc0, 0xa8, 0x55, 0x4d, 0x1a, 0x4d, 0x69, 0xfc, 0xe4, 0x79, 0x3d, 0x3f, 0xc6, 0xa7, 0xb9, - 0xb1, 0xea, 0x1e, 0x37, 0xc1, 0xd1, 0x86, 0xa5, 0xef, 0xaf, 0xcf, 0xcd, 0xf1, 0x77, 0xa7, 0x6c, - 0x1a, 0x9d, 0xc7, 0xd0, 0xc9, 0x0e, 0x77, 0x30, 0xd9, 0x96, 0xaf, 0xea, 0xde, 0x3f, 0xcf, 0xd2, - 0xab, 0x95, 0x25, 0x2a, 0xd6, 0xa2, 0xa7, 0x46, 0xc6, 0x2f, 0x15, 0x99, 0x04, 0x2f, 0x92, 0x6d, - 0x7a, 0xbc, 0x55, 0xa1, 0xeb, 0x1f, 0x8c, 0xab, 0x82, 0x78, 0x8f, 0xcb, 0x3b, 0xec, 0x02, 0xbd, - 0xbf, 0x30, 0xda, 0x18, 0x8f, 0x2d, 0x27, 0xc4, 0x0a, 0xb6, 0x1b, 0x47, 0x12, 0xae, 0x73, 0x16, - 0x56, 0x9f, 0xea, 0xa9, 0x4a, 0xc6, 0x37, 0xc7, 0x02, 0x42, 0xf6, 0xf0, 0xfd, 0x4d, 0x0c, 0xec, - 0xc6, 0x4e, 0x5a, 0xfe, 0x5f, 0x55, 0x60, 0xac, 0x4c, 0xef, 0x11, 0x7c, 0x5a, 0xd7, 0x07, 0x25, - 0x07, 0xb7, 0xfd, 0xed, 0x51, 0xb6, 0x83, 0x92, 0x30, 0xd5, 0x21, 0xe5, 0xaf, 0xec, 0x6d, 0xff, - 0x04, 0xb2, 0xb1, 0xac, 0x62, 0x2d, 0xcd, 0x7c, 0xde, 0xed, 0xb2, 0xbc, 0x42, 0xb8, 0xff, 0x61, - 0x59, 0xd7, 0xf7, 0x5a, 0x5d, 0xda, 0x2f, 0x80, 0xed, 0xae, 0xa6, 0xe1, 0x91, 0x8d, 0x09, 0x64, - 0xf7, 0x56, 0x8d, 0x7a, 0xdd, 0xc8, 0xfb, 0x5b, 0x7f, 0xb9, 0x8e, 0x47, 0xa7, 0x3b, 0x30, 0x77, - 0x42, 0xc2, 0x7c, 0x4c, 0x5e, 0x4f, 0xd4, 0xd9, 0x5d, 0xef, 0xbf, 0x4c, 0x7e, 0x12, 0x23, 0x91, - 0x6a, 0x9c, 0xa1, 0xb8, 0x2a, 0xef, 0x73, 0x28, 0xe7, 0x77, 0xb7, 0xe8, 0x8f, 0x14, 0x9d, 0x31, - 0x04, 0xb8, 0x97, 0xf0, 0xb9, 0xdd, 0xef, 0x01, 0x3d, 0x6b, 0x1e, 0xcc, 0x35, 0x9a, 0xac, 0xfe, - 0xe9, 0x2c, 0xb3, 0xca, 0xf8, 0x27, 0x56, 0xd0, 0xb9, 0x53, 0x74, 0x09, 0x4d, 0xae, 0x5c, 0x8b, - 0xbc, 0xc4, 0x4b, 0xdb, 0x75, 0x55, 0x51, 0x57, 0x68, 0x51, 0x69, 0x74, 0x8d, 0xa7, 0xcf, 0x24, - 0x5d, 0xc5, 0xf6, 0x79, 0xaf, 0xc6, 0xae, 0x45, 0x5d, 0x44, 0x80, 0x12, 0x0a, 0x7d, 0x27, 0x37, - 0x1c, 0x93, 0x8c, 0x0c, 0x1b, 0x7e, 0x39, 0x24, 0x4d, 0x58, 0xa1, 0xe4, 0x98, 0x61, 0x10, 0xf2, - 0xfa, 0xe7, 0x52, 0x37, 0x80, 0xa8, 0x60, 0x35, 0x7c, 0x8a, 0x49, 0xa3, 0x44, 0x23, 0x20, 0xb5, - 0x18, 0x9a, 0xe6, 0x51, 0x16, 0x75, 0xdf, 0x46, 0x57, 0x00, 0xea, 0xaf, 0x86, 0xe1, 0xa6, 0x68, - 0x84, 0x62, 0xb7, 0x7b, 0xf3, 0xf5, 0x3b, 0x3f, 0x14, 0xed, 0x5f, 0xed, 0x13, 0xd1, 0x94, 0x9f, - 0xc7, 0x16, 0x0b, 0x18, 0xa5, 0x1d, 0xf7, 0x27, 0xad, 0xe6, 0x5f, 0x39, 0x2d, 0x48, 0xd9, 0x24, - 0x9a, 0x50, 0xfe, 0x70, 0x6a, 0xd7, 0xbb, 0x75, 0x77, 0x98, 0x3e, 0x3b, 0x6c, 0xfc, 0xa3, 0xa1, - 0xe4, 0x9d, 0x35, 0x3e, 0x02, 0x42, 0xc7, 0xf0, 0xfa, 0x5b, 0x10, 0xd9, 0x1c, 0x94, 0x44, 0x7c, - 0x9f, 0x55, 0x60, 0xa8, 0x26, 0x6f, 0x64, 0x9e, 0xcd, 0x65, 0x62, 0xf6, 0x07, 0x24, 0x35, 0xe7, - 0x72, 0x52, 0x1a, 0xb0, 0x6f, 0x0d, 0x8b, 0xa5, 0xbf, 0x6b, 0x94, 0xe6, 0x27, 0xb6, 0xcf, 0x4d, - 0x72, 0x30, 0x59, 0xbc, 0xd4, 0x57, 0x4b, 0xb5, 0xbf, 0x59, 0x71, 0x2c, 0x7c, 0x8a, 0x69, 0xa3, - 0x79, 0x86, 0x32, 0x99, 0x6b, 0xa6, 0x83, 0x4f, 0x48, 0xd7, 0xbe, 0xdc, 0xd2, 0x29, 0x04, 0x73, - 0x72, 0xaf, 0x37, 0x4c, 0x09, 0x30, 0x33, 0xdf, 0x60, 0xb6, 0x9e, 0x6f, 0x8f, 0x77, 0x1f, 0x33, - 0x5e, 0x8a, 0x75, 0x1e, 0x6b, 0xc0, 0xed, 0x81, 0xcf, 0xc5, 0xf0, 0xc3, 0xf0, 0x95, 0xd3, 0x3b, - 0x47, 0x42, 0xe6, 0x29, 0xb4, 0xef, 0x6f, 0x12, 0x63, 0x3d, 0x98, 0xa3, 0x4f, 0x81, 0xc3, 0xfc, - 0xb3, 0xf4, 0x35, 0xb7, 0x2c, 0xa7, 0x0e, 0xeb, 0xe3, 0xdc, 0xc0, 0xdd, 0x75, 0x2b, 0x76, 0x9e, - 0xbe, 0x0a, 0x0d, 0x82, 0x54, 0xcd, 0xab, 0x01, 0x5b, 0x58, 0x6a, 0xd8, 0xbb, 0x75, 0x4e, 0x2a, - 0xd0, 0x2f, 0x58, 0xce, 0x8b, 0x59, 0x2c, 0x9c, 0xab, 0x01, 0xc9, 0x6e, 0x1b, 0xc1, 0x12, 0xa2, - 0xb6, 0x80, 0x07, 0x25, 0x8c, 0xad, 0xc1, 0x7e, 0x08, 0x4c, 0x54, 0xfa, 0x8d, 0x7c, 0x95, 0x81, - 0x47, 0xe5, 0xe6, 0x4f, 0x04, 0xd0, 0xf2, 0x29, 0xb0, 0x86, 0xa2, 0x1a, 0xca, 0x82, 0xd0, 0x19, - 0xda, 0xd3, 0x1c, 0x33, 0xb8, 0x61, 0x93, 0xf2, 0x1f, 0x02, 0xd9, 0x5d, 0xc8, 0x43, 0xdd, 0xd5, - 0x7c, 0x07, 0x34, 0xac, 0x54, 0x3f, 0xcb, 0x2c, 0x5e, 0x59, 0xb7, 0x43, 0x73, 0xa8, 0x23, 0xf0, - 0x7a, 0xd3, 0xde, 0x58, 0xb1, 0x1d, 0x89, 0xf3, 0x26, 0x92, 0x88, 0xb4, 0x10, 0x7c, 0x19, 0x5f, - 0x94, 0xbb, 0xe5, 0x12, 0xae, 0xde, 0xcb, 0xaa, 0x71, 0x1a, 0xe2, 0xee, 0xe0, 0x9c, 0x8a, 0x36, - 0xdc, 0xef, 0x16, 0x21, 0x04, 0xe6, 0xc9, 0xc3, 0xc0, 0x52, 0x55, 0xf7, 0x53, 0xf5, 0x9c, 0xf5, - 0x44, 0x53, 0x8f, 0x7e, 0x22, 0xa7, 0xa4, 0x06, 0x80, 0x92, 0x17, 0xb5, 0x54, 0x58, 0x50, 0xe1, - 0x4e, 0xfb, 0x10, 0x6f, 0xb0, 0x15, 0x64, 0x86, 0xce, 0xbc, 0xe5, 0x80, 0xd9, 0x6b, 0xc4, 0x0d, - 0x8d, 0xce, 0x42, 0x36, 0xf0, 0x02, 0xed, 0xbe, 0xe1, 0xfd, 0xdd, 0xce, 0x55, 0x22, 0x7d, 0xfd, - 0x7b, 0x05, 0xf0, 0x53, 0x22, 0x49, 0x48, 0x36, 0xf0, 0x72, 0x1a, 0x79, 0x39, 0x2c, 0x0d, 0x58, - 0x5e, 0x13, 0x7e, 0xc2, 0xf9, 0xf8, 0x81, 0x89, 0x68, 0x7b, 0x1a, 0xc5, 0xef, 0xa1, 0xce, 0x01, - 0xb9, 0x20, 0x67, 0x96, 0x58, 0x01, 0x7c, 0x07, 0x55, 0x5b, 0x55, 0x77, 0xa6, 0x38, 0x92, 0xfc, - 0x59, 0xb6, 0x60, 0x12, 0x5f, 0x98, 0x01, 0xc1, 0x98, 0xdb, 0x7d, 0xff, 0x6f, 0x7a, 0xc5, 0x9e, - 0xa4, 0xd1, 0x1e, 0xa2, 0x3a, 0xe0, 0x27, 0xd9, 0x18, 0x6d, 0x7f, 0xa8, 0xc1, 0x39, 0x3a, 0x52, - 0x4c, 0x72, 0x7a, 0x08, 0xef, 0xb9, 0xa8, 0x73, 0x35, 0x31, 0x7c, 0xfb, 0x30, 0x2a, 0x98, 0x3f, - 0xb2, 0xc0, 0x51, 0xa5, 0xb7, 0xce, 0xf1, 0xc8, 0x54, 0xf8, 0xec, 0x69, 0x28, 0x74, 0x53, 0x22, - 0x75, 0x09, 0xeb, 0x85, 0x24, 0x44, 0x97, 0x83, 0x09, 0xb8, 0x49, 0x78, 0x53, 0x34, 0xcc, 0xdb, - 0x22, 0x76, 0xf6, 0xd6, 0xc2, 0x15, 0xc7, 0x61, 0xaa, 0x27, 0xf7, 0x14, 0x1a, 0xb7, 0xad, 0xf6, - 0xc0, 0x20, 0xaa, 0xb0, 0x33, 0xa8, 0x64, 0x7e, 0xe7, 0x69, 0x2d, 0x6b, 0xf8, 0x64, 0xee, 0xaf, - 0xb0, 0x2d, 0x2f, 0xae, 0xba, 0xb2, 0x52, 0xa4, 0xba, 0x4f, 0xc9, 0x7e, 0x68, 0xc1, 0x49, 0xd9, - 0x92, 0xdb, 0x5f, 0x83, 0xb9, 0xb3, 0xc6, 0x7a, 0xeb, 0x44, 0x3d, 0x63, 0x6b, 0x01, 0x00, 0xf9, - 0x58, 0x09, 0x72, 0x22, 0x70, 0x15, 0x30, 0x1d, 0x4e, 0xb2, 0x97, 0x53, 0xc8, 0x89, 0x85, 0x5f, - 0xd0, 0x1b, 0x00, 0x88, 0xf0, 0xc3, 0x86, 0x2c, 0x21, 0x07, 0xe9, 0x2c, 0x24, 0x8c, 0x94, 0x90, - 0x31, 0xb1, 0x7b, 0xff, 0xf6, 0xdf, 0xf9, 0xd8, 0x4b, 0xdc, 0x7d, 0xaa, 0x18, 0xe7, 0x37, 0xd3, - 0x48, 0xa5, 0x04, 0x28, 0xc0, 0x5d, 0xf9, 0x0b, 0xb0, 0x96, 0x97, 0x3a, 0x7c, 0xf7, 0x21, 0x57, - 0xac, 0x9c, 0x98, 0x34, 0xb9, 0xfa, 0xb0, 0x49, 0x79, 0x5e, 0x86, 0xad, 0x29, 0x25, 0x31, 0x03, - 0xdf, 0x1b, 0xd9, 0xbb, 0xcb, 0x4c, 0x8a, 0x8f, 0xbd, 0x58, 0x31, 0xc7, 0x0c, 0x02, 0x0e, 0xa5, - 0xd5, 0x8e, 0x23, 0xce, 0x0e, 0x24, 0xd7, 0xd3, 0x01, 0x25, 0xf0, 0xf8, 0x1c, 0xae, 0x86, 0x4f, - 0xad, 0xb2, 0xf4, 0xf1, 0xe3, 0xcc, 0x8d, 0xec, 0xae, 0x01, 0xc7, 0xa8, 0x8c, 0x5e, 0xe0, 0xe4, - 0x0c, 0x5a, 0x0e, 0x48, 0xa3, 0x56, 0x2d, 0xa1, 0x31, 0x62, 0x56, 0x1c, 0x48, 0x7e, 0x4d, 0x46, - 0x26, 0x10, 0x65, 0x1d, 0x45, 0x38, 0x1f, 0xbe, 0x7e, 0x5e, 0x70, 0x26, 0x5f, 0x13, 0xa7, 0xf1, - 0x8b, 0xc8, 0x0c, 0xc8, 0x98, 0xbc, 0xbd, 0x7e, 0x17, 0xce, 0xad, 0x3c, 0x27, 0xd9, 0x35, 0x8a, - 0xfd, 0x47, 0x83, 0x34, 0x43, 0x00, 0x1b, 0x19, 0xbf, 0xf3, 0xed, 0xf7, 0xae, 0x48, 0x65, 0xcc, - 0x34, 0x3a, 0x62, 0x5a, 0x30, 0x45, 0xb5, 0x84, 0x55, 0x56, 0x21, 0x7b, 0xb9, 0xad, 0xc6, 0xbc, - 0x16, 0x8e, 0xb0, 0x63, 0x94, 0x5a, 0xb7, 0xbf, 0x4f, 0x00, 0x23, 0x07, 0x2f, 0x1f, 0x40, 0x37, - 0xc4, 0xf0, 0x88, 0x7a, 0xe6, 0x37, 0x89, 0xfd, 0xbb, 0xfd, 0x48, 0x88, 0x70, 0x3b, 0x69, 0x5a, - 0x46, 0xdb, 0xbb, 0x75, 0x06, 0xc7, 0xff, 0x39, 0xd2, 0x9b, 0x79, 0x3c, 0x0e, 0xa5, 0xdd, 0x64, - 0x80, 0x12, 0x25, 0x09, 0x3f, 0x07, 0x0c, 0x0e, 0xc7, 0xaf, 0x2d, 0x9e, 0xc1, 0xc9, 0x34, 0x6a, - 0xf9, 0xba, 0x89, 0x99, 0x91, 0x2f, 0xc6, 0xc2, 0x77, 0xe8, 0x92, 0xd5, 0x05, 0x01, 0x3e, 0x18, - 0x2f, 0x8b, 0xd1, 0x4c, 0x46, 0x00, 0x13, 0xe1, 0x28, 0x99, 0x34, 0xd2, 0x9f, 0xf5, 0xb7, 0x27, - 0xf1, 0x89, 0xe6, 0x91, 0x9e, 0x8a, 0x78, 0x42, 0x64, 0xde, 0xd8, 0x50, 0xc0, 0x70, 0xfb, 0x9b, - 0xad, 0x95, 0x11, 0xc1, 0x3f, 0xa7, 0x1c, 0xfc, 0x28, 0xe8, 0xad, 0x25, 0x5b, 0x13, 0xb5, 0x0b, - 0xb8, 0x48, 0xa4, 0x25, 0xec, 0xfc, 0xc9, 0x0d, 0x29, 0xc0, 0x47, 0x86, 0xcf, 0xf4, 0xe6, 0x74, - 0x55, 0x09, 0x6d, 0x3e, 0xef, 0xc4, 0xdb, 0x49, 0xe7, 0x01, 0xf9, 0x81, 0x0e, 0x15, 0x0d, 0x3d, - 0xd7, 0x28, 0x4c, 0x34, 0x39, 0x39, 0x98, 0xec, 0x0e, 0xd2, 0x02, 0x5b, 0x8f, 0x0c, 0x8e, 0xed, - 0xa7, 0xdc, 0x36, 0x48, 0x71, 0x72, 0xef, 0x7a, 0xfc, 0x9f, 0x92, 0xfb, 0x00, 0x4a, 0xea, 0x2e, - 0xf3, 0xcc, 0xe0, 0x87, 0x89, 0x2a, 0xc0, 0x2d, 0xe3, 0xf7, 0x2d, 0x8e, 0xc2, 0xd6, 0xe7, 0xfe, - 0xec, 0x7a, 0x48, 0xc5, 0x6e, 0x0e, 0xbe, 0x07, 0xe8, 0x97, 0x0d, 0x24, 0xd1, 0xa0, 0xa2, 0x9e, - 0x05, 0x19, 0x5e, 0x18, 0xfa, 0x5f, 0xd6, 0xd0, 0x7c, 0x21, 0x8f, 0xf9, 0xc9, 0xc3, 0x5c, 0x24, - 0xf8, 0x5f, 0x6f, 0xe4, 0xb8, 0xfa, 0xab, 0xe7, 0xa2, 0x81, 0x33, 0x03, 0x97, 0x80, 0xdb, 0x7c, - 0xd0, 0xcd, 0x05, 0x33, 0x84, 0xec, 0x27, 0x9f, 0x0a, 0xb5, 0x9d, 0xcf, 0x7c, 0x34, 0x03, 0xe0, - 0x1c, 0x43, 0xc1, 0x65, 0x3f, 0x01, 0x9d, 0x1a, 0x7c, 0x9f, 0xf7, 0xc6, 0xed, 0x39, 0x52, 0x8e, - 0xf0, 0x0f, 0xa3, 0x74, 0x2d, 0xce, 0x93, 0x22, 0x75, 0xf0, 0x6d, 0x06, 0xfd, 0x54, 0xec, 0x1a, - 0x31, 0xc8, 0xe5, 0x21, 0xcb, 0xbf, 0xac, 0x88, 0xcb, 0x30, 0x3a, 0xf0, 0x3d, 0xe6, 0x65, 0x79, - 0x54, 0x69, 0xa1, 0x80, 0x56, 0x52, 0xda, 0x7a, 0x76, 0xef, 0xfb, 0x27, 0xc3, 0x92, 0x53, 0xca, - 0x19, 0x29, 0x73, 0x81, 0x1a, 0x96, 0xc8, 0x51, 0x10, 0x0b, 0x10, 0x93, 0x37, 0xb5, 0xb0, 0xe6, - 0xe4, 0x80, 0xdb, 0xe0, 0x91, 0x6b, 0x8c, 0x1c, 0x7e, 0x8e, 0x51, 0x6f, 0xee, 0xd5, 0x87, 0x0a, - 0x18, 0x7f, 0x50, 0x98, 0x3d, 0x9f, 0x92, 0x7b, 0xd5, 0x83, 0xeb, 0x30, 0x6d, 0x80, 0x40, 0x64, - 0xa9, 0x57, 0x15, 0x80, 0x5a, 0x4e, 0x7e, 0x98, 0x96, 0x4a, 0x8e, 0xc3, 0xfe, 0x4d, 0x6d, 0x02, - 0x1f, 0x5b, 0x6b, 0x99, 0x2f, 0x2d, 0x8a, 0x71, 0x60, 0x13, 0xc4, 0x38, 0x00, 0x82, 0x9a, 0xc3, - 0x02, 0x0a, 0x36, 0x0c, 0xb0, 0x12, 0x67, 0x86, 0x63, 0x85, 0x34, 0x87, 0x7d, 0x67, 0x47, 0xc7, - 0x73, 0xa3, 0x8f, 0x7b, 0x3e, 0xf8, 0x6d, 0x5b, 0x37, 0x4c, 0x29, 0xf6, 0x83, 0x2b, 0xd1, 0xf3, - 0xaa, 0x4f, 0xec, 0x6a, 0xad, 0xba, 0x49, 0x1a, 0x4e, 0x61, 0xb1, 0xb0, 0x6f, 0x05, 0xe4, 0x44, - 0x7c, 0x30, 0x36, 0x0a, 0x28, 0x4d, 0x60, 0xc0, 0xba, 0xb5, 0xcc, 0x5d, 0x5d, 0xbb, 0x60, 0x12, - 0x5f, 0x00, 0x3f, 0xa7, 0xf0, 0xaf, 0x34, 0x62, 0xdf, 0xdb, 0xff, 0x34, 0xde, 0x19, 0x27, 0x11, - 0x78, 0x01, 0xc2, 0x4d, 0xe8, 0xd1, 0x9e, 0xca, 0xff, 0x02, 0x2d, 0xbd, 0xf9, 0x10, 0x0b, 0xdd, - 0x1a, 0xdc, 0xac, 0x77, 0x64, 0x88, 0xb5, 0xeb, 0xba, 0xb7, 0xc0, 0xb7, 0x2d, 0xcf, 0x0e, 0x4a, - 0xa3, 0x56, 0x43, 0xd1, 0xb2, 0x92, 0x6e, 0x03, 0x2a, 0x1f, 0x9b, 0x4c, 0x5d, 0x65, 0x61, 0x80, - 0x41, 0x17, 0x86, 0x01, 0xcb, 0xc0, 0xcc, 0x73, 0xda, 0x9c, 0x9e, 0x5e, 0x93, 0x90, 0x11, 0xcf, - 0xc3, 0x0c, 0x95, 0x34, 0x83, 0x00, 0x02, 0xad, 0xcd, 0x1c, 0x23, 0xca, 0x90, 0xd1, 0x63, 0xd9, - 0xee, 0x50, 0x05, 0x28, 0xf2, 0xe6, 0x77, 0x4c, 0x1a, 0x94, 0xac, 0xed, 0x48, 0x62, 0xf6, 0xbb, - 0x76, 0xf8, 0x85, 0xe0, 0x4f, 0x3a, 0x2c, 0x19, 0xd8, 0xf1, 0x09, 0xc4, 0x36, 0x58, 0xdb, 0xaa, - 0x30, 0x0d, 0xf1, 0x65, 0xe0, 0x43, 0xa3, 0x7e, 0x50, 0x17, 0x05, 0x99, 0x87, 0xc4, 0x03, 0x84, - 0x83, 0x92, 0xd6, 0x67, 0x01, 0x20, 0x63, 0x78, 0x8a, 0xb4, 0xf7, 0xde, 0x75, 0x54, 0x85, 0x47, - 0x2f, 0xc3, 0x37, 0xc1, 0xaa, 0xa8, 0xde, 0xc9, 0x88, 0x86, 0xe0, 0xe4, 0xaa, 0x9d, 0x35, 0xba, - 0x49, 0xd1, 0x44, 0x1a, 0x5a, 0xc3, 0x62, 0xeb, 0xb6, 0x4f, 0x63, 0x7c, 0x3e, 0x8e, 0x4b, 0x2d, - 0xb0, 0xd6, 0xd8, 0x2f, 0x3a, 0xbc, 0x80, 0x56, 0xbf, 0xc1, 0x14, 0x23, 0x4f, 0x12, 0x72, 0xfe, - 0xed, 0x77, 0xd6, 0x52, 0x8b, 0x05, 0x3c, 0x7c, 0x0a, 0x1b, 0x04, 0x55, 0x21, 0x47, 0x1c, 0x16, - 0x25, 0x60, 0x86, 0x01, 0xad, 0x09, 0x1b, 0xe6, 0x66, 0x88, 0x47, 0x66, 0x12, 0x2e, 0x5c, 0x5a, - 0xd3, 0xe8, 0x3d, 0x76, 0xf4, 0x95, 0x4a, 0x3b, 0x4e, 0x8d, 0xb2, 0xc0, 0xca, 0x2a, 0xac, 0xbe, - 0x10, 0xbb, 0x5f, 0x9e, 0xd7, 0x9f, 0x25, 0x80, 0x69, 0x1b, 0xff, 0xcf, 0xe5, 0x42, 0xde, 0xcc, - 0xf0, 0xe3, 0x56, 0x85, 0x16, 0x53, 0x40, 0x60, 0x77, 0x55, 0xc8, 0x8b, 0xc0, 0x45, 0x80, 0xe7, - 0x00, 0x0f, 0x0d, 0x63, 0x0e, 0x5f, 0xb3, 0xc0, 0x73, 0x78, 0xf7, 0xa3, 0x97, 0x87, 0xc5, 0x1f, - 0x0e, 0x49, 0x93, 0x5e, 0x02, 0x50, 0x73, 0x70, 0xf2, 0xbf, 0xcd, 0x83, 0xa0, 0x81, 0x3f, 0x50, - 0x25, 0xd5, 0xeb, 0x00, 0xb7, 0xb2, 0xa7, 0x35, 0x7f, 0x7c, 0x44, 0x73, 0xf0, 0x72, 0x44, 0x86, - 0x69, 0x27, 0x8d, 0x20, 0x16, 0xf4, 0x15, 0x4d, 0x2e, 0x7e, 0xaf, 0xb2, 0x12, 0x81, 0xe6, 0x38, - 0xe4, 0xb4, 0xb4, 0xd7, 0xa9, 0xfc, 0x5a, 0x1c, 0xe9, 0x3d, 0x7a, 0xc4, 0xf6, 0x91, 0x2c, 0x98, - 0x00, 0x49, 0x3d, 0xce, 0x47, 0xc8, 0x8f, 0xbf, 0xc9, 0xed, 0xe7, 0x87, 0x1e, 0x75, 0x7d, 0xf6, - 0xbb, 0x4e, 0x99, 0x52, 0xc0, 0xd2, 0x48, 0x25, 0xc4, 0xc5, 0x93, 0x97, 0xdb, 0x4b, 0x87, 0x33, - 0xca, 0x64, 0x50, 0x0a, 0x30, 0xa6, 0x50, 0x94, 0xfe, 0x56, 0xa4, 0xbb, 0xc0, 0x24, 0x56, 0xb0, - 0xd7, 0x55, 0x74, 0x0c, 0x90, 0x6d, 0xe7, 0x4a, 0x00, 0xa0, 0xee, 0x3c, 0x51, 0xdf, 0xf0, 0xec, - 0x5b, 0xfc, 0xbf, 0xf1, 0xb9, 0xb4, 0x98, 0x00, 0xda, 0x55, 0x45, 0xa8, 0xf0, 0x02, 0xa8, 0xd6, - 0xe0, 0xe4, 0x54, 0x4f, 0x5d, 0x75, 0xb1, 0xdc, 0xf2, 0x22, 0x80, 0xff, 0xeb, 0x13, 0xf7, 0xb1, - 0x14, 0xed, 0x07, 0x24, 0xd1, 0xab, 0xe1, 0xc8, 0x53, 0x52, 0x60, 0x25, 0xc8, 0x89, 0xe0, 0x30, - 0xd2, 0xa4, 0x61, 0xf6, 0x65, 0xc7, 0x3a, 0x19, 0x79, 0x2a, 0x35, 0x03, 0x22, 0x88, 0x65, 0x1f, - 0x92, 0x65, 0x2d, 0xb1, 0x71, 0xc2, 0x04, 0x16, 0x96, 0x18, 0x2c, 0xa4, 0xd0, 0xc0, 0xdc, 0xac, - 0x3d, 0xb7, 0x82, 0xb2, 0x3f, 0xc0, 0x1b, 0xff, 0xae, 0x5c, 0xb8, 0x63, 0xd2, 0xb3, 0xd0, 0x55, - 0xfa, 0xb0, 0xf3, 0xd1, 0xc2, 0x55, 0xb5, 0x6a, 0x5d, 0x60, 0x3d, 0x94, 0xa4, 0x26, 0x6f, 0x5e, - 0x8e, 0x01, 0xf8, 0xe1, 0xd4, 0x1a, 0x0c, 0xd7, 0x32, 0xcd, 0xf0, 0xdc, 0x70, 0x04, 0x61, 0x42, - 0xd0, 0x81, 0xaf, 0x12, 0x04, 0x54, 0x76, 0x18, 0x3a, 0x57, 0x09, 0xbe, 0x5b, 0xa8, 0xf0, 0x72, - 0xa8, 0xb6, 0x60, 0xe4, 0xc2, 0xb5, 0x01, 0x1b, 0x87, 0x91, 0x24, 0x5a, 0xbf, 0x07, 0x95, 0x1d, - 0xac, 0x1c, 0xcf, 0x66, 0x8d, 0x38, 0x16, 0xf4, 0x0a, 0xe5, 0xd9, 0x58, 0x2f, 0x16, 0x6d, 0x04, - 0x18, 0x9a, 0x06, 0x01, 0xdc, 0xff, 0x1c, 0xec, 0x23, 0x7c, 0x19, 0xfc, 0x6a, 0x73, 0x9e, 0xbb, - 0x9c, 0x01, 0x40, 0x7c, 0xc1, 0x80, 0x5d, 0x46, 0x98, 0xe1, 0x92, 0x04, 0xe7, 0x32, 0xc4, 0x1d, - 0xb8, 0x0e, 0x23, 0x4f, 0x41, 0xc5, 0x81, 0xba, 0xfb, 0x3f, 0xad, 0xb6, 0x94, 0x76, 0xdc, 0x9e, - 0x0f, 0x9b, 0x33, 0xcf, 0xff, 0xed, 0xbf, 0xf3, 0xd1, 0xc1, 0x1f, 0x59, 0x54, 0xf0, 0xa7, 0x9d, - 0x1d, 0x3c, 0x5f, 0x28, 0x33, 0x78, 0x9f, 0x85, 0x58, 0x8b, 0x6e, 0xad, 0x23, 0x17, 0x60, 0xc0, - 0x10, 0x45, 0x16, 0xa0, 0xe4, 0x44, 0x7c, 0x2c, 0x94, 0x1d, 0x24, 0x5a, 0xbf, 0x00, 0x95, 0x17, - 0x7c, 0x1c, 0x55, 0x40, 0x73, 0x63, 0x44, 0x0a, 0x74, 0xe4, 0xbc, 0xe0, 0xec, 0x7a, 0x11, 0xdd, - 0x39, 0x2f, 0x24, 0xb8, 0x49, 0xd1, 0x4c, 0x1a, 0xba, 0x43, 0x22, 0x74, 0x0a, 0x32, 0x9a, 0xaf, - 0x00, 0x0d, 0x66, 0xd3, 0x69, 0x65, 0x6a, 0x1f, 0x80, 0x41, 0xc5, 0xe1, 0xdc, 0xc8, 0x5f, 0xac, - 0xa1, 0x80, 0x90, 0xee, 0x85, 0x78, 0x1f, 0x22, 0x7c, 0x1b, 0x69, 0xdb, 0x35, 0x87, 0x8c, 0xcb, - 0x31, 0x69, 0x7c, 0xbf, 0x99, 0xa3, 0xe3, 0xf9, 0x1c, 0xce, 0x82, 0x3b, 0xd7, 0x2f, 0xa5, 0x83, - 0xfa, 0xb9, 0x31, 0x62, 0xf2, 0x96, 0x85, 0xb2, 0x04, 0x94, 0x8c, 0x18, 0xff, 0xcd, 0x2a, 0x42, - 0x0c, 0x02, 0xa9, 0x4f, 0xbd, 0x6a, 0xc0, 0x82, 0x9b, 0x4d, 0x25, 0x80, 0x87, 0x22, 0x5b, 0xe0, - 0x6b, 0x77, 0xba, 0xa3, 0x40, 0xdd, 0x03, 0x9d, 0x19, 0x11, 0xbc, 0x0d, 0xc6, 0x89, 0x35, 0xd6, - 0xa3, 0x88, 0xaf, 0x17, 0xad, 0x3d, 0xb0, 0x26, 0x42, 0x61, 0xb0, 0x72, 0x08, 0x9a, 0xdd, 0x42, - 0x83, 0x92, 0x45, 0x37, 0x3a, 0x97, 0x93, 0x55, 0xb4, 0x38, 0xa3, 0x42, 0x2a, 0x62, 0xe2, 0x67, - 0x4d, 0x1b, 0x98, 0xdb, 0x5d, 0xff, 0xd4, 0xfe, 0x02, 0x80, 0x81, 0x0c, 0xaa, 0x06, 0xa2, 0x96, - 0xab, 0x20, 0xe4, 0x96, 0xeb, 0xe9, 0x1a, 0xae, 0xb2, 0xae, 0x0c, 0xbf, 0x42, 0xa4, 0xd6, 0x02, - 0x16, 0x39, 0x4a, 0x9c, 0x73, 0x33, 0xb6, 0xcf, 0xf8, 0x48, 0x1e, 0xf9, 0xe7, 0xdf, 0xb3, 0xb4, - 0xa1, 0x85, 0x23, 0x81, 0x62, 0xe0, 0x4b, 0xf2, 0x76, 0xb9, 0xc4, 0xf2, 0x61, 0x56, 0x7d, 0xba, - 0x86, 0x01, 0x17, 0x86, 0x48, 0xe0, 0x14, 0x61, 0x07, 0xbf, 0x5c, 0x58, 0xd0, 0xe1, 0xfc, 0xb3, - 0x56, 0x1b, 0xe7, 0x46, 0x9e, 0x15, 0x11, 0x19, 0x12, 0x39, 0x57, 0xf8, 0xdd, 0xe0, 0x84, 0xf8, - 0x0c, 0x6e, 0x27, 0xd3, 0x9f, 0x22, 0xd5, 0x50, 0x71, 0x48, 0xa2, 0x8a, 0xe0, 0xe4, 0xa5, 0x85, - 0x5a, 0xed, 0x00, 0x24, 0xb2, 0x7f, 0x9f, 0xa5, 0x41, 0xf5, 0xc1, 0xc9, 0x55, 0x47, 0xf1, 0xf5, - 0x63, 0xb8, 0xc9, 0x8b, 0x17, 0x70, 0x63, 0xd5, 0xee, 0xef, 0xc9, 0x78, 0x47, 0xc1, 0x9d, 0x13, - 0x00, 0xc4, 0xf2, 0x8d, 0xf6, 0x18, 0x7f, 0xe7, 0xcc, 0xab, 0x86, 0xcd, 0xa8, 0x1b, 0x13, 0xd1, - 0x4c, 0x33, 0x96, 0x98, 0x81, 0xbc, 0x44, 0x1a, 0x0f, 0x91, 0x21, 0xab, 0x98, 0xaa, 0x92, 0x04, - 0xaf, 0x32, 0x75, 0x1b, 0x26, 0xf0, 0xf5, 0x60, 0xe0, 0x16, 0x60, 0xfe, 0xb9, 0xf8, 0x78, 0x13, - 0xb7, 0xd0, 0xb6, 0x9d, 0xc3, 0x00, 0x55, 0x46, 0x59, 0x5d, 0xf0, 0xe1, 0x38, 0x5a, 0xcb, 0x01, - 0xec, 0xa2, 0x02, 0x31, 0xf5, 0x0c, 0xff, 0xae, 0xe2, 0xcd, 0xa3, 0x09, 0x70, 0x00, 0x7b, 0x78, - 0x29, 0x86, 0x05, 0x86, 0x62, 0x18, 0x05, 0x84, 0x09, 0xaa, 0x58, 0x30, 0xff, 0x9d, 0x10, 0x2d, - 0xb7, 0x79, 0xfb, 0xd7, 0x83, 0x92, 0x07, 0x6e, 0x6c, 0xde, 0x02, 0xf4, 0xb4, 0xa2, 0xb7, 0x01, - 0xc8, 0x8b, 0x55, 0x14, 0x2e, 0xbd, 0x6f, 0xf4, 0x4b, 0x75, 0xc6, 0x00, 0x0e, 0x48, 0x1b, 0x56, - 0x5e, 0x8d, 0xaf, 0x5d, 0x6f, 0xbd, 0x88, 0xc4, 0x0c, 0x2e, 0x04, 0xfa, 0x69, 0x06, 0x53, 0xd4, - 0x50, 0x15, 0xb2, 0x40, 0x82, 0x51, 0x9a, 0xb2, 0x54, 0x73, 0x15, 0x55, 0xf2, 0x91, 0x3c, 0xd3, - 0x92, 0x66, 0xf4, 0xf0, 0x92, 0xef, 0xf8, 0x97, 0x26, 0x7c, 0x1d, 0xfa, 0x93, 0xbf, 0x08, 0x0f, - 0x9c, 0x30, 0x21, 0x62, 0xb5, 0x44, 0xab, 0xb4, 0x00, 0x8a, 0x85, 0x83, 0xfa, 0x1e, 0xbb, 0xc3, - 0x54, 0x72, 0x80, 0x18, 0xca, 0xa7, 0xae, 0xe2, 0xf1, 0x48, 0x07, 0xfa, 0xd3, 0x43, 0x56, 0x11, - 0x4a, 0x3b, 0x02, 0x31, 0x66, 0x0c, 0x7f, 0xe7, 0x4c, 0x9b, 0x7d, 0x94, 0xcc, 0x90, 0x46, 0x06, - 0x36, 0x94, 0x70, 0x9a, 0x58, 0x59, 0x1e, 0xe0, 0x5e, 0x9b, 0x15, 0xe2, 0xae, 0x23, 0x1a, 0x52, - 0xbe, 0xfd, 0xfb, 0x15, 0xd7, 0xce, 0xc5, 0xcf, 0x42, 0x78, 0x00, 0x36, 0xc8, 0x88, 0xea, 0x54, - 0x1c, 0x94, 0x7f, 0xbc, 0x2e, 0x7b, 0x44, 0x5c, 0x09, 0x64, 0xdb, 0xf0, 0x63, 0xb8, 0xcb, 0x8b, - 0x3f, 0x5b, 0x8f, 0x50, 0xdf, 0xbd, 0xc8, 0xec, 0x7c, 0xf1, 0xde, 0xd0, 0xc0, 0xf3, 0x89, 0x03, - 0x62, 0x4e, 0xba, 0x88, 0x65, 0x3d, 0xc0, 0xb1, 0x9c, 0xc1, 0xf6, 0xd2, 0xa3, 0xa4, 0x8c, 0x32, - 0x60, 0x9a, 0x18, 0x36, 0xcf, 0x9a, 0xe6, 0x45, 0x57, 0x66, 0xe6, 0x85, 0x01, 0x66, 0x51, 0x96, - 0x61, 0xec, 0xb2, 0xbf, 0xcf, 0x28, 0x97, 0x8d, 0x5d, 0xd5, 0x6c, 0x65, 0xc1, 0x23, 0x1f, 0x22, - 0x05, 0xd6, 0x2a, 0x18, 0x3f, 0x2d, 0xe0, 0x12, 0xc3, 0x78, 0xbf, 0xf3, 0x85, 0x79, 0x96, 0x8b, - 0x87, 0x75, 0x48, 0x33, 0x95, 0x9b, 0x82, 0xb2, 0x58, 0x4a, 0xc1, 0x80, 0x47, 0x46, 0x46, 0x29, - 0xc1, 0x80, 0x03, 0xa8, 0xc7, 0x3e, 0x00, 0xbe, 0xb2, 0xc3, 0x14, 0x06, 0x48, 0x2e, 0xfc, 0x3b, - 0x95, 0x0c, 0x7f, 0xe7, 0xf0, 0x3b, 0xec, 0x0a, 0x9e, 0x00, 0x97, 0x8a, 0xa2, 0xe9, 0x55, 0x2d, - 0x38, 0x3a, 0xfb, 0xe7, 0x7e, 0x77, 0x72, 0x6a, 0xc7, 0x1b, 0x4e, 0x18, 0xbc, 0x20, 0x4b, 0x6b, - 0x5f, 0xbf, 0xf1, 0x0e, 0x11, 0x68, 0xf8, 0xc9, 0x00, 0xd6, 0x90, 0x9b, 0xbc, 0x00, 0xca, 0xbe, - 0xf2, 0x7a, 0xe1, 0x4f, 0xc6, 0x8d, 0xb6, 0x6b, 0x7d, 0x77, 0x7b, 0x32, 0x69, 0x56, 0x50, 0xc4, - 0x50, 0x35, 0xc0, 0xe0, 0xe8, 0xc6, 0xf5, 0x77, 0x73, 0xc0, 0x00, 0xb3, 0xe1, 0x0f, 0x71, 0x0b, - 0x80, 0x35, 0x09, 0x7f, 0x44, 0x2d, 0xbb, 0x4f, 0x70, 0xae, 0x69, 0x99, 0x19, 0xed, 0xaa, 0xe3, - 0x31, 0x3e, 0x37, 0xcb, 0x95, 0x9a, 0xc0, 0x05, 0xbe, 0x7d, 0xb4, 0xed, 0x72, 0xd7, 0x41, 0x82, - 0xa4, 0x05, 0x19, 0x21, 0xc9, 0x38, 0x28, 0xb0, 0xd3, 0xfb, 0x01, 0x51, 0x86, 0x86, 0x7f, 0xd6, - 0xa6, 0x86, 0x60, 0x13, 0x83, 0x98, 0xd1, 0xaf, 0xb9, 0x4f, 0x10, 0x73, 0xb6, 0x28, 0x2f, 0xf2, - 0xda, 0x53, 0x6d, 0x19, 0xbd, 0x78, 0x77, 0xf7, 0x05, 0x36, 0x7f, 0x22, 0x78, 0x2d, 0x14, 0x62, - 0xc5, 0xdd, 0x5f, 0xa8, 0x12, 0x5d, 0x7f, 0x80, 0x9d, 0xd9, 0x41, 0x67, 0xd4, 0x30, 0x1a, 0xbe, - 0x59, 0xf8, 0xb1, 0xdc, 0xa4, 0xc5, 0xbf, 0xb3, 0xc7, 0xaf, 0x05, 0x5e, 0xc1, 0xc9, 0x26, 0x9f, - 0x89, 0x3a, 0x1a, 0x41, 0x6c, 0xd1, 0xc2, 0x07, 0x69, 0xcf, 0xff, 0xaf, 0xa1, 0x2d, 0x5f, 0xaa, - 0xeb, 0xc0, 0xd5, 0x3d, 0x34, 0x1b, 0x01, 0xdd, 0x08, 0xdc, 0x15, 0xdc, 0x6f, 0xda, 0x44, 0x35, - 0x95, 0x05, 0xb0, 0x13, 0x58, 0x66, 0x7e, 0xa8, 0x4d, 0x55, 0xb0, 0xfe, 0xc8, 0x49, 0xcd, 0xe3, - 0x5e, 0xfb, 0x9a, 0x1a, 0x9b, 0xd7, 0x3f, 0xe9, 0x4c, 0xe8, 0x1d, 0x0b, 0x67, 0xa5, 0x0d, 0x82, - 0x17, 0x4c, 0x35, 0x5e, 0x86, 0xa1, 0x22, 0x20, 0xf1, 0x23, 0x9c, 0x55, 0x21, 0xb3, 0xf0, 0xc0, - 0x67, 0x4c, 0xc3, 0xc3, 0xe0, 0xcf, 0x44, 0xeb, 0xcc, 0x8c, 0xb3, 0x0a, 0x77, 0x0c, 0x76, 0x22, - 0x95, 0xe7, 0xc1, 0xa5, 0xb1, 0xdf, 0x82, 0xb8, 0x00, 0xb0, 0xae, 0x58, 0x0c, 0xff, 0x02, 0xf1, - 0xe1, 0x0c, 0x2b, 0x62, 0x0f, 0xc7, 0x18, 0xcd, 0xbe, 0x77, 0xee, 0x15, 0x49, 0x53, 0xa1, 0x14, - 0xc9, 0x6e, 0x98, 0xc1, 0xef, 0xd1, 0xbe, 0x0d, 0xd7, 0x5a, 0xfe, 0x61, 0xdf, 0x11, 0xc5, 0x34, - 0x2a, 0xfe, 0x58, 0x39, 0x46, 0x8d, 0x59, 0x3c, 0x58, 0xcd, 0x0b, 0x01, 0x55, 0x00, 0x49, 0xbd, - 0xfe, 0x44, 0x37, 0x8c, 0xae, 0x12, 0x7b, 0x25, 0x03, 0x70, 0x09, 0x5e, 0xc0, 0xb6, 0x8b, 0x72, - 0x00, 0xb0, 0x8d, 0x83, 0xd5, 0x10, 0xbe, 0xda, 0x38, 0x42, 0xaf, 0x8b, 0xb1, 0xcc, 0x54, 0x16, - 0x62, 0x86, 0xff, 0x9c, 0x03, 0xbf, 0x8d, 0x9b, 0x1e, 0x1b, 0x3d, 0x1c, 0x6b, 0x78, 0xd7, 0x08, - 0xfc, 0xc7, 0x24, 0xdb, 0xc6, 0xff, 0xed, 0x11, 0xa7, 0x86, 0x14, 0x47, 0x0e, 0x5e, 0xf6, 0x96, - 0xb1, 0x79, 0x03, 0x4a, 0x0b, 0x53, 0xfd, 0x93, 0x47, 0x1b, 0x6c, 0x25, 0x6a, 0x90, 0xf4, 0x21, - 0x00, 0x7b, 0xd6, 0x96, 0xbe, 0x73, 0x3c, 0xe2, 0xd4, 0xe2, 0xf6, 0xd2, 0x23, 0xe9, 0x0d, 0xb2, - 0x4a, 0x2f, 0xe6, 0x1f, 0x3d, 0x89, 0x42, 0x79, 0x62, 0xbf, 0x02, 0xf0, 0x86, 0x0c, 0xd7, 0x3b, - 0x04, 0x95, 0x44, 0x18, 0x5c, 0xe4, 0x6d, 0x7c, 0x8d, 0xb4, 0x16, 0x55, 0xa3, 0xf3, 0xa9, 0xf7, - 0x4b, 0x54, 0x20, 0x3d, 0x28, 0x39, 0x97, 0x24, 0x5c, 0x00, 0x99, 0xdc, 0x7f, 0xe7, 0x92, 0x82, - 0x5b, 0x83, 0x3b, 0x81, 0x8e, 0xe3, 0x4e, 0x2d, 0x7c, 0x03, 0x1e, 0xb2, 0xcd, 0x7b, 0x39, 0x22, - 0x8d, 0x58, 0xfe, 0xba, 0xc5, 0xa2, 0xe3, 0x6c, 0xc3, 0xf2, 0x72, 0x3a, 0x30, 0xbc, 0xba, 0x69, - 0x06, 0xf9, 0x46, 0x21, 0xa1, 0x80, 0x83, 0x62, 0xaa, 0xa0, 0xd8, 0x8b, 0xe7, 0x27, 0x28, 0xd5, - 0xd7, 0xec, 0xae, 0x15, 0xfd, 0x92, 0x63, 0x64, 0x1c, 0x04, 0xab, 0x23, 0x1b, 0x77, 0xf1, 0x5e, - 0x34, 0x93, 0x01, 0xc9, 0x06, 0xdb, 0xcf, 0x98, 0xc4, 0x39, 0x31, 0xbf, 0x70, 0xde, 0x69, 0x47, - 0x6f, 0x75, 0xe0, 0x81, 0x0a, 0xea, 0x89, 0x26, 0x4d, 0xc8, 0x3a, 0xc0, 0xf0, 0xbc, 0x06, 0xd7, - 0xfb, 0xbc, 0xc7, 0x97, 0x7e, 0x4b, 0xfb, 0xcd, 0x8b, 0xfe, 0xee, 0xdb, 0xd5, 0x54, 0xbe, 0x5d, - 0x05, 0xf3, 0x8f, 0x7e, 0x8e, 0xe9, 0x78, 0x1f, 0xcf, 0xfa, 0xae, 0x21, 0x91, 0x15, 0x80, 0x17, - 0x78, 0x55, 0xc4, 0x21, 0x44, 0xdd, 0xbf, 0xaf, 0x6f, 0xd2, 0x11, 0xcb, 0x9a, 0x8a, 0x34, 0xa5, - 0xf0, 0x2d, 0x51, 0x42, 0x31, 0xce, 0xf2, 0x8e, 0xa4, 0x12, 0x16, 0x71, 0xb6, 0x8a, 0x49, 0x54, - 0x6b, 0x0e, 0x79, 0xa6, 0x8f, 0xf2, 0xe3, 0x00, 0x3b, 0x4b, 0xaf, 0xcf, 0x02, 0x41, 0xeb, 0xf0, - 0x75, 0xd1, 0xb7, 0xb8, 0x92, 0x86, 0xfd, 0x25, 0x08, 0x7c, 0xb3, 0xdf, 0x8b, 0x5e, 0x66, 0xbd, - 0x1c, 0x91, 0x46, 0xac, 0x5d, 0xbd, 0xe3, 0xaa, 0x15, 0xf1, 0xb7, 0x04, 0xff, 0x31, 0x65, 0xbb, - 0x81, 0x4d, 0x9b, 0x9d, 0x0d, 0x02, 0xfc, 0xc2, 0x91, 0x70, 0x0b, 0x70, 0x1d, 0xa4, 0x0a, 0xa2, - 0xba, 0x60, 0x58, 0x81, 0x5d, 0x13, 0xd1, 0xbe, 0xe7, 0x81, 0x9a, 0x4c, 0xed, 0x81, 0x72, 0x22, - 0xaa, 0xa9, 0x66, 0xc6, 0x12, 0x51, 0x58, 0x72, 0x5a, 0x13, 0xde, 0xcc, 0x18, 0xab, 0x75, 0x67, - 0xbe, 0x28, 0x7c, 0x9e, 0x88, 0x2d, 0x42, 0xc8, 0xe2, 0xe0, 0x61, 0x62, 0xe0, 0x84, 0x69, 0xef, - 0xdf, 0x35, 0x5a, 0xf9, 0xfd, 0x19, 0x17, 0x4d, 0xf2, 0x37, 0x29, 0xfc, 0xe0, 0x39, 0x17, 0x6f, - 0xab, 0xff, 0x8d, 0x8a, 0x2d, 0xa2, 0xd6, 0x55, 0x37, 0x8c, 0xa1, 0x43, 0xb9, 0x9f, 0x90, 0x8d, - 0x7c, 0x1c, 0xb7, 0xa5, 0x5e, 0x10, 0xdf, 0xab, 0x75, 0x49, 0xc1, 0xc9, 0xd4, 0xcf, 0xaf, 0x63, - 0x24, 0x99, 0xab, 0x07, 0xef, 0x51, 0x9b, 0xdb, 0xfa, 0xc2, 0xe3, 0x5f, 0xa6, 0x19, 0x21, 0x83, - 0x04, 0xed, 0x00, 0x92, 0x47, 0xa6, 0xd5, 0xc0, 0x7f, 0x9c, 0x30, 0x13, 0x78, 0x16, 0x44, 0x40, - 0xaa, 0xae, 0xef, 0xf0, 0x4b, 0x13, 0x46, 0x1f, 0x05, 0x64, 0x11, 0xd3, 0x13, 0xdb, 0x66, 0x86, - 0x30, 0x31, 0x77, 0x4d, 0xf0, 0x32, 0x88, 0xa4, 0x8d, 0x9c, 0xf7, 0xef, 0x57, 0x80, 0xc3, 0x84, - 0x27, 0x34, 0x9c, 0x1b, 0x6d, 0x9f, 0x98, 0x11, 0xf8, 0x63, 0xc9, 0xfd, 0x2c, 0x29, 0xf1, 0xa8, - 0x4e, 0x19, 0x5c, 0x41, 0x00, 0xa5, 0x17, 0xcc, 0x0c, 0x91, 0x5a, 0xbe, 0x93, 0x06, 0x84, 0xdb, - 0x0c, 0xa3, 0x35, 0x4f, 0xdc, 0xc5, 0x35, 0xa7, 0x61, 0x45, 0xf7, 0x84, 0xd3, 0xe1, 0xae, 0x6c, - 0x02, 0x55, 0x94, 0x30, 0x79, 0xc3, 0xaa, 0x87, 0xab, 0x6e, 0xf8, 0x70, 0x80, 0x7b, 0xea, 0xa3, - 0xd7, 0xb5, 0x92, 0x2c, 0xd5, 0x83, 0xac, 0x68, 0xb6, 0x03, 0xfe, 0xb2, 0x5c, 0xd7, 0xa1, 0x85, - 0x04, 0x04, 0x54, 0x42, 0x1a, 0xc7, 0x80, 0x76, 0xaa, 0x7b, 0x30, 0x08, 0xcb, 0x0c, 0x87, 0x08, - 0x2e, 0x19, 0x10, 0x60, 0x05, 0x53, 0xd9, 0xa9, 0xe0, 0xc8, 0xb4, 0x49, 0x51, 0xc5, 0xd0, 0x8e, - 0x33, 0x8c, 0xc0, 0x9c, 0x70, 0x02, 0x9b, 0x58, 0xdb, 0xf0, 0x43, 0x99, 0x75, 0x39, 0xb6, 0x78, - 0x99, 0xd1, 0xe3, 0xe9, 0x8f, 0x80, 0x92, 0x12, 0x9b, 0xa0, 0xc1, 0x60, 0xdf, 0x01, 0x64, 0x7c, - 0x1f, 0x07, 0xc4, 0x3e, 0xe3, 0xbb, 0x00, 0x58, 0x0f, 0x00, 0x49, 0x3b, 0x41, 0x44, 0xa4, 0x54, - 0x88, 0xd5, 0xd7, 0xad, 0xcd, 0x0c, 0x2a, 0x26, 0x50, 0xaa, 0x8b, 0x0b, 0xf2, 0xbb, 0x16, 0x74, - 0xcb, 0x6a, 0x37, 0xe0, 0x72, 0x2d, 0x23, 0x11, 0xb2, 0xae, 0x28, 0xa4, 0x30, 0xc0, 0x18, 0x0b, - 0xda, 0x55, 0x63, 0x69, 0xc5, 0x95, 0xce, 0xa2, 0x7d, 0xc8, 0xb5, 0x2a, 0x75, 0xad, 0x00, 0x49, - 0x89, 0x6e, 0x0e, 0x4a, 0x38, 0xe6, 0x24, 0x88, 0xab, 0x07, 0xef, 0x51, 0xb5, 0x5f, 0x80, 0xec, - 0x87, 0xdb, 0x87, 0x0a, 0xb6, 0xcf, 0xc0, 0x20, 0x1c, 0x10, 0x87, 0x01, 0x18, 0x05, 0xd3, 0x8c, - 0x02, 0x6c, 0x43, 0x0c, 0x18, 0x32, 0x3f, 0xb7, 0x45, 0xb6, 0x24, 0xb8, 0xe1, 0x61, 0x1b, 0x73, - 0xd7, 0x3c, 0x67, 0x95, 0x57, 0x69, 0x3c, 0x39, 0x5e, 0x3a, 0xc6, 0x44, 0x28, 0xc4, 0x95, 0x0e, - 0x5d, 0x33, 0x85, 0x43, 0x8d, 0xd8, 0xc6, 0xf1, 0x2d, 0x51, 0x31, 0x3c, 0x7b, 0xdb, 0xb6, 0xb5, - 0x94, 0xe6, 0xbd, 0x75, 0xd6, 0x05, 0x2a, 0xf4, 0xfa, 0x6b, 0xbc, 0x0a, 0xa7, 0xda, 0x54, 0xe4, - 0x6b, 0xc9, 0x72, 0x71, 0x8b, 0x54, 0xa3, 0x93, 0x79, 0x0a, 0x7d, 0xd5, 0x81, 0x9f, 0xc2, 0x82, - 0x77, 0x1f, 0xd8, 0xe5, 0x5f, 0xd2, 0xee, 0xbe, 0x84, 0x19, 0x10, 0x04, 0xfc, 0x6c, 0x71, 0xa6, - 0xc2, 0x2d, 0xd3, 0xed, 0x1c, 0xbd, 0x9e, 0xc6, 0x97, 0x82, 0xb8, 0x10, 0xb7, 0xae, 0x9a, 0xc0, - 0x65, 0x3e, 0x6f, 0x6d, 0xce, 0x81, 0xc6, 0xbc, 0x96, 0xfc, 0x67, 0xd2, 0xfc, 0x0d, 0x95, 0x9e, - 0x05, 0xbd, 0xfb, 0xe6, 0x74, 0x3a, 0x56, 0x36, 0xec, 0x0f, 0x69, 0xca, 0xcf, 0xcd, 0xa9, 0xef, - 0xb3, 0x86, 0x63, 0xb3, 0xed, 0xde, 0x0b, 0x66, 0x5f, 0x3f, 0xaf, 0x80, 0x7f, 0xce, 0x92, 0x4d, - 0xaf, 0x83, 0x11, 0xf6, 0x83, 0xac, 0x4f, 0xc1, 0x49, 0x2b, 0x16, 0x40, 0x8f, 0x0b, 0xcb, 0xec, - 0x6e, 0xfc, 0xe4, 0x8c, 0xcf, 0xe0, 0x94, 0xd3, 0xac, 0x1c, 0xcd, 0x46, 0x58, 0x0e, 0xa6, 0x44, - 0x47, 0x00, 0xb6, 0x94, 0x9f, 0xa7, 0x25, 0x9a, 0xb8, 0x6b, 0xd6, 0x93, 0x5b, 0xb5, 0xb7, 0x59, - 0xf0, 0x2c, 0x2c, 0x90, 0x61, 0x4a, 0xbd, 0x52, 0xea, 0x19, 0x97, 0x0a, 0x91, 0xb1, 0x75, 0x05, - 0xd4, 0xdd, 0x3d, 0x64, 0x5b, 0x50, 0x70, 0x7c, 0xb7, 0x45, 0x01, 0xdf, 0x37, 0x83, 0x1a, 0xdf, - 0xc0, 0x76, 0x81, 0x2b, 0xc1, 0x63, 0x62, 0x5b, 0x35, 0xb1, 0x89, 0xa7, 0xf2, 0x17, 0xc3, 0xd7, - 0x16, 0xf8, 0x7c, 0x61, 0x96, 0x4b, 0x86, 0x93, 0x7c, 0x0d, 0x1c, 0x6c, 0x3e, 0x87, 0x27, 0xb5, - 0x09, 0xb0, 0xf7, 0x2c, 0x88, 0xef, 0x50, 0xc9, 0x4a, 0x36, 0xc6, 0x47, 0xfa, 0xcb, 0xa6, 0x3f, - 0x70, 0xc6, 0xbf, 0xe8, 0xed, 0xae, 0x38, 0x0d, 0xa4, 0xe0, 0x4a, 0xcb, 0xe1, 0x6a, 0xa3, 0x0d, - 0x78, 0x5a, 0x93, 0x43, 0x6a, 0x96, 0x52, 0xad, 0x23, 0x80, 0x5d, 0x10, 0x5d, 0x34, 0xa5, 0x6c, - 0xb5, 0xca, 0xcb, 0x7c, 0x23, 0xbf, 0x04, 0xa9, 0xde, 0xe0, 0x72, 0xbc, 0x32, 0x5b, 0xc0, 0x09, - 0x4b, 0x46, 0x42, 0x0e, 0x94, 0x93, 0x8c, 0x9d, 0x9e, 0xa3, 0xdf, 0xa7, 0xf8, 0x7a, 0xc5, 0x79, - 0x39, 0x53, 0xe9, 0x42, 0xe9, 0x56, 0xff, 0xcf, 0x48, 0x5a, 0x8a, 0xc0, 0x31, 0x79, 0x95, 0x36, - 0xf4, 0x3e, 0x4e, 0xdb, 0x6b, 0x3f, 0x42, 0x22, 0xd3, 0x73, 0xc0, 0xdd, 0x31, 0x4b, 0xad, 0x87, - 0x6f, 0xf0, 0xdf, 0x3c, 0xff, 0xb5, 0xb0, 0xdc, 0x3d, 0xe5, 0x36, 0x05, 0x07, 0xf7, 0xf2, 0x7a, - 0x08, 0x8b, 0xc6, 0xfd, 0x89, 0x50, 0xa6, 0xbd, 0xfc, 0x27, 0x5b, 0x2c, 0x0b, 0xec, 0x25, 0x35, - 0x49, 0x83, 0x1a, 0xc0, 0x11, 0x9a, 0x34, 0x4e, 0x12, 0x3c, 0x88, 0x87, 0xf3, 0xde, 0x60, 0x1e, - 0xbe, 0x38, 0xf5, 0x8c, 0x24, 0x9a, 0x37, 0x07, 0xc7, 0xf7, 0x94, 0xa9, 0x17, 0x3d, 0xac, 0x77, - 0xbc, 0x88, 0x78, 0x16, 0x3d, 0x43, 0x9a, 0xf6, 0x72, 0x51, 0x1a, 0xb0, 0x95, 0xfb, 0xae, 0x03, - 0xc0, 0x26, 0x91, 0x60, 0x5d, 0x40, 0xd3, 0x61, 0xaa, 0x21, 0x01, 0x18, 0xd5, 0x86, 0xb5, 0x78, - 0x01, 0x4c, 0xf8, 0x4f, 0x52, 0xbd, 0xe8, 0x7d, 0x99, 0x03, 0x7d, 0x8d, 0xce, 0x1a, 0x7d, 0xce, - 0xc2, 0xb2, 0xfb, 0x02, 0xfc, 0x67, 0xbf, 0x1b, 0xaa, 0x8c, 0x35, 0x26, 0x15, 0x2d, 0x84, 0x96, - 0xc4, 0xac, 0xf6, 0x5b, 0xc0, 0x03, 0x77, 0x6f, 0xc2, 0xe4, 0xbd, 0xe1, 0x25, 0xa6, 0x84, 0xaf, - 0x20, 0xab, 0x54, 0xf1, 0x71, 0x05, 0x83, 0x91, 0x98, 0x81, 0x7b, 0x77, 0xaa, 0xbd, 0x2e, 0xae, - 0x3f, 0xd6, 0x27, 0x2e, 0xcd, 0x3d, 0x61, 0x19, 0xb1, 0x24, 0xc0, 0x2f, 0xbd, 0x2b, 0x36, 0x05, - 0xd7, 0x06, 0x3d, 0xcf, 0x27, 0x8e, 0x50, 0x82, 0x16, 0xa6, 0xc0, 0x09, 0xa3, 0x9b, 0x8f, 0x4b, - 0x4b, 0x6c, 0x56, 0x0e, 0x97, 0xb3, 0xf5, 0x3a, 0xe0, 0x38, 0xcf, 0x72, 0x93, 0x28, 0xa3, 0x85, - 0x6b, 0x5f, 0xfe, 0x61, 0x10, 0x77, 0xb0, 0x15, 0x92, 0x4c, 0x00, 0x86, 0x92, 0xc3, 0x09, 0x68, - 0xb9, 0xc8, 0xc5, 0x78, 0x01, 0xcb, 0x9e, 0x2f, 0xf4, 0xf3, 0xd8, 0x41, 0xcd, 0x88, 0xd6, 0x8b, - 0xae, 0x5b, 0x1e, 0x54, 0x7e, 0xf1, 0xec, 0xa0, 0xef, 0x75, 0xd6, 0xd9, 0xce, 0x1f, 0x6c, 0x8e, - 0xe6, 0x5a, 0x15, 0x46, 0x1e, 0x88, 0x2e, 0x2b, 0xbb, 0xb9, 0xb4, 0xbf, 0x4f, 0x63, 0xf9, 0x5e, - 0x8e, 0xcd, 0xa3, 0xfd, 0x11, 0x53, 0x2c, 0xf3, 0x54, 0x57, 0x3a, 0xf7, 0x88, 0x18, 0x57, 0x11, - 0x9d, 0x89, 0xb5, 0xff, 0xca, 0xb1, 0x66, 0x22, 0xbe, 0x24, 0x78, 0x13, 0x69, 0x47, 0x16, 0xa3, - 0xc0, 0x09, 0x6e, 0x9f, 0x0f, 0xed, 0x5f, 0x2f, 0xab, 0x9c, 0x95, 0xaa, 0x6f, 0xea, 0x00, 0xcf, - 0x55, 0xde, 0xbd, 0x8f, 0xc9, 0x18, 0xc7, 0xc1, 0x41, 0x9b, 0xb0, 0x72, 0x35, 0x1a, 0x0f, 0xb9, - 0x19, 0x11, 0x97, 0x85, 0x07, 0xa5, 0xe1, 0xc0, 0xb2, 0xb3, 0x0c, 0x74, 0x2f, 0x33, 0xb0, 0xc0, - 0xe9, 0xe2, 0x48, 0xe0, 0x42, 0xb0, 0x23, 0xe5, 0x58, 0x93, 0x60, 0x17, 0x30, 0xa8, 0x13, 0x2f, - 0x3c, 0x48, 0x18, 0x3b, 0xb1, 0x1b, 0x16, 0xc1, 0x57, 0xd6, 0xed, 0xd5, 0x75, 0x78, 0x01, 0xc1, - 0x23, 0x2f, 0x8e, 0xf3, 0x91, 0xcd, 0x72, 0x5e, 0x12, 0x53, 0x8d, 0xfa, 0xc0, 0x7d, 0xc5, 0x93, - 0x3f, 0xcf, 0xff, 0xf1, 0xf5, 0xc3, 0x23, 0xeb, 0x2e, 0x4b, 0x92, 0x9a, 0xe5, 0xb8, 0x2f, 0x6c, - 0xc3, 0x47, 0x07, 0xec, 0x83, 0x0d, 0xff, 0x9d, 0xa9, 0x4d, 0x09, 0x9d, 0x75, 0xb4, 0x24, 0x16, - 0xaf, 0x00, 0xe7, 0xc6, 0x1a, 0x8f, 0xaf, 0x64, 0x47, 0xa9, 0x50, 0xbf, 0x08, 0xfb, 0x2c, 0xf8, - 0x77, 0xff, 0x14, 0x6d, 0x58, 0xe0, 0x74, 0xb3, 0x02, 0x50, 0xa6, 0x0c, 0xaa, 0xb1, 0x0b, 0x2b, - 0x1d, 0x15, 0xa0, 0x4d, 0xfc, 0x88, 0xb7, 0x0f, 0x57, 0xf4, 0x92, 0xcc, 0x50, 0x3e, 0x35, 0x09, - 0x0a, 0x18, 0xab, 0xcc, 0xf8, 0x72, 0xfd, 0xf7, 0x9f, 0x1b, 0xdd, 0x5d, 0x2b, 0xcb, 0xcd, 0xbd, - 0xb7, 0x1d, 0x96, 0xdd, 0xb0, 0xd3, 0xdb, 0x64, 0xbe, 0x33, 0xa8, 0x92, 0x01, 0x0f, 0x2c, 0xe5, - 0x85, 0xd2, 0x79, 0x9d, 0x23, 0xfe, 0xf8, 0xda, 0x1d, 0x34, 0xd6, 0x95, 0x7f, 0x93, 0x4d, 0x7e, - 0xec, 0x4f, 0x03, 0xfe, 0xc1, 0x9d, 0xc0, 0x54, 0xe0, 0xca, 0xea, 0x95, 0x4d, 0x34, 0x82, 0x8c, - 0x94, 0xd7, 0x87, 0xd2, 0x24, 0x5a, 0x1f, 0x00, 0x9e, 0xd8, 0x85, 0xe3, 0xf3, 0xe0, 0x1c, 0xfb, - 0x9b, 0xf0, 0x63, 0xb8, 0x64, 0x45, 0x70, 0x32, 0x3d, 0x69, 0x9a, 0xf6, 0x72, 0x59, 0x1a, 0xb0, - 0x3a, 0xb5, 0xfb, 0x60, 0x38, 0x05, 0x0e, 0x52, 0x17, 0x3f, 0xfc, 0x09, 0x14, 0xee, 0x18, 0x04, - 0xe3, 0x76, 0x13, 0xad, 0x09, 0x5c, 0x2c, 0x2c, 0x5c, 0xed, 0x5d, 0xd6, 0xae, 0xe0, 0xfb, 0x2d, - 0x18, 0x47, 0x11, 0xb2, 0x15, 0x74, 0x67, 0x94, 0x05, 0x83, 0x9f, 0xe3, 0xd5, 0x53, 0x55, 0x9d, - 0x72, 0xbe, 0xf0, 0x2f, 0x69, 0x48, 0x6f, 0x63, 0xf9, 0x5e, 0xf2, 0xc0, 0xb0, 0xee, 0x6f, 0x66, - 0x51, 0x53, 0xbb, 0x4d, 0x28, 0xb6, 0x11, 0x36, 0x16, 0xc8, 0xea, 0xfd, 0x5e, 0xba, 0xda, 0x1e, - 0x76, 0x99, 0xd0, 0x65, 0x54, 0xea, 0xc0, 0x72, 0x6e, 0x77, 0xe7, 0xee, 0xdb, 0xd7, 0xfb, 0x9b, - 0x4d, 0xda, 0x37, 0x30, 0x6e, 0xf8, 0xc5, 0xef, 0x60, 0x13, 0x0e, 0x18, 0x58, 0x9c, 0x79, 0xda, - 0xd0, 0xc2, 0xa3, 0x2c, 0x66, 0xb2, 0x8b, 0xa3, 0x73, 0x3b, 0x35, 0x5a, 0xb1, 0x39, 0x09, 0x26, - 0x0d, 0xc0, 0x24, 0x89, 0xaf, 0x00, 0x53, 0xc4, 0xaa, 0x5c, 0x5e, 0xdd, 0x03, 0xb4, 0xf5, 0xfa, - 0x91, 0x66, 0xac, 0x1c, 0xad, 0x46, 0x38, 0x0e, 0x80, 0xa8, 0xba, 0x74, 0xf5, 0xf5, 0x60, 0xbf, - 0xfe, 0x7f, 0x0d, 0xb7, 0xad, 0x38, 0x3d, 0xb4, 0x23, 0xa3, 0xbc, 0x63, 0xc2, 0x08, 0xde, 0x9a, - 0x00, 0x88, 0xbf, 0x83, 0xe6, 0xec, 0xfc, 0x57, 0xf0, 0xff, 0xd5, 0xb9, 0x07, 0x3d, 0x42, 0x4d, - 0x82, 0xcb, 0xf9, 0x3d, 0xc8, 0x70, 0xea, 0xb5, 0x50, 0xb3, 0x11, 0x7c, 0x82, 0x3f, 0xfe, 0x57, - 0xf0, 0x0e, 0xf3, 0x8a, 0xbd, 0x9f, 0x93, 0xb4, 0x96, 0xe5, 0xf1, 0x97, 0x96, 0x0c, 0xd1, 0x79, - 0xdf, 0xf9, 0x6f, 0xc0, 0xd5, 0x54, 0x81, 0xbb, 0x97, 0x5f, 0xfb, 0xb6, 0x2e, 0x15, 0xb1, 0x7c, - 0x5b, 0x8b, 0x4b, 0xa3, 0x9a, 0x30, 0xf5, 0x82, 0x1a, 0x7d, 0x1c, 0x16, 0x6c, 0x08, 0xf2, 0x5c, - 0x17, 0x52, 0xbe, 0xff, 0x52, 0x3e, 0xf7, 0xbb, 0x25, 0x80, 0x5c, 0x46, 0x89, 0xe5, 0xc7, 0x62, - 0x74, 0xea, 0xdc, 0xa0, 0xda, 0xa0, 0x3f, 0x08, 0xdf, 0xcf, 0xaf, 0x9b, 0xdf, 0x78, 0x91, 0x6b, - 0x7c, 0x00, 0x77, 0x74, 0xb0, 0x3e, 0x0c, 0xd4, 0x6c, 0xaf, 0xdd, 0xed, 0xc7, 0x71, 0xa7, 0x16, - 0x3f, 0x33, 0x8f, 0x5a, 0xc7, 0xbd, 0x47, 0x76, 0x07, 0x24, 0x11, 0xd7, 0xa6, 0x9a, 0x56, 0x69, - 0x3b, 0x12, 0xb0, 0xe0, 0xd0, 0x12, 0x23, 0xc4, 0x8c, 0x32, 0xc4, 0x3a, 0x00, 0xba, 0x6e, 0xc3, - 0x89, 0x7c, 0x96, 0x48, 0x0a, 0x08, 0x24, 0x30, 0x8d, 0x2c, 0x0b, 0x56, 0xe6, 0xd5, 0x55, 0x39, - 0x5e, 0xf5, 0xed, 0x3c, 0xc0, 0x5b, 0x59, 0x0b, 0xe9, 0xbe, 0x2e, 0xb9, 0xb5, 0x7e, 0xff, 0xbd, - 0x6f, 0x80, 0x1e, 0xc4, 0xe4, 0x1b, 0xaf, 0xfc, 0x55, 0x1f, 0x19, 0x7d, 0x4c, 0x4f, 0xcc, 0xbc, - 0xee, 0xb2, 0x67, 0x02, 0xe9, 0x2f, 0x1b, 0xe4, 0xfa, 0x1b, 0xc5, 0xfc, 0x9a, 0x2e, 0x41, 0x82, - 0xc6, 0xfe, 0x01, 0x8f, 0x4b, 0x1b, 0x79, 0x1b, 0x2b, 0x85, 0xe9, 0x5f, 0x92, 0xe1, 0xba, 0x97, - 0xae, 0x9b, 0x68, 0x7c, 0xd2, 0x4c, 0x8d, 0xdc, 0xb2, 0xc0, 0x46, 0xd2, 0xe1, 0x5e, 0x6b, 0xf3, - 0x79, 0x7a, 0xf3, 0xcb, 0x3c, 0x5d, 0x23, 0xb0, 0x93, 0x47, 0x39, 0xfd, 0x4e, 0x1a, 0xe5, 0x95, - 0xc1, 0x47, 0x5f, 0xf9, 0xed, 0x0b, 0xdc, 0xcc, 0x75, 0x2a, 0x6a, 0x06, 0x00, 0x91, 0x19, 0x8c, - 0x56, 0xfd, 0x00, 0x93, 0x18, 0xfc, 0xd2, 0x30, 0xbd, 0xa2, 0xa2, 0xa6, 0xd8, 0x96, 0x78, 0xf1, - 0x8e, 0x7c, 0x46, 0xc8, 0x79, 0xf8, 0xda, 0xcb, 0x3b, 0x02, 0x6d, 0x5e, 0x01, 0x32, 0xf4, 0x86, - 0x7f, 0xe6, 0x7c, 0xfd, 0xcf, 0x08, 0x0f, 0x09, 0x6f, 0x03, 0xfa, 0x11, 0x96, 0x7b, 0x73, 0x75, - 0x90, 0xdc, 0xfe, 0x5e, 0x62, 0x61, 0x67, 0x1b, 0xc8, 0x8c, 0xb9, 0x32, 0x98, 0x4d, 0x9a, 0xd4, - 0xa0, 0x39, 0x5b, 0xd6, 0x0b, 0x56, 0x56, 0xcf, 0x55, 0x43, 0x2f, 0x6f, 0xb8, 0xf6, 0x83, 0xff, - 0xe7, 0x62, 0x7b, 0x73, 0xf9, 0x4e, 0xea, 0xec, 0x3e, 0x1e, 0xa6, 0xbf, 0xbf, 0x87, 0xdb, 0x1a, - 0xdb, 0xca, 0xb4, 0xc7, 0xa5, 0x30, 0x2b, 0xcd, 0x79, 0xef, 0x9b, 0x58, 0xdc, 0x30, 0xf8, 0x70, - 0x8e, 0x2f, 0x42, 0xde, 0x83, 0x44, 0x25, 0xf7, 0xdd, 0x55, 0x3e, 0x12, 0x55, 0x4e, 0x15, 0x5f, - 0x37, 0x91, 0xe9, 0xe3, 0x1f, 0x20, 0xda, 0x51, 0xcb, 0xff, 0xfd, 0x6d, 0x72, 0xfc, 0x3f, 0x5b, - 0x0f, 0xc7, 0x70, 0xcd, 0x84, 0xd9, 0x8e, 0x36, 0x92, 0x1d, 0x4a, 0x61, 0x70, 0x9b, 0x9b, 0x68, - 0x9b, 0x27, 0xc6, 0x99, 0x10, 0xa3, 0xce, 0x53, 0x21, 0xf4, 0x31, 0x3c, 0x87, 0x84, 0x69, 0x81, - 0x9d, 0xa5, 0xef, 0x0f, 0xf1, 0xca, 0xae, 0xf0, 0x63, 0x1c, 0x84, 0x5b, 0x8f, 0x77, 0xe5, 0x6b, - 0x11, 0xec, 0x26, 0x59, 0x9f, 0x16, 0x89, 0xe1, 0xc2, 0xad, 0x56, 0xb8, 0x2e, 0x31, 0x68, 0x5d, - 0x2a, 0x83, 0xf6, 0xef, 0xfe, 0x61, 0x76, 0x9d, 0x60, 0x2a, 0x87, 0xc5, 0x85, 0xff, 0x22, 0xe4, - 0x4b, 0x08, 0x48, 0x13, 0x8a, 0x00, 0x3b, 0x48, 0xc9, 0x21, 0x06, 0xc1, 0xbb, 0xd9, 0xd1, 0x3d, - 0x52, 0x49, 0x6a, 0x44, 0x93, 0x09, 0xc8, 0x8b, 0x8a, 0x5e, 0x7e, 0x8d, 0x0b, 0x26, 0xc3, 0x59, - 0xbb, 0xad, 0x92, 0xaa, 0x46, 0x0b, 0xbe, 0xd6, 0xaa, 0xa0, 0x36, 0x5f, 0x34, 0x6a, 0x88, 0x84, - 0x0a, 0xfc, 0xa8, 0xb8, 0xbd, 0xb4, 0xa4, 0xf4, 0xc6, 0xe1, 0x88, 0x55, 0x5d, 0x4e, 0xc9, 0xdc, - 0x7d, 0xa2, 0x71, 0x0d, 0x18, 0x1e, 0x16, 0x1d, 0x17, 0x11, 0xb3, 0x91, 0x92, 0xf0, 0xc6, 0x1b, - 0x3a, 0x54, 0x80, 0x8f, 0x11, 0x71, 0x9b, 0x02, 0x16, 0xf4, 0x8f, 0xf0, 0x37, 0xf2, 0xea, 0xa8, - 0x95, 0x61, 0x8e, 0x8f, 0x22, 0x22, 0xc0, 0xef, 0x51, 0x0b, 0x18, 0x8d, 0xd8, 0xe8, 0x0b, 0x76, - 0x3e, 0xa5, 0x28, 0xc3, 0x6f, 0xde, 0xf1, 0xf4, 0x55, 0x7d, 0x48, 0xfd, 0xe3, 0xa5, 0x64, 0x45, - 0x70, 0x3c, 0xbe, 0x0f, 0x06, 0x22, 0xc8, 0x95, 0x89, 0x0a, 0x56, 0xd6, 0x8a, 0x36, 0x42, 0xbe, - 0xe6, 0x20, 0x00, 0x5c, 0xaa, 0xc6, 0x2e, 0xea, 0x19, 0x11, 0xfc, 0x07, 0x38, 0x08, 0x30, 0x7f, - 0xb1, 0xe7, 0xfd, 0x71, 0x1c, 0x37, 0xc1, 0xd1, 0x4c, 0x3f, 0x16, 0x4c, 0x4d, 0x06, 0x69, 0xca, - 0x3b, 0x8b, 0x79, 0xfd, 0x05, 0x0c, 0x8c, 0x60, 0xee, 0xaa, 0x91, 0x16, 0xf1, 0xab, 0x8a, 0x55, - 0xf1, 0xb2, 0x85, 0xfc, 0xa7, 0xde, 0x6f, 0x32, 0xd3, 0x1f, 0xfd, 0xc2, 0x0d, 0xc7, 0x74, 0x4d, - 0xcb, 0xae, 0x77, 0x96, 0xd3, 0xf3, 0x0a, 0xa0, 0x97, 0xd1, 0xf5, 0x54, 0xb8, 0xba, 0x45, 0x63, - 0x1f, 0xe4, 0xef, 0x80, 0x63, 0xd4, 0xef, 0xef, 0x74, 0x56, 0x93, 0xf3, 0xfe, 0x60, 0x97, 0xcb, - 0xf5, 0x55, 0x89, 0x0b, 0x92, 0x4e, 0xb5, 0x22, 0xe3, 0x0e, 0xc4, 0x5e, 0xc9, 0x0b, 0xc8, 0x52, - 0xc1, 0x43, 0x0a, 0x6e, 0x6e, 0xee, 0xe9, 0xd2, 0x58, 0xe1, 0x08, 0xd5, 0x93, 0xdd, 0x96, 0x57, - 0x8b, 0x06, 0x2f, 0xb4, 0x3b, 0x0a, 0x00, 0x5f, 0x9d, 0x55, 0x14, 0x57, 0xfe, 0xee, 0xbe, 0x19, - 0x61, 0xa5, 0x63, 0x81, 0x6a, 0xf0, 0x1e, 0xf8, 0xdc, 0xa0, 0xf4, 0x98, 0xaa, 0x0b, 0x40, 0xfa, - 0xea, 0xb1, 0xb7, 0xce, 0xb7, 0x80, 0x3b, 0x56, 0x09, 0xb6, 0xa5, 0x92, 0x84, 0x0b, 0x01, 0xca, - 0x51, 0x86, 0xad, 0xd5, 0x1a, 0xc5, 0x9f, 0xba, 0x2b, 0xc5, 0x30, 0x66, 0xd2, 0xbc, 0xa5, 0xb1, - 0xcd, 0x3a, 0x73, 0x29, 0x49, 0x47, 0x58, 0xe3, 0xb7, 0x55, 0xeb, 0x15, 0x7f, 0x0d, 0xf8, 0x12, - 0x55, 0x02, 0x92, 0x3a, 0xe7, 0x60, 0xdf, 0xfa, 0x3a, 0x3a, 0x01, 0x35, 0xf0, 0x06, 0xe5, 0x85, - 0xdd, 0x21, 0xef, 0xe7, 0x84, 0xda, 0x08, 0x22, 0xa2, 0xab, 0x83, 0x92, 0x25, 0x15, 0x8b, 0x00, - 0x4f, 0x6a, 0xc9, 0x01, 0xa4, 0xc1, 0x62, 0xf6, 0x07, 0x24, 0x19, 0xbb, 0x5d, 0xe0, 0x36, 0x69, - 0xf5, 0x6a, 0xef, 0x22, 0x73, 0xc7, 0xb6, 0xc2, 0x03, 0xc9, 0x53, 0x9f, 0x4d, 0xd5, 0x1e, 0x03, - 0x00, 0xd9, 0xa4, 0x44, 0x44, 0x45, 0x15, 0x2e, 0xdb, 0x91, 0x09, 0xf0, 0xd8, 0x30, 0x0b, 0x08, - 0x29, 0x55, 0x1e, 0xd2, 0x58, 0xa1, 0xed, 0xda, 0xe0, 0x64, 0xec, 0x83, 0x2b, 0x5b, 0x30, 0x7a, - 0x90, 0xb0, 0x5f, 0x1a, 0x55, 0x38, 0xa6, 0x5d, 0x6f, 0xaa, 0x4e, 0x03, 0x6e, 0x00, 0x0b, 0xc6, - 0x35, 0x5d, 0x37, 0x23, 0xea, 0xa9, 0x81, 0xa2, 0x52, 0x0e, 0x9c, 0xd5, 0x7e, 0xaa, 0x98, 0x05, - 0x5c, 0x0c, 0xf3, 0x41, 0x07, 0x3e, 0x81, 0x6b, 0xf1, 0x7f, 0x50, 0xef, 0x9b, 0x8f, 0xc2, 0xf0, - 0x97, 0xaf, 0xbf, 0x00, 0x52, 0x02, 0x57, 0x59, 0xfc, 0x75, 0x0c, 0x90, 0x1a, 0x47, 0x17, 0x0e, - 0xf0, 0x0d, 0x3f, 0x6e, 0x97, 0x80, 0x99, 0x60, 0x37, 0x6a, 0xcc, 0xe9, 0xd9, 0x11, 0x09, 0xc4, - 0x09, 0x60, 0x00, 0x25, 0x06, 0x2f, 0xb6, 0x8e, 0xaf, 0x68, 0xa9, 0x29, 0xab, 0xa9, 0xaa, 0xa7, - 0x45, 0xcb, 0x0c, 0xe4, 0x85, 0xbc, 0x27, 0xd5, 0xa6, 0x00, 0x72, 0xa5, 0xc0, 0x72, 0xf1, 0xef, - 0x71, 0x42, 0x0c, 0x1b, 0x02, 0xdb, 0x44, 0x40, 0x0b, 0xde, 0x15, 0x7c, 0x43, 0xdf, 0xe2, 0x52, - 0x0b, 0x2c, 0x9f, 0xf5, 0x24, 0xab, 0xc4, 0x69, 0xaa, 0xa2, 0xe0, 0x39, 0xe0, 0x2e, 0x11, 0x2e, - 0x11, 0x39, 0x0f, 0x38, 0x5e, 0x6f, 0x2a, 0x70, 0xa3, 0x5e, 0x9c, 0xdc, 0xe8, 0xd5, 0x63, 0x6b, - 0x70, 0x05, 0xf0, 0x27, 0xbd, 0x70, 0x0d, 0x4b, 0xf5, 0x54, 0xe0, 0x79, 0x11, 0x4a, 0x16, 0xb9, - 0x03, 0x2f, 0x58, 0xf5, 0x39, 0xbc, 0xa9, 0xc9, 0xff, 0xc5, 0x94, 0x6a, 0xa8, 0x51, 0x05, 0x0b, - 0x82, 0xfe, 0xa0, 0xd7, 0xd5, 0xc4, 0xae, 0xb7, 0x45, 0xfc, 0x4a, 0x2f, 0x07, 0x72, 0x87, 0x70, - 0x1c, 0x88, 0x97, 0x8d, 0x59, 0x30, 0x3d, 0xfa, 0x80, 0xd3, 0xd8, 0x09, 0xaa, 0x8f, 0xbc, 0x03, - 0xfc, 0x0a, 0xaf, 0x00, 0x70, 0x16, 0xa4, 0xec, 0xaa, 0xa3, 0xe3, 0x76, 0xd2, 0x85, 0x11, 0xef, - 0x91, 0x91, 0x1c, 0xc0, 0x67, 0xbc, 0x50, 0xf8, 0x67, 0xbc, 0x32, 0x78, 0xf5, 0xde, 0xed, 0x27, - 0x67, 0x01, 0x12, 0xf0, 0x46, 0x7d, 0x49, 0xe3, 0x75, 0xfc, 0x3a, 0x54, 0xe2, 0xf0, 0xe6, 0x71, - 0xbf, 0x55, 0x14, 0xaa, 0x28, 0xe0, 0xec, 0x65, 0x5e, 0x7f, 0x16, 0x44, 0x97, 0x02, 0x92, 0x13, - 0x34, 0x9f, 0x4b, 0xc4, 0xd3, 0x78, 0xe5, 0x6b, 0x99, 0x29, 0xa3, 0xa4, 0xad, 0xd1, 0xe5, 0x39, - 0xc9, 0x07, 0x00, 0x24, 0x65, 0x03, 0x6b, 0x27, 0xb7, 0xb1, 0x48, 0xbf, 0x56, 0x0e, 0xe6, 0xa3, - 0xb9, 0x46, 0x42, 0x18, 0xe8, 0xfa, 0x07, 0x80, 0x87, 0xee, 0xc8, 0x88, 0xc0, 0x21, 0x89, 0x8f, - 0x58, 0xe9, 0x08, 0xb4, 0x6b, 0xbc, 0x79, 0xac, 0x56, 0x5f, 0xa6, 0x4b, 0x89, 0x6f, 0x88, 0xe2, - 0xc0, 0x69, 0x93, 0x51, 0x1f, 0x63, 0xda, 0xaa, 0xe7, 0x8b, 0xfe, 0xf4, 0xf6, 0x92, 0x34, 0xb5, - 0x55, 0x0a, 0x41, 0x5d, 0x8c, 0x48, 0x2d, 0x22, 0x64, 0x44, 0xf0, 0x22, 0xc0, 0x77, 0x44, 0x67, - 0xb4, 0xc4, 0x2b, 0x97, 0x85, 0xe0, 0x4b, 0xe1, 0x77, 0x0e, 0x83, 0x04, 0x74, 0xe8, 0x6d, 0x4c, - 0xf0, 0xcb, 0x84, 0xe9, 0x60, 0x4b, 0x21, 0x6a, 0x73, 0xa6, 0x49, 0x1d, 0x2c, 0x22, 0x72, 0xae, - 0xd7, 0xb8, 0xc5, 0xf8, 0x22, 0x00, 0x76, 0xf2, 0x85, 0x7c, 0x8e, 0x30, 0x92, 0x1f, 0x02, 0xe1, - 0x12, 0x83, 0xc5, 0x80, 0xc1, 0xc4, 0x0d, 0x53, 0x5b, 0xd8, 0xe8, 0x95, 0x4d, 0x24, 0x81, 0xc0, - 0x2a, 0x34, 0x24, 0x6a, 0x47, 0x7f, 0xf3, 0x8c, 0x15, 0x6d, 0xda, 0xf8, 0x1d, 0xe1, 0x6d, 0x1c, - 0x00, 0xb8, 0x4c, 0x74, 0xfa, 0xd1, 0xaa, 0x35, 0xce, 0xba, 0x51, 0xa8, 0xc3, 0x87, 0x22, 0x10, - 0x21, 0xf2, 0xbc, 0xbc, 0xa6, 0x8d, 0x6f, 0x6d, 0x74, 0x66, 0xb8, 0x64, 0xe6, 0x7f, 0xe3, 0x50, - 0xef, 0x59, 0x02, 0x31, 0xeb, 0x0c, 0x69, 0x2a, 0x5a, 0xe3, 0x73, 0xe4, 0x8d, 0xfe, 0xcd, 0xab, - 0x00, 0x4b, 0x46, 0x06, 0x0d, 0xbf, 0x57, 0xb2, 0xe2, 0x4d, 0x69, 0xb0, 0xda, 0x69, 0x22, 0x17, - 0xde, 0x65, 0xdf, 0xe4, 0x3b, 0x98, 0x18, 0x6b, 0xda, 0xd3, 0x25, 0xbd, 0x36, 0x1c, 0xa5, 0x56, - 0x8e, 0x2c, 0x60, 0x17, 0x38, 0x70, 0x3b, 0xf6, 0x64, 0x44, 0x5e, 0x34, 0xd8, 0xe3, 0x6d, 0x74, - 0xd8, 0xcd, 0xe1, 0x16, 0x31, 0xc2, 0x5c, 0x2d, 0xb6, 0x34, 0xb7, 0x95, 0x6e, 0x8e, 0x2e, 0x31, - 0x02, 0xac, 0x20, 0x9e, 0x05, 0x45, 0x86, 0x01, 0x10, 0x54, 0xe3, 0x91, 0xad, 0xf0, 0x9e, 0x3d, - 0x96, 0xda, 0x7d, 0xe1, 0x25, 0x06, 0x45, 0x00, 0x48, 0xe4, 0xcd, 0xe0, 0xec, 0x06, 0x4e, 0x2d, - 0x92, 0x74, 0xa1, 0x26, 0x5e, 0xe9, 0x26, 0x8a, 0x30, 0x21, 0x34, 0x47, 0x44, 0x67, 0xea, 0xd6, - 0x59, 0xa4, 0x39, 0xb5, 0x87, 0x22, 0x3f, 0x63, 0x52, 0xe3, 0xda, 0xbc, 0x80, 0x01, 0x45, 0x17, - 0xdd, 0x32, 0xcd, 0x89, 0x8c, 0x22, 0xc2, 0xc8, 0x16, 0xa8, 0x44, 0x61, 0x18, 0x56, 0x15, 0x99, - 0x66, 0x46, 0x64, 0x61, 0x18, 0x56, 0x22, 0xd5, 0xce, 0x8c, 0xe7, 0x0a, 0xcc, 0x8e, 0xba, 0xf2, - 0x2d, 0x91, 0xd7, 0xd6, 0x37, 0xc7, 0xbb, 0xe1, 0xc9, 0x3d, 0xf1, 0xbf, 0x93, 0x8f, 0x28, 0xdb, - 0xf4, 0x28, 0x32, 0x0e, 0xa2, 0xb3, 0x35, 0x5f, 0x02, 0x4e, 0xda, 0xb0, 0xf7, 0xe8, 0xcb, 0x50, - 0x9a, 0xf6, 0xe7, 0x1a, 0xe3, 0x80, 0x4f, 0x29, 0xb5, 0x04, 0xfd, 0x8a, 0x95, 0x8c, 0x09, 0xa4, - 0x0e, 0x58, 0x13, 0x47, 0xa8, 0x13, 0x34, 0xec, 0xf6, 0x7f, 0x2b, 0x30, 0xf2, 0xe2, 0xca, 0xcd, - 0x44, 0xff, 0x75, 0xeb, 0xfd, 0xa7, 0x8f, 0x6e, 0x6f, 0xf4, 0x6e, 0x7c, 0x0f, 0x75, 0x5b, 0x9f, - 0x97, 0x5d, 0xc6, 0x38, 0xaa, 0xe3, 0x2d, 0x5a, 0x22, 0x8f, 0xcc, 0xb0, 0x82, 0xcc, 0xa6, 0xbd, - 0x00, 0xe6, 0xcf, 0x2a, 0x50, 0xd0, 0x0e, 0xca, 0x4d, 0xb8, 0x27, 0xec, 0x86, 0x8c, 0xe4, 0xaa, - 0xc1, 0xec, 0xd9, 0x7e, 0x87, 0x4d, 0x51, 0xa3, 0x1d, 0x94, 0x88, 0xf0, 0x30, 0xac, 0x20, 0xfb, - 0xbe, 0x76, 0xf2, 0xbb, 0x1f, 0xca, 0x0e, 0x83, 0x13, 0x78, 0x6c, 0xf0, 0x97, 0x4a, 0x62, 0x53, - 0xd0, 0x21, 0xa5, 0xc8, 0x5f, 0x3b, 0xe0, 0x1a, 0x17, 0xdf, 0x9b, 0x01, 0x68, 0x1b, 0x6a, 0xcf, - 0xa6, 0x41, 0xe3, 0x46, 0x70, 0x1c, 0xfb, 0x3c, 0xb0, 0x1c, 0x3b, 0xe5, 0x7c, 0xf4, 0x21, 0x77, - 0x62, 0x2c, 0x2a, 0x5d, 0xee, 0xd2, 0xec, 0x70, 0x88, 0x57, 0x11, 0xc8, 0x42, 0xf8, 0x67, 0x8e, - 0xc8, 0x8c, 0xd4, 0x1e, 0xce, 0x0d, 0xdb, 0x03, 0xf4, 0x73, 0x43, 0x05, 0xbf, 0xad, 0xa1, 0x4c, - 0x6e, 0xa4, 0x55, 0x00, 0x0b, 0x5d, 0x07, 0xbc, 0x19, 0x6f, 0x3d, 0x4f, 0x80, 0xe4, 0x53, 0x7f, - 0xdf, 0xd5, 0xc2, 0x0f, 0xc5, 0xde, 0xfa, 0x78, 0xf5, 0xd6, 0xfb, 0xda, 0xaa, 0xba, 0xae, 0xfe, - 0xf3, 0xce, 0x8a, 0xa4, 0x41, 0x0b, 0xe3, 0xc7, 0x01, 0x1b, 0x35, 0xdb, 0x83, 0xfc, 0x91, 0x4d, - 0xf2, 0xe7, 0x76, 0x0f, 0xc0, 0xaf, 0x68, 0xe1, 0x81, 0x18, 0xb3, 0xf0, 0x02, 0x8d, 0xcd, 0x36, - 0x01, 0x4a, 0x94, 0xe2, 0x7e, 0xaa, 0xc2, 0x91, 0x44, 0xa5, 0xd5, 0x50, 0x45, 0x87, 0xf5, 0xe4, - 0x3b, 0xc0, 0xd9, 0x81, 0x1b, 0x24, 0x29, 0x98, 0xd4, 0x9e, 0x7f, 0xe7, 0xea, 0xa9, 0x83, 0xab, - 0xf7, 0xb4, 0x88, 0x98, 0x87, 0x9c, 0xf6, 0xb7, 0x35, 0xf8, 0xd8, 0x35, 0x4b, 0xfb, 0xde, 0xd1, - 0x81, 0xc6, 0x6e, 0x0e, 0x9c, 0x76, 0x8e, 0x03, 0x95, 0x27, 0x74, 0x10, 0xc2, 0x9f, 0x82, 0x8f, - 0x4d, 0x75, 0x78, 0xf3, 0x91, 0xeb, 0x8e, 0x1d, 0x91, 0xfd, 0x80, 0x80, 0x39, 0xc9, 0xb1, 0x07, - 0xbe, 0x03, 0x63, 0x65, 0x58, 0x5f, 0x74, 0x2e, 0x4d, 0x35, 0xe6, 0xb4, 0x55, 0x5c, 0x62, 0xe7, - 0x3e, 0x71, 0x55, 0x5a, 0x03, 0xe7, 0x6d, 0xf3, 0x6b, 0xd9, 0x0e, 0x56, 0x88, 0xe6, 0x35, 0x50, - 0x09, 0x52, 0xdf, 0x41, 0xad, 0xbb, 0xad, 0x9f, 0xf4, 0xc1, 0x07, 0xfa, 0x84, 0x0f, 0x9e, 0x5e, - 0xa0, 0xe3, 0x3c, 0xa5, 0x6e, 0x02, 0x6f, 0x11, 0xc1, 0x35, 0xc8, 0xc1, 0xce, 0xe2, 0x5f, 0x3c, - 0x13, 0x58, 0xac, 0xa9, 0xc5, 0xf9, 0xc3, 0xb4, 0x8e, 0xcf, 0x71, 0xf4, 0x38, 0x0e, 0xeb, 0x1e, - 0xe8, 0x21, 0x39, 0xad, 0x9a, 0xe5, 0x36, 0x68, 0x9d, 0xe0, 0xac, 0x76, 0x1c, 0x3b, 0xa5, 0x8d, - 0xfe, 0xb8, 0x84, 0xf7, 0xf6, 0xd2, 0xc3, 0x89, 0x0c, 0xb2, 0x1c, 0xcb, 0x9a, 0x40, 0x83, 0x98, - 0x97, 0xe4, 0xfa, 0xdb, 0x77, 0x39, 0x17, 0x69, 0xc1, 0x9d, 0x4d, 0xaa, 0x54, 0x7f, 0xff, 0xd5, - 0xe9, 0x4a, 0x1c, 0x92, 0x84, 0x4d, 0x41, 0x0b, 0xb3, 0xc7, 0x19, 0x6f, 0xa5, 0x92, 0xe3, 0x46, - 0x15, 0x8a, 0x6c, 0xdd, 0x66, 0x08, 0xbc, 0x68, 0xa7, 0x80, 0xea, 0xf3, 0xec, 0x70, 0x9c, 0x8f, - 0x6f, 0x89, 0x5f, 0x05, 0x42, 0xd2, 0xfb, 0xfb, 0x0b, 0x3b, 0xf3, 0x3b, 0xb2, 0xdc, 0x8f, 0xb1, - 0x6e, 0x1f, 0xe8, 0x89, 0xef, 0xc2, 0xfe, 0x02, 0x85, 0x3e, 0x72, 0x4b, 0x21, 0x34, 0x01, 0xce, - 0x63, 0xc7, 0x04, 0x6d, 0x33, 0xbc, 0x7c, 0xa7, 0x55, 0x7a, 0x0f, 0x0f, 0x45, 0x04, 0xf3, 0xa5, - 0xe5, 0xc0, 0xfb, 0x2e, 0xb1, 0xd9, 0x73, 0x1f, 0x7f, 0x96, 0x40, 0xe3, 0xc0, 0x76, 0xf6, 0xaf, - 0x2b, 0x2b, 0x0a, 0x7b, 0x7f, 0xde, 0x05, 0xbd, 0xbf, 0x7e, 0x17, 0x23, 0x25, 0x2e, 0x62, 0x5b, - 0xf0, 0x27, 0x55, 0x4e, 0xc5, 0x7d, 0x25, 0xf2, 0x9a, 0x3a, 0xe7, 0x14, 0xe3, 0x80, 0xea, 0x31, - 0x0b, 0x80, 0x8b, 0xc0, 0x05, 0x5d, 0xdd, 0x1e, 0xe3, 0x93, 0x6b, 0xcb, 0x79, 0x7b, 0x3f, 0xb5, - 0x06, 0x52, 0x2b, 0xe6, 0x3a, 0xaa, 0xf1, 0xaf, 0x1d, 0x96, 0x6b, 0x0e, 0x52, 0x04, 0xd7, 0x7e, - 0x69, 0xf7, 0x2b, 0x58, 0x69, 0xb6, 0xf5, 0x50, 0xbc, 0x7a, 0x85, 0x79, 0x42, 0x9c, 0x95, 0x5e, - 0x60, 0x5c, 0x72, 0x1b, 0xe4, 0xaa, 0xb6, 0xf1, 0xe6, 0x77, 0xec, 0xb4, 0x5f, 0x6c, 0xd1, 0xe9, - 0x28, 0xb0, 0x25, 0x40, 0xc2, 0x5e, 0xbe, 0x73, 0x06, 0xcb, 0xd2, 0x3c, 0xd0, 0x71, 0x75, 0x20, - 0xb9, 0xaa, 0x90, 0x1d, 0xc8, 0x88, 0xe0, 0x4a, 0xf0, 0x48, 0x07, 0x8a, 0x1c, 0xcc, 0x41, 0x92, - 0x27, 0xd9, 0xa9, 0xd0, 0x2f, 0x78, 0x64, 0x6d, 0x79, 0x5f, 0x06, 0xbf, 0xa1, 0xf6, 0xe3, 0xc1, - 0xf7, 0xd6, 0xb8, 0x69, 0xac, 0x1e, 0xdf, 0x9f, 0x17, 0x00, 0xd1, 0xb9, 0x63, 0xaf, 0x46, 0x7f, - 0x2e, 0x44, 0x7e, 0x01, 0xf6, 0x96, 0x34, 0x75, 0xdd, 0x01, 0xf7, 0xc0, 0x2f, 0x80, 0x15, 0x14, - 0x1c, 0xe4, 0x32, 0x8e, 0x01, 0xce, 0x20, 0xc7, 0x5f, 0x22, 0x3e, 0x02, 0xd9, 0x6f, 0x01, 0x6c, - 0x18, 0x4f, 0x5a, 0xfe, 0x6d, 0x55, 0xa1, 0xce, 0xc3, 0x82, 0x48, 0x31, 0xe4, 0x44, 0xe0, 0x28, - 0x3c, 0x19, 0xc0, 0x39, 0x91, 0x83, 0xc0, 0xe5, 0x81, 0x77, 0xa8, 0x1f, 0xf6, 0xea, 0x2f, 0xb4, - 0xd1, 0xc6, 0x38, 0x9c, 0x1c, 0x07, 0x88, 0x83, 0x07, 0x4c, 0xc6, 0x9e, 0xe3, 0x5e, 0x08, 0xb1, - 0x98, 0xf8, 0x3e, 0xaa, 0xc9, 0x6e, 0xc3, 0x9e, 0x1c, 0x61, 0x99, 0x11, 0xdc, 0x01, 0x1c, 0x07, - 0xf6, 0x97, 0x18, 0xb5, 0x13, 0xa2, 0xe9, 0x58, 0xef, 0xfb, 0xe2, 0xe5, 0x97, 0xff, 0xea, 0xa9, - 0x34, 0xca, 0xcc, 0x2f, 0x7f, 0xb1, 0x1c, 0xe0, 0x05, 0x70, 0x64, 0x44, 0xf0, 0x0c, 0xe0, 0x19, - 0xc0, 0x63, 0x2a, 0x10, 0x9c, 0x44, 0xdc, 0x6b, 0xaa, 0x57, 0xbc, 0xef, 0x78, 0x00, 0x39, 0xc4, - 0xc7, 0x5e, 0x8a, 0x81, 0x8c, 0x88, 0xde, 0x00, 0x8c, 0x06, 0xbe, 0xc3, 0xc9, 0xae, 0x51, 0x60, - 0xd3, 0x8a, 0x78, 0xc0, 0x0e, 0x25, 0xff, 0xfd, 0xdb, 0x8f, 0x09, 0xd7, 0x52, 0xac, 0x4d, 0xd5, - 0x5c, 0xa9, 0xe3, 0xad, 0xc1, 0x80, 0x60, 0x39, 0xc3, 0x87, 0x70, 0xe1, 0x52, 0x38, 0x15, 0xc0, - 0x70, 0xe2, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, - 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, - 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, - 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, - 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, - 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, - 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, - 0x87, 0x0e, 0x05, 0x23, 0x0f, 0xfe, 0xf6, 0xa7, 0xbf, 0x78, 0xfb, 0x2d, 0xfb, 0xc5, 0x00, 0x00, - 0x00, 0x00, 0x45, 0x49, 0x44, 0x4e, 0x42, 0xae, 0x82, 0x60, - ], - disp: function() - { - // Do Nothing - - throw "Does Nothing!"; - } - -}; - -try -{ - LOGO.disp(); -} -catch(e) -{ - alert("Error: " + e + "\n"); -} diff --git a/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties deleted file mode 100644 index be1b7aa594..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,10 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.spdy.LEVEL=DEBUG -#org.eclipse.jetty.server.LEVEL=DEBUG -#org.eclipse.jetty.io.ssl.LEVEL=DEBUG -#org.eclipse.jetty.spdy.LEVEL=DEBUG -#org.eclipse.jetty.client.LEVEL=DEBUG -#org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy.LEVEL=DEBUG -#org.eclipse.jetty.spdy.server.proxy.LEVEL=DEBUG -#org.mortbay.LEVEL=DEBUG - diff --git a/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks b/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks b/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml deleted file mode 100644 index 7b54c55fe2..0000000000 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.11-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-npn-tests</artifactId> - <name>Jetty :: SPDY :: NPN Tests</name> - - <build> - <plugins> - <plugin> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy</id> - <phase>generate-resources</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>org.mortbay.jetty.npn</groupId> - <artifactId>npn-boot</artifactId> - <version>${npn.version}</version> - <type>jar</type> - <overWrite>false</overWrite> - <outputDirectory>${project.build.directory}/npn</outputDirectory> - </artifactItem> - </artifactItems> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine> - </configuration> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.npn</groupId> - <artifactId>npn-api</artifactId> - <version>${npn.api.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-start</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-http-server</artifactId> - <version>${project.version}</version> - <classifier>tests</classifier> - <scope>test</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java deleted file mode 100644 index d225d1fc04..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; - -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Rule; - -public class AbstractNPNTest -{ - @Rule - public final TestTracker tracker = new TestTracker(); - protected Server server; - protected SPDYServerConnector connector; - protected SPDYClient.Factory clientFactory; - - protected InetSocketAddress prepare() throws Exception - { - server = new Server(); - connector = new SPDYServerConnector(server, newSslContextFactory(), null); - connector.setPort(0); - connector.setIdleTimeout(30000); - server.addConnector(connector); - server.start(); - - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = new SPDYClient.Factory(threadPool); - clientFactory.start(); - - NextProtoNego.debug = true; - - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected SslContextFactory newSslContextFactory() - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslContextFactory.setProtocol("TLSv1"); - sslContextFactory.setIncludeProtocols("TLSv1"); - return sslContextFactory; - } - - @After - public void dispose() throws Exception - { - clientFactory.stop(); - server.stop(); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java deleted file mode 100644 index 72c1c6d077..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java +++ /dev/null @@ -1,193 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import org.eclipse.jetty.start.BaseHome; -import org.eclipse.jetty.start.FileArg; -import org.eclipse.jetty.start.Module; -import org.eclipse.jetty.toolchain.test.FS; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.IO; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -@RunWith(Parameterized.class) -public class NPNModuleTest -{ - /** This is here to prevent pointless download attempts */ - private static final List<String> KNOWN_GOOD_NPN_URLS = new ArrayList<>(); - - static - { - /** The main() method in this test case can be run to validate this list independently */ - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.11.v20150415/npn-boot-1.1.11.v20150415.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.2.v20130305/npn-boot-1.1.2.v20130305.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar"); - KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar"); - } - - @Parameters(name = "{index}: mod:{0}") - public static List<Object[]> data() - { - File npnBootModDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config/modules/protonego-impl"); - List<Object[]> data = new ArrayList<>(); - for (File file : npnBootModDir.listFiles()) - { - if (Pattern.matches("npn-.*\\.mod",file.getName())) - { - data.add(new Object[] { file.getName() }); - } - } - return data; - } - - @Parameter(value = 0) - public String modBootFile; - - private static BaseHome basehome; - - @BeforeClass - public static void initBaseHome() throws IOException - { - File homeDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config"); - File baseDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getName()); - FS.ensureEmpty(baseDir); - - String cmdLine[] = { "jetty.home="+homeDir.getAbsolutePath(),"jetty.base="+baseDir.getAbsolutePath() }; - basehome = new BaseHome(cmdLine); - } - - /** - * Check the sanity of the npn-boot file module - */ - @Test - public void testModuleValues() throws IOException - { - Path modFile = basehome.getPath("modules/protonego-impl/" + modBootFile); - Module mod = new Module(basehome,modFile); - assertNotNull("module",mod); - - // Validate logical name - assertThat("Module name",mod.getName(),is("protonego-boot")); - - List<String> expectedBootClasspath = new ArrayList<>(); - - for (String line : mod.getFiles()) - { - FileArg farg = new FileArg(line); - if (farg.uri != null) - { - assertTrue("Not a known good NPN URL: " + farg.uri,KNOWN_GOOD_NPN_URLS.contains(farg.uri)); - expectedBootClasspath.add("-Xbootclasspath/p:" + farg.location); - } - } - - for (String line : mod.getJvmArgs()) - { - expectedBootClasspath.remove(line); - } - - if (expectedBootClasspath.size() > 0) - { - StringBuilder err = new StringBuilder(); - err.append("XBootClasspath mismatch between [files] and [exec]"); - err.append("\nThe following are inferred from your [files] definition in "); - err.append(modFile.toAbsolutePath().toString()); - err.append("\nbut are not referenced in your [exec] section"); - for (String entry : expectedBootClasspath) - { - err.append("\n").append(entry); - } - fail(err.toString()); - } - } - - public static void main(String[] args) - { - File outputDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getSimpleName() + "-main"); - FS.ensureEmpty(outputDir); - for (String ref : KNOWN_GOOD_NPN_URLS) - { - try - { - URL url = new URL(ref); - System.err.printf("Attempting: %s%n",ref); - HttpURLConnection connection = (HttpURLConnection)url.openConnection(); - String refname = url.toURI().getPath(); - int idx = refname.lastIndexOf('/'); - File outputFile = new File(outputDir,refname.substring(idx)); - try (InputStream stream = connection.getInputStream(); FileOutputStream out = new FileOutputStream(outputFile)) - { - assertThat("Response Status Code",connection.getResponseCode(),is(200)); - IO.copy(stream,out); - System.err.printf("Downloaded %,d bytes%n",outputFile.length()); - } - catch (IOException e) - { - e.printStackTrace(System.err); - } - } - catch (MalformedURLException e) - { - System.err.printf("Bad Ref: %s%n",ref); - e.printStackTrace(System.err); - } - catch (URISyntaxException e) - { - System.err.printf("Bad Ref Syntax: %s%n",ref); - e.printStackTrace(System.err); - } - catch (IOException e) - { - System.err.printf("Bad Connection: %s%n",ref); - e.printStackTrace(System.err); - } - } - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java deleted file mode 100644 index 57f46005cb..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java +++ /dev/null @@ -1,207 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.List; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; - -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Test; - -public class NPNNegotiationTest extends AbstractNPNTest -{ - @Test - public void testServerAdvertisingHTTPSpeaksHTTP() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List<String> strings) - { - Assert.assertNotNull(strings); - String protocol = "http/1.1"; - Assert.assertTrue(strings.contains(protocol)); - return protocol; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } - - @Test - public void testServerAdvertisingSPDYAndHTTPSpeaksHTTPWhenNegotiated() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List<String> strings) - { - Assert.assertNotNull(strings); - String spdyProtocol = "spdy/2"; - Assert.assertTrue(strings.contains(spdyProtocol)); - String httpProtocol = "http/1.1"; - Assert.assertTrue(strings.contains(httpProtocol)); - Assert.assertTrue(strings.indexOf(spdyProtocol) < strings.indexOf(httpProtocol)); - return httpProtocol; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } - - @Test - public void testServerAdvertisingSPDYAndHTTPSpeaksDefaultProtocolWhenNPNMissing() throws Exception - { - InetSocketAddress address = prepare(); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) - { - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return false; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List<String> strings) - { - return null; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - } - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java deleted file mode 100644 index f2350eddc1..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.junit.Assert; -import org.junit.Test; - -public class SSLEngineLeakTest extends AbstractNPNTest -{ - @Test - public void testSSLEngineLeak() throws Exception - { - System.gc(); - Thread.sleep(1000); - - Field field = NextProtoNego.class.getDeclaredField("objects"); - field.setAccessible(true); - @SuppressWarnings("unchecked") - Map<Object, NextProtoNego.Provider> objects = (Map<Object, NextProtoNego.Provider>)field.get(null); - int initialSize = objects.size(); - - avoidStackLocalVariables(); - // Allow the close to arrive to the server and the selector to process it - Thread.sleep(1000); - - // Perform GC to be sure that the map is cleared - System.gc(); - Thread.sleep(1000); - - // Check that the map is empty - if (objects.size() != initialSize) - { - System.err.println(objects); - server.dumpStdErr(); - } - - Assert.assertEquals(initialSize, objects.size()); - } - - private void avoidStackLocalVariables() throws Exception - { - InetSocketAddress address = prepare(); - Session session = clientFactory.newSPDYClient(SPDY.V3).connect(address, null); - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java deleted file mode 100644 index 1bb2a14743..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java +++ /dev/null @@ -1,150 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; -import java.util.List; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Test; - -public class SSLSynReplyTest extends AbstractNPNTest -{ - @Test - public void testGentleCloseDuringHandshake() throws Exception - { - InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); - sslEngine.setUseClientMode(true); - NextProtoNego.put(sslEngine, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List<String> protocols) - { - return null; - } - }); - sslEngine.beginHandshake(); - - ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - - try (SocketChannel channel = SocketChannel.open(address)) - { - // Send ClientHello, immediately followed by TLS Close Alert and then by FIN - channel.write(encrypted); - sslEngine.closeOutbound(); - encrypted.clear(); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - channel.write(encrypted); - channel.shutdownOutput(); - - // Read ServerHello from server - encrypted.clear(); - int read = channel.read(encrypted); - encrypted.flip(); - Assert.assertTrue(read > 0); - // Cannot decrypt, as the SSLEngine has been already closed - - // Now if we read more, we should either read the TLS Close Alert, or directly -1 - encrypted.clear(); - read = channel.read(encrypted); - // Sending a TLS Close Alert during handshake results in an exception when - // unwrapping that the server react to by closing the connection abruptly. - Assert.assertTrue(read < 0); - } - } - - @Test - public void testAbruptCloseDuringHandshake() throws Exception - { - InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); - sslEngine.setUseClientMode(true); - NextProtoNego.put(sslEngine, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List<String> protocols) - { - return null; - } - }); - sslEngine.beginHandshake(); - - ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); - sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); - encrypted.flip(); - - try (SocketChannel channel = SocketChannel.open(address)) - { - // Send ClientHello, immediately followed by FIN (no TLS Close Alert) - channel.write(encrypted); - channel.shutdownOutput(); - - // Read ServerHello from server - encrypted.clear(); - int read = channel.read(encrypted); - encrypted.flip(); - Assert.assertTrue(read > 0); - ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize()); - sslEngine.unwrap(encrypted, decrypted); - - // Now if we read more, we should either read the TLS Close Alert, or directly -1 - encrypted.clear(); - read = channel.read(encrypted); - // Since we have close the connection abruptly, the server also does so - Assert.assertTrue(read < 0); - } - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java deleted file mode 100644 index 72f6ca4733..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java +++ /dev/null @@ -1,29 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; - -public class NPNProxySPDYToHTTPLoadTest extends ProxySPDYToHTTPLoadTest -{ - public NPNProxySPDYToHTTPLoadTest(short version) - { - super(version, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java deleted file mode 100644 index e28ca0e4b8..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java +++ /dev/null @@ -1,27 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -public class NPNProxySPDYToHTTPTest extends ProxySPDYToHTTPTest -{ - public NPNProxySPDYToHTTPTest(short version) - { - super(version); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java deleted file mode 100644 index 3d00c6eac4..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java +++ /dev/null @@ -1,27 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -public class NPNProxySPDYToSPDYLoadTest extends ProxySPDYToSPDYLoadTest -{ - public NPNProxySPDYToSPDYLoadTest(short version) - { - super(version); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java deleted file mode 100644 index d92ba2b0d5..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java +++ /dev/null @@ -1,27 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server.proxy; - -public class NPNProxySPDYToSPDYTest extends ProxySPDYToSPDYTest -{ - public NPNProxySPDYToSPDYTest(short version) - { - super(version); - } -} diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties deleted file mode 100644 index ead13ec197..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.spdy.LEVEL=DEBUG diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks Binary files differdeleted file mode 100644 index 428ba54776..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks Binary files differdeleted file mode 100644 index 839cb8c351..0000000000 --- a/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks +++ /dev/null diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml deleted file mode 100644 index bd16a8646f..0000000000 --- a/jetty-spdy/spdy-server/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-parent</artifactId> - <version>9.2.15-SNAPSHOT</version> - </parent> - - <modelVersion>4.0.0</modelVersion> - <artifactId>spdy-server</artifactId> - <name>Jetty :: SPDY :: Server Binding</name> - - <properties> - <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name> - </properties> - - <url>http://www.eclipse.org/jetty</url> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.spdy.server;version="9.1"</Export-Package> - <Import-Package>org.eclipse.jetty.alpn;resolution:=optional,org.eclipse.jetty.alpn.server;resolution:=optional, org.eclipse.jetty.npn;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.spdy</groupId> - <artifactId>spdy-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.npn</groupId> - <artifactId>npn-api</artifactId> - <version>${npn.api.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.alpn</groupId> - <artifactId>alpn-api</artifactId> - <version>${alpn.api.version}</version> - <scope>provided</scope> - </dependency> - </dependencies> - -</project> diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java deleted file mode 100644 index 0d5e20b6a1..0000000000 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java +++ /dev/null @@ -1,68 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.util.List; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.NegotiatingServerConnection; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class NPNServerConnection extends NegotiatingServerConnection implements NextProtoNego.ServerProvider -{ - private static final Logger LOG = Log.getLogger(NPNServerConnection.class); - - public NPNServerConnection(EndPoint endPoint, SSLEngine engine, Connector connector, List<String> protocols, String defaultProtocol) - { - super(connector, endPoint, engine, protocols, defaultProtocol); - NextProtoNego.put(engine, this); - } - - @Override - public void unsupported() - { - protocolSelected(getDefaultProtocol()); - } - - @Override - public List<String> protocols() - { - return getProtocols(); - } - - @Override - public void protocolSelected(String protocol) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} protocol selected {}", this, protocol); - setProtocol(protocol != null ? protocol : getDefaultProtocol()); - NextProtoNego.remove(getSSLEngine()); - } - - @Override - public void close() - { - NextProtoNego.remove(getSSLEngine()); - super.close(); - } -} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java deleted file mode 100644 index 628d542ab2..0000000000 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.util.List; -import javax.net.ssl.SSLEngine; - -import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; -import org.eclipse.jetty.util.annotation.Name; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class NPNServerConnectionFactory extends NegotiatingServerConnectionFactory -{ - private static final Logger LOG = Log.getLogger(NPNServerConnectionFactory.class); - - public NPNServerConnectionFactory(@Name("protocols") String... protocols) - { - super("npn", protocols); - try - { - ClassLoader npnClassLoader = NextProtoNego.class.getClassLoader(); - if (npnClassLoader != null) - { - LOG.warn("NPN must be in the boot classloader, not in: " + npnClassLoader); - throw new IllegalStateException("NPN must be in the boot classloader"); - } - } - catch (Throwable x) - { - LOG.warn("NPN not available: " + x); - throw new IllegalStateException("NPN not available", x); - } - } - - @Override - protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol) - { - return new NPNServerConnection(endPoint, engine, connector, protocols, defaultProtocol); - } -} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java deleted file mode 100644 index 6ced409bd8..0000000000 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java +++ /dev/null @@ -1,245 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.spdy.CompressionFactory; -import org.eclipse.jetty.spdy.FlowControlStrategy; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.StandardSession; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory; -import org.eclipse.jetty.spdy.client.SPDYConnection; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; - -@ManagedObject("SPDY Server Connection Factory") -public class SPDYServerConnectionFactory extends AbstractConnectionFactory -{ - /** - * @deprecated use {@link #checkProtocolNegotiationAvailable()} instead. - */ - @Deprecated - public static void checkNPNAvailable() - { - checkProtocolNegotiationAvailable(); - } - - public static void checkProtocolNegotiationAvailable() - { - if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") && - !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego")) - throw new IllegalStateException("No ALPN nor NPN classes available"); - } - - private static boolean isAvailableInBootClassPath(String className) - { - try - { - Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className); - if (klass.getClassLoader() != null) - throw new IllegalStateException(className + " must be on JVM boot classpath"); - return true; - } - catch (ClassNotFoundException x) - { - return false; - } - } - - private final Queue<Session> sessions = new ConcurrentLinkedQueue<>(); - private final short version; - private final ServerSessionFrameListener listener; - private int initialWindowSize; - private boolean dispatchIO; - - public SPDYServerConnectionFactory(int version) - { - this(version, null); - } - - public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener) - { - super("spdy/" + version); - this.version = (short)version; - this.listener = listener; - setInitialWindowSize(65536); - setDispatchIO(true); - } - - @ManagedAttribute("SPDY version") - public short getVersion() - { - return version; - } - - public ServerSessionFrameListener getServerSessionFrameListener() - { - return listener; - } - - @Override - public Connection newConnection(Connector connector, EndPoint endPoint) - { - CompressionFactory compressionFactory = new StandardCompressionFactory(); - Parser parser = new Parser(compressionFactory.newDecompressor()); - Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor()); - - ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint); - SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener, - isDispatchIO(), getInputBufferSize()); - - FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version); - - StandardSession session = new StandardSession(getVersion(), connector.getByteBufferPool(), - connector.getScheduler(), connection, endPoint, connection, 2, listener, - generator, flowControlStrategy); - session.setWindowSize(getInitialWindowSize()); - parser.addListener(session); - connection.setSession(session); - - sessionOpened(session); - - return configure(connection, connector, endPoint); - } - - protected FlowControlStrategy newFlowControlStrategy(short version) - { - return FlowControlStrategyFactory.newFlowControlStrategy(version); - } - - protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint) - { - return listener; - } - - @ManagedAttribute("Initial Window Size") - public int getInitialWindowSize() - { - return initialWindowSize; - } - - public void setInitialWindowSize(int initialWindowSize) - { - this.initialWindowSize = initialWindowSize; - } - - @ManagedAttribute("Dispatch I/O to a pooled thread") - public boolean isDispatchIO() - { - return dispatchIO; - } - - public void setDispatchIO(boolean dispatchIO) - { - this.dispatchIO = dispatchIO; - } - - protected boolean sessionOpened(Session session) - { - // Add sessions only if the connector is not stopping - return sessions.offer(session); - } - - protected boolean sessionClosed(Session session) - { - // Remove sessions only if the connector is not stopping - // to avoid concurrent removes during iterations - return sessions.remove(session); - } - - void closeSessions() - { - for (Session session : sessions) - session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE); - sessions.clear(); - } - - @Override - protected void doStop() throws Exception - { - closeSessions(); - super.doStop(); - } - - public Collection<Session> getSessions() - { - return Collections.unmodifiableCollection(sessions); - } - - @Override - protected void dumpThis(Appendable out) throws IOException - { - super.dumpThis(out); - dump(out, "", sessions); - } - - private class ServerSPDYConnection extends SPDYConnection implements Runnable - { - private final ServerSessionFrameListener listener; - private final AtomicBoolean connected = new AtomicBoolean(); - - private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser, - ServerSessionFrameListener listener, boolean dispatchIO, int bufferSize) - { - super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(), - dispatchIO, bufferSize); - this.listener = listener; - } - - @Override - public void onOpen() - { - super.onOpen(); - if (connected.compareAndSet(false, true)) - getExecutor().execute(this); - } - - @Override - public void onClose() - { - super.onClose(); - sessionClosed(getSession()); - } - - @Override - public void run() - { - // NPE guard to support tests - if (listener != null) - listener.onConnect(getSession()); - } - } - -} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java deleted file mode 100644 index 4faee0bb60..0000000000 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.util.Objects; - -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class SPDYServerConnector extends ServerConnector -{ - public SPDYServerConnector(Server server, ServerSessionFrameListener listener) - { - super(server, (SslContextFactory)null, new SPDYServerConnectionFactory(SPDY.V2, listener)); - } - - public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener) - { - this(server, sslContextFactory, listener, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); - } - - public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener, NegotiatingServerConnectionFactory negotiator) - { - super(server, Objects.requireNonNull(sslContextFactory), - negotiator, - new SPDYServerConnectionFactory(SPDY.V3, listener), - new SPDYServerConnectionFactory(SPDY.V2, listener), - new HttpConnectionFactory()); - negotiator.setDefaultProtocol("http/1.1"); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java deleted file mode 100644 index 1366f0fec6..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java +++ /dev/null @@ -1,150 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.util.concurrent.Executor; - -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; -import org.junit.Rule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -public abstract class AbstractTest -{ - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - protected final short version = SPDY.V2; - - protected Server server; - protected SPDYClient.Factory clientFactory; - protected ServerConnector connector; - - protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception - { - return startServer(version, listener); - } - - protected InetSocketAddress startServer(short version, ServerSessionFrameListener listener) throws Exception - { - if (server == null) - server = newServer(); - if (connector == null) - connector = newSPDYServerConnector(server, listener); - if (listener == null) - listener = connector.getConnectionFactory(SPDYServerConnectionFactory.class).getServerSessionFrameListener(); - - ConnectionFactory spdy = new SPDYServerConnectionFactory(version, listener); - connector.addConnectionFactory(spdy); - connector.setPort(0); - server.addConnector(connector); - - if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null) - connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(spdy.getProtocol()); - else - connector.setDefaultProtocol(spdy.getProtocol()); - - server.start(); - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected Server newServer() - { - QueuedThreadPool pool = new QueuedThreadPool(); - pool.setName(pool.getName()+"-server"); - return new Server(pool); - } - - protected ServerConnector newSPDYServerConnector(Server server, ServerSessionFrameListener listener) - { - return new SPDYServerConnector(server, listener); - } - - protected Session startClient(InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception - { - return startClient(version, socketAddress, listener); - } - - protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception - { - if (clientFactory == null) - { - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = newSPDYClientFactory(threadPool); - } - clientFactory.start(); - - return clientFactory.newSPDYClient(version).connect(socketAddress, listener); - } - - protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) - { - return new SPDYClient.Factory(threadPool); - } - - protected SslContextFactory newSslContextFactory() - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslContextFactory.setProtocol("TLSv1"); - sslContextFactory.setIncludeProtocols("TLSv1"); - return sslContextFactory; - } - - @After - public void destroy() throws Exception - { - if (clientFactory != null) - { - clientFactory.stop(); - } - if (server != null) - { - server.stop(); - server.join(); - } - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java deleted file mode 100644 index 07eb552d18..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java +++ /dev/null @@ -1,273 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.GoAwayFrame; -import org.eclipse.jetty.spdy.frames.RstStreamFrame; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.spdy.parser.Parser.Listener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -public class ClosedStreamTest extends AbstractTest -{ - //TODO: Right now it sends a rst as the stream is unknown to the session once it's closed. - //TODO: But according to the spec we probably should just ignore the data?! - @Test - public void testDataSentOnClosedStreamIsIgnored() throws Exception - { - ServerSocketChannel server = ServerSocketChannel.open(); - server.bind(new InetSocketAddress("localhost", 0)); - - Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); - final CountDownLatch dataLatch = new CountDownLatch(2); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataLatch.countDown(); - } - }); - - SocketChannel channel = server.accept(); - ByteBuffer readBuffer = ByteBuffer.allocate(1024); - channel.read(readBuffer); - readBuffer.flip(); - int streamId = readBuffer.getInt(8); - - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - - ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Fields())); - channel.write(writeBuffer); - Assert.assertThat(writeBuffer.hasRemaining(), is(false)); - - byte[] bytes = new byte[1]; - writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true)); - channel.write(writeBuffer); - Assert.assertThat(writeBuffer.hasRemaining(), is(false)); - - // Write again to simulate the faulty condition - writeBuffer.flip(); - channel.write(writeBuffer); - Assert.assertThat(writeBuffer.hasRemaining(), is(false)); - - Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); - - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - server.close(); - } - - @Test - public void testSendDataOnHalfClosedStreamCausesExceptionOnServer() throws Exception - { - final CountDownLatch replyReceivedLatch = new CountDownLatch(1); - final CountDownLatch clientReceivedDataLatch = new CountDownLatch(1); - final CountDownLatch exceptionWhenSendingData = new CountDownLatch(1); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - try - { - replyReceivedLatch.await(5,TimeUnit.SECONDS); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - try - { - stream.data(new StringDataInfo("data send after half closed",false), new Callback.Adapter()); - } - catch (RuntimeException e) - { - // we expect an exception here, but we don't want it to be logged - exceptionWhenSendingData.countDown(); - } - - return null; - } - }),null); - - Stream stream = clientSession.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyReceivedLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - clientReceivedDataLatch.countDown(); - } - }); - assertThat("reply has been received by client",replyReceivedLatch.await(5,TimeUnit.SECONDS),is(true)); - assertThat("stream is half closed from server",stream.isHalfClosed(),is(true)); - assertThat("client has not received any data sent after stream was half closed by server", - clientReceivedDataLatch.await(1,TimeUnit.SECONDS), is(false)); - assertThat("sending data threw an exception",exceptionWhenSendingData.await(5,TimeUnit.SECONDS), is(true)); - } - - @Test - public void testV2ReceiveDataOnHalfClosedStream() throws Exception - { - runReceiveDataOnHalfClosedStream(SPDY.V2); - } - - @Test - @Ignore("until v3 is properly implemented") - public void testV3ReceiveDataOnHalfClosedStream() throws Exception - { - runReceiveDataOnHalfClosedStream(SPDY.V3); - } - - private void runReceiveDataOnHalfClosedStream(short version) throws Exception - { - final CountDownLatch clientResetReceivedLatch = new CountDownLatch(1); - final CountDownLatch serverReplySentLatch = new CountDownLatch(1); - final CountDownLatch clientReplyReceivedLatch = new CountDownLatch(1); - final CountDownLatch serverDataReceivedLatch = new CountDownLatch(1); - final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1); - - InetSocketAddress startServer = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - serverReplySentLatch.countDown(); - try - { - clientReplyReceivedLatch.await(5,TimeUnit.SECONDS); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - serverDataReceivedLatch.countDown(); - } - }; - } - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - goAwayReceivedLatch.countDown(); - } - }); - - final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor()); - int streamId = 1; - ByteBuffer synData = generator.control(new SynStreamFrame(version,SynInfo.FLAG_CLOSE, streamId,0,(byte)0,(short)0,new Fields())); - - final SocketChannel socketChannel = SocketChannel.open(startServer); - socketChannel.write(synData); - assertThat("synData is fully written", synData.hasRemaining(), is(false)); - - assertThat("server: push reply is sent",serverReplySentLatch.await(5,TimeUnit.SECONDS),is(true)); - - Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); - parser.addListener(new Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - if (frame instanceof SynReplyFrame) - { - SynReplyFrame synReplyFrame = (SynReplyFrame)frame; - clientReplyReceivedLatch.countDown(); - int streamId = synReplyFrame.getStreamId(); - ByteBuffer data = generator.data(streamId,0,new StringDataInfo("data",false)); - try - { - socketChannel.write(data); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - else if (frame instanceof RstStreamFrame) - { - clientResetReceivedLatch.countDown(); - } - } - }); - ByteBuffer response = ByteBuffer.allocate(28); - socketChannel.read(response); - response.flip(); - parser.parse(response); - - assertThat("server didn't receive data",serverDataReceivedLatch.await(1,TimeUnit.SECONDS),not(true)); - assertThat("client didn't receive reset",clientResetReceivedLatch.await(1,TimeUnit.SECONDS),not(true)); - - ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode())); - socketChannel.write(buffer); - Assert.assertThat(buffer.hasRemaining(), is(false)); - - assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5,TimeUnit.SECONDS), is(true)); - - socketChannel.close(); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java deleted file mode 100644 index 2953f9c25e..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java +++ /dev/null @@ -1,493 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.nio.ByteBuffer; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Exchanger; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.SPDYException; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.FutureCallback; -import org.junit.Assert; -import org.junit.Test; - -public class FlowControlTest extends AbstractTest -{ - @Test - public void testFlowControlWithConcurrentSettings() throws Exception - { - // Initial window is 64 KiB. We allow the client to send 1024 B - // then we change the window to 512 B. At this point, the client - // must stop sending data (although the initial window allows it) - - final int size = 512; - final AtomicReference<DataInfo> dataInfoRef = new AtomicReference<>(); - final CountDownLatch dataLatch = new CountDownLatch(2); - final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - private final AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int dataFrameCount = dataFrames.incrementAndGet(); - if (dataFrameCount == 1) - { - dataInfoRef.set(dataInfo); - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, size)); - stream.getSession().settings(new SettingsInfo(settings), new FutureCallback()); - } - else if (dataFrameCount > 1) - { - dataInfo.consume(dataInfo.length()); - dataLatch.countDown(); - } - } - }; - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - settingsLatch.countDown(); - } - }); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - stream.data(new BytesDataInfo(new byte[size * 2], false)); - settingsLatch.await(5, TimeUnit.SECONDS); - - // Send the second chunk of data, must not arrive since we're flow control stalled now - stream.data(new BytesDataInfo(new byte[size * 2], true), new Callback.Adapter()); - Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); - - // Consume the data arrived to server, this will resume flow control - DataInfo dataInfo = dataInfoRef.get(); - dataInfo.consume(dataInfo.length()); - - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testServerFlowControlOneBigWrite() throws Exception - { - final int windowSize = 1536; - final int length = 5 * windowSize; - final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - settingsLatch.countDown(); - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); - return null; - } - }), null); - - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings)); - - Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - - final Exchanger<DataInfo> exchanger = new Exchanger<>(); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - private AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - try - { - int dataFrames = this.dataFrames.incrementAndGet(); - if (dataFrames == 1) - { - // Do not consume nor read from the data frame. - // We should then be flow-control stalled - exchanger.exchange(dataInfo); - } - else if (dataFrames == 2) - { - // Read but not consume, we should be flow-control stalled - dataInfo.asByteBuffer(false); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 3) - { - // Consume partially, we should be flow-control stalled - dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 4 || dataFrames == 5) - { - // Consume totally - dataInfo.asByteBuffer(true); - exchanger.exchange(dataInfo); - } - else - { - Assert.fail(); - } - } - catch (InterruptedException x) - { - throw new SPDYException(x); - } - } - }); - - DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(windowSize, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(0, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.consume(dataInfo.length()); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - // Check that we are not flow control stalled - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - } - - @Test - public void testClientFlowControlOneBigWrite() throws Exception - { - final int windowSize = 1536; - final Exchanger<DataInfo> exchanger = new Exchanger<>(); - final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings), new FutureCallback()); - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - private AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - try - { - int dataFrames = this.dataFrames.incrementAndGet(); - if (dataFrames == 1) - { - // Do not consume nor read from the data frame. - // We should then be flow-control stalled - exchanger.exchange(dataInfo); - } - else if (dataFrames == 2) - { - // Read but not consume, we should be flow-control stalled - dataInfo.asByteBuffer(false); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 3) - { - // Consume partially, we should be flow-control stalled - dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 4 || dataFrames == 5) - { - // Consume totally - dataInfo.asByteBuffer(true); - exchanger.exchange(dataInfo); - } - else - { - Assert.fail(); - } - } - catch (InterruptedException x) - { - throw new SPDYException(x); - } - } - }; - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - settingsLatch.countDown(); - } - }); - - Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - final int length = 5 * windowSize; - stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); - - DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(windowSize, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(0, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.consume(dataInfo.length()); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - // Check that we are not flow control stalled - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - } - - @Test - public void testStreamsStalledDoesNotStallOtherStreams() throws Exception - { - final int windowSize = 1024; - final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - settingsLatch.countDown(); - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new BytesDataInfo(new byte[windowSize * 2], true), new Callback.Adapter()); - return null; - } - }), null); - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings)); - - Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - - final CountDownLatch latch = new CountDownLatch(3); - final AtomicReference<DataInfo> dataInfoRef1 = new AtomicReference<>(); - final AtomicReference<DataInfo> dataInfoRef2 = new AtomicReference<>(); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - private final AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int frames = dataFrames.incrementAndGet(); - if (frames == 1) - { - // Do not consume it to stall flow control - dataInfoRef1.set(dataInfo); - } - else - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.countDown(); - } - } - }); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - private final AtomicInteger dataFrames = new AtomicInteger(); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int frames = dataFrames.incrementAndGet(); - if (frames == 1) - { - // Do not consume it to stall flow control - dataInfoRef2.set(dataInfo); - } - else - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.countDown(); - } - } - }); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - DataInfo dataInfo1 = dataInfoRef1.getAndSet(null); - if (dataInfo1 != null) - dataInfo1.consume(dataInfo1.length()); - DataInfo dataInfo2 = dataInfoRef2.getAndSet(null); - if (dataInfo2 != null) - dataInfo2.consume(dataInfo2.length()); - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.countDown(); - } - }); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testSendBigFileWithoutFlowControl() throws Exception - { - testSendBigFile(SPDY.V2); - } - - @Test - public void testSendBigFileWithFlowControl() throws Exception - { - testSendBigFile(SPDY.V3); - } - - private void testSendBigFile(short version) throws Exception - { - final int dataSize = 1024 * 1024; - final ByteBufferDataInfo bigByteBufferDataInfo = new ByteBufferDataInfo(ByteBuffer.allocate(dataSize),false); - final CountDownLatch allDataReceivedLatch = new CountDownLatch(1); - - Session session = startClient(version, startServer(version, new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(bigByteBufferDataInfo, new Callback.Adapter()); - return null; - } - }),new SessionFrameListener.Adapter()); - - session.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter() - { - private int dataBytesReceived; - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataBytesReceived = dataBytesReceived + dataInfo.length(); - dataInfo.consume(dataInfo.length()); - if (dataBytesReceived == dataSize) - allDataReceivedLatch.countDown(); - } - }); - - assertThat("all data bytes have been received by the client", allDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private void checkThatWeAreFlowControlStalled(final Exchanger<DataInfo> exchanger) - { - expectException(TimeoutException.class, new Callable<DataInfo>() - { - @Override - public DataInfo call() throws Exception - { - return exchanger.exchange(null, 1, TimeUnit.SECONDS); - } - }); - } - - private void expectException(Class<? extends Exception> exception, Callable<DataInfo> command) - { - try - { - command.call(); - Assert.fail(); - } - catch (Exception x) - { - Assert.assertSame(exception, x.getClass()); - } - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java deleted file mode 100644 index a8342027a4..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java +++ /dev/null @@ -1,234 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.FutureCallback; -import org.eclipse.jetty.util.FuturePromise; -import org.junit.Assert; -import org.junit.Test; - -public class GoAwayTest extends AbstractTest -{ - @Test - public void testServerReceivesGoAwayOnClientGoAway() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return null; - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - Assert.assertEquals(0, goAwayInfo.getLastStreamId()); - Assert.assertSame(SessionStatus.OK, goAwayInfo.getSessionStatus()); - latch.countDown(); - } - }; - Session session = startClient(startServer(serverSessionFrameListener), null); - - session.syn(new SynInfo(new Fields(), true), null); - - session.goAway(new GoAwayInfo()); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testClientReceivesGoAwayOnServerGoAway() throws Exception - { - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - stream.getSession().goAway(new GoAwayInfo(), new FutureCallback()); - return null; - } - }; - final AtomicReference<GoAwayResultInfo> ref = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(1); - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - ref.set(goAwayInfo); - latch.countDown(); - } - }; - Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); - - Stream stream1 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - GoAwayResultInfo goAwayResultInfo = ref.get(); - Assert.assertNotNull(goAwayResultInfo); - Assert.assertEquals(stream1.getId(), goAwayResultInfo.getLastStreamId()); - Assert.assertSame(SessionStatus.OK, goAwayResultInfo.getSessionStatus()); - } - - @Test - public void testSynStreamIgnoredAfterGoAway() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - private final AtomicInteger syns = new AtomicInteger(); - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - int synCount = syns.incrementAndGet(); - if (synCount == 1) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - stream.getSession().goAway(new GoAwayInfo(), new FutureCallback()); - } - else - { - latch.countDown(); - } - return null; - } - }; - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - session.syn(new SynInfo(new Fields(), true), null, new FuturePromise<Stream>()); - } - }; - Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); - - session.syn(new SynInfo(new Fields(), true), null); - - Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); - } - - @Test - public void testDataNotProcessedAfterGoAway() throws Exception - { - final CountDownLatch closeLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - private AtomicInteger syns = new AtomicInteger(); - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - int synCount = syns.incrementAndGet(); - if (synCount == 1) - { - return null; - } - else - { - stream.getSession().goAway(new GoAwayInfo(), new FutureCallback()); - closeLatch.countDown(); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataLatch.countDown(); - } - }; - } - } - }; - final AtomicReference<GoAwayResultInfo> goAwayRef = new AtomicReference<>(); - final CountDownLatch goAwayLatch = new CountDownLatch(1); - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - goAwayRef.set(goAwayInfo); - goAwayLatch.countDown(); - } - }; - Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); - - // First stream is processed ok - final CountDownLatch reply1Latch = new CountDownLatch(1); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - reply1Latch.countDown(); - } - }); - Assert.assertTrue(reply1Latch.await(5, TimeUnit.SECONDS)); - - // Second stream is closed in the middle - Stream stream2 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); - - // There is a race between the data we want to send, and the client - // closing the connection because the server closed it after the - // go_away, so we guard with a try/catch to have the test pass cleanly - try - { - stream2.data(new StringDataInfo("foo", true)); - Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); - } - catch (ExecutionException x) - { - // doesn't matter which exception we get, it's important that the data is not been written and the - // previous assertion is true - } - - // The last good stream is the second, because it was received by the server - Assert.assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS)); - GoAwayResultInfo goAway = goAwayRef.get(); - Assert.assertNotNull(goAway); - Assert.assertEquals(stream2.getId(), goAway.getLastStreamId()); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java deleted file mode 100644 index 34f3c82791..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java +++ /dev/null @@ -1,86 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class HeadersTest extends AbstractTest -{ - @Test - public void testHeaders() throws Exception - { - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - Assert.assertTrue(stream.isHalfClosed()); - stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter()); - Assert.assertTrue(stream.isClosed()); - } - }; - } - }; - - Session session = startClient(startServer(serverSessionFrameListener), null); - - final CountDownLatch latch = new CountDownLatch(1); - session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Fields headers = new Fields(); - headers.put("foo", "bar"); - headers.put("baz", "woo"); - stream.headers(new HeadersInfo(headers, true), new Callback.Adapter()); - Assert.assertTrue(stream.isHalfClosed()); - } - - @Override - public void onHeaders(Stream stream, HeadersInfo headersInfo) - { - Assert.assertTrue(stream.isClosed()); - latch.countDown(); - } - }); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java deleted file mode 100644 index 195bb6a950..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java +++ /dev/null @@ -1,257 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.Assert; -import org.junit.Test; - -public class IdleTimeoutTest extends AbstractTest -{ - private final int idleTimeout = 1000; - - @Test - public void testServerEnforcingIdleTimeout() throws Exception - { - server = newServer(); - connector = newSPDYServerConnector(server, new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return null; - } - }); - connector.setIdleTimeout(idleTimeout); - - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startServer(null), new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - latch.countDown(); - } - }); - - session.syn(new SynInfo(new Fields(), true), null); - - Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - } - - @Test - public void testServerEnforcingIdleTimeoutWithUnrespondedStream() throws Exception - { - server = newServer(); - connector = newSPDYServerConnector(server, null); - connector.setIdleTimeout(idleTimeout); - - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startServer(null), new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - latch.countDown(); - } - }); - - // The SYN is not replied, and the server should idle timeout - session.syn(new SynInfo(new Fields(), true), null); - - Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - } - - @Test - public void testServerNotEnforcingIdleTimeoutWithPendingStream() throws Exception - { - server = newServer(); - connector = newSPDYServerConnector(server, new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - try - { - Thread.sleep(2 * idleTimeout); - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return null; - } - catch (InterruptedException x) - { - Assert.fail(); - return null; - } - } - }); - connector.setIdleTimeout(idleTimeout); - - final CountDownLatch goAwayLatch = new CountDownLatch(1); - Session session = startClient(startServer(null), new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - goAwayLatch.countDown(); - } - }); - - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - }); - - Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); - - // Just make sure onGoAway has never been called, but don't wait too much - Assert.assertFalse(goAwayLatch.await(idleTimeout / 2, TimeUnit.MILLISECONDS)); - } - - @Test - public void testClientEnforcingIdleTimeout() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return null; - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - latch.countDown(); - } - }); - - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = newSPDYClientFactory(threadPool); - clientFactory.start(); - SPDYClient client = clientFactory.newSPDYClient(SPDY.V2); - client.setIdleTimeout(idleTimeout); - Session session = client.connect(address, null); - - session.syn(new SynInfo(new Fields(), true), null); - - Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - } - - @Test - public void testClientEnforcingIdleTimeoutWithUnrespondedStream() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - latch.countDown(); - } - }); - - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = newSPDYClientFactory(threadPool); - clientFactory.start(); - SPDYClient client = clientFactory.newSPDYClient(SPDY.V2); - client.setIdleTimeout(idleTimeout); - Session session = client.connect(address, null); - - session.syn(new SynInfo(new Fields(), true), null); - - Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - } - - @Test - public void testClientNotEnforcingIdleTimeoutWithPendingStream() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - return null; - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - latch.countDown(); - } - }); - - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setName(threadPool.getName() + "-client"); - clientFactory = newSPDYClientFactory(threadPool); - clientFactory.start(); - SPDYClient client = clientFactory.newSPDYClient(SPDY.V2); - client.setIdleTimeout(idleTimeout); - Session session = client.connect(address, null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - try - { - Thread.sleep(2 * idleTimeout); - replyLatch.countDown(); - } - catch (InterruptedException e) - { - Assert.fail(); - } - } - }); - - Assert.assertFalse(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java deleted file mode 100644 index 9cc8115f5e..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java +++ /dev/null @@ -1,121 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Fields; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class MaxConcurrentStreamTest extends AbstractTest -{ - @Test - public void testMaxConcurrentStreamsSetByServer() throws Exception, ExecutionException - { - final CountDownLatch settingsReceivedLatch = new CountDownLatch(1); - final CountDownLatch dataReceivedLatch = new CountDownLatch(1); - - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 1)); - try - { - session.settings(new SettingsInfo(settings)); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - e.printStackTrace(); - } - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - try - { - stream.reply(new ReplyInfo(true)); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - e.printStackTrace(); - } - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataReceivedLatch.countDown(); - } - }; - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - settingsReceivedLatch.countDown(); - } - }); - - assertThat("Settings frame received", settingsReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - - SynInfo synInfo = new SynInfo(new Fields(), false); - Stream stream = session.syn(synInfo, null); - - boolean failed = false; - try - { - session.syn(synInfo, null); - } - catch (ExecutionException | InterruptedException | TimeoutException e) - { - failed = true; - } - - assertThat("Opening second stream failed", failed, is(true)); - - stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true)); - assertThat("Data has been received on first stream.", dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java deleted file mode 100644 index 1684229dda..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java +++ /dev/null @@ -1,106 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.PingInfo; -import org.eclipse.jetty.spdy.api.PingResultInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Promise; -import org.junit.Assert; -import org.junit.Test; - -public class PingTest extends AbstractTest -{ - @Test - public void testPingPong() throws Exception - { - final AtomicReference<PingResultInfo> ref = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(1); - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public void onPing(Session session, PingResultInfo pingInfo) - { - ref.set(pingInfo); - latch.countDown(); - } - }; - Session session = startClient(startServer(null), clientSessionFrameListener); - PingResultInfo pingResultInfo = session.ping(new PingInfo(5, TimeUnit.SECONDS)); - Assert.assertEquals(1, pingResultInfo.getPingId() % 2); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - PingResultInfo pongInfo = ref.get(); - Assert.assertNotNull(pongInfo); - Assert.assertEquals(pingResultInfo.getPingId(), pongInfo.getPingId()); - } - - @Test - public void testServerPingPong() throws Exception - { - final CountDownLatch pingReceived = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - private final CountDownLatch pingSent = new CountDownLatch(1); - private int pingId; - - @Override - public void onConnect(Session session) - { - session.ping(new PingInfo(), new Promise.Adapter<PingResultInfo>() - { - @Override - public void succeeded(PingResultInfo pingInfo) - { - pingId = pingInfo.getPingId(); - pingSent.countDown(); - } - }); - } - - @Override - public void onPing(Session session, PingResultInfo pingInfo) - { - try - { - // This callback may be notified before the promise above, - // so make sure we wait here to know the pingId - Assert.assertTrue(pingSent.await(5, TimeUnit.SECONDS)); - Assert.assertEquals(0, pingInfo.getPingId() % 2); - Assert.assertEquals(pingId, pingInfo.getPingId()); - pingReceived.countDown(); - } - catch (InterruptedException x) - { - Assert.fail(); - } - } - }; - startClient(startServer(serverSessionFrameListener), null); - - Assert.assertTrue(pingReceived.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java deleted file mode 100644 index cedf9e14a7..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java +++ /dev/null @@ -1,185 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.HeadersInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.SynReplyFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class ProtocolViolationsTest extends AbstractTest -{ - @Test - public void testSendDataBeforeReplyIsIllegal() throws Exception - { - final CountDownLatch resetLatch = new CountDownLatch(1); - final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - try - { - stream.data(new StringDataInfo("failure", true), new Callback.Adapter()); - return null; - } - catch (IllegalStateException x) - { - latch.countDown(); - return null; - } - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus()); - resetLatch.countDown(); - } - }); - session.syn(new SynInfo(new Fields(), true), null); - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testReceiveDataBeforeReplyIsIllegal() throws Exception - { - ServerSocketChannel server = ServerSocketChannel.open(); - server.bind(new InetSocketAddress("localhost", 0)); - - Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); - session.syn(new SynInfo(new Fields(), true), null); - - SocketChannel channel = server.accept(); - ByteBuffer readBuffer = ByteBuffer.allocate(1024); - channel.read(readBuffer); - readBuffer.flip(); - int streamId = readBuffer.getInt(8); - - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - byte[] bytes = new byte[1]; - ByteBuffer writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true)); - channel.write(writeBuffer); - assertThat("data is fully written", writeBuffer.hasRemaining(),is(false)); - - readBuffer.clear(); - channel.read(readBuffer); - readBuffer.flip(); - Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2)); - Assert.assertEquals(streamId, readBuffer.getInt(8)); - - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - server.close(); - } - - @Test(expected = IllegalStateException.class) - public void testSendDataAfterCloseIsIllegal() throws Exception - { - Session session = startClient(startServer(null), null); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null); - stream.data(new StringDataInfo("test", true)); - } - - @Test(expected = IllegalStateException.class) - public void testSendHeadersAfterCloseIsIllegal() throws Exception - { - Session session = startClient(startServer(null), null); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null); - stream.headers(new HeadersInfo(new Fields(), true)); - } - - @Test //TODO: throws an ISException in StandardStream.updateCloseState(). But instead we should send a rst or something to the server probably?! - public void testServerClosesStreamTwice() throws Exception - { - ServerSocketChannel server = ServerSocketChannel.open(); - server.bind(new InetSocketAddress("localhost", 0)); - - Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); - final CountDownLatch dataLatch = new CountDownLatch(2); - session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataLatch.countDown(); - } - }); - - SocketChannel channel = server.accept(); - ByteBuffer readBuffer = ByteBuffer.allocate(1024); - channel.read(readBuffer); - readBuffer.flip(); - int streamId = readBuffer.getInt(8); - - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - - ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Fields())); - channel.write(writeBuffer); - assertThat("SynReply is fully written", writeBuffer.hasRemaining(), is(false)); - - byte[] bytes = new byte[1]; - writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true)); - channel.write(writeBuffer); - assertThat("data is fully written", writeBuffer.hasRemaining(), is(false)); - - // Write again to simulate the faulty condition - writeBuffer.flip(); - channel.write(writeBuffer); - assertThat("data is fully written", writeBuffer.hasRemaining(), is(false)); - - Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); - - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - server.close(); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java deleted file mode 100644 index ab4e5edb2d..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java +++ /dev/null @@ -1,591 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.sameInstance; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.Exchanger; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.PushInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.SessionStatus; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.DataFrame; -import org.eclipse.jetty.spdy.frames.GoAwayFrame; -import org.eclipse.jetty.spdy.frames.RstStreamFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.frames.WindowUpdateFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.spdy.parser.Parser.Listener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.Assert; -import org.junit.Test; - -public class PushStreamTest extends AbstractTest -{ - private static final Logger LOG = Log.getLogger(PushStreamTest.class); - - @Test - public void testSynPushStream() throws Exception - { - final AtomicReference<Stream> pushStreamRef = new AtomicReference<>(); - final CountDownLatch pushStreamLatch = new CountDownLatch(1); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.push(new PushInfo(new Fields(), true), new Promise.Adapter<Stream>()); - return null; - } - }), null); - - Stream stream = clientSession.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - assertThat("streamId is even", stream.getId() % 2, is(0)); - assertThat("stream is unidirectional", stream.isUnidirectional(), is(true)); - assertThat("stream is closed", stream.isClosed(), is(true)); - assertThat("stream has associated stream", stream.getAssociatedStream(), notNullValue()); - try - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - fail("Cannot reply to push streams"); - } - catch (IllegalStateException x) - { - // Expected - } - pushStreamRef.set(stream); - pushStreamLatch.countDown(); - return null; - } - }); - assertThat("onSyn has been called", pushStreamLatch.await(5, TimeUnit.SECONDS), is(true)); - Stream pushStream = pushStreamRef.get(); - assertThat("main stream and associated stream are the same", stream, sameInstance(pushStream.getAssociatedStream())); - } - - @Test - public void testSendDataOnPushStreamAfterAssociatedStreamIsClosed() throws Exception - { - final Exchanger<Stream> streamExchanger = new Exchanger<>(); - final CountDownLatch pushStreamSynLatch = new CountDownLatch(1); - final CyclicBarrier replyBarrier = new CyclicBarrier(3); - final CyclicBarrier closeBarrier = new CyclicBarrier(3); - final CountDownLatch streamDataSent = new CountDownLatch(2); - final CountDownLatch pushStreamDataReceived = new CountDownLatch(2); - final CountDownLatch exceptionCountDownLatch = new CountDownLatch(1); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - try - { - replyBarrier.await(5, TimeUnit.SECONDS); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - try - { - if (dataInfo.isClose()) - { - stream.data(new StringDataInfo("close stream", true)); - closeBarrier.await(5, TimeUnit.SECONDS); - } - streamDataSent.countDown(); - if (pushStreamDataReceived.getCount() == 2) - { - Stream pushStream = stream.push(new PushInfo(new Fields(), false)); - streamExchanger.exchange(pushStream, 5, TimeUnit.SECONDS); - } - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - } - } - }; - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - throw new IllegalStateException(e); - } - } - - }), null); - - Stream stream = clientSession.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - pushStreamSynLatch.countDown(); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - pushStreamDataReceived.countDown(); - super.onData(stream, dataInfo); - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - try - { - replyBarrier.await(5, TimeUnit.SECONDS); - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - } - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - try - { - closeBarrier.await(5, TimeUnit.SECONDS); - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - } - } - }); - - replyBarrier.await(5, TimeUnit.SECONDS); - stream.data(new StringDataInfo("client data", false)); - Stream pushStream = streamExchanger.exchange(null, 5, TimeUnit.SECONDS); - pushStream.data(new StringDataInfo("first push data frame", false)); - // nasty, but less complex than using another cyclicBarrier for example - while (pushStreamDataReceived.getCount() != 1) - Thread.sleep(1); - stream.data(new StringDataInfo("client close", true)); - closeBarrier.await(5, TimeUnit.SECONDS); - assertThat("stream is closed", stream.isClosed(), is(true)); - pushStream.data(new StringDataInfo("second push data frame while associated stream has been closed already", false)); - assertThat("2 pushStream data frames have been received.", pushStreamDataReceived.await(5, TimeUnit.SECONDS), is(true)); - assertThat("2 data frames have been sent", streamDataSent.await(5, TimeUnit.SECONDS), is(true)); - assertThatNoExceptionOccurred(exceptionCountDownLatch); - } - - @Test - public void testSynPushStreamOnClosedStream() throws Exception - { - final CountDownLatch pushStreamFailedLatch = new CountDownLatch(1); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false), - new Promise.Adapter<Stream>() - { - @Override - public void failed(Throwable x) - { - pushStreamFailedLatch.countDown(); - } - }); - return super.onSyn(stream, synInfo); - } - }), new SessionFrameListener.Adapter()); - - clientSession.syn(new SynInfo(new Fields(), true), null); - assertThat("pushStream push has failed", pushStreamFailedLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - @Test - public void testSendBigDataOnPushStreamWhenAssociatedStreamIsClosed() throws Exception - { - final CountDownLatch streamClosedLatch = new CountDownLatch(1); - final CountDownLatch allDataReceived = new CountDownLatch(1); - final CountDownLatch exceptionCountDownLatch = new CountDownLatch(1); - final Exchanger<ByteBuffer> exchanger = new Exchanger<>(); - final int dataSizeInBytes = 1024 * 1024 * 1; - final byte[] transferBytes = createHugeByteArray(dataSizeInBytes); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - try - { - Stream pushStream = stream.push(new PushInfo(new Fields(), false)); - stream.reply(new ReplyInfo(true)); - // wait until stream is closed - streamClosedLatch.await(5, TimeUnit.SECONDS); - pushStream.data(new BytesDataInfo(transferBytes, true), new Callback.Adapter()); - return null; - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - throw new IllegalStateException(e); - } - } - }), null); - - Stream stream = clientSession.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - return new StreamFrameListener.Adapter() - { - ByteBuffer receivedBytes = ByteBuffer.allocate(dataSizeInBytes); - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataInfo.consumeInto(receivedBytes); - if (dataInfo.isClose()) - { - allDataReceived.countDown(); - try - { - receivedBytes.flip(); - exchanger.exchange(receivedBytes.slice(), 5, TimeUnit.SECONDS); - } - catch (Exception e) - { - exceptionCountDownLatch.countDown(); - } - } - } - }; - } - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - streamClosedLatch.countDown(); - super.onReply(stream, replyInfo); - } - }); - - ByteBuffer receivedBytes = exchanger.exchange(null, 5, TimeUnit.SECONDS); - - assertThat("received byte array is the same as transferred byte array", Arrays.equals(transferBytes, receivedBytes.array()), is(true)); - assertThat("onReply has been called to close the stream", streamClosedLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("stream is closed", stream.isClosed(), is(true)); - assertThat("all data has been received", allDataReceived.await(20, TimeUnit.SECONDS), is(true)); - assertThatNoExceptionOccurred(exceptionCountDownLatch); - } - - private byte[] createHugeByteArray(int sizeInBytes) - { - byte[] bytes = new byte[sizeInBytes]; - ThreadLocalRandom.current().nextBytes(bytes); - return bytes; - } - - - @Test - public void testClientResetsStreamAfterPushSynDoesPreventSendingDataFramesWithFlowControl() throws Exception - { - final boolean flowControl = true; - testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(flowControl); - } - - @Test - public void testClientResetsStreamAfterPushSynDoesPreventSendingDataFramesWithoutFlowControl() throws Exception - { - final boolean flowControl = false; - testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(flowControl); - } - - private volatile boolean read = true; - - private void testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(final boolean flowControl) throws Exception - { - final short version = SPDY.V3; - final AtomicBoolean unexpectedExceptionOccurred = new AtomicBoolean(false); - final CountDownLatch resetReceivedLatch = new CountDownLatch(1); - final CountDownLatch allDataFramesReceivedLatch = new CountDownLatch(1); - final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1); - final int dataSizeInBytes = 1024 * 256; - final byte[] transferBytes = createHugeByteArray(dataSizeInBytes); - - InetSocketAddress serverAddress = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo) - { - new Thread(new Runnable() - { - - @Override - public void run() - { - Stream pushStream = null; - try - { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - pushStream = stream.push(new PushInfo(new Fields(), false)); - resetReceivedLatch.await(5, TimeUnit.SECONDS); - } - catch (InterruptedException | ExecutionException | TimeoutException e) - { - e.printStackTrace(); - unexpectedExceptionOccurred.set(true); - } - assert pushStream != null; - try - { - pushStream.data(new BytesDataInfo(transferBytes, true)); - stream.data(new StringDataInfo("close", true)); - } - catch (InterruptedException | ExecutionException | TimeoutException e) - { - LOG.debug(e.getMessage()); - } - } - }).start(); - return null; - } - - @Override - public void onRst(Session session, RstInfo rstInfo) - { - resetReceivedLatch.countDown(); - } - - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayInfo) - { - goAwayReceivedLatch.countDown(); - } - }/*TODO, flowControl*/); - - final SocketChannel channel = SocketChannel.open(serverAddress); - final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - int streamId = 1; - ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version, (byte)0, streamId, 0, (byte)0, (short)0, new Fields())); - channel.write(writeBuffer); - assertThat("writeBuffer is fully written", writeBuffer.hasRemaining(), is(false)); - - final Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); - parser.addListener(new Listener.Adapter() - { - int bytesRead = 0; - - @Override - public void onControlFrame(ControlFrame frame) - { - if (frame instanceof SynStreamFrame) - { - int pushStreamId = ((SynStreamFrame)frame).getStreamId(); - ByteBuffer writeBuffer = generator.control(new RstStreamFrame(version, pushStreamId, StreamStatus.CANCEL_STREAM.getCode(version))); - try - { - channel.write(writeBuffer); - } - catch (IOException e) - { - e.printStackTrace(); - unexpectedExceptionOccurred.set(true); - } - } - } - - @Override - public void onDataFrame(DataFrame frame, ByteBuffer data) - { - if (frame.getStreamId() == 2) - bytesRead = bytesRead + frame.getLength(); - if (bytesRead == dataSizeInBytes) - { - allDataFramesReceivedLatch.countDown(); - return; - } - if (flowControl) - { - ByteBuffer writeBuffer = generator.control(new WindowUpdateFrame(version, frame.getStreamId(), frame.getLength())); - try - { - channel.write(writeBuffer); - } - catch (IOException e) - { - e.printStackTrace(); - unexpectedExceptionOccurred.set(true); - } - } - } - }); - - Thread reader = new Thread(new Runnable() - { - @Override - public void run() - { - ByteBuffer readBuffer = ByteBuffer.allocate(dataSizeInBytes * 2); - while (read) - { - try - { - channel.read(readBuffer); - } - catch (IOException e) - { - e.printStackTrace(); - unexpectedExceptionOccurred.set(true); - } - readBuffer.flip(); - parser.parse(readBuffer); - readBuffer.clear(); - } - - } - }); - reader.start(); - read = false; - - assertThat("no unexpected exceptions occurred", unexpectedExceptionOccurred.get(), is(false)); - assertThat("not all dataframes have been received as the pushstream has been reset by the client.", allDataFramesReceivedLatch.await(streamId, TimeUnit.SECONDS), is(false)); - - - ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode())); - channel.write(buffer); - Assert.assertThat(buffer.hasRemaining(), is(false)); - - assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); - channel.shutdownOutput(); - channel.close(); - } - - @Test - public void testOddEvenStreamIds() throws Exception - { - final CountDownLatch pushStreamIdIsEvenLatch = new CountDownLatch(3); - - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.push(new PushInfo(new Fields(), false), new Promise.Adapter<Stream>()); - return null; - } - }), null); - - Stream stream = clientSession.syn(new SynInfo(new Fields(), false), - new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch)); - Stream stream2 = clientSession.syn(new SynInfo(new Fields(), false), - new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch)); - Stream stream3 = clientSession.syn(new SynInfo(new Fields(), false), - new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch)); - assertStreamIdIsOdd(stream); - assertStreamIdIsOdd(stream2); - assertStreamIdIsOdd(stream3); - - assertThat("all pushStreams had even ids", pushStreamIdIsEvenLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - private class VerifyPushStreamIdIsEvenStreamFrameListener extends StreamFrameListener.Adapter - { - final CountDownLatch pushStreamIdIsEvenLatch; - - private VerifyPushStreamIdIsEvenStreamFrameListener(CountDownLatch pushStreamIdIsEvenLatch) - { - this.pushStreamIdIsEvenLatch = pushStreamIdIsEvenLatch; - } - - @Override - public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) - { - assertStreamIdIsEven(stream); - pushStreamIdIsEvenLatch.countDown(); - return super.onPush(stream, pushInfo); - } - } - - private void assertStreamIdIsEven(Stream stream) - { - assertThat("streamId is odd", stream.getId() % 2, is(0)); - } - - private void assertStreamIdIsOdd(Stream stream) - { - assertThat("streamId is odd", stream.getId() % 2, is(1)); - } - - private void assertThatNoExceptionOccurred(final CountDownLatch exceptionCountDownLatch) throws InterruptedException - { - assertThat("No exception occurred", exceptionCountDownLatch.await(1, TimeUnit.SECONDS), is(false)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java deleted file mode 100644 index c28657c637..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java +++ /dev/null @@ -1,204 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.RstInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.FutureCallback; -import org.junit.Test; - -public class ResetStreamTest extends AbstractTest -{ - @Test - public void testResetStreamIsRemoved() throws Exception - { - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()/*TODO, true*/), null); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - session.rst(new RstInfo(5, TimeUnit.SECONDS, stream.getId(), StreamStatus.CANCEL_STREAM)); - - assertEquals("session expected to contain 0 streams", 0, session.getStreams().size()); - } - - @Test - public void testRefusedStreamIsRemoved() throws Exception - { - final AtomicReference<Session> serverSessionRef = new AtomicReference<>(); - final CountDownLatch synLatch = new CountDownLatch(1); - final CountDownLatch rstLatch = new CountDownLatch(1); - Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Session serverSession = stream.getSession(); - serverSessionRef.set(serverSession); - serverSession.rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback()); - synLatch.countDown(); - return null; - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - rstLatch.countDown(); - } - }); - - Stream stream = clientSession.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - - assertTrue("syncLatch didn't count down", synLatch.await(5, TimeUnit.SECONDS)); - Session serverSession = serverSessionRef.get(); - assertEquals("serverSession expected to contain 0 streams", 0, serverSession.getStreams().size()); - - assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS)); - // Need to sleep a while to give the chance to the implementation to remove the stream - TimeUnit.SECONDS.sleep(1); - assertTrue("stream is expected to be reset", stream.isReset()); - assertEquals("clientSession expected to contain 0 streams", 0, clientSession.getStreams().size()); - } - - @Test - public void testRefusedStreamIgnoresData() throws Exception - { - final CountDownLatch synLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - final CountDownLatch rstLatch = new CountDownLatch(1); - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - try - { - // Refuse the stream, we must ignore data frames - assertTrue(synLatch.await(5, TimeUnit.SECONDS)); - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback()); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataLatch.countDown(); - } - }; - } - catch (InterruptedException x) - { - x.printStackTrace(); - return null; - } - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - rstLatch.countDown(); - } - }); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", true), new Callback.Adapter() - { - @Override - public void succeeded() - { - synLatch.countDown(); - } - }); - - assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS)); - assertTrue("stream is expected to be reset", stream.isReset()); - assertFalse("dataLatch shouldn't be count down", dataLatch.await(1, TimeUnit.SECONDS)); - } - - @Test - public void testResetAfterServerReceivedFirstDataFrameAndSecondDataFrameFails() throws Exception - { - final CountDownLatch synLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - final CountDownLatch rstLatch = new CountDownLatch(1); - final CountDownLatch failLatch = new CountDownLatch(1); - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - synLatch.countDown(); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataLatch.countDown(); - stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback()); - } - }; - } - }), new SessionFrameListener.Adapter() - { - @Override - public void onRst(Session session, RstInfo rstInfo) - { - rstLatch.countDown(); - } - }); - - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); - assertThat("push is received by server", synLatch.await(5, TimeUnit.SECONDS), is(true)); - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), new Callback.Adapter()); - assertThat("stream is reset", rstLatch.await(5, TimeUnit.SECONDS), is(true)); - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "2nd dataframe", false), new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - failLatch.countDown(); - } - }); - - assertThat("2nd data call failed", failLatch.await(5, TimeUnit.SECONDS), is(true)); - assertThat("stream is reset", stream.isReset(), is(true)); - } - - // TODO: If server already received 2nd dataframe after it rst, it should ignore it. Not easy to do. - -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java deleted file mode 100644 index 91f197bea2..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java +++ /dev/null @@ -1,75 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.junit.Assert; -import org.junit.Test; - -public class SPDYClientFactoryTest extends AbstractTest -{ - @Test - public void testStoppingClientFactorySendsGoAway() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo) - { - latch.countDown(); - } - }), null); - - // Sleep a while to avoid the factory is - // stopped before a session can be opened - TimeUnit.SECONDS.sleep(1); - - clientFactory.stop(); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(clientFactory.getSessions().isEmpty()); - } - - @Test - public void testSessionClosedIsRemovedFromClientFactory() throws Exception - { - Session session = startClient(startServer(null), null); - - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - for (int i=0;i<10;i++) - { - // Sleep a while to allow the factory to remove the session - // since it is done asynchronously by the selector thread - TimeUnit.SECONDS.sleep(1); - if (clientFactory.getSessions().isEmpty()) - return; - } - - Assert.fail(clientFactory.getSessions().toString()); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java deleted file mode 100644 index 46c664c830..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java +++ /dev/null @@ -1,70 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.spdy.api.GoAwayInfo; -import org.eclipse.jetty.spdy.api.GoAwayResultInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.junit.Assert; -import org.junit.Test; - -public class SPDYServerConnectorTest extends AbstractTest -{ - @Test - public void testStoppingServerConnectorSendsGoAway() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - startClient(startServer(null), new SessionFrameListener.Adapter() - { - @Override - public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo) - { - latch.countDown(); - } - }); - - // Sleep a while to avoid the connector is - // stopped before a session can be opened - TimeUnit.SECONDS.sleep(1); - - connector.stop(); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(connector.getConnectionFactory(SPDYServerConnectionFactory.class).getSessions().isEmpty()); - } - - @Test - public void testSessionClosedIsRemovedFromServerConnector() throws Exception - { - Session session = startClient(startServer(null), null); - - session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); - - // Sleep a while to allow the connector to remove the session - // since it is done asynchronously by the selector thread - TimeUnit.SECONDS.sleep(1); - - Assert.assertTrue(connector.getConnectionFactory(SPDYServerConnectionFactory.class).getSessions().isEmpty()); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java deleted file mode 100644 index 5a13bb93dd..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java +++ /dev/null @@ -1,168 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Settings; -import org.eclipse.jetty.spdy.api.SettingsInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.FutureCallback; -import org.junit.Assert; -import org.junit.Test; - -public class SettingsTest extends AbstractTest -{ - @Test - public void testSettingsUsage() throws Exception - { - Settings settings = new Settings(); - int streamsValue = 100; - settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, Settings.Flag.PERSIST, streamsValue)); - int windowValue = 32768; - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowValue)); - int newCode = 91; - Settings.ID newID = Settings.ID.from(newCode); - int newValue = 97; - settings.put(new Settings.Setting(newID, newValue)); - - Settings.Setting setting1 = settings.get(Settings.ID.MAX_CONCURRENT_STREAMS); - Assert.assertSame(Settings.ID.MAX_CONCURRENT_STREAMS, setting1.id()); - Assert.assertSame(Settings.Flag.PERSIST, setting1.flag()); - Assert.assertEquals(streamsValue, setting1.value()); - - Settings.Setting setting2 = settings.get(Settings.ID.INITIAL_WINDOW_SIZE); - Assert.assertSame(Settings.ID.INITIAL_WINDOW_SIZE, setting2.id()); - Assert.assertSame(Settings.Flag.NONE, setting2.flag()); - Assert.assertEquals(windowValue, setting2.value()); - - int size = settings.size(); - Settings.Setting setting3 = settings.remove(Settings.ID.from(newCode)); - Assert.assertEquals(size - 1, settings.size()); - Assert.assertNotNull(setting3); - Assert.assertSame(newID, setting3.id()); - Assert.assertEquals(newValue, setting3.value()); - } - - @Test - public void testSettings() throws Exception - { - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.UPLOAD_BANDWIDTH, 1024 * 1024)); - settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_BANDWIDTH, 1024 * 1024)); - settings.put(new Settings.Setting(Settings.ID.CURRENT_CONGESTION_WINDOW, Settings.Flag.PERSISTED, 1024)); - final SettingsInfo clientSettingsInfo = new SettingsInfo(settings); - final CountDownLatch latch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo serverSettingsInfo) - { - Assert.assertEquals(clientSettingsInfo.getFlags(), serverSettingsInfo.getFlags()); - Assert.assertEquals(clientSettingsInfo.getSettings(), serverSettingsInfo.getSettings()); - latch.countDown(); - } - }; - Session session = startClient(startServer(serverSessionFrameListener), null); - - session.settings(clientSettingsInfo); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testServerSettings() throws Exception - { - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.UPLOAD_BANDWIDTH, 1024 * 1024)); - settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_BANDWIDTH, 1024 * 1024)); - settings.put(new Settings.Setting(Settings.ID.CURRENT_CONGESTION_WINDOW, Settings.Flag.PERSIST, 1024)); - final SettingsInfo serverSettingsInfo = new SettingsInfo(settings); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - session.settings(serverSettingsInfo, new FutureCallback()); - } - }; - - final CountDownLatch latch = new CountDownLatch(1); - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public void onSettings(Session session, SettingsInfo clientSettingsInfo) - { - Assert.assertEquals(serverSettingsInfo.getFlags(), clientSettingsInfo.getFlags()); - Assert.assertEquals(serverSettingsInfo.getSettings(), clientSettingsInfo.getSettings()); - latch.countDown(); - } - }; - - startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testSettingIDIsTheSameInBothV2AndV3() throws Exception - { - final AtomicReference<SettingsInfo> v2 = new AtomicReference<>(); - final AtomicReference<SettingsInfo> v3 = new AtomicReference<>(); - final CountDownLatch settingsLatch = new CountDownLatch(2); - InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() - { - private final AtomicInteger count = new AtomicInteger(); - - @Override - public void onSettings(Session session, SettingsInfo settingsInfo) - { - int count = this.count.incrementAndGet(); - if (count == 1) - v2.set(settingsInfo); - else if (count == 2) - v3.set(settingsInfo); - else - Assert.fail(); - settingsLatch.countDown(); - } - }); - - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, Settings.Flag.PERSIST, 0xC0_00)); - SettingsInfo settingsInfo = new SettingsInfo(settings); - - Session sessionV2 = startClient(address, null); - sessionV2.settings(settingsInfo); - - Session sessionV3 = clientFactory.newSPDYClient(SPDY.V3).connect(address, null); - sessionV3.settings(settingsInfo); - - Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - Assert.assertEquals(v2.get().getSettings(), v3.get().getSettings()); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java deleted file mode 100644 index 6dfdb5b691..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java +++ /dev/null @@ -1,288 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.io.LeakTrackingByteBufferPool; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.util.thread.Scheduler; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -public class SynDataReplyDataLoadTest extends AbstractTest -{ - private static final int TIMEOUT = 60 * 1000; - private static final Logger logger = Log.getLogger(SynDataReplyDataLoadTest.class); - - @Test(timeout = TIMEOUT) - @Ignore("Test needs to be rewritten") - public void testSynDataReplyDataLoad() throws Exception - { - LeakTrackingByteBufferPool serverBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()); - LeakTrackingByteBufferPool clientBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()); - - ServerSessionFrameListener listener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - stream.reply(new ReplyInfo(synInfo.getHeaders(), false), new Callback.Adapter()); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - ByteBuffer buffer = dataInfo.asByteBuffer(true); - stream.data(new ByteBufferDataInfo(buffer, dataInfo.isClose()), new Callback.Adapter()); - } - }; - } - }; - - short spdyVersion = SPDY.V2; - long idleTimeout = 2 * TIMEOUT; - - server = newServer(); - connector = new ServerConnector(server, null, null, serverBufferPool, 1, - Math.max(1, Runtime.getRuntime().availableProcessors() / 2), - new SPDYServerConnectionFactory(spdyVersion, listener)); - connector.setIdleTimeout(idleTimeout); - - QueuedThreadPool clientExecutor = new QueuedThreadPool(); - clientExecutor.setName(clientExecutor.getName() + "-client"); - clientFactory = new SPDYClient.Factory(clientExecutor, null, clientBufferPool, null, idleTimeout); - final Session session = startClient(spdyVersion, startServer(spdyVersion, listener), null); - - final Thread testThread = Thread.currentThread(); - Runnable timeout = new Runnable() - { - @Override - public void run() - { - logger.warn("Interrupting test, it is taking too long"); - logger.warn("SERVER: {}", server.dump()); - logger.warn("CLIENT: {}", clientFactory.dump()); - testThread.interrupt(); - } - }; - - final int iterations = 500; - final int count = 50; - - final Fields headers = new Fields(); - headers.put("method", "get"); - headers.put("url", "/"); - headers.put("version", "http/1.1"); - headers.put("host", "localhost:8080"); - headers.put("content-type", "application/octet-stream"); - - final CountDownLatch latch = new CountDownLatch(count * iterations); - session.addListener(new Session.StreamListener.Adapter() - { - @Override - public void onStreamClosed(Stream stream) - { - latch.countDown(); - } - }); - - ExecutorService threadPool = Executors.newFixedThreadPool(count); - List<Callable<Object>> tasks = new ArrayList<>(); - - tasks.clear(); - for (int i = 0; i < count; ++i) - { - tasks.add(new Callable<Object>() - { - @Override - public Object call() throws Exception - { - synGetDataGet(session, headers, iterations); - return null; - } - }); - } - Scheduler.Task syncTimeoutTask = clientFactory.getScheduler().schedule(timeout, TIMEOUT / 2, TimeUnit.MILLISECONDS); - { - long begin = System.nanoTime(); - List<Future<Object>> futures = threadPool.invokeAll(tasks); - for (Future<Object> future : futures) - future.get(iterations, TimeUnit.SECONDS); - Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS)); - long end = System.nanoTime(); - System.err.printf("SYN+GET+DATA+GET completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin)); - } - syncTimeoutTask.cancel(); - - tasks.clear(); - for (int i = 0; i < count; ++i) - { - tasks.add(new Callable<Object>() - { - @Override - public Object call() throws Exception - { - synCompletedData(session, headers, iterations); - return null; - } - }); - } - Scheduler.Task asyncTimeoutTask = clientFactory.getScheduler().schedule(timeout, TIMEOUT / 2, TimeUnit.MILLISECONDS); - { - long begin = System.nanoTime(); - List<Future<Object>> futures = threadPool.invokeAll(tasks); - for (Future<Object> future : futures) - future.get(iterations, TimeUnit.SECONDS); - Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS)); - long end = System.nanoTime(); - System.err.printf("SYN+COMPLETED+DATA completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin)); - } - asyncTimeoutTask.cancel(); - - threadPool.shutdown(); - - System.gc(); - - assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), is(0L)); - assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), is(0L)); - assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), is(0L)); - - assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), is(0L)); - assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), is(0L)); - assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), is(0L)); - } - - private void synCompletedData(Session session, Fields headers, int iterations) throws Exception - { - final Map<Integer, Integer> counter = new ConcurrentHashMap<>(iterations); - final CountDownLatch requestsLatch = new CountDownLatch(2 * iterations); - for (int i = 0; i < iterations; ++i) - { - final AtomicInteger count = new AtomicInteger(2); - final int index = i; - counter.put(index, index); - session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertEquals(2, count.getAndDecrement()); - requestsLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - // TCP can split the data frames, so I may be receiving more than 1 data frame - dataInfo.asBytes(true); - if (dataInfo.isClose()) - { - Assert.assertEquals(1, count.getAndDecrement()); - counter.remove(index); - requestsLatch.countDown(); - } - } - }, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream stream) - { - stream.data(new StringDataInfo("data_" + stream.getId(), true), - new Callback.Adapter()); - } - } - ); - } - Assert.assertTrue(requestsLatch.await(iterations, TimeUnit.SECONDS)); - Assert.assertTrue(counter.toString(), counter.isEmpty()); - } - - private void synGetDataGet(Session session, Fields headers, int iterations) throws Exception - { - final Map<Integer, Integer> counter = new ConcurrentHashMap<>(iterations); - final CountDownLatch latch = new CountDownLatch(2 * iterations); - for (int i = 0; i < iterations; ++i) - { - final AtomicInteger count = new AtomicInteger(2); - final int index = i; - counter.put(index, index); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertEquals(2, count.getAndDecrement()); - latch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - // TCP can split the data frames, so I may be receiving more than 1 data frame - dataInfo.asBytes(true); - if (dataInfo.isClose()) - { - Assert.assertEquals(1, count.getAndDecrement()); - counter.remove(index); - latch.countDown(); - } - } - }); - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data_" + stream.getId(), true)); - } - Assert.assertTrue(latch.await(iterations, TimeUnit.SECONDS)); - Assert.assertTrue(counter.toString(), counter.isEmpty()); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java deleted file mode 100644 index 29c2b50385..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java +++ /dev/null @@ -1,375 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.spdy.api.BytesDataInfo; -import org.eclipse.jetty.spdy.api.DataInfo; -import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.SessionFrameListener; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StringDataInfo; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Fields; -import org.eclipse.jetty.util.Promise; -import org.junit.Assert; -import org.junit.Test; - -public class SynReplyTest extends AbstractTest -{ - @Test - public void testSynReply() throws Exception - { - final AtomicReference<Session> sessionRef = new AtomicReference<>(); - final CountDownLatch sessionLatch = new CountDownLatch(1); - final CountDownLatch synLatch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - sessionRef.set(session); - sessionLatch.countDown(); - } - - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(stream.isHalfClosed()); - stream.reply(new ReplyInfo(new Fields(), true), new Callback.Adapter()); - synLatch.countDown(); - return null; - } - }; - - Session session = startClient(startServer(serverSessionFrameListener), null); - - Assert.assertTrue(sessionLatch.await(5, TimeUnit.SECONDS)); - Session serverSession = sessionRef.get(); - Assert.assertNotNull(serverSession); - - final CountDownLatch streamCreatedLatch = new CountDownLatch(1); - final CountDownLatch streamRemovedLatch = new CountDownLatch(1); - session.addListener(new Session.StreamListener() - { - @Override - public void onStreamCreated(Stream stream) - { - streamCreatedLatch.countDown(); - } - - @Override - public void onStreamClosed(Stream stream) - { - streamRemovedLatch.countDown(); - } - }); - - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertTrue(stream.isClosed()); - replyLatch.countDown(); - } - }); - - Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS)); - - Assert.assertTrue(streamCreatedLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(stream.isClosed()); - - Assert.assertTrue(streamRemovedLatch.await(5, TimeUnit.SECONDS)); - Assert.assertEquals(0, session.getStreams().size()); - } - - @Test - public void testSynDataReply() throws Exception - { - final byte[] dataBytes = "foo".getBytes(StandardCharsets.UTF_8); - - final CountDownLatch synLatch = new CountDownLatch(1); - final CountDownLatch dataLatch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertFalse(stream.isHalfClosed()); - Assert.assertFalse(stream.isClosed()); - synLatch.countDown(); - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - ByteBuffer buffer = ByteBuffer.allocate(2); - while (dataInfo.available() > 0) - { - dataInfo.readInto(buffer); - buffer.flip(); - bytes.write(buffer.array(), buffer.arrayOffset(), buffer.remaining()); - buffer.clear(); - } - Assert.assertTrue(Arrays.equals(dataBytes, bytes.toByteArray())); - Assert.assertTrue(stream.isHalfClosed()); - Assert.assertFalse(stream.isClosed()); - - stream.reply(new ReplyInfo(true), new Callback.Adapter()); - Assert.assertTrue(stream.isClosed()); - dataLatch.countDown(); - } - }; - } - }; - - Session session = startClient(startServer(serverSessionFrameListener), null); - - final CountDownLatch streamRemovedLatch = new CountDownLatch(1); - session.addListener(new Session.StreamListener.Adapter() - { - @Override - public void onStreamClosed(Stream stream) - { - streamRemovedLatch.countDown(); - } - }); - - final CountDownLatch replyLatch = new CountDownLatch(1); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), - new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - }); - stream.data(new BytesDataInfo(dataBytes, true)); - - Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS)); - - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - - Assert.assertTrue(streamRemovedLatch.await(5, TimeUnit.SECONDS)); - Assert.assertEquals(0, session.getStreams().size()); - } - - @Test - public void testSynReplyDataData() throws Exception - { - final String data1 = "foo"; - final String data2 = "bar"; - Session session = startClient(startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo) - { - Assert.assertTrue(stream.isHalfClosed()); - - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new StringDataInfo(5, TimeUnit.SECONDS, data1, false), new Callback.Adapter() - { - @Override - public void succeeded() - { - stream.data(new StringDataInfo(data2, true), new Adapter()); - } - }); - - return null; - } - }), null); - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch dataLatch1 = new CountDownLatch(1); - final CountDownLatch dataLatch2 = new CountDownLatch(1); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() - { - private AtomicInteger dataCount = new AtomicInteger(); - - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - int dataCount = this.dataCount.incrementAndGet(); - if (dataCount == 1) - { - String chunk1 = dataInfo.asString(StandardCharsets.UTF_8, true); - Assert.assertEquals(data1, chunk1); - dataLatch1.countDown(); - } - else if (dataCount == 2) - { - String chunk2 = dataInfo.asString(StandardCharsets.UTF_8, true); - Assert.assertEquals(data2, chunk2); - dataLatch2.countDown(); - } - } - }); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch1.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch2.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testServerSynDataReplyData() throws Exception - { - final String serverData = "server"; - final String clientData = "client"; - - final CountDownLatch replyLatch = new CountDownLatch(1); - final CountDownLatch clientDataLatch = new CountDownLatch(1); - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public void onConnect(Session session) - { - session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - String data = dataInfo.asString(StandardCharsets.UTF_8, true); - Assert.assertEquals(clientData, data); - clientDataLatch.countDown(); - } - }, new Promise.Adapter<Stream>() - { - @Override - public void succeeded(Stream stream) - { - stream.data(new StringDataInfo(serverData, true), new Callback.Adapter()); - } - }); - } - }; - - final CountDownLatch synLatch = new CountDownLatch(1); - final CountDownLatch serverDataLatch = new CountDownLatch(1); - SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertEquals(0, stream.getId() % 2); - - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new StringDataInfo(clientData, true), new Callback.Adapter()); - synLatch.countDown(); - - return new StreamFrameListener.Adapter() - { - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - ByteBuffer buffer = dataInfo.asByteBuffer(false); - String data = StandardCharsets.UTF_8.decode(buffer).toString(); - Assert.assertEquals(serverData, data); - serverDataLatch.countDown(); - } - }; - } - }; - - startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); - - Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(clientDataLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testSynReplyDataSynReplyData() throws Exception - { - final String data = "foo"; - ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - Assert.assertTrue(stream.isHalfClosed()); - - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new StringDataInfo(data, true), new Callback.Adapter()); - - return null; - } - }; - - Session session = startClient(startServer(serverSessionFrameListener), null); - - final CountDownLatch replyLatch = new CountDownLatch(2); - final CountDownLatch dataLatch = new CountDownLatch(2); - StreamFrameListener clientStreamFrameListener = new StreamFrameListener.Adapter() - { - @Override - public void onReply(Stream stream, ReplyInfo replyInfo) - { - Assert.assertFalse(replyInfo.isClose()); - replyLatch.countDown(); - } - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - String chunk = dataInfo.asString(StandardCharsets.UTF_8, true); - Assert.assertEquals(data, chunk); - dataLatch.countDown(); - } - }; - session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener); - session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener); - - Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); - Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java deleted file mode 100644 index 5d92bee910..0000000000 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java +++ /dev/null @@ -1,100 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.spdy.server; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.spdy.StandardCompressionFactory; -import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.Stream; -import org.eclipse.jetty.spdy.api.StreamFrameListener; -import org.eclipse.jetty.spdy.api.StreamStatus; -import org.eclipse.jetty.spdy.api.SynInfo; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.frames.ControlFrame; -import org.eclipse.jetty.spdy.frames.ControlFrameType; -import org.eclipse.jetty.spdy.frames.RstStreamFrame; -import org.eclipse.jetty.spdy.frames.SynStreamFrame; -import org.eclipse.jetty.spdy.generator.Generator; -import org.eclipse.jetty.spdy.parser.Parser; -import org.eclipse.jetty.util.Fields; -import org.junit.Assert; -import org.junit.Test; - -public class UnsupportedVersionTest extends AbstractTest -{ - @Test - public void testSynWithUnsupportedVersion() throws Exception - { - final CountDownLatch synLatch = new CountDownLatch(1); - InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() - { - @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) - { - synLatch.countDown(); - return null; - } - - @Override - public void onFailure(Session session, Throwable x) - { - // Suppress exception logging for this test - } - }); - - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Fields()); - Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); - ByteBuffer buffer = generator.control(frame); - // Replace the version byte with an unsupported version - buffer.putShort(0, (short)0x8001); - - SocketChannel channel = SocketChannel.open(address); - channel.write(buffer); - Assert.assertFalse(buffer.hasRemaining()); - - Assert.assertFalse(synLatch.await(1, TimeUnit.SECONDS)); - - buffer = ByteBuffer.allocate(1024); - channel.read(buffer); - buffer.flip(); - - final CountDownLatch rstLatch = new CountDownLatch(1); - Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); - parser.addListener(new Parser.Listener.Adapter() - { - @Override - public void onControlFrame(ControlFrame frame) - { - Assert.assertSame(ControlFrameType.RST_STREAM, frame.getType()); - Assert.assertEquals(StreamStatus.UNSUPPORTED_VERSION.getCode(frame.getVersion()), ((RstStreamFrame)frame).getStatusCode()); - rstLatch.countDown(); - } - }); - parser.parse(buffer); - - Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties deleted file mode 100644 index ead13ec197..0000000000 --- a/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.spdy.LEVEL=DEBUG |