Merged branch 'master' into 'jetty-9-alpn'.

This commit is contained in:
Simone Bordet 2014-03-20 16:34:44 +01:00
commit 3692ac17d4
12 changed files with 286 additions and 166 deletions

View File

@ -24,13 +24,17 @@
<module>spdy-example-webapp</module>
</modules>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jdk7-npn</id>
<activation>
<jdk>[1.7,1.8)</jdk>
</activation>
<modules>
<module>spdy-npn-tests</module>
</modules>
</profile>
</profiles>
<build>
<plugins>
@ -71,16 +75,12 @@
</plugins>
</build>
<profiles>
<profile>
<id>jdk7-npn</id>
<activation>
<jdk>[1.7,1.8)</jdk>
</activation>
<modules>
<module>spdy-npn-tests</module>
</modules>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -18,87 +18,28 @@
package org.eclipse.jetty.spdy.client;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.npn.NextProtoNego;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class NPNClientConnection extends AbstractConnection implements NextProtoNego.ClientProvider
public class NPNClientConnection extends NegotiatingClientConnection implements NextProtoNego.ClientProvider
{
private final Logger LOG = Log.getLogger(getClass());
private final SPDYClient client;
private final ClientConnectionFactory connectionFactory;
private final SSLEngine engine;
private final Map<String, Object> context;
private volatile boolean completed;
private static final Logger LOG = Log.getLogger(NPNClientConnection.class);
public NPNClientConnection(EndPoint endPoint, SPDYClient client, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context)
{
super(endPoint, client.getFactory().getExecutor());
this.client = client;
this.connectionFactory = connectionFactory;
this.engine = sslEngine;
this.context = context;
NextProtoNego.put(engine, this);
}
private final String protocol;
@Override
public void onOpen()
public NPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, String protocol)
{
super.onOpen();
try
{
getEndPoint().flush(BufferUtil.EMPTY_BUFFER);
if (completed)
replaceConnection();
else
fillInterested();
}
catch(IOException e)
{
throw new RuntimeIOException(e);
}
}
@Override
public void onFillable()
{
while (true)
{
int filled = fill();
if (filled == 0 && !completed)
fillInterested();
if (filled <= 0 || completed)
break;
}
if (completed)
replaceConnection();
}
private int fill()
{
try
{
return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
}
catch (IOException x)
{
LOG.debug(x);
NextProtoNego.remove(engine);
close();
return -1;
}
super(endPoint, executor, sslEngine, connectionFactory, context);
this.protocol = protocol;
NextProtoNego.put(sslEngine, this);
}
@Override
@ -110,31 +51,31 @@ public class NPNClientConnection extends AbstractConnection implements NextProto
@Override
public void unsupported()
{
NextProtoNego.remove(engine);
completed = true;
NextProtoNego.remove(getSSLEngine());
completed();
}
@Override
public String selectProtocol(List<String> protocols)
{
NextProtoNego.remove(engine);
completed = true;
return client.selectProtocol(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;
}
}
private void replaceConnection()
@Override
public void close()
{
EndPoint endPoint = getEndPoint();
try
{
Connection oldConnection = endPoint.getConnection();
Connection newConnection = connectionFactory.newConnection(endPoint, context);
ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection);
}
catch (Throwable x)
{
LOG.debug(x);
close();
}
NextProtoNego.remove(getSSLEngine());
super.close();
}
}

View File

@ -20,7 +20,7 @@ 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;
@ -28,21 +28,22 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
public class NPNClientConnectionFactory implements ClientConnectionFactory
public class NPNClientConnectionFactory extends NegotiatingClientConnectionFactory
{
private final SPDYClient client;
private final ClientConnectionFactory connectionFactory;
private final Executor executor;
private final String protocol;
public NPNClientConnectionFactory(SPDYClient client, ClientConnectionFactory connectionFactory)
public NPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol)
{
this.client = client;
this.connectionFactory = connectionFactory;
super(connectionFactory);
this.executor = executor;
this.protocol = protocol;
}
@Override
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
{
return new NPNClientConnection(endPoint, client, connectionFactory,
(SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context);
return new NPNClientConnection(endPoint, executor, getClientConnectionFactory(),
(SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol);
}
}

View File

@ -0,0 +1,133 @@
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.spdy.client;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Executor;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public abstract class NegotiatingClientConnection extends AbstractConnection
{
private static final Logger LOG = Log.getLogger(NegotiatingClientConnection.class);
private final SSLEngine engine;
private final ClientConnectionFactory connectionFactory;
private final Map<String, Object> context;
private volatile boolean completed;
protected NegotiatingClientConnection(EndPoint endp, Executor executor, SSLEngine sslEngine, ClientConnectionFactory connectionFactory, Map<String, Object> context)
{
super(endp, executor);
this.engine = sslEngine;
this.connectionFactory = connectionFactory;
this.context = context;
}
protected SSLEngine getSSLEngine()
{
return engine;
}
protected void completed()
{
completed = true;
}
@Override
public void onOpen()
{
super.onOpen();
try
{
getEndPoint().flush(BufferUtil.EMPTY_BUFFER);
if (completed)
replaceConnection();
else
fillInterested();
}
catch (IOException x)
{
close();
throw new RuntimeIOException(x);
}
}
@Override
public void onFillable()
{
while (true)
{
int filled = fill();
if (filled == 0 && !completed)
fillInterested();
if (filled <= 0 || completed)
break;
}
if (completed)
replaceConnection();
}
private int fill()
{
try
{
return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
}
catch (IOException x)
{
LOG.debug(x);
close();
return -1;
}
}
private void replaceConnection()
{
EndPoint endPoint = getEndPoint();
try
{
Connection oldConnection = endPoint.getConnection();
Connection newConnection = connectionFactory.newConnection(endPoint, context);
ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection);
}
catch (Throwable x)
{
LOG.debug(x);
close();
}
}
@Override
public void close()
{
// Gentler close for SSL.
getEndPoint().shutdownOutput();
super.close();
}
}

View File

@ -0,0 +1,36 @@
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.spdy.client;
import org.eclipse.jetty.io.ClientConnectionFactory;
public abstract class NegotiatingClientConnectionFactory implements ClientConnectionFactory
{
private final ClientConnectionFactory connectionFactory;
protected NegotiatingClientConnectionFactory(ClientConnectionFactory connectionFactory)
{
this.connectionFactory = connectionFactory;
}
public ClientConnectionFactory getClientConnectionFactory()
{
return connectionFactory;
}
}

View File

@ -26,7 +26,6 @@ import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@ -86,10 +85,6 @@ public class SPDYClient
this.factory = factory;
setInitialWindowSize(65536);
setDispatchIO(true);
ClientConnectionFactory connectionFactory = new SPDYClientConnectionFactory();
if (factory.sslContextFactory != null)
connectionFactory = new SslClientConnectionFactory(factory.getSslContextFactory(), factory.getByteBufferPool(), factory.getExecutor(), new NPNClientConnectionFactory(this, connectionFactory));
setClientConnectionFactory(connectionFactory);
}
public short getVersion()
@ -239,17 +234,6 @@ public class SPDYClient
this.connectionFactory = connectionFactory;
}
protected String selectProtocol(List<String> serverProtocols)
{
String protocol = "spdy/" + version;
for (String serverProtocol : serverProtocols)
{
if (serverProtocol.equals(protocol))
return protocol;
}
return null;
}
protected FlowControlStrategy newFlowControlStrategy()
{
return FlowControlStrategyFactory.newFlowControlStrategy(version);
@ -357,7 +341,19 @@ public class SPDYClient
public SPDYClient newSPDYClient(short version)
{
return new SPDYClient(version, this);
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

View File

@ -77,16 +77,15 @@ import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public abstract class ProxySPDYToHTTPTest
{
@Rule
public final TestTracker tracker = new TestTracker();
private final short version;
@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;

View File

@ -67,16 +67,15 @@ import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public abstract class ProxySPDYToSPDYLoadTest
{
@Rule
public final TestTracker tracker = new TestTracker();
private final short version;
@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;

View File

@ -68,16 +68,15 @@ import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public abstract class ProxySPDYToSPDYTest
{
@Rule
public final TestTracker tracker = new TestTracker();
private final short version;
@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;

View File

@ -42,7 +42,7 @@ public abstract class NegotiatingServerConnection extends AbstractConnection
private final String defaultProtocol;
private String protocol; // No need to be volatile: it is modified and read by the same thread
public NegotiatingServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
protected NegotiatingServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
{
super(endPoint, connector.getExecutor());
this.connector = connector;

View File

@ -18,7 +18,7 @@
package org.eclipse.jetty.xml;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Assert;
@ -31,24 +31,40 @@ public class XmlAppendableTest
{
StringBuilder b = new StringBuilder();
XmlAppendable out = new XmlAppendable(b);
Map<String,String> attr = new HashMap<>();
Map<String, String> attr = new LinkedHashMap<>();
out.open("test");
attr.put("name","attr value");
attr.put("noval",null);
attr.put("quotes","'\"");
attr.put("name", "attr value");
attr.put("noval", null);
attr.put("quotes", "'\"");
out.tag("tag");
out.tag("tag",attr);
out.tag("tag",attr,"content");
out.open("level1").tag("tag","content").tag("tag","content").close();
out.open("level1",attr).open("level2").tag("tag","content").tag("tag","content").close().close();
out.tag("tag", attr);
out.tag("tag", attr, "content");
out.open("level1").tag("tag", "content").tag("tag", "content").close();
out.open("level1", attr).open("level2").tag("tag", "content").tag("tag", "content").close().close();
out.close();
String s = b.toString();
Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n <tag/>\n <tag quotes=\"&apos;&quot;\" name=\"attr value\" noval=\"\"/>\n <tag quotes=\"&apos;&quot;\" name=\"attr value\" noval=\"\">content</tag>\n <level1>\n <tag>content</tag>\n <tag>content</tag>\n </level1>\n <level1 quotes=\"&apos;&quot;\" name=\"attr value\" noval=\"\">\n <level2>\n <tag>content</tag>\n <tag>content</tag>\n </level2>\n </level1>\n</test>\n",s);
String expected = "" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<test>\n" +
" <tag/>\n" +
" <tag name=\"attr value\" noval=\"\" quotes=\"&apos;&quot;\"/>\n" +
" <tag name=\"attr value\" noval=\"\" quotes=\"&apos;&quot;\">content</tag>\n" +
" <level1>\n" +
" <tag>content</tag>\n" +
" <tag>content</tag>\n" +
" </level1>\n" +
" <level1 name=\"attr value\" noval=\"\" quotes=\"&apos;&quot;\">\n" +
" <level2>\n" +
" <tag>content</tag>\n" +
" <tag>content</tag>\n" +
" </level2>\n" +
" </level1>\n" +
"</test>\n";
Assert.assertEquals(expected, b.toString());
}
}

14
pom.xml
View File

@ -814,13 +814,13 @@
</build>
</profile>
<profile>
<id>osgi</id>
<activation>
<jdk>[1.7,1.8)</jdk>
</activation>
<modules>
<module>jetty-osgi</module>
</modules>
<id>osgi</id>
<activation>
<jdk>[1.7,1.8)</jdk>
</activation>
<modules>
<module>jetty-osgi</module>
</modules>
</profile>
<profile>
<id>7u9</id>