Issue #3216 - Autobahn WebSocketServer failures in jetty 10

removed maxFrameSize from CompressExtension now use the
WebSocketChannel.getMaxFrameSize() to fix a bug where a change in the
WebSocketChanel maxFrameSize was not reaching the CompressExtension

create dummy WebSocketChannel in tests using CompressExtension without
a channel to replace the setter for maxFrameSize

increased the maxFrameSize in AutobahnWebSocketNegotiator to fix
autobahn tests being over maxFrameSize after being inflated

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2018-12-20 19:57:46 +11:00
parent 1999b23d67
commit 164859fb9f
7 changed files with 83 additions and 55 deletions

View File

@ -12,9 +12,7 @@
}
}
],
"cases": [
"*"
],
"cases": ["*"],
"exclude-cases": [],
"exclude-agent-cases": {}
}

View File

@ -18,6 +18,16 @@
package org.eclipse.jetty.websocket.core.internal.compress;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
@ -29,16 +39,6 @@ import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.internal.FrameEntry;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
public abstract class CompressExtension extends AbstractExtension
{
protected static final byte[] TAIL_BYTES = new byte[] { 0x00, 0x00, (byte)0xFF, (byte)0xFF };
@ -93,17 +93,6 @@ public abstract class CompressExtension extends AbstractExtension
protected AtomicInteger decompressCount = new AtomicInteger(0);
private int tailDrop = TAIL_DROP_NEVER;
private int rsvUse = RSV_USE_ALWAYS;
private int maxFrameSize = Integer.MAX_VALUE;
public int getMaxFrameSize()
{
return maxFrameSize;
}
public void setMaxFrameSize(int maxFrameSize)
{
this.maxFrameSize = maxFrameSize;
}
protected CompressExtension()
{
@ -115,9 +104,6 @@ public abstract class CompressExtension extends AbstractExtension
public void setWebSocketChannel(WebSocketChannel webSocketChannel)
{
super.setWebSocketChannel(webSocketChannel);
if (webSocketChannel.getMaxFrameSize() > Integer.MAX_VALUE)
throw new IllegalArgumentException("maxFrameSize too large");
setMaxFrameSize((int)webSocketChannel.getMaxFrameSize());
}
public Deflater getDeflater()

View File

@ -18,13 +18,13 @@
package org.eclipse.jetty.websocket.core.internal.compress;
import java.util.zip.DataFormatException;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.BadPayloadException;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import java.util.zip.DataFormatException;
/**
* Implementation of the
* <a href="https://tools.ietf.org/id/draft-tyoshino-hybi-websocket-perframe-deflate.txt">deflate-frame</a>
@ -65,7 +65,10 @@ public class DeflateFrameExtension extends CompressExtension
try
{
ByteAccumulator accumulator = new ByteAccumulator(getMaxFrameSize());
//TODO fix this to use long instead of int
if (getWebSocketChannel().getMaxFrameSize() > Integer.MAX_VALUE)
throw new IllegalArgumentException("maxFrameSize too large for ByteAccumulator");
ByteAccumulator accumulator = new ByteAccumulator((int)getWebSocketChannel().getMaxFrameSize());
decompress(accumulator, frame.getPayload());
decompress(accumulator, TAIL_BYTES_BUF.slice());
forwardIncoming(frame, callback, accumulator);

View File

@ -18,6 +18,11 @@
package org.eclipse.jetty.websocket.core.internal.compress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DataFormatException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
@ -27,11 +32,6 @@ import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DataFormatException;
/**
* Per Message Deflate Compression extension for WebSocket.
* <p>
@ -73,7 +73,10 @@ public class PerMessageDeflateExtension extends CompressExtension
return;
}
ByteAccumulator accumulator = new ByteAccumulator(getMaxFrameSize());
//TODO fix this to use long instead of int
if (getWebSocketChannel().getMaxFrameSize() > Integer.MAX_VALUE)
throw new IllegalArgumentException("maxFrameSize too large for ByteAccumulator");
ByteAccumulator accumulator = new ByteAccumulator((int)getWebSocketChannel().getMaxFrameSize());
try
{

View File

@ -18,6 +18,10 @@
package org.eclipse.jetty.websocket.core.autobahn;
import java.io.IOException;
import java.time.Duration;
import java.util.List;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
@ -26,10 +30,6 @@ import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.core.server.Negotiation;
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
import java.io.IOException;
import java.time.Duration;
import java.util.List;
class AutobahnWebSocketNegotiator implements WebSocketNegotiator
{
final DecoratedObjectFactory objectFactory;
@ -85,7 +85,7 @@ class AutobahnWebSocketNegotiator implements WebSocketNegotiator
public void customize(FrameHandler.CoreSession session)
{
session.setIdleTimeout(Duration.ofMillis(5000));
session.setMaxFrameSize(65536*2);
}
@Override

View File

@ -18,14 +18,29 @@
package org.eclipse.jetty.websocket.core.extensions;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.toolchain.test.ByteBufferAssert;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.AbstractTestFrameHandler;
import org.eclipse.jetty.websocket.core.Behavior;
import org.eclipse.jetty.websocket.core.CapturedHexPayloads;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.Frame;
@ -34,20 +49,15 @@ import org.eclipse.jetty.websocket.core.IncomingFramesCapture;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.OutgoingFrames;
import org.eclipse.jetty.websocket.core.OutgoingNetworkBytesCapture;
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.core.internal.ExtensionStack;
import org.eclipse.jetty.websocket.core.internal.Generator;
import org.eclipse.jetty.websocket.core.internal.Negotiated;
import org.eclipse.jetty.websocket.core.internal.Parser;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
import org.eclipse.jetty.websocket.core.internal.compress.DeflateFrameExtension;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Random;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import static org.eclipse.jetty.websocket.core.OpCode.TEXT;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@ -229,7 +239,7 @@ public class DeflateFrameExtensionTest extends AbstractExtensionTest
private void init(DeflateFrameExtension ext)
{
ext.setMaxFrameSize(20 * 1024 * 1024);
ext.setWebSocketChannel(channelWithMaxMessageSize(20 * 1024 * 1024));
ext.init(new ExtensionConfig(ext.getName()), bufferPool);
}
@ -371,11 +381,11 @@ public class DeflateFrameExtensionTest extends AbstractExtensionTest
DeflateFrameExtension clientExtension = new DeflateFrameExtension();
init(clientExtension);
clientExtension.setMaxFrameSize(maxMessageSize);
clientExtension.setWebSocketChannel(channelWithMaxMessageSize(maxMessageSize));
final DeflateFrameExtension serverExtension = new DeflateFrameExtension();
init(serverExtension);
serverExtension.setMaxFrameSize(maxMessageSize);
serverExtension.setWebSocketChannel(channelWithMaxMessageSize(maxMessageSize));
// Chain the next element to decompress.
clientExtension.setNextOutgoingFrames(new OutgoingFrames()
@ -414,4 +424,16 @@ public class DeflateFrameExtensionTest extends AbstractExtensionTest
assertArrayEquals(input, result.toByteArray());
}
private WebSocketChannel channelWithMaxMessageSize(int maxMessageSize)
{
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>());
WebSocketChannel channel = new WebSocketChannel(new AbstractTestFrameHandler(), Behavior.SERVER, Negotiated.from(exStack));
channel.setMaxFrameSize(maxMessageSize);
return channel;
}
}

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.websocket.core.extensions;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.toolchain.test.ByteBufferAssert;
@ -25,17 +28,20 @@ import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.websocket.core.AbstractTestFrameHandler;
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;
import org.eclipse.jetty.websocket.core.IncomingFramesCapture;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.core.internal.ExtensionStack;
import org.eclipse.jetty.websocket.core.internal.Negotiated;
import org.eclipse.jetty.websocket.core.internal.Parser;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
import org.hamcrest.Matchers;
import java.nio.ByteBuffer;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@ -70,6 +76,7 @@ public class ExtensionTool
{
this.ext = factory.newInstance(objectFactory, bufferPool, extConfig);
this.ext.setNextIncomingFrames(capture);
this.ext.setWebSocketChannel(newWebsocketChannel());
}
public void parseIncomingHex(String... rawhex)
@ -141,4 +148,13 @@ public class ExtensionTool
{
return new Tester(parameterizedExtension);
}
private WebSocketChannel newWebsocketChannel()
{
ByteBufferPool bufferPool = new MappedByteBufferPool();
ExtensionStack exStack = new ExtensionStack(new WebSocketExtensionRegistry());
exStack.negotiate(new DecoratedObjectFactory(), bufferPool, new LinkedList<>());
WebSocketChannel channel = new WebSocketChannel(new AbstractTestFrameHandler(), Behavior.SERVER, Negotiated.from(exStack));
return channel;
}
}