diff options
author | Koushik Dutta <koushd@gmail.com> | 2014-07-23 23:52:42 -0700 |
---|---|---|
committer | Koushik Dutta <koushd@gmail.com> | 2014-07-23 23:52:42 -0700 |
commit | ad5709a17b41306f76fc446673bb5779fcd98666 (patch) | |
tree | 6362f0dd8d59df852954792acecf76250521a544 /AndroidAsync | |
parent | 26c3c5bf969faadaf3d001b58c4c2731b9b0154a (diff) | |
download | AndroidAsync-ad5709a17b41306f76fc446673bb5779fcd98666.tar.gz AndroidAsync-ad5709a17b41306f76fc446673bb5779fcd98666.tar.bz2 AndroidAsync-ad5709a17b41306f76fc446673bb5779fcd98666.zip |
Fix header chunking bug in AsyncHttpServerResponseImpl.
Fix resume bugs in ChunkedInputFilter.
Diffstat (limited to 'AndroidAsync')
3 files changed, 35 insertions, 37 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java index 5413896..0f777e6 100644 --- a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java +++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java @@ -140,17 +140,6 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket } }); - - // here's the stack of emitters - // ssl emitter - // buffered data emitter - // socket - - // ssl emitter needs a buffered emitter - // in case there is an underflow. - // buffered emitter will read from the socket, - // and replay data forever. - // on pause, the emitter is paused to prevent the buffered // socket and itself from firing. // on resume, emitter is resumed, ssl buffer is flushed as well diff --git a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java index 652e907..f049a06 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java @@ -43,6 +43,7 @@ public class ChunkedInputFilter extends FilteredDataEmitter { super.report(e); } + ByteBufferList pending = new ByteBufferList(); @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { try { @@ -82,12 +83,8 @@ public class ChunkedInputFilter extends FilteredDataEmitter { } if (reading == 0) break; - ByteBufferList chunk = bb.get(reading); - int newRemaining = bb.remaining(); - assert remaining == chunk.remaining() + bb.remaining(); - assert reading == chunk.remaining(); - Util.emitAllData(this, chunk); - assert newRemaining == bb.remaining(); + bb.get(pending, reading); + Util.emitAllData(this, pending); break; case CHUNK_CR: if (!checkCR(bb.getByteChar())) diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java index fbf4ba2..cdbfa5c 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java @@ -51,18 +51,21 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { @Override public void write(ByteBufferList bb) { - if (bb.remaining() == 0) - return; - + // order is important here... assert !mEnded; - if (!mHasWritten) { + // do the header write... this will call onWritable, which may be reentrant + if (!mHasWritten) initFirstWrite(); + + // now check to see if the list is empty. reentrancy may cause it to empty itself. + if (bb.remaining() == 0) return; - } - if (mSink == null) { - System.out.println("poop squat"); + + // null sink means that the header has not finished writing + if (mSink == null) return; - } + + // can successfully write! mSink.write(bb); } @@ -74,23 +77,32 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { mHasWritten = true; + final boolean isChunked; + String currentEncoding = mRawHeaders.get("Transfer-Encoding"); + if ("".equals(currentEncoding)) + mRawHeaders.removeAll("Transfer-Encoding"); + boolean canUseChunked = ("Chunked".equalsIgnoreCase(currentEncoding) || currentEncoding == null) + && !"close".equalsIgnoreCase(mRawHeaders.get("Connection")); + if (mContentLength < 0) { + String contentLength = mRawHeaders.get("Content-Length"); + if (!TextUtils.isEmpty(contentLength)) + mContentLength = Long.valueOf(contentLength); + } + if (mContentLength < 0 && canUseChunked) { + mRawHeaders.set("Transfer-Encoding", "Chunked"); + isChunked = true; + } + else { + isChunked = false; + } + String statusLine = String.format("HTTP/1.1 %s %s", code, AsyncHttpServer.getResponseCodeDescription(code)); String rh = mRawHeaders.toPrefixString(statusLine); + Util.writeAll(mSocket, rh.getBytes(), new CompletedCallback() { @Override public void onCompleted(Exception ex) { - String currentEncoding = mRawHeaders.get("Transfer-Encoding"); - if ("".equals(currentEncoding)) - mRawHeaders.removeAll("Transfer-Encoding"); - boolean canUseChunked = ("Chunked".equalsIgnoreCase(currentEncoding) || currentEncoding == null) - && !"close".equalsIgnoreCase(mRawHeaders.get("Connection")); - if (mContentLength < 0) { - String contentLength = mRawHeaders.get("Content-Length"); - if (!TextUtils.isEmpty(contentLength)) - mContentLength = Long.valueOf(contentLength); - } - if (mContentLength < 0 && canUseChunked) { - mRawHeaders.set("Transfer-Encoding", "Chunked"); + if (isChunked) { ChunkedOutputFilter chunked = new ChunkedOutputFilter(mSocket); chunked.setMaxBuffer(0); mSink = chunked; |