diff options
15 files changed, 152 insertions, 128 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java b/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java index ee7c2bd..496004a 100644 --- a/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java +++ b/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java @@ -10,8 +10,8 @@ public class FilteredDataEmitter implements DataEmitter, DataCallback { } protected void report(Exception e) { - if (mEndCallback != null) - mEndCallback.onCompleted(e); + if (getEndCallback() != null) + getEndCallback().onCompleted(e); } public void setDataEmitter(DataEmitter emitter) { diff --git a/AndroidAsync/src/com/koushikdutta/async/LineEmitter.java b/AndroidAsync/src/com/koushikdutta/async/LineEmitter.java index 9694d5b..5bcf164 100644 --- a/AndroidAsync/src/com/koushikdutta/async/LineEmitter.java +++ b/AndroidAsync/src/com/koushikdutta/async/LineEmitter.java @@ -4,34 +4,13 @@ import junit.framework.Assert; import com.koushikdutta.async.callback.DataCallback; -public class LineEmitter { +public class LineEmitter implements DataCallback { static public interface StringCallback { public void onStringAvailable(String s); } StringBuilder data = new StringBuilder(); - public LineEmitter(final DataEmitter emitter) { - emitter.setDataCallback(new DataCallback() { - @Override - public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { - while (bb.remaining() > 0) { - byte b = bb.get(); - if (b == '\n') { - Assert.assertNotNull(mLineCallback); - mLineCallback.onStringAvailable(data.toString()); - if (emitter.getDataCallback() != this) - return; - data = new StringBuilder(); - } - else { - data.append((char)b); - } - } - } - }); - } - StringCallback mLineCallback; public void setLineCallback(StringCallback callback) { mLineCallback = callback; @@ -40,4 +19,20 @@ public class LineEmitter { public StringCallback getLineCallback() { return mLineCallback; } + + @Override + public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { + while (bb.remaining() > 0) { + byte b = bb.get(); + if (b == '\n') { + Assert.assertNotNull(mLineCallback); + mLineCallback.onStringAvailable(data.toString()); + data = new StringBuilder(); + return; + } + else { + data.append((char)b); + } + } + } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequestBody.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequestBody.java index bc67aad..4edcdd7 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequestBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequestBody.java @@ -1,9 +1,8 @@ package com.koushikdutta.async.http; -import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; -public interface AsyncHttpRequestBody extends DataCallback, CompletedCallback { +public interface AsyncHttpRequestBody extends DataCallback { public void write(AsyncHttpRequest request, AsyncHttpResponse sink); public String getContentType(); public boolean readFullyOnRequest(); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java index a4a00e5..1997e19 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java @@ -62,7 +62,8 @@ abstract class AsyncHttpResponseImpl extends FilteredDataEmitter implements Asyn } }); - LineEmitter liner = new LineEmitter(exchange); + LineEmitter liner = new LineEmitter(); + exchange.setDataCallback(liner); liner.setLineCallback(mHeaderCallback); mSocket.setEndCallback(mReporter); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/JSONRequestBody.java b/AndroidAsync/src/com/koushikdutta/async/http/JSONRequestBody.java index 2085938..eb0a926 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/JSONRequestBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/JSONRequestBody.java @@ -28,10 +28,6 @@ public class JSONRequestBody implements AsyncHttpRequestBody { } @Override - public void onCompleted(Exception ex) { - } - - @Override public void write(AsyncHttpRequest request, AsyncHttpResponse sink) { Util.writeAll(sink, mBodyBytes, new CompletedCallback() { @Override diff --git a/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java b/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java index e3eb950..4ecc34f 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java @@ -4,5 +4,5 @@ import com.koushikdutta.async.callback.DataCallback; public interface MultipartCallback { - public DataCallback onPart(Part part); + public void onPart(Part part); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java b/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java index 5016447..d816736 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java @@ -1,48 +1,64 @@ package com.koushikdutta.async.http; +import junit.framework.Assert; + +import com.koushikdutta.async.ByteBufferList; +import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.LineEmitter; import com.koushikdutta.async.LineEmitter.StringCallback; import com.koushikdutta.async.NullDataCallback; -import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.http.libcore.RawHeaders; -import com.koushikdutta.async.http.server.AsyncHttpRequestBodyBase; import com.koushikdutta.async.http.server.BoundaryEmitter; -public class MultipartFormDataBody extends AsyncHttpRequestBodyBase { +public class MultipartFormDataBody extends BoundaryEmitter implements AsyncHttpRequestBody { + LineEmitter liner; + + @Override + protected void onBoundaryStart() { + final RawHeaders headers = new RawHeaders(); + liner = new LineEmitter(); + liner.setLineCallback(new StringCallback() { + @Override + public void onStringAvailable(String s) { + if (!"\r".equals(s)){ + headers.addLine(s); + } + else { + liner = null; + setDataCallback(null); + if (mCallback != null) + mCallback.onPart(new Part(headers)); + if (getDataCallback() == null) + setDataCallback(new NullDataCallback()); + } + } + }); + setDataCallback(liner); + } + + @Override + protected void report(Exception e) { + super.report(e); + } + + @Override + public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { + if (liner != null) { + liner.onDataAvailable(emitter, bb); + return; + } + super.onDataAvailable(emitter, bb); + } + public static final String CONTENT_TYPE = "multipart/form-data"; - BoundaryEmitter boundaryEmitter; - String boundary; public MultipartFormDataBody(String contentType, String[] values) { - super(contentType); for (String value: values) { String[] splits = value.split("="); if (splits.length != 2) continue; if (!"boundary".equals(splits[0])) continue; - boundary = splits[1]; - boundaryEmitter = new BoundaryEmitter(boundary) { - @Override - protected void onBoundaryStart() { - final RawHeaders headers = new RawHeaders(); - new LineEmitter(boundaryEmitter).setLineCallback(new StringCallback() { - @Override - public void onStringAvailable(String s) { - if (!"\r".equals(s)){ - headers.addLine(s); - } - else { - boundaryEmitter.setDataCallback(onPart(new Part(headers))); - } - } - }); - } - @Override - protected void onBoundaryEnd() { -// System.out.println("boundary end"); - } - }; - boundaryEmitter.setDataEmitter(this); + setBoundary(splits[1]); return; } report(new Exception ("No boundary found for multipart/form-data")); @@ -57,11 +73,23 @@ public class MultipartFormDataBody extends AsyncHttpRequestBodyBase { return mCallback; } - private DataCallback onPart(Part part) { -// System.out.println("here"); -// System.out.println(headers.toHeaderString()); - if (mCallback == null) - return new NullDataCallback(); - return mCallback.onPart(part); + @Override + public void write(AsyncHttpRequest request, AsyncHttpResponse sink) { + Assert.fail(); + } + + @Override + public String getContentType() { + return CONTENT_TYPE; + } + + @Override + public boolean readFullyOnRequest() { + return false; + } + + @Override + public int length() { + return -1; } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/UrlEncodedFormBody.java b/AndroidAsync/src/com/koushikdutta/async/http/UrlEncodedFormBody.java index fa9bb55..b653a88 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/UrlEncodedFormBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/UrlEncodedFormBody.java @@ -61,7 +61,7 @@ public class UrlEncodedFormBody implements AsyncHttpRequestBody { return CONTENT_TYPE; } - private ByteBufferList data = null; + private ByteBufferList data; @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { if (data == null) @@ -86,30 +86,28 @@ public class UrlEncodedFormBody implements AsyncHttpRequestBody { return Collections.unmodifiableMap(map); } - @Override - public void onCompleted(Exception ex) { - ArrayList<NameValuePair> params; - mParameters = params = new ArrayList<NameValuePair>(); - String[] pairs = data.peekString().split("&"); - for (String p : pairs) { - String[] pair = p.split("=", 2); - if (pair.length == 0) - continue; - String name = Uri.decode(pair[0]); - String value = null; - if (pair.length == 2) - value = Uri.decode(pair[1]); - params.add(new BasicNameValuePair(name, value)); - } - } - public Iterable<NameValuePair> getParameters() { + if (mParameters == null && data != null) { + ArrayList<NameValuePair> params; + mParameters = params = new ArrayList<NameValuePair>(); + String[] pairs = data.peekString().split("&"); + for (String p : pairs) { + String[] pair = p.split("=", 2); + if (pair.length == 0) + continue; + String name = Uri.decode(pair[0]); + String value = null; + if (pair.length == 2) + value = Uri.decode(pair[1]); + params.add(new BasicNameValuePair(name, value)); + } + } return mParameters; } public Map<String, String> getParameterMap() { HashMap<String, String> map = new HashMap<String, String>(); - for (NameValuePair pair: mParameters) { + for (NameValuePair pair: getParameters()) { if (!map.containsKey(pair.getName())) map.put(pair.getName(), pair.getValue()); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/Util.java b/AndroidAsync/src/com/koushikdutta/async/http/Util.java index 189dd23..cafe9fc 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/Util.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/Util.java @@ -1,20 +1,16 @@ package com.koushikdutta.async.http; -import junit.framework.Assert; -import android.util.Log; - -import com.koushikdutta.async.ByteBufferList; import com.koushikdutta.async.DataEmitter; -import com.koushikdutta.async.FilteredDataEmitter; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.http.filter.ChunkedInputFilter; +import com.koushikdutta.async.http.filter.ContentLengthFilter; import com.koushikdutta.async.http.filter.GZIPInputFilter; import com.koushikdutta.async.http.filter.InflaterInputFilter; import com.koushikdutta.async.http.libcore.RawHeaders; import com.koushikdutta.async.http.server.UnknownRequestBody; public class Util { - public static AsyncHttpRequestBody getBody(DataEmitter emitter, final CompletedCallback reporter, RawHeaders headers) { + public static AsyncHttpRequestBody getBody(DataEmitter emitter, CompletedCallback reporter, RawHeaders headers) { String contentType = headers.get("Content-Type"); if (contentType != null) { String[] values = contentType.split(";"); @@ -22,18 +18,23 @@ public class Util { values[i] = values[i].trim(); } for (String ct: values) { - if (UrlEncodedFormBody.CONTENT_TYPE.equals(ct)) - return new UrlEncodedFormBody(); + if (UrlEncodedFormBody.CONTENT_TYPE.equals(ct)) { + UrlEncodedFormBody ret = new UrlEncodedFormBody(); + emitter.setDataCallback(ret); + return ret; + } if (MultipartFormDataBody.CONTENT_TYPE.equals(ct)) { MultipartFormDataBody ret = new MultipartFormDataBody(contentType, values); ret.setDataEmitter(emitter); - ret.setEndCallback(null); - emitter.setEndCallback(reporter); + ret.setEndCallback(reporter); return ret; } } } - return new UnknownRequestBody(contentType); + + UnknownRequestBody ret = new UnknownRequestBody(contentType); + emitter.setDataCallback(ret); + return ret; } public static DataEmitter getBodyDecoder(DataEmitter emitter, RawHeaders headers, boolean server, final CompletedCallback reporter) { @@ -64,26 +65,13 @@ public class Util { }); return emitter; } - FilteredDataEmitter contentLengthWatcher = new FilteredDataEmitter() { - int totalRead = 0; - @Override - public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { - Assert.assertTrue(totalRead < contentLength); - ByteBufferList list = bb.get(Math.min(contentLength - totalRead, bb.remaining())); - totalRead += list.remaining(); - super.onDataAvailable(emitter, list); - if (totalRead == contentLength) - report(null); - } - }; + ContentLengthFilter contentLengthWatcher = new ContentLengthFilter(contentLength); contentLengthWatcher.setDataEmitter(emitter); - contentLengthWatcher.setEndCallback(reporter); emitter = contentLengthWatcher; } else if ("chunked".equalsIgnoreCase(headers.get("Transfer-Encoding"))) { ChunkedInputFilter chunker = new ChunkedInputFilter(); chunker.setDataEmitter(emitter); - chunker.setEndCallback(reporter); emitter = chunker; } else if (server) { @@ -94,6 +82,7 @@ public class Util { reporter.onCompleted(null); } }); + return emitter; } if ("gzip".equals(headers.get("Content-Encoding"))) { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java index 36d9227..411dbf0 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedInputFilter.java @@ -103,9 +103,9 @@ public class ChunkedInputFilter extends FilteredDataEmitter { mChunkLength = 0; break; case COMPLETE: - Exception fail = new Exception("Continued receiving data after chunk complete"); - report(fail); - report(fail); + Assert.fail(); +// Exception fail = new Exception("Continued receiving data after chunk complete"); +// report(fail); return; } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/filter/InflaterInputFilter.java b/AndroidAsync/src/com/koushikdutta/async/http/filter/InflaterInputFilter.java index 9b8797f..544358e 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/filter/InflaterInputFilter.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/filter/InflaterInputFilter.java @@ -1,5 +1,6 @@ package com.koushikdutta.async.http.filter; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.zip.Inflater; @@ -12,13 +13,20 @@ import com.koushikdutta.async.Util; public class InflaterInputFilter extends FilteredDataEmitter { private Inflater mInflater; + + @Override + protected void report(Exception e) { + if (e != null && mInflater.getRemaining() > 0) { + e = new IOException("data still remaining in inflater"); + } + super.report(e); + } @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { try { ByteBufferList transformed = new ByteBufferList(); ByteBuffer output = ByteBuffer.allocate(bb.remaining() * 2); - int totalInflated = 0; int totalRead = 0; while (bb.size() > 0) { ByteBuffer b = bb.remove(); @@ -27,7 +35,6 @@ public class InflaterInputFilter extends FilteredDataEmitter { mInflater.setInput(b.array(), b.arrayOffset() + b.position(), b.remaining()); do { int inflated = mInflater.inflate(output.array(), output.arrayOffset() + output.position(), output.remaining()); - totalInflated += inflated; output.position(output.position() + inflated); if (!output.hasRemaining()) { output.limit(output.position()); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpRequestBodyBase.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpRequestBodyBase.java index eaa21e4..c04c2b4 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpRequestBodyBase.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpRequestBodyBase.java @@ -23,10 +23,10 @@ public class AsyncHttpRequestBodyBase extends FilteredDataEmitter implements Asy return mContentType; } - @Override - public void onCompleted(Exception ex) { - report(ex); - } +// @Override +// public void onCompleted(Exception ex) { +// report(ex); +// } @Override public boolean readFullyOnRequest() { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java index 307519b..758cdd1 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java @@ -28,8 +28,8 @@ public abstract class AsyncHttpServerRequestImpl extends FilteredDataEmitter imp @Override public void onCompleted(Exception e) { - if (mBody != null) - mBody.onCompleted(e); +// if (mBody != null) +// mBody.onCompleted(e); report(e); } @@ -56,8 +56,8 @@ public abstract class AsyncHttpServerRequestImpl extends FilteredDataEmitter imp } else { DataEmitter emitter = Util.getBodyDecoder(mSocket, mRawHeaders, true, mReporter); + emitter.setEndCallback(mReporter); mBody = Util.getBody(emitter, mReporter, mRawHeaders); - emitter.setDataCallback(mBody); onHeadersReceived(); } } @@ -74,7 +74,8 @@ public abstract class AsyncHttpServerRequestImpl extends FilteredDataEmitter imp void setSocket(AsyncSocket socket) { mSocket = socket; - LineEmitter liner = new LineEmitter(mSocket); + LineEmitter liner = new LineEmitter(); + mSocket.setDataCallback(liner); liner.setLineCallback(mHeaderCallback); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java index f893164..58c9923 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java @@ -10,7 +10,7 @@ import com.koushikdutta.async.FilteredDataEmitter; public class BoundaryEmitter extends FilteredDataEmitter { private byte[] boundary; - public BoundaryEmitter(String boundary) { + public void setBoundary(String boundary) { this.boundary = ("--" + boundary).getBytes(); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/UnknownRequestBody.java b/AndroidAsync/src/com/koushikdutta/async/http/server/UnknownRequestBody.java index e50e05c..40ed935 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/UnknownRequestBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/UnknownRequestBody.java @@ -4,12 +4,12 @@ import junit.framework.Assert; import com.koushikdutta.async.NullDataCallback; import com.koushikdutta.async.http.AsyncHttpRequest; +import com.koushikdutta.async.http.AsyncHttpRequestBody; import com.koushikdutta.async.http.AsyncHttpResponse; -public class UnknownRequestBody extends AsyncHttpRequestBodyBase { +public class UnknownRequestBody extends NullDataCallback implements AsyncHttpRequestBody { public UnknownRequestBody(String contentType) { - super(contentType); - setDataCallback(new NullDataCallback()); + mContentType = contentType; } @Override @@ -22,4 +22,14 @@ public class UnknownRequestBody extends AsyncHttpRequestBodyBase { public String getContentType() { return mContentType; } + + @Override + public boolean readFullyOnRequest() { + return false; + } + + @Override + public int length() { + return -1; + } } |