Updated to correct version of NPN artifact.

Implemented plain HTTP AsyncConnectionFactory and tested protocol negotiation.
This commit is contained in:
Simone Bordet 2012-02-24 00:48:26 +01:00
parent 7be63d7f76
commit cb1be263c4
8 changed files with 320 additions and 1 deletions

View File

@ -25,5 +25,6 @@ public class HTTPSPDYServerConnector extends SPDYServerConnector
{
super(null);
putAsyncConnectionFactory("spdy/2", new ServerHTTPSPDYAsyncConnectionFactory(SPDY.V2, this));
setDefaultProtocol("http/1.1");
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.jetty.spdy.http;
import java.nio.channels.SocketChannel;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.server.AsyncHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.spdy.AsyncConnectionFactory;
public class ServerHTTPAsyncConnectionFactory implements AsyncConnectionFactory
{
private final Connector connector;
public ServerHTTPAsyncConnectionFactory(Connector connector)
{
this.connector = connector;
}
@Override
public AsyncConnection newAsyncConnection(SocketChannel channel, AsyncEndPoint endPoint, Object attachment)
{
return new AsyncHttpConnection(connector, endPoint, connector.getServer());
}
}

View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.jetty.spdy.http;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
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.Server;
import org.eclipse.jetty.spdy.SPDYServerConnector;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
public class ProtocolNegotiationTest
{
@Rule
public final TestWatchman testName = new TestWatchman()
{
@Override
public void starting(FrameworkMethod method)
{
super.starting(method);
System.err.printf("Running %s.%s()%n",
method.getMethod().getDeclaringClass().getName(),
method.getName());
}
};
protected Server server;
protected SPDYServerConnector connector;
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
{
server = new Server();
SslContextFactory sslContextFactory = newSslContextFactory();
connector = new SPDYServerConnector(listener, sslContextFactory);
connector.setPort(0);
server.addConnector(connector);
server.start();
return new InetSocketAddress("localhost", connector.getLocalPort());
}
protected SslContextFactory newSslContextFactory()
{
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setTrustStore("src/test/resources/truststore.jks");
sslContextFactory.setTrustStorePassword("storepwd");
sslContextFactory.setProtocol("TLSv1");
sslContextFactory.setIncludeProtocols("TLSv1");
return sslContextFactory;
}
@Test
public void testServerAdvertisingHTTPSpeaksHTTP() throws Exception
{
InetSocketAddress address = startServer(null);
connector.removeAsyncConnectionFactory("spdy/2");
connector.putAsyncConnectionFactory("http/1.1", new ServerHTTPAsyncConnectionFactory(connector));
SslContextFactory sslContextFactory = newSslContextFactory();
sslContextFactory.start();
SSLContext sslContext = sslContextFactory.getSslContext();
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);
Assert.assertEquals(1, strings.size());
String protocol = strings.get(0);
Assert.assertEquals("http/1.1", 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("UTF-8"));
output.flush();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line = reader.readLine();
Assert.assertTrue(line.contains(" 404 "));
client.close();
}
@Test
public void testServerAdvertisingSPDYAndHTTPSpeaksHTTPWhenNegotiated() throws Exception
{
InetSocketAddress address = startServer(null);
connector.putAsyncConnectionFactory("http/1.1", new ServerHTTPAsyncConnectionFactory(connector));
SslContextFactory sslContextFactory = newSslContextFactory();
sslContextFactory.start();
SSLContext sslContext = sslContextFactory.getSslContext();
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);
Assert.assertEquals(2, strings.size());
String spdyProtocol = strings.get(0);
Assert.assertEquals("spdy/2", spdyProtocol);
String httpProtocol = strings.get(1);
Assert.assertEquals("http/1.1", 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("UTF-8"));
output.flush();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line = reader.readLine();
Assert.assertTrue(line.contains(" 404 "));
client.close();
}
@Test
public void testServerAdvertisingSPDYAndHTTPSpeaksDefaultProtocolWhenNPNMissing() throws Exception
{
InetSocketAddress address = startServer(null);
connector.putAsyncConnectionFactory("http/1.1", new ServerHTTPAsyncConnectionFactory(connector));
connector.setDefaultProtocol("http/1.1");
SslContextFactory sslContextFactory = newSslContextFactory();
sslContextFactory.start();
SSLContext sslContext = sslContextFactory.getSslContext();
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("UTF-8"));
output.flush();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line = reader.readLine();
Assert.assertTrue(line.contains(" 404 "));
client.close();
}
}

Binary file not shown.

Binary file not shown.

View File

@ -39,7 +39,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-npn-boot</artifactId>
<artifactId>npn-boot</artifactId>
<version>${npn.version}</version>
</dependency>
<dependency>

View File

@ -290,6 +290,15 @@ public class SPDYClient
return true;
}
@Override
public void unsupported()
{
// Server does not support NPN, but this is a SPDY client, so hardcode SPDY
ClientSPDYAsyncConnectionFactory connectionFactory = new ClientSPDYAsyncConnectionFactory();
AsyncConnection connection = connectionFactory.newAsyncConnection(channel, sslEndPoint, attachment);
sslEndPoint.setConnection(connection);
}
@Override
public String selectProtocol(List<String> protocols)
{

View File

@ -38,6 +38,7 @@ public class SPDYServerConnector extends SelectChannelConnector
// Order is important on server side, so we use a LinkedHashMap
private final Map<String, AsyncConnectionFactory> factories = new LinkedHashMap<>();
private final SslContextFactory sslContextFactory;
private volatile String defaultProtocol = "spdy/2";
public SPDYServerConnector(ServerSessionFrameListener listener)
{
@ -92,6 +93,16 @@ public class SPDYServerConnector extends SelectChannelConnector
}
}
public String getDefaultProtocol()
{
return defaultProtocol;
}
public void setDefaultProtocol(String defaultProtocol)
{
this.defaultProtocol = defaultProtocol;
}
@Override
protected AsyncConnection newConnection(final SocketChannel channel, AsyncEndPoint endPoint)
{
@ -104,6 +115,12 @@ public class SPDYServerConnector extends SelectChannelConnector
NextProtoNego.put(engine, new NextProtoNego.ServerProvider()
{
@Override
public void unsupported()
{
protocolSelected(getDefaultProtocol());
}
@Override
public List<String> protocols()
{