Fixing Frame Decompress to work in Chrome 20.x
This commit is contained in:
parent
d67fdfdd85
commit
169498cd9d
|
@ -24,6 +24,7 @@ import java.util.zip.Deflater;
|
|||
import java.util.zip.Inflater;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
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.api.BadPayloadException;
|
||||
|
@ -125,6 +126,9 @@ public class DeflateCompressionMethod implements CompressionMethod
|
|||
|
||||
private static class InflaterProcess implements CompressionMethod.Process
|
||||
{
|
||||
/** Tail Bytes per Spec */
|
||||
private static final byte[] TAIL = new byte[]
|
||||
{ 0x00, 0x00, (byte)0xFF, (byte)0xFF };
|
||||
private final Inflater inflater;
|
||||
private int bufferSize = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
|
@ -150,11 +154,16 @@ public class DeflateCompressionMethod implements CompressionMethod
|
|||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("inflate: {}",BufferUtil.toDetailString(input));
|
||||
LOG.debug("Input Data: {}",TypeUtil.toHexString(BufferUtil.toArray(input)));
|
||||
}
|
||||
|
||||
// Set the data that is compressed to the inflater
|
||||
byte compressed[] = BufferUtil.toArray(input);
|
||||
inflater.setInput(compressed,0,compressed.length);
|
||||
// Set the data that is compressed (+ TAIL) to the inflater
|
||||
int len = input.remaining() + 4;
|
||||
byte raw[] = new byte[len];
|
||||
int inlen = input.remaining();
|
||||
input.slice().get(raw,0,inlen);
|
||||
System.arraycopy(TAIL,0,raw,inlen,TAIL.length);
|
||||
inflater.setInput(raw,0,raw.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -65,7 +65,7 @@ public class FrameCompressionExtension extends AbstractExtension
|
|||
}
|
||||
|
||||
// reset on every frame.
|
||||
method.decompress().end();
|
||||
// method.decompress().end();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
package org.eclipse.jetty.websocket.common.extensions;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.DeflateCompressionMethodTest;
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.PerMessageCompressionExtensionTest;
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.WebkitDeflateFrameExtensionTest;
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.MessageCompressionExtensionTest;
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.FrameCompressionExtensionTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses(
|
||||
{ ExtensionStackTest.class, DeflateCompressionMethodTest.class, PerMessageCompressionExtensionTest.class, FragmentExtensionTest.class,
|
||||
IdentityExtensionTest.class, WebkitDeflateFrameExtensionTest.class })
|
||||
{ ExtensionStackTest.class, DeflateCompressionMethodTest.class, MessageCompressionExtensionTest.class, FragmentExtensionTest.class,
|
||||
IdentityExtensionTest.class, FrameCompressionExtensionTest.class })
|
||||
public class AllTests
|
||||
{
|
||||
/* nothing to do here, its all done in the annotations */
|
||||
|
|
|
@ -26,10 +26,9 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
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.common.extensions.compress.CompressionMethod;
|
||||
import org.eclipse.jetty.websocket.common.extensions.compress.DeflateCompressionMethod;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -76,6 +75,50 @@ public class DeflateCompressionMethodTest
|
|||
Assert.assertEquals("Message Contents",expected,actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test decompression with 2 buffers. First buffer is normal, second relies on back buffers created from first.
|
||||
*/
|
||||
@Test
|
||||
public void testFollowupBackDistance()
|
||||
{
|
||||
// The Sample (Compressed) Data
|
||||
byte buf1[] = TypeUtil.fromHexString("2aC9Cc4dB50200"); // DEFLATE -> "time:"
|
||||
byte buf2[] = TypeUtil.fromHexString("2a01110000"); // DEFLATE -> "time:"
|
||||
|
||||
// Setup Compression Method
|
||||
CompressionMethod method = new DeflateCompressionMethod();
|
||||
|
||||
// Decompressed Data Holder
|
||||
ByteBuffer decompressed = ByteBuffer.allocate(32);
|
||||
BufferUtil.flipToFill(decompressed);
|
||||
|
||||
// Perform Decompress on Buf 1
|
||||
BufferUtil.clearToFill(decompressed);
|
||||
// IGNORE method.decompress().begin();
|
||||
method.decompress().input(ByteBuffer.wrap(buf1));
|
||||
while (!method.decompress().isDone())
|
||||
{
|
||||
ByteBuffer window = method.decompress().process();
|
||||
BufferUtil.put(window,decompressed);
|
||||
}
|
||||
BufferUtil.flipToFlush(decompressed,0);
|
||||
LOG.debug("decompressed[1]: {}",BufferUtil.toDetailString(decompressed));
|
||||
// IGNORE method.decompress().end();
|
||||
|
||||
// Perform Decompress on Buf 2
|
||||
BufferUtil.clearToFill(decompressed);
|
||||
// IGNORE method.decompress().begin();
|
||||
method.decompress().input(ByteBuffer.wrap(buf2));
|
||||
while (!method.decompress().isDone())
|
||||
{
|
||||
ByteBuffer window = method.decompress().process();
|
||||
BufferUtil.put(window,decompressed);
|
||||
}
|
||||
BufferUtil.flipToFlush(decompressed,0);
|
||||
LOG.debug("decompressed[2]: {}",BufferUtil.toDetailString(decompressed));
|
||||
// IGNORE method.decompress().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a large payload (a payload length over 65535 bytes).
|
||||
*
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WebkitDeflateFrameExtensionTest
|
||||
public class FrameCompressionExtensionTest
|
||||
{
|
||||
private void assertIncoming(byte[] raw, String... expectedTextDatas)
|
||||
{
|
||||
|
@ -130,6 +130,16 @@ public class WebkitDeflateFrameExtensionTest
|
|||
assertIncoming(rawbuf,"info:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChrome20_TimeTime()
|
||||
{
|
||||
// Captured from Chrome 20.x - "time:" then "time:" once more (sent from browser/client)
|
||||
String time1 = "c1 87 82 46 74 24 a8 8f b8 69 37 44 74".replaceAll("\\s*","");
|
||||
String time2 = "c1 85 3c fd a1 7f 16 fc b0 7f 3c".replaceAll("\\s*","");
|
||||
byte rawbuf[] = TypeUtil.fromHexString(time1 + time2);
|
||||
assertIncoming(rawbuf,"time:","time:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeflateBasics() throws Exception
|
||||
{
|
|
@ -41,7 +41,7 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PerMessageCompressionExtensionTest
|
||||
public class MessageCompressionExtensionTest
|
||||
{
|
||||
private void assertDraftExample(String hexStr, String expectedStr)
|
||||
{
|
|
@ -445,11 +445,6 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
throw new IOException("Unable to start Extension Stack",e);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("{}",extensionStack.dump());
|
||||
}
|
||||
|
||||
// Tell jetty about the new connection
|
||||
request.setAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE,connection);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.junit.runners.Suite;
|
|||
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses(
|
||||
{ org.eclipse.jetty.websocket.server.ab.AllTests.class, ChromeTest.class, DeflateExtensionTest.class, FragmentExtensionTest.class, IdentityExtensionTest.class,
|
||||
{ org.eclipse.jetty.websocket.server.ab.AllTests.class, ChromeTest.class, FrameCompressionExtensionTest.class, FragmentExtensionTest.class, IdentityExtensionTest.class,
|
||||
LoadTest.class, WebSocketInvalidVersionTest.class, WebSocketLoadRFC6455Test.class, WebSocketOverSSLTest.class, WebSocketServletRFCTest.class })
|
||||
public class AllTests
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.junit.Assert;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DeflateExtensionTest
|
||||
public class FrameCompressionExtensionTest
|
||||
{
|
||||
private static SimpleServletServer server;
|
||||
|
||||
|
@ -68,12 +68,21 @@ public class DeflateExtensionTest
|
|||
|
||||
String msg = "Hello";
|
||||
|
||||
// Client sends message.
|
||||
// Client sends first message
|
||||
client.write(WebSocketFrame.text(msg));
|
||||
|
||||
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,1000);
|
||||
WebSocketFrame frame = capture.getFrames().get(0);
|
||||
Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(msg.toString()));
|
||||
|
||||
// Client sends second message
|
||||
client.clearCaptured();
|
||||
msg = "There";
|
||||
client.write(WebSocketFrame.text(msg));
|
||||
|
||||
capture = client.readFrames(1,TimeUnit.MILLISECONDS,1000);
|
||||
frame = capture.getFrames().get(0);
|
||||
Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(msg.toString()));
|
||||
}
|
||||
finally
|
||||
{
|
|
@ -139,6 +139,11 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||
this.extensions.add(xtension);
|
||||
}
|
||||
|
||||
public void clearCaptured()
|
||||
{
|
||||
this.incomingFrames.clear();
|
||||
}
|
||||
|
||||
public void clearExtensions()
|
||||
{
|
||||
extensions.clear();
|
||||
|
|
|
@ -73,6 +73,11 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
Assert.assertThat("Has no errors",errors.size(),is(0));
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
frames.clear();
|
||||
}
|
||||
|
||||
public void dump()
|
||||
{
|
||||
System.err.printf("Captured %d incoming frames%n",frames.size());
|
||||
|
|
Loading…
Reference in New Issue