diff options
author | Ole André Vadla Ravnås <ole.andre.ravnas@soundrop.com> | 2013-07-23 17:44:31 +0200 |
---|---|---|
committer | Ole André Vadla Ravnås <ole.andre.ravnas@soundrop.com> | 2013-09-26 15:27:42 +0200 |
commit | 1b7f44cd463aa1dcfe6bd5a682c15ca21e0352b5 (patch) | |
tree | 5796df2c2983f5b9c8dc9a4c82081576fa5b1cdc | |
parent | 6700db32923d6f8da14a40562d03a57821d67084 (diff) | |
download | AndroidAsync-1b7f44cd463aa1dcfe6bd5a682c15ca21e0352b5.tar.gz AndroidAsync-1b7f44cd463aa1dcfe6bd5a682c15ca21e0352b5.tar.bz2 AndroidAsync-1b7f44cd463aa1dcfe6bd5a682c15ca21e0352b5.zip |
Add support for the x-webkit-deflate-frame extension
-rw-r--r-- | AndroidAsync/src/com/koushikdutta/async/http/HybiParser.java | 42 | ||||
-rw-r--r-- | AndroidAsync/src/com/koushikdutta/async/http/WebSocketImpl.java | 16 |
2 files changed, 52 insertions, 6 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/HybiParser.java b/AndroidAsync/src/com/koushikdutta/async/http/HybiParser.java index 9d23425..05b70d4 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/HybiParser.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/HybiParser.java @@ -40,16 +40,20 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.List; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; abstract class HybiParser { private static final String TAG = "HybiParser"; private boolean mMasking = true; + private boolean mDeflate = false; private int mStage; private boolean mFinal; private boolean mMasked; + private boolean mDeflated; private int mOpcode; private int mLengthSize; private int mLength; @@ -61,6 +65,8 @@ abstract class HybiParser { private boolean mClosed = false; private ByteArrayOutputStream mBuffer = new ByteArrayOutputStream(); + private Inflater mInflater = new Inflater(true); + private byte[] mInflateBuffer = new byte[4096]; private static final int BYTE = 255; private static final int FIN = 128; @@ -106,11 +112,33 @@ abstract class HybiParser { } return payload; } - + + private byte[] inflate(byte[] payload) throws DataFormatException { + ByteArrayOutputStream inflated = new ByteArrayOutputStream(); + + mInflater.setInput(payload); + while (!mInflater.needsInput()) { + int chunkSize = mInflater.inflate(mInflateBuffer); + inflated.write(mInflateBuffer, 0, chunkSize); + } + + mInflater.setInput(new byte[] { 0, 0, -1, -1 }); + while (!mInflater.needsInput()) { + int chunkSize = mInflater.inflate(mInflateBuffer); + inflated.write(mInflateBuffer, 0, chunkSize); + } + + return inflated.toByteArray(); + } + public void setMasking(boolean masking) { mMasking = masking; } - + + public void setDeflate(boolean deflate) { + mDeflate = deflate; + } + DataCallback mStage0 = new DataCallback() { @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { @@ -208,12 +236,13 @@ abstract class HybiParser { boolean rsv2 = (data & RSV2) == RSV2; boolean rsv3 = (data & RSV3) == RSV3; - if (rsv1 || rsv2 || rsv3) { + if ((!mDeflate && rsv1) || rsv2 || rsv3) { throw new ProtocolError("RSV not zero"); } mFinal = (data & FIN) == FIN; mOpcode = (data & OPCODE); + mDeflated = rsv1; mMask = new byte[0]; mPayload = new byte[0]; @@ -324,6 +353,13 @@ abstract class HybiParser { private void emitFrame() throws IOException { byte[] payload = mask(mPayload, mMask, 0); + if (mDeflated) { + try { + payload = inflate(payload); + } catch (DataFormatException e) { + throw new IOException("Invalid deflated data"); + } + } int opcode = mOpcode; if (opcode == OP_CONTINUATION) { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/WebSocketImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/WebSocketImpl.java index c96fcad..71e5663 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/WebSocketImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/WebSocketImpl.java @@ -71,7 +71,7 @@ public class WebSocketImpl implements WebSocket { pending = null; } - private void setupParser(boolean masking) { + private void setupParser(boolean masking, boolean deflate) { mParser = new HybiParser(mSocket) { @Override protected void report(Exception ex) { @@ -100,6 +100,7 @@ public class WebSocketImpl implements WebSocket { } }; mParser.setMasking(masking); + mParser.setDeflate(deflate); if (mSocket.isPaused()) mSocket.resume(); } @@ -126,7 +127,7 @@ public class WebSocketImpl implements WebSocket { // response.getHeaders().getHeaders().set("Access-Control-Allow-Origin", "http://" + origin); response.writeHead(); - setupParser(false); + setupParser(false, false); } public static void addWebSocketUpgradeHeaders(AsyncHttpRequest req, String protocol) { @@ -134,6 +135,7 @@ public class WebSocketImpl implements WebSocket { final String key = Base64.encodeToString(toByteArray(UUID.randomUUID()),Base64.NO_WRAP); headers.set("Sec-WebSocket-Version", "13"); headers.set("Sec-WebSocket-Key", key); + headers.set("Sec-WebSocket-Extensions", "x-webkit-deflate-frame"); headers.set("Connection", "Upgrade"); headers.set("Upgrade", "websocket"); if (protocol != null) @@ -166,9 +168,17 @@ public class WebSocketImpl implements WebSocket { String expected = SHA1(concat).trim(); if (!sha1.equalsIgnoreCase(expected)) return null; + String extensions = requestHeaders.get("Sec-WebSocket-Extensions"); + boolean deflate = false; + if (extensions != null) { + if (extensions.equals("x-webkit-deflate-frame")) + deflate = true; + else + return null; + } WebSocketImpl ret = new WebSocketImpl(response.detachSocket()); - ret.setupParser(true); + ret.setupParser(true, deflate); return ret; } |