Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project

This commit is contained in:
Jan Bartel 2012-03-09 11:28:41 +11:00
commit c596add40c
22 changed files with 807 additions and 309 deletions

View File

@ -1,22 +1,19 @@
package org.eclipse.jetty.annotations.resources;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.eclipse.jetty.annotations.AnnotationIntrospector;
import org.eclipse.jetty.annotations.AnnotationParser;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.annotations.ResourceAnnotationHandler;
import org.eclipse.jetty.annotations.ResourcesAnnotationHandler;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -24,24 +21,39 @@ import static org.junit.Assert.assertNotNull;
public class TestResourceAnnotations
{
Object objA=new Integer(1000);
Object objB=new Integer(2000);
private Server server;
private WebAppContext wac;
private InjectionCollection injections;
private Context comp;
private Context env;
private Object objA = 1000;
private Object objB = 2000;
@Before
public void init() throws Exception
{
server = new Server();
wac = new WebAppContext();
wac.setServer(server);
injections = new InjectionCollection();
wac.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
InitialContext ic = new InitialContext();
comp = (Context)ic.lookup("java:comp");
env = comp.createSubcontext("env");
}
@After
public void destroy() throws Exception
{
comp.destroySubcontext("env");
}
@Test
public void testResourceAnnotations ()
throws Exception
{
Server server = new Server();
WebAppContext wac = new WebAppContext();
wac.setServer(server);
InjectionCollection injections = new InjectionCollection();
wac.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
InitialContext ic = new InitialContext();
Context comp = (Context)ic.lookup("java:comp");
Context env = comp.createSubcontext("env");
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
AnnotationIntrospector parser = new AnnotationIntrospector();
ResourceAnnotationHandler handler = new ResourceAnnotationHandler(wac);
@ -116,32 +128,21 @@ public class TestResourceAnnotations
f = ResourceA.class.getDeclaredField("n");
f.setAccessible(true);
assertEquals(objB, f.get(binst));
comp.destroySubcontext("env");
}
@Test
public void testResourcesAnnotation ()
throws Exception
{
Server server = new Server();
WebAppContext wac = new WebAppContext();
wac.setServer(server);
InjectionCollection injections = new InjectionCollection();
wac.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
InitialContext ic = new InitialContext();
Context comp = (Context)ic.lookup("java:comp");
Context env = comp.createSubcontext("env");
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
AnnotationIntrospector introspector = new AnnotationIntrospector();
ResourcesAnnotationHandler handler = new ResourcesAnnotationHandler(wac);
introspector.registerHandler(handler);
introspector.introspect(ResourceA.class);
introspector.introspect(ResourceB.class);
assertEquals(objA, env.lookup("peach"));
assertEquals(objB, env.lookup("pear"));
}

View File

@ -13,11 +13,15 @@
package org.eclipse.jetty.plus.jndi;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
@ -25,6 +29,7 @@ import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -125,6 +130,35 @@ public class TestNamingEntries
public void init()
{
this.someObject = new SomeObject(4);
}
/**
* after each test we should scrape out any lingering bindings to prevent cross test pollution
* as observed when running java 7
*
* @throws Exception
*/
@After
public void after() throws Exception
{
InitialContext icontext = new InitialContext();
NamingEnumeration<Binding> bindings = icontext.listBindings("");
List<String> names = new ArrayList<String>();
while (bindings.hasMore())
{
Binding bd = (Binding)bindings.next();
names.add(bd.getName());
}
for (String name : names)
{
icontext.unbind(name);
}
}
@Test
@ -199,6 +233,7 @@ public class TestNamingEntries
ne = NamingEntryUtil.lookupNamingEntry(new ScopeB(), "resourceB");
assertNull(ne);
testLink();
}
@Test

View File

@ -1,8 +1,5 @@
package org.eclipse.jetty.server.handler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -13,7 +10,6 @@ import java.net.Socket;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
@ -31,6 +27,9 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
/**
* @version $Revision$ $Date$
*/
@ -85,7 +84,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest
output = sslSocket.getOutputStream();
input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
request =
request =
"GET /echo HTTP/1.1\r\n" +
"Host: " + hostPort + "\r\n" +
"\r\n";
@ -188,7 +187,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest
public X509Certificate[] getAcceptedIssuers()
{
return null;
return new X509Certificate[]{};
}
}

View File

@ -3,7 +3,7 @@
//------------------------------------------------------------------------
//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
//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,
@ -27,7 +27,6 @@ import java.io.OutputStream;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
@ -36,7 +35,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.TestCase;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
@ -53,20 +51,18 @@ public class SSLCloseTest extends TestCase
{
public X509Certificate[] getAcceptedIssuers()
{
return null;
return new X509Certificate[]{};
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
{
return;
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
{
return;
}
}
private static final TrustManager[] s_dummyTrustManagers=new TrustManager[] { new CredulousTM() };
// ~ Methods
@ -74,7 +70,7 @@ public class SSLCloseTest extends TestCase
/**
* Feed the server the entire request at once.
*
*
* @throws Exception
*/
public void testClose() throws Exception
@ -83,7 +79,7 @@ public class SSLCloseTest extends TestCase
SslSelectChannelConnector connector=new SslSelectChannelConnector();
String keystore = System.getProperty("user.dir")+File.separator+"src"+File.separator+"test"+File.separator+"resources"+File.separator+"keystore";
connector.setPort(0);
connector.getSslContextFactory().setKeyStorePath(keystore);
connector.getSslContextFactory().setKeyStorePassword("storepwd");
@ -92,7 +88,7 @@ public class SSLCloseTest extends TestCase
server.setConnectors(new Connector[]
{ connector });
server.setHandler(new WriteHandler());
server.start();
@ -107,7 +103,7 @@ public class SSLCloseTest extends TestCase
os.write("GET /test HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n".getBytes());
os.flush();
BufferedReader in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
@ -123,7 +119,7 @@ public class SSLCloseTest extends TestCase
while ((line=in.readLine())!=null)
System.err.println(line);
}
@ -137,7 +133,7 @@ public class SSLCloseTest extends TestCase
response.setStatus(200);
response.setHeader("test","value");
__endp=(AsyncEndPoint)baseRequest.getConnection().getEndPoint();
OutputStream out=response.getOutputStream();
String data = "Now is the time for all good men to come to the aid of the party.\n";

View File

@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@ -67,12 +68,17 @@ public class GzipFilter extends UserAgentFilter
protected Set<String> _mimeTypes;
protected int _bufferSize=8192;
protected int _minGzipSize=256;
protected Set<String> _excluded;
protected Set<String> _excludedAgents;
protected Set<Pattern> _excludedAgentPatterns;
protected Set<String> _excludedPaths;
protected Set<Pattern> _excludedPathPatterns;
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.UserAgentFilter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
super.init(filterConfig);
@ -93,21 +99,48 @@ public class GzipFilter extends UserAgentFilter
while (tok.hasMoreTokens())
_mimeTypes.add(tok.nextToken());
}
tmp=filterConfig.getInitParameter("excludedAgents");
if (tmp!=null)
{
_excluded=new HashSet<String>();
_excludedAgents=new HashSet<String>();
StringTokenizer tok = new StringTokenizer(tmp,",",false);
while (tok.hasMoreTokens())
_excluded.add(tok.nextToken());
_excludedAgents.add(tok.nextToken());
}
tmp=filterConfig.getInitParameter("excludeAgentPatterns");
if (tmp!=null)
{
_excludedAgentPatterns=new HashSet<Pattern>();
StringTokenizer tok = new StringTokenizer(tmp,",",false);
while (tok.hasMoreTokens())
_excludedAgentPatterns.add(Pattern.compile(tok.nextToken()));
}
tmp=filterConfig.getInitParameter("excludePaths");
if (tmp!=null)
{
_excludedPaths=new HashSet<String>();
StringTokenizer tok = new StringTokenizer(tmp,",",false);
while (tok.hasMoreTokens())
_excludedPaths.add(tok.nextToken());
}
tmp=filterConfig.getInitParameter("excludePathPatterns");
if (tmp!=null)
{
_excludedPathPatterns=new HashSet<Pattern>();
StringTokenizer tok = new StringTokenizer(tmp,",",false);
while (tok.hasMoreTokens())
_excludedPathPatterns.add(Pattern.compile(tok.nextToken()));
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.UserAgentFilter#destroy()
*/
@Override
public void destroy()
{
}
@ -116,6 +149,7 @@ public class GzipFilter extends UserAgentFilter
/**
* @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
@ -126,14 +160,17 @@ public class GzipFilter extends UserAgentFilter
if (ae != null && ae.indexOf("gzip")>=0 && !response.containsHeader("Content-Encoding")
&& !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod()))
{
if (_excluded!=null)
String ua = getUserAgent(request);
if (isExcludedAgent(ua))
{
String ua=getUserAgent(request);
if (_excluded.contains(ua))
{
super.doFilter(request,response,chain);
return;
}
super.doFilter(request,response,chain);
return;
}
String requestURI = request.getRequestURI();
if (isExcludedPath(requestURI))
{
super.doFilter(request,response,chain);
return;
}
final GzipResponseWrapper wrappedResponse=newGzipResponseWrapper(request,response);
@ -181,7 +218,64 @@ public class GzipFilter extends UserAgentFilter
super.doFilter(request,response,chain);
}
}
/**
* Checks to see if the UserAgent is excluded
*
* @param ua
* the user agent
* @return boolean true if excluded
*/
private boolean isExcludedAgent(String ua)
{
if (ua == null)
return false;
if (_excludedAgents != null)
{
if (_excludedAgents.contains(ua))
{
return true;
}
}
else if (_excludedAgentPatterns != null)
{
for (Pattern pattern : _excludedAgentPatterns)
{
if (pattern.matcher(ua).matches())
{
return true;
}
}
}
return false;
}
/**
* Checks to see if the Path is excluded
*
* @param ua
* the request uri
* @return boolean true if excluded
*/
private boolean isExcludedPath(String requestURI)
{
if (requestURI == null)
return false;
if (_excludedPathPatterns != null)
{
for (Pattern pattern : _excludedPathPatterns)
{
if (pattern.matcher(requestURI).matches())
{
return true;
}
}
}
return false;
}
/**
* Allows derived implementations to replace ResponseWrapper implementation.
*

View File

@ -4,11 +4,11 @@
// 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
// 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.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.servlets;
@ -18,7 +18,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@ -39,20 +38,20 @@ import javax.servlet.http.HttpServletRequest;
* <dt>attribute</dt><dd>If set, then the request attribute of this name is set with the matched user agent string</dd>
* <dt>cacheSize</dt><dd>The size of the user-agent cache, used to avoid reparsing of user agent strings. The entire cache is flushed
* when this size is reached</dd>
* <dt>userAgent</dt><dd>A regex {@link Pattern} to extract the essential elements of the user agent.
* <dt>userAgent</dt><dd>A regex {@link Pattern} to extract the essential elements of the user agent.
* The concatenation of matched pattern groups is used as the user agent name</dd>
* <dl>
* <dl>
* An example value for pattern is <code>(?:Mozilla[^\(]*\(compatible;\s*+([^;]*);.*)|(?:.*?([^\s]+/[^\s]+).*)</code>. These two
* pattern match the common compatibility user-agent strings and extract the real user agent, failing that, the first
* element of the agent string is returned.
*
* element of the agent string is returned.
*
*
*/
public class UserAgentFilter implements Filter
{
private static final String __defaultPattern = "(?:Mozilla[^\\(]*\\(compatible;\\s*+([^;]*);.*)|(?:.*?([^\\s]+/[^\\s]+).*)";
private Pattern _pattern = Pattern.compile(__defaultPattern);
private Map _agentCache = new ConcurrentHashMap();
private Map<String, String> _agentCache = new ConcurrentHashMap<String, String>();
private int _agentCacheSize=1024;
private String _attribute;
@ -71,7 +70,7 @@ public class UserAgentFilter implements Filter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
if (_attribute!=null && _pattern!=null)
{
{
String ua=getUserAgent(request);
request.setAttribute(_attribute,ua);
}
@ -85,11 +84,11 @@ public class UserAgentFilter implements Filter
public void init(FilterConfig filterConfig) throws ServletException
{
_attribute=filterConfig.getInitParameter("attribute");
String p=filterConfig.getInitParameter("userAgent");
if (p!=null)
_pattern=Pattern.compile(p);
String size=filterConfig.getInitParameter("cacheSize");
if (size!=null)
_agentCacheSize=Integer.parseInt(size);
@ -101,7 +100,7 @@ public class UserAgentFilter implements Filter
String ua=((HttpServletRequest)request).getHeader("User-Agent");
return getUserAgent(ua);
}
/* ------------------------------------------------------------ */
/** Get UserAgent.
* The configured agent patterns are used to match against the passed user agent string.
@ -112,37 +111,42 @@ public class UserAgentFilter implements Filter
*/
public String getUserAgent(String ua)
{
if (ua==null)
if (ua == null)
return null;
String tag = (String)_agentCache.get(ua);
if (tag==null)
String tag = _agentCache.get(ua);
if (tag == null)
{
Matcher matcher=_pattern.matcher(ua);
if (matcher.matches())
if (_pattern != null)
{
if(matcher.groupCount()>0)
Matcher matcher = _pattern.matcher(ua);
if (matcher.matches())
{
for (int g=1;g<=matcher.groupCount();g++)
if (matcher.groupCount() > 0)
{
String group=matcher.group(g);
if (group!=null)
tag=tag==null?group:(tag+group);
for (int g = 1; g <= matcher.groupCount(); g++)
{
String group = matcher.group(g);
if (group != null)
tag = tag == null ? group : tag + group;
}
}
else
{
tag = matcher.group();
}
}
else
tag=matcher.group();
}
else
tag=ua;
if (_agentCache.size()>=_agentCacheSize)
_agentCache.clear();
_agentCache.put(ua,tag);
if (tag == null)
tag = ua;
if (_agentCache.size() >= _agentCacheSize)
_agentCache.clear();
_agentCache.put(ua, tag);
}
return tag;
}
}

View File

@ -38,4 +38,9 @@ public class SessionException extends RuntimeException
super(cause);
this.sessionStatus = sessionStatus;
}
public SessionStatus getSessionStatus()
{
return sessionStatus;
}
}

View File

@ -135,7 +135,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
@Override
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, final Handler<Stream> handler)
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Handler<Stream> handler)
{
// Synchronization is necessary.
// SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent
@ -154,7 +154,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
{
int streamId = streamIds.getAndAdd(2);
SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, 0, synInfo.getPriority(), synInfo.getHeaders());
final IStream stream = createStream(synStream, listener);
IStream stream = createStream(synStream, listener);
control(stream, synStream, timeout, unit, handler, stream);
}
}
@ -178,7 +178,11 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
else
{
RstStreamFrame frame = new RstStreamFrame(version, rstInfo.getStreamId(), rstInfo.getStreamStatus().getCode(version));
int streamId = rstInfo.getStreamId();
IStream stream = streams.get(streamId);
if (stream != null)
removeStream(stream);
RstStreamFrame frame = new RstStreamFrame(version, streamId, rstInfo.getStreamStatus().getCode(version));
control(null, frame, timeout, unit, handler, null);
}
}
@ -207,7 +211,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
@Override
public void ping(long timeout, TimeUnit unit, final Handler<PingInfo> handler)
public void ping(long timeout, TimeUnit unit, Handler<PingInfo> handler)
{
int pingId = pingIds.getAndAdd(2);
PingInfo pingInfo = new PingInfo(pingId);
@ -217,20 +221,30 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public Future<Void> goAway()
{
return goAway(SessionStatus.OK);
}
private Future<Void> goAway(SessionStatus sessionStatus)
{
Promise<Void> result = new Promise<>();
goAway(0, TimeUnit.MILLISECONDS, result);
goAway(sessionStatus, 0, TimeUnit.MILLISECONDS, result);
return result;
}
@Override
public void goAway(long timeout, TimeUnit unit, Handler<Void> handler)
{
goAway(SessionStatus.OK, timeout, unit, handler);
}
private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Handler<Void> handler)
{
if (goAwaySent.compareAndSet(false, true))
{
if (!goAwayReceived.get())
{
GoAwayFrame frame = new GoAwayFrame(version, lastStreamId.get(), SessionStatus.OK.getCode());
GoAwayFrame frame = new GoAwayFrame(version, lastStreamId.get(), sessionStatus.getCode());
control(null, frame, timeout, unit, handler, null);
return;
}
@ -320,7 +334,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
@Override
public void onDataFrame(final DataFrame frame, final ByteBuffer data)
public void onDataFrame(DataFrame frame, ByteBuffer data)
{
notifyIdle(idleListener, false);
try
@ -334,7 +348,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
int streamId = frame.getStreamId();
final IStream stream = streams.get(streamId);
IStream stream = streams.get(streamId);
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
@ -369,20 +383,21 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public void onStreamException(StreamException x)
{
logger.info("Caught stream exception", x);
notifyOnException(listener, x);
rst(new RstInfo(x.getStreamId(), x.getStreamStatus()));
}
@Override
public void onSessionException(SessionException x)
{
logger.info("Caught session exception", x);
goAway();
Throwable cause = x.getCause();
notifyOnException(listener, cause == null ? x : cause);
goAway(x.getSessionStatus());
}
private void onSyn(final SynStreamFrame frame)
private void onSyn(SynStreamFrame frame)
{
final IStream stream = newStream(frame);
IStream stream = newStream(frame);
logger.debug("Opening {}", stream);
int streamId = frame.getStreamId();
IStream existing = streams.putIfAbsent(streamId, stream);
@ -480,10 +495,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
private void onReply(final SynReplyFrame frame)
private void onReply(SynReplyFrame frame)
{
int streamId = frame.getStreamId();
final IStream stream = streams.get(streamId);
IStream stream = streams.get(streamId);
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
@ -503,11 +518,11 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
removeStream(stream);
}
private void onRst(final RstStreamFrame frame)
private void onRst(RstStreamFrame frame)
{
// TODO: implement logic to clean up unidirectional streams associated with this stream
final IStream stream = streams.get(frame.getStreamId());
IStream stream = streams.get(frame.getStreamId());
if (stream != null)
stream.process(frame);
@ -520,7 +535,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
removeStream(stream);
}
private void onSettings(final SettingsFrame frame)
private void onSettings(SettingsFrame frame)
{
Settings.Setting windowSizeSetting = frame.getSettings().get(Settings.ID.INITIAL_WINDOW_SIZE);
if (windowSizeSetting != null)
@ -534,7 +549,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
flush();
}
private void onPing(final PingFrame frame)
private void onPing(PingFrame frame)
{
int pingId = frame.getPingId();
if (pingId % 2 == pingIds.get() % 2)
@ -549,7 +564,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
private void onGoAway(final GoAwayFrame frame)
private void onGoAway(GoAwayFrame frame)
{
if (goAwayReceived.compareAndSet(false, true))
{
@ -563,10 +578,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
private void onHeaders(final HeadersFrame frame)
private void onHeaders(HeadersFrame frame)
{
int streamId = frame.getStreamId();
final IStream stream = streams.get(streamId);
IStream stream = streams.get(streamId);
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
@ -601,6 +616,22 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
controller.close(false);
}
private void notifyOnException(SessionFrameListener listener, Throwable x)
{
try
{
if (listener != null)
{
logger.debug("Invoking callback with {} on listener {}", x, listener);
listener.onException(x);
}
}
catch (Exception xx)
{
logger.info("Exception while notifying listener " + listener, xx);
}
}
private StreamFrameListener notifyOnSyn(SessionFrameListener listener, Stream stream, SynInfo synInfo)
{
try
@ -650,7 +681,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
private void notifyOnPing(SessionFrameListener listener, final PingInfo pingInfo)
private void notifyOnPing(SessionFrameListener listener, PingInfo pingInfo)
{
try
{
@ -683,7 +714,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
@Override
public <C> void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, final Handler<C> handler, C context)
public <C> void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Handler<C> handler, C context)
{
try
{
@ -705,7 +736,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
flush();
}
catch (final Throwable x)
catch (Throwable x)
{
notifyHandlerFailed(handler, x);
}
@ -738,7 +769,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
flush();
}
private void execute(final Runnable task)
private void execute(Runnable task)
{
threadPool.execute(task);
}
@ -813,7 +844,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
throw new SPDYException(x);
}
protected void write(final ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
protected void write(ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
{
if (controller != null)
controller.write(buffer, handler, frameBytes);
@ -828,7 +859,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
// starvation (for the last frames sent) and stack overflow.
// Therefore every some invocation, we dispatch to a new thread
Integer invocations = handlerInvocations.get();
if (invocations >= 8)
if (invocations >= 4)
{
execute(new Runnable()
{
@ -850,7 +881,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
finally
{
handlerInvocations.set(invocations - 1);
handlerInvocations.set(invocations);
}
}
}
@ -910,7 +941,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
StandardSession.this.complete(handler, context);
}
protected void fail(final Throwable x)
protected void fail(Throwable x)
{
notifyHandlerFailed(handler, x);
}

View File

@ -36,13 +36,6 @@ public class StreamException extends RuntimeException
this.streamStatus = streamStatus;
}
public StreamException(int streamId, StreamStatus streamStatus, Throwable x)
{
super(x);
this.streamId = streamId;
this.streamStatus = streamStatus;
}
public int getStreamId()
{
return streamId;

View File

@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.api;
import java.util.EventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>A {@link SessionFrameListener} is the passive counterpart of a {@link Session} and receives events happening
* on a SPDY session.</p>
@ -105,11 +108,22 @@ public interface SessionFrameListener extends EventListener
*/
public void onGoAway(Session session, GoAwayInfo goAwayInfo);
/**
* <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 x the exception that caused the event processing failure
*/
public void onException(Throwable x);
/**
* <p>Empty implementation of {@link SessionFrameListener}</p>
*/
public static class Adapter implements SessionFrameListener
{
private static final Logger logger = LoggerFactory.getLogger(Adapter.class);
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
@ -135,5 +149,11 @@ public interface SessionFrameListener extends EventListener
public void onGoAway(Session session, GoAwayInfo goAwayInfo)
{
}
@Override
public void onException(Throwable x)
{
logger.info("", x);
}
}
}

View File

@ -47,27 +47,27 @@ public enum StreamStatus
/**
* <p>The stream status indicating an implementation error</p>
*/
INTERNAL_ERROR(6, 11),
INTERNAL_ERROR(6, 6),
/**
* <p>The stream status indicating a flow control error</p>
*/
FLOW_CONTROL_ERROR(7, 6),
FLOW_CONTROL_ERROR(7, 7),
/**
* <p>The stream status indicating a stream opened more than once</p>
*/
STREAM_IN_USE(-1, 7),
STREAM_IN_USE(-1, 8),
/**
* <p>The stream status indicating data on a stream already closed</p>
*/
STREAM_ALREADY_CLOSED(-1, 8),
STREAM_ALREADY_CLOSED(-1, 9),
/**
* <p>The stream status indicating credentials not valid</p>
*/
INVALID_CREDENTIALS(-1, 9),
INVALID_CREDENTIALS(-1, 10),
/**
* <p>The stream status indicating that the implementation could not support a frame too large</p>
*/
FRAME_TOO_LARGE(-1, 10);
FRAME_TOO_LARGE(-1, 11);
/**
* @param version the SPDY protocol version

View File

@ -20,9 +20,6 @@ import java.nio.ByteBuffer;
import java.util.EnumMap;
import org.eclipse.jetty.spdy.CompressionFactory;
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.ControlFrameType;
@ -77,7 +74,6 @@ public abstract class ControlFrameParser
if (buffer.remaining() >= 2)
{
version = (short)(buffer.getShort() & 0x7F_FF);
checkVersion(version);
state = State.TYPE;
}
else
@ -95,7 +91,6 @@ public abstract class ControlFrameParser
if (cursor == 0)
{
version &= 0x7F_FF;
checkVersion(version);
state = State.TYPE;
}
break;
@ -171,12 +166,6 @@ public abstract class ControlFrameParser
return false;
}
private void checkVersion(short version)
{
if (version != SPDY.V2 && version != SPDY.V3)
throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Unrecognized version " + version);
}
private void reset()
{
state = State.VERSION;

View File

@ -19,8 +19,10 @@ package org.eclipse.jetty.spdy.parser;
import java.nio.ByteBuffer;
import org.eclipse.jetty.spdy.CompressionFactory;
import org.eclipse.jetty.spdy.StreamException;
import org.eclipse.jetty.spdy.api.Headers;
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;
@ -77,6 +79,10 @@ public class SynStreamBodyParser extends ControlFrameBodyParser
}
case ASSOCIATED_STREAM_ID:
{
// Now we know the streamId, we can do the version check
// and if it is wrong, issue a RST_STREAM
checkVersion(controlFrameParser.getVersion(), streamId);
if (buffer.remaining() >= 4)
{
associatedStreamId = buffer.getInt() & 0x7F_FF_FF_FF;
@ -145,6 +151,12 @@ public class SynStreamBodyParser extends ControlFrameBodyParser
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,

View File

@ -20,19 +20,51 @@ 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.remaining = controlFrameParser.getLength();
this.controlFrameParser = controlFrameParser;
}
@Override
public boolean parse(ByteBuffer buffer)
{
int consumed = Math.min(remaining, buffer.remaining());
buffer.position(buffer.position() + consumed);
remaining -= consumed;
return remaining == 0;
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
}
}

View File

@ -0,0 +1,64 @@
package org.eclipse.jetty.spdy.parser;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.SessionException;
import org.eclipse.jetty.spdy.StandardByteBufferPool;
import org.eclipse.jetty.spdy.StandardCompressionFactory;
import org.eclipse.jetty.spdy.StreamException;
import org.eclipse.jetty.spdy.api.Headers;
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.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, new Headers());
Generator generator = new Generator(new StandardByteBufferPool(), 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));
}
}

View File

@ -1,48 +1,47 @@
<?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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty-http-webapp</artifactId>
<packaging>war</packaging>
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
<build>
<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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty-http-webapp</artifactId>
<packaging>war</packaging>
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
<!--
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${project.version}</version>
<configuration>
<stopPort>8888</stopPort>
<stopKey>quit</stopKey>
<jvmArgs>
-Dlog4j.configuration=file://${basedir}/src/main/resources/log4j.properties
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
</jvmArgs>
<jettyXml>${basedir}/src/main/config/jetty-spdy.xml</jettyXml>
<contextPath>/</contextPath>
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${project.version}</version>
<configuration>
<stopPort>8888</stopPort>
<stopKey>quit</stopKey>
<jvmArgs>
-Dlog4j.configuration=file://${basedir}/src/main/resources/log4j.properties
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
</jvmArgs>
<jettyXml>${basedir}/src/main/config/jetty-spdy.xml</jettyXml>
<contextPath>/</contextPath>
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
</build>
-->
</project>

View File

@ -1,52 +1,60 @@
<?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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty-http</artifactId>
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
<build>
<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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty-http</artifactId>
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar </argLine>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>eclipse-release</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-jetty</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-jetty</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,57 +1,65 @@
<?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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty</artifactId>
<name>Jetty :: SPDY :: Jetty Binding</name>
<build>
<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>7.6.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty</artifactId>
<name>Jetty :: SPDY :: Jetty Binding</name>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar </argLine>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>eclipse-release</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</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-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
</build>
</profile>
</profiles>
<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-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -53,9 +53,10 @@ public abstract class AbstractTest
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
{
server = new Server();
connector = newSPDYServerConnector(listener);
if (connector == null)
connector = newSPDYServerConnector(listener);
connector.setPort(0);
server = new Server();
server.addConnector(connector);
server.start();
return new InetSocketAddress("localhost", connector.getLocalPort());

View File

@ -0,0 +1,123 @@
package org.eclipse.jetty.spdy;
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.Handler;
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.junit.Assert;
import org.junit.Test;
public class ResetStreamTest extends AbstractTest
{
@Test
public void testResetStreamIsRemoved() throws Exception
{
Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()), null);
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS);
session.rst(new RstInfo(stream.getId(), StreamStatus.CANCEL_STREAM)).get(5, TimeUnit.SECONDS);
Assert.assertEquals(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));
synLatch.countDown();
return null;
}
}), new SessionFrameListener.Adapter()
{
@Override
public void onRst(Session session, RstInfo rstInfo)
{
rstLatch.countDown();
}
});
clientSession.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS);
Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
Session serverSession = serverSessionRef.get();
Assert.assertEquals(0, serverSession.getStreams().size());
Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS));
Assert.assertEquals(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
Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM));
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(false), null).get(5, TimeUnit.SECONDS);
stream.data(new StringDataInfo("data", true), 5, TimeUnit.SECONDS, new Handler.Adapter<Void>()
{
@Override
public void completed(Void context)
{
synLatch.countDown();
}
});
Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS));
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
}
}

View File

@ -0,0 +1,79 @@
package org.eclipse.jetty.spdy;
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.spdy.api.Headers;
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.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.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 onException(Throwable x)
{
// Suppress exception logging for this test
}
});
SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, new Headers());
Generator generator = new Generator(new StandardByteBufferPool(), 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));
}
}

View File

@ -232,10 +232,15 @@ public class CertificateValidator
}
// Enable On-Line Certificate Status Protocol (OCSP) support
Security.setProperty("ocsp.enable","true");
if (_enableOCSP)
{
Security.setProperty("ocsp.enable","true");
}
// Enable Certificate Revocation List Distribution Points (CRLDP) support
System.setProperty("com.sun.security.enableCRLDP","true");
if (_enableCRLDP)
{
System.setProperty("com.sun.security.enableCRLDP","true");
}
// Build certification path
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);