Issue #3465 - client/server error handling behavior for ExtensionStack

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2019-03-26 16:29:45 +11:00
parent 0d570dd6b6
commit 46ef94c1b9
9 changed files with 43 additions and 15 deletions

View File

@ -296,7 +296,7 @@ public abstract class ClientUpgradeRequest extends HttpRequest implements Respon
// Negotiate the extension stack
HttpClient httpClient = wsClient.getHttpClient();
ExtensionStack extensionStack = new ExtensionStack(wsClient.getExtensionRegistry());
ExtensionStack extensionStack = new ExtensionStack(wsClient.getExtensionRegistry(), Behavior.CLIENT);
extensionStack.negotiate(wsClient.getObjectFactory(), httpClient.getByteBufferPool(), offeredExtensions, negotiatedExtensions);
// Get the negotiated subprotocol

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
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.websocket.core.Behavior;
import org.eclipse.jetty.websocket.core.Extension;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.Frame;
@ -51,13 +52,15 @@ public class ExtensionStack implements IncomingFrames, OutgoingFrames, Dumpable
private static final Logger LOG = Log.getLogger(ExtensionStack.class);
private final WebSocketExtensionRegistry factory;
private final Behavior behavior;
private List<Extension> extensions;
private IncomingFrames incoming;
private OutgoingFrames outgoing;
public ExtensionStack(WebSocketExtensionRegistry factory)
public ExtensionStack(WebSocketExtensionRegistry factory, Behavior behavior)
{
this.factory = factory;
this.behavior = behavior;
}
@ManagedAttribute(name = "Extension List", readonly = true)
@ -131,13 +134,36 @@ public class ExtensionStack implements IncomingFrames, OutgoingFrames, Dumpable
}
catch (Throwable t)
{
for (ExtensionConfig offered : offeredConfigs)
{
if (offered.getParameterizedName().equals(config.getParameterizedName()))
throw new BadMessageException("offered extension had bad parameters: ", t);
}
/* If there was an error creating the extension we need to differentiate between a
bad ExtensionConfig offered by the client and a bad ExtensionConfig negotiated by the server.
throw new WebSocketException("negotiated extension had bad parameters: ", t);
When deciding whether to throw a BadMessageException and send a 400 response or a WebSocketException
and send a 500 response it depends on whether this is running on the client or the server. */
switch (behavior)
{
case SERVER:
{
String parameterizedName = config.getParameterizedName();
for (ExtensionConfig offered : offeredConfigs)
{
if (offered.getParameterizedName().equals(parameterizedName))
throw new BadMessageException("could not instantiate offered extension", t);
}
throw new WebSocketException("could not instantiate negotiated extension", t);
}
case CLIENT:
{
String parameterizedName = config.getParameterizedName();
for (ExtensionConfig offered : offeredConfigs)
{
if (offered.getParameterizedName().equals(parameterizedName))
throw new WebSocketException("could not instantiate offered extension", t);
}
throw new BadMessageException("could not instantiate negotiated extension", t);
}
default:
throw new IllegalStateException();
}
}
if (ext == null)

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.http.QuotedCSV;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.websocket.core.Behavior;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.core.internal.ExtensionStack;
@ -227,7 +228,7 @@ public class Negotiation
if (extensionStack == null)
{
// Extension stack can decide to drop any of these extensions or their parameters
extensionStack = new ExtensionStack(registry);
extensionStack = new ExtensionStack(registry, Behavior.SERVER);
extensionStack.negotiate(objectFactory, bufferPool, offeredExtensions, negotiatedExtensions);
negotiatedExtensions = extensionStack.getNegotiatedExtensions();

View File

@ -63,7 +63,7 @@ public class GeneratorFrameFlagsTest
public void setup(Frame invalidFrame)
{
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>(), new LinkedList<>());
this.channel = new WebSocketChannel(new AbstractTestFrameHandler(), Behavior.CLIENT, Negotiated.from(exStack));
}

View File

@ -55,7 +55,7 @@ public class GeneratorTest
private static WebSocketChannel newChannel(Behavior behavior)
{
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>(), new LinkedList<>());
return new WebSocketChannel(new AbstractTestFrameHandler(), behavior, Negotiated.from(exStack));
}

View File

@ -58,7 +58,7 @@ public class ParserCapture
this.copy = copy;
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>(), new LinkedList<>());
this.channel = new WebSocketChannel(new AbstractTestFrameHandler(), behavior, Negotiated.from(exStack));
}

View File

@ -419,7 +419,7 @@ public class DeflateFrameExtensionTest extends AbstractExtensionTest
private WebSocketChannel channelWithMaxMessageSize(int maxMessageSize)
{
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>(), new LinkedList<>());
WebSocketChannel channel = new WebSocketChannel(new AbstractTestFrameHandler(), Behavior.SERVER, Negotiated.from(exStack));

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.Behavior;
import org.eclipse.jetty.websocket.core.Extension;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.IncomingFrames;
@ -55,7 +56,7 @@ public class ExtensionStackTest
{
objectFactory = new DecoratedObjectFactory();
bufferPool = new MappedByteBufferPool();
stack = new ExtensionStack(new WebSocketExtensionRegistry());
stack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
}
@SuppressWarnings("unchecked")

View File

@ -153,7 +153,7 @@ public class ExtensionTool
private WebSocketChannel newWebsocketChannel()
{
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry(), Behavior.SERVER);
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>(), new LinkedList<>());
WebSocketChannel channel = new WebSocketChannel(new AbstractTestFrameHandler(), Behavior.SERVER, Negotiated.from(exStack));
return channel;