Merge branch jetty-9.4.x into jetty-10.0.x

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>

# Conflicts:
#	jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java
#	jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryWholeMessage.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextWholeMessage.java
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtension.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java
This commit is contained in:
Joakim Erdfelt 2019-03-04 09:44:47 -05:00
commit 715bac2660
3 changed files with 104 additions and 7 deletions

View File

@ -105,7 +105,7 @@ public class TestOSGiUtil
return CoreOptions.when(Boolean.getBoolean("pax.exam.debug.remote"))
.useOptions(CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"));
}
public static List<Option> coreJettyDependencies()
{
List<Option> res = new ArrayList<>();

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.core.BadPayloadException;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.ProtocolException;
/**
* Per Message Deflate Compression extension for WebSocket.
@ -73,9 +74,16 @@ public class PerMessageDeflateExtension extends CompressExtension
return;
}
if (frame.getOpCode() == OpCode.CONTINUATION && frame.isRsv1())
{
// Per RFC7692 we MUST Fail the websocket connection
throw new ProtocolException("Invalid RSV1 set on permessage-deflate CONTINUATION frame");
}
//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,12 @@
package org.eclipse.jetty.websocket.core.extensions;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.toolchain.test.ByteBufferAssert;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@ -27,18 +33,14 @@ 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.OutgoingFramesCapture;
import org.eclipse.jetty.websocket.core.ProtocolException;
import org.eclipse.jetty.websocket.core.internal.compress.CompressExtension;
import org.eclipse.jetty.websocket.core.internal.compress.PerMessageDeflateExtension;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Client side behavioral tests for permessage-deflate extension.
@ -219,6 +221,56 @@ public class PerMessageDeflateExtensionTest extends AbstractExtensionTest
tester.assertHasFrames("Hello");
}
/**
* Decode fragmented message (3 parts: TEXT, CONTINUATION, CONTINUATION)
*/
@Test
public void testParseFragmentedMessage_Good()
{
ExtensionTool.Tester tester = clientExtensions.newTester("permessage-deflate");
tester.assertNegotiated("permessage-deflate");
tester.parseIncomingHex(// 1 message, 3 frame
"410C", // HEADER TEXT / fin=false / rsv1=true
"F248CDC9C95700000000FFFF",
"000B", // HEADER CONTINUATION / fin=false / rsv1=false
"0ACF2FCA4901000000FFFF",
"8003", // HEADER CONTINUATION / fin=true / rsv1=false
"520400"
);
Frame txtFrame = new Frame(OpCode.TEXT).setPayload("Hello ").setFin(false);
Frame con1Frame = new Frame(OpCode.CONTINUATION).setPayload("World").setFin(false);
Frame con2Frame = new Frame(OpCode.CONTINUATION).setPayload("!").setFin(true);
tester.assertHasFrames(txtFrame, con1Frame, con2Frame);
}
/**
* Decode fragmented message (3 parts: TEXT, CONTINUATION, CONTINUATION)
* <p>
* Continuation frames have RSV1 set, which MUST result in Failure
* </p>
*/
@Test
public void testParseFragmentedMessage_BadRsv1()
{
ExtensionTool.Tester tester = clientExtensions.newTester("permessage-deflate");
tester.assertNegotiated("permessage-deflate");
assertThrows(ProtocolException.class, () ->
tester.parseIncomingHex(// 1 message, 3 frame
"410C", // Header TEXT / fin=false / rsv1=true
"F248CDC9C95700000000FFFF", // Payload
"400B", // Header CONTINUATION / fin=false / rsv1=true
"0ACF2FCA4901000000FFFF", // Payload
"C003", // Header CONTINUATION / fin=true / rsv1=true
"520400" // Payload
));
}
/**
* Incoming PING (Control Frame) should pass through extension unmodified
*/
@ -255,6 +307,43 @@ public class PerMessageDeflateExtensionTest extends AbstractExtensionTest
}
/**
* Incoming Text Message fragmented into 3 pieces.
*/
@Test
public void testIncomingFragmented()
{
PerMessageDeflateExtension ext = new PerMessageDeflateExtension();
ExtensionConfig config = ExtensionConfig.parse("permessage-deflate");
ext.init(config, bufferPool);
// Setup capture of incoming frames
IncomingFramesCapture capture = new IncomingFramesCapture();
// Wire up stack
ext.setNextIncomingFrames(capture);
String payload = "Are you there?";
Frame ping = new Frame(OpCode.PING).setPayload(payload);
ext.onFrame(ping, Callback.NOOP);
capture.assertFrameCount(1);
capture.assertHasOpCount(OpCode.PING, 1);
Frame actual = capture.frames.poll();
assertThat("Frame.opcode", actual.getOpCode(), is(OpCode.PING));
assertThat("Frame.fin", actual.isFin(), is(true));
assertThat("Frame.rsv1", actual.isRsv1(), is(false));
assertThat("Frame.rsv2", actual.isRsv2(), is(false));
assertThat("Frame.rsv3", actual.isRsv3(), is(false));
ByteBuffer expected = BufferUtil.toBuffer(payload, StandardCharsets.UTF_8);
assertThat("Frame.payloadLength", actual.getPayloadLength(), is(expected.remaining()));
ByteBufferAssert.assertEquals("Frame.payload", expected, actual.getPayload().slice());
}
/**
/**
* Verify that incoming uncompressed frames are properly passed through
*/
@Test