diff options
23 files changed, 507 insertions, 165 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncServer.java b/AndroidAsync/src/com/koushikdutta/async/AsyncServer.java index e077566..c88d14a 100644 --- a/AndroidAsync/src/com/koushikdutta/async/AsyncServer.java +++ b/AndroidAsync/src/com/koushikdutta/async/AsyncServer.java @@ -70,7 +70,7 @@ public class AsyncServer { final ChannelWrapper sc = handler.getChannel(); SelectionKey ckey = sc.register(mSelector); ckey.attach(handler); - handler.mKey = ckey; + handler.setup(this, ckey); } public void post(Runnable runnable) { @@ -366,7 +366,7 @@ public class AsyncServer { ListenCallback serverHandler = (ListenCallback) key.attachment(); AsyncSocketImpl handler = new AsyncSocketImpl(); handler.attach(sc); - handler.mKey = ckey; + handler.setup(server, ckey); ckey.attach(handler); serverHandler.onAccepted(handler); } @@ -386,7 +386,7 @@ public class AsyncServer { try { sc.finishConnect(); AsyncSocketImpl newHandler = new AsyncSocketImpl(); - newHandler.mKey = key; + newHandler.setup(server, key); newHandler.attach(sc); key.attach(newHandler); handler.onConnectCompleted(null, newHandler); diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSocketImpl.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSocketImpl.java index 639ca39..997f097 100644 --- a/AndroidAsync/src/com/koushikdutta/async/AsyncSocketImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSocketImpl.java @@ -39,10 +39,19 @@ class AsyncSocketImpl implements AsyncSocket { } private ChannelWrapper mChannel; - SelectionKey mKey; + private SelectionKey mKey; +// private AsyncServer mServer; + private Thread mAffinity; + + void setup(AsyncServer server, SelectionKey key) { + mAffinity = Thread.currentThread(); +// mServer = server; + mKey = key; + } @Override public void write(ByteBufferList list) { + Assert.assertEquals(mAffinity, Thread.currentThread()); if (!mChannel.isConnected()) { Assert.assertFalse(mChannel.isChunked()); return; @@ -73,6 +82,7 @@ class AsyncSocketImpl implements AsyncSocket { @Override public void write(ByteBuffer b) { + Assert.assertEquals(mAffinity, Thread.currentThread()); try { if (!mChannel.isConnected()) { Assert.assertFalse(mChannel.isChunked()); @@ -241,6 +251,7 @@ class AsyncSocketImpl implements AsyncSocket { boolean mPaused = false; @Override public void pause() { + Assert.assertEquals(mAffinity, Thread.currentThread()); if (mPaused) return; mPaused = true; @@ -264,6 +275,7 @@ class AsyncSocketImpl implements AsyncSocket { @Override public void resume() { + Assert.assertEquals(mAffinity, Thread.currentThread()); if (!mPaused) return; mPaused = false; diff --git a/AndroidAsync/src/com/koushikdutta/async/ByteBufferList.java b/AndroidAsync/src/com/koushikdutta/async/ByteBufferList.java index b2b25fc..7071957 100644 --- a/AndroidAsync/src/com/koushikdutta/async/ByteBufferList.java +++ b/AndroidAsync/src/com/koushikdutta/async/ByteBufferList.java @@ -15,6 +15,16 @@ public class ByteBufferList implements Iterable<ByteBuffer> { public ByteBufferList() { } + + public ByteBufferList(ByteBuffer b) { + add(b); + } + + public ByteBufferList(byte[] buf) { + super(); + ByteBuffer b = ByteBuffer.wrap(buf); + add(b); + } public ByteBuffer[] toArray() { ByteBuffer[] ret = new ByteBuffer[mBuffers.size()]; diff --git a/AndroidAsync/src/com/koushikdutta/async/Continuation.java b/AndroidAsync/src/com/koushikdutta/async/Continuation.java new file mode 100644 index 0000000..e9b1719 --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/Continuation.java @@ -0,0 +1,54 @@ +package com.koushikdutta.async; + +import java.util.LinkedList; + +import junit.framework.Assert; + +import com.koushikdutta.async.callback.CompletedCallback; +import com.koushikdutta.async.callback.ContinuationCallback; + +public class Continuation { + CompletedCallback callback; + CompletedCallback wrapper; + public Continuation(CompletedCallback callback) { + this.callback = callback; + wrapper = new CompletedCallback() { + @Override + public void onCompleted(Exception ex) { + if (ex == null) { + next(); + return; + } + Continuation.this.callback.onCompleted(ex); + } + }; + } + + LinkedList<ContinuationCallback> mCallbacks = new LinkedList<ContinuationCallback>(); + + public void add(ContinuationCallback callback) { + mCallbacks.add(callback); + } + + private void next() { + if (mCallbacks.size() > 0) { + ContinuationCallback cb = mCallbacks.remove(); + try { + cb.onContinue(wrapper); + } + catch (Exception e) { + callback.onCompleted(e); + } + return; + } + + callback.onCompleted(null); + } + + boolean started; + public void start() { + Assert.assertTrue(!started); + started = true; + next(); + } +} diff --git a/AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java b/AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java index 64efffe..9b61fec 100644 --- a/AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java +++ b/AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java @@ -17,9 +17,25 @@ public class FilteredDataSink implements DataSink { mPendingWritable = false; mWritable.onWriteable(); } + testFlushed(); } }); } + + private void testFlushed() { + if (mPending == null) + onFlushed(); + } + + protected void onFlushed() { + } + + public int getPending() { + if (mPending == null) + return 0; + return mPending.remaining(); + } + DataSink mSink; public DataSink getSink() { return mSink; @@ -63,19 +79,20 @@ public class FilteredDataSink implements DataSink { return false; return true; } - + @Override public final void write(ByteBufferList bb) { if (!handlePending(bb)) return; ByteBufferList filtered = filter(bb); - Assert.assertTrue(filtered == bb || bb.remaining() == 0); + Assert.assertTrue(bb == null || filtered == bb || bb.remaining() == 0); mSink.write(filtered); if (filtered.remaining() > 0) { mPending = new ByteBufferList(); mPending.add(filtered.read(filtered.remaining())); } bb.clear(); + testFlushed(); } WritableCallback mWritable; diff --git a/AndroidAsync/src/com/koushikdutta/async/Util.java b/AndroidAsync/src/com/koushikdutta/async/Util.java index 4e14fc7..2710b4a 100644 --- a/AndroidAsync/src/com/koushikdutta/async/Util.java +++ b/AndroidAsync/src/com/koushikdutta/async/Util.java @@ -1,5 +1,7 @@ package com.koushikdutta.async; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; @@ -89,6 +91,27 @@ public class Util { cb.onWriteable(); } + public static void pump(final File file, final DataSink ds, final CompletedCallback callback) { + try { + final InputStream is = new FileInputStream(file); + pump(is, ds, new CompletedCallback() { + @Override + public void onCompleted(Exception ex) { + try { + is.close(); + callback.onCompleted(ex); + } + catch (IOException e) { + callback.onCompleted(e); + } + } + }); + } + catch (Exception e) { + callback.onCompleted(e); + } + } + public static void writeAll(final DataSink sink, final ByteBufferList bb, final CompletedCallback callback) { sink.setWriteableCallback(new WritableCallback() { @Override diff --git a/AndroidAsync/src/com/koushikdutta/async/ZipDataSink.java b/AndroidAsync/src/com/koushikdutta/async/ZipDataSink.java new file mode 100644 index 0000000..3014ca3 --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/ZipDataSink.java @@ -0,0 +1,87 @@ +package com.koushikdutta.async; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import com.koushikdutta.async.callback.CompletedCallback; + +public class ZipDataSink extends FilteredDataSink implements CompletedEmitter { + public ZipDataSink(DataSink sink) { + super(sink); + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ZipOutputStream zop = new ZipOutputStream(bout); + boolean first = true; + + public void putNextEntry(ZipEntry ze) throws IOException { + zop.putNextEntry(ze); + } + + public void closeEntry() throws IOException { + zop.closeEntry(); + } + + protected void report(Exception e) { + if (mCompleted != null) + mCompleted.onCompleted(null); + } + + private boolean closed = false; + public void close() { + closed = true; + try { + zop.close(); + } + catch (IOException e) { + report(e); + return; + } + write(new ByteBufferList()); + } + + + @Override + protected void onFlushed() { + if (closed) { + if (bout.size() > 0) { + write(new ByteBufferList()); + return; + } + report(null); + } + } + + @Override + public ByteBufferList filter(ByteBufferList bb) { + try { + if (bb != null) { + for (ByteBuffer b: bb) { + zop.write(b.array(), b.arrayOffset() + b.position(), b.remaining()); + } + } + ByteBufferList ret = new ByteBufferList(bout.toByteArray()); + bout.reset(); + bb.clear(); + return ret; + } + catch (IOException e) { + report(e); + return null; + } + } + + private CompletedCallback mCompleted; + @Override + public void setCompletedCallback(CompletedCallback callback) { + mCompleted = callback; + } + + @Override + public CompletedCallback getCompletedCallback() { + return mCompleted; + } +} diff --git a/AndroidAsync/src/com/koushikdutta/async/callback/ContinuationCallback.java b/AndroidAsync/src/com/koushikdutta/async/callback/ContinuationCallback.java new file mode 100644 index 0000000..71508ac --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/callback/ContinuationCallback.java @@ -0,0 +1,5 @@ +package com.koushikdutta.async.callback; + +public interface ContinuationCallback { + public void onContinue(CompletedCallback next) throws Exception; +} diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java index 0a36a72..517bf1b 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java @@ -302,6 +302,26 @@ public class AsyncHttpClient { } } + public static class WebSocketCallback implements CompletedCallback { + @Override + public void onCompleted(Exception ex) { + } + } + + public static void websocket(String uri, final WebSocketCallback callback) { + try { + execute(new AsyncHttpGet(uri), new HttpConnectCallback() { + @Override + public void onConnectCompleted(Exception ex, AsyncHttpResponse response) { +// response.get + } + }); + } + catch (URISyntaxException e) { + callback.onCompleted(e); + } + } + public static void execute(AsyncHttpRequest req, final String filename, final FileCallback callback) { final Handler handler = Looper.myLooper() == null ? null : new Handler(); final File file = new File(filename); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/HeaderMap.java b/AndroidAsync/src/com/koushikdutta/async/http/HeaderMap.java new file mode 100644 index 0000000..81e0abb --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/http/HeaderMap.java @@ -0,0 +1,24 @@ +package com.koushikdutta.async.http; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.koushikdutta.async.http.libcore.RawHeaders; + +public class HeaderMap { + public static Map<String,String> parse(RawHeaders headers, String header) { + HashMap<String, String> map = new HashMap<String, String>(); + String value = headers.get(header); + String[] parts = value.split(";"); + for (String part: parts) { + String[] pair = part.split("=", 2); + String key = pair[0].trim(); + String v = null; + if (pair.length > 1) + v = pair[1]; + map.put(key, v); + } + return Collections.unmodifiableMap(map); + } +} diff --git a/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java b/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java new file mode 100644 index 0000000..f3f3026 --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/http/MultipartCallback.java @@ -0,0 +1,7 @@ +package com.koushikdutta.async.http; + +import com.koushikdutta.async.callback.DataCallback; + +public interface MultipartCallback { + public DataCallback onPart(Part part); +} diff --git a/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java b/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java index 2f5cbcb..53035f6 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/MultipartFormDataBody.java @@ -33,15 +33,16 @@ public class MultipartFormDataBody extends AsyncHttpRequestBodyBase { headers.addLine(s); } else { - DataCallback callback = onPart(headers); + Part part = new Part(headers); + DataCallback callback = onPart(part); if (callback == null) callback = new DataCallback() { int total; @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { total += bb.remaining(); - System.out.println(total); - System.out.println(bb.peekString()); +// System.out.println(total); +// System.out.println(bb.peekString()); bb.clear(); } }; @@ -52,7 +53,7 @@ public class MultipartFormDataBody extends AsyncHttpRequestBodyBase { } @Override protected void onBoundaryEnd() { - System.out.println("boundary end"); +// System.out.println("boundary end"); } }; return; @@ -65,7 +66,20 @@ public class MultipartFormDataBody extends AsyncHttpRequestBodyBase { boundaryEmitter.onDataAvailable(emitter, bb); } - public DataCallback onPart(RawHeaders headers) { - return null; + MultipartCallback mCallback; + public void setMultipartCallback(MultipartCallback callback) { + mCallback = callback; + } + + public MultipartCallback getMultipartCallback() { + return mCallback; + } + + private DataCallback onPart(Part part) { +// System.out.println("here"); +// System.out.println(headers.toHeaderString()); + if (mCallback == null) + return null; + return mCallback.onPart(part); } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/Part.java b/AndroidAsync/src/com/koushikdutta/async/http/Part.java new file mode 100644 index 0000000..61c9afc --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/http/Part.java @@ -0,0 +1,34 @@ +package com.koushikdutta.async.http; + +import java.io.File; +import java.util.Map; + +import com.koushikdutta.async.http.libcore.RawHeaders; + +public class Part { + RawHeaders mHeaders; + Map<String, String> mContentDisposition; + public Part(RawHeaders headers) { + mHeaders = headers; + mContentDisposition = HeaderMap.parse(mHeaders, "Content-Disposition"); + } + + public RawHeaders getRawHeaders() { + return mHeaders; + } + + public String getContentType() { + return mHeaders.get("Content-Type"); + } + + public String getFilename() { + String file = mContentDisposition.get("filename"); + if (file == null) + return null; + return new File(file).getName(); + } + + public boolean isFile() { + return mContentDisposition.containsKey("filename"); + } +} diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java index 14cbc84..cd9306b 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java @@ -28,120 +28,127 @@ import com.koushikdutta.async.http.AsyncHttpPost; import com.koushikdutta.async.http.libcore.RawHeaders; public class AsyncHttpServer implements CompletedEmitter { - AsyncServerSocket mListener; + ArrayList<AsyncServerSocket> mListeners = new ArrayList<AsyncServerSocket>(); public void stop() { - if (mListener != null) - mListener.stop(); + if (mListeners != null) { + for (AsyncServerSocket listener: mListeners) { + listener.stop(); + } + } } - public AsyncHttpServer(AsyncServer server, int port) { - server.listen(null, port, new ListenCallback() { - @Override - public void onAccepted(final AsyncSocket socket) { - AsyncHttpServerRequestImpl req = new AsyncHttpServerRequestImpl() { - Pair match; - boolean responseComplete; - boolean requestComplete; - AsyncHttpServerResponseImpl res; - boolean hasContinued; - @Override - protected void onHeadersReceived() { - RawHeaders headers = getRawHeaders(); + ListenCallback mListenCallback = new ListenCallback() { + @Override + public void onAccepted(final AsyncSocket socket) { + AsyncHttpServerRequestImpl req = new AsyncHttpServerRequestImpl() { + Pair match; + boolean responseComplete; + boolean requestComplete; + AsyncHttpServerResponseImpl res; + boolean hasContinued; + @Override + protected void onHeadersReceived() { + RawHeaders headers = getRawHeaders(); - // should the negotiation of 100 continue be here, or in the request impl? - // probably here, so AsyncResponse can negotiate a 100 continue. - if (!hasContinued && "100-continue".equals(headers.get("Expect"))) { -// System.out.println("continuing..."); - Util.writeAll(mSocket, "HTTP/1.1 100 Continue\r\n".getBytes(), new CompletedCallback() { - @Override - public void onCompleted(Exception ex) { - if (ex != null) { - report(ex); - return; - } - hasContinued = true; - onHeadersReceived(); + // should the negotiation of 100 continue be here, or in the request impl? + // probably here, so AsyncResponse can negotiate a 100 continue. + if (!hasContinued && "100-continue".equals(headers.get("Expect"))) { + pause(); +// System.out.println("continuing..."); + Util.writeAll(mSocket, "HTTP/1.1 100 Continue\r\n".getBytes(), new CompletedCallback() { + @Override + public void onCompleted(Exception ex) { + resume(); + if (ex != null) { + report(ex); + return; } - }); - return; - } -// System.out.println(headers.toHeaderString()); - - String statusLine = headers.getStatusLine(); - String[] parts = statusLine.split(" "); - String path = parts[1]; - path = path.split("\\?")[0]; - String action = parts[0]; - synchronized (mActions) { - ArrayList<Pair> pairs = mActions.get(action); - if (pairs != null) { - for (Pair p: pairs) { - Matcher m = p.regex.matcher(path); - if (m.matches()) { - mMatcher = m; - match = p; - break; - } + hasContinued = true; + onHeadersReceived(); + } + }); + return; + } +// System.out.println(headers.toHeaderString()); + + String statusLine = headers.getStatusLine(); + String[] parts = statusLine.split(" "); + String path = parts[1]; + path = path.split("\\?")[0]; + String action = parts[0]; + synchronized (mActions) { + ArrayList<Pair> pairs = mActions.get(action); + if (pairs != null) { + for (Pair p: pairs) { + Matcher m = p.regex.matcher(path); + if (m.matches()) { + mMatcher = m; + match = p; + break; } } } - res = new AsyncHttpServerResponseImpl(socket) { - @Override - protected void onCompleted() { - responseComplete = true; - // reuse the socket for a subsequent request. - handleOnCompleted(); - } - }; - if (match == null) { - res.responseCode(404); - res.end(); - return; + } + res = new AsyncHttpServerResponseImpl(socket) { + @Override + protected void onEnd() { + responseComplete = true; + // reuse the socket for a subsequent request. + handleOnCompleted(); } + }; + if (match == null) { + res.responseCode(404); + res.end(); + return; + } - if (!getBody().readFullyOnRequest()) { -// Assert.assertTrue(getBody() instanceof CompletedEmitter); -// CompletedEmitter completed = (CompletedEmitter)getBody(); -// completed.setCompletedCallback(this); - match.callback.onRequest(this, res); - } - else if (requestComplete) { - match.callback.onRequest(this, res); - } + if (!getBody().readFullyOnRequest()) { +// Assert.assertTrue(getBody() instanceof CompletedEmitter); +// CompletedEmitter completed = (CompletedEmitter)getBody(); +// completed.setCompletedCallback(this); + match.callback.onRequest(this, res); + } + else if (requestComplete) { + match.callback.onRequest(this, res); } + } - @Override - public void onCompleted(Exception e) { - requestComplete = true; - super.onCompleted(e); - mSocket.setDataCallback(null); - mSocket.pause(); - handleOnCompleted(); + @Override + public void onCompleted(Exception e) { + requestComplete = true; + super.onCompleted(e); + mSocket.setDataCallback(null); + mSocket.pause(); + handleOnCompleted(); - if (getBody().readFullyOnRequest()) { - match.callback.onRequest(this, res); - } + if (getBody().readFullyOnRequest()) { + match.callback.onRequest(this, res); } - - private void handleOnCompleted() { - if (requestComplete && responseComplete) { - onAccepted(socket); - } + } + + private void handleOnCompleted() { + if (requestComplete && responseComplete) { + onAccepted(socket); } - }; - req.setSocket(socket); - socket.resume(); - } + } + }; + req.setSocket(socket); + socket.resume(); + } - @Override - public void onCompleted(Exception error) { - report(error); - } + @Override + public void onCompleted(Exception error) { + report(error); + } - @Override - public void onListening(AsyncServerSocket socket) { - mListener = socket; - } - }); + @Override + public void onListening(AsyncServerSocket socket) { + mListeners.add(socket); + } + }; + + public void listen(AsyncServer server, int port) { + server.listen(null, port, mListenCallback); } private void report(Exception ex) { @@ -149,8 +156,12 @@ public class AsyncHttpServer implements CompletedEmitter { mCompletedCallback.onCompleted(ex); } - public AsyncHttpServer(int port) { - this(AsyncServer.getDefault(), port); + public void listen(int port) { + listen(AsyncServer.getDefault(), port); + } + + public ListenCallback getListenCallback() { + return mListenCallback; } CompletedCallback mCompletedCallback; @@ -206,9 +217,7 @@ public class AsyncHttpServer implements CompletedEmitter { response.end(); return; } - AsyncHttpServerRequestImpl impl = (AsyncHttpServerRequestImpl)request; - - callback.onConnected(new WebSocketImpl(impl, response)); + callback.onConnected(new WebSocketImpl(request, response)); } }); } @@ -242,6 +251,7 @@ public class AsyncHttpServer implements CompletedEmitter { static Hashtable<String, String> mContentTypes = new Hashtable<String, String>(); { mContentTypes.put("js", "application/javascript"); + mContentTypes.put("json", "application/json"); mContentTypes.put("png", "image/png"); mContentTypes.put("jpg", "image/jpeg"); mContentTypes.put("html", "text/html"); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java index 17ade33..2dce8e1 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java @@ -2,12 +2,15 @@ package com.koushikdutta.async.http.server; import java.util.regex.Matcher; +import com.koushikdutta.async.AsyncSocket; +import com.koushikdutta.async.CompletedEmitter; import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.http.AsyncHttpRequestBody; import com.koushikdutta.async.http.libcore.RequestHeaders; -public interface AsyncHttpServerRequest extends DataEmitter { +public interface AsyncHttpServerRequest extends DataEmitter, CompletedEmitter { public RequestHeaders getHeaders(); public Matcher getMatcher(); public AsyncHttpRequestBody getBody(); + public AsyncSocket getSocket(); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java index 2fb081a..1cd3f86 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java @@ -17,6 +17,17 @@ public abstract class AsyncHttpServerRequestImpl implements AsyncHttpServerReque AsyncSocket mSocket; Matcher mMatcher; + private CompletedCallback mCompleted; + @Override + public void setCompletedCallback(CompletedCallback callback) { + mCompleted = callback; + } + + @Override + public CompletedCallback getCompletedCallback() { + return mCompleted; + } + private CompletedCallback mReporter = new CompletedCallback() { @Override public void onCompleted(Exception error) { @@ -29,6 +40,8 @@ public abstract class AsyncHttpServerRequestImpl implements AsyncHttpServerReque public void onCompleted(Exception e) { if (mBody != null) mBody.onCompleted(e); + if (mCompleted != null) + mCompleted.onCompleted(e); } abstract protected void onHeadersReceived(); @@ -76,6 +89,11 @@ public abstract class AsyncHttpServerRequestImpl implements AsyncHttpServerReque LineEmitter liner = new LineEmitter(mSocket); liner.setLineCallback(mHeaderCallback); } + + @Override + public AsyncSocket getSocket() { + return mSocket; + } private RequestHeaders mHeaders = new RequestHeaders(null, mRawHeaders); @Override diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java index 49e97b0..5430895 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java @@ -5,9 +5,10 @@ import java.io.File; import org.json.JSONObject; import com.koushikdutta.async.DataSink; +import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.http.libcore.ResponseHeaders; -public interface AsyncHttpServerResponse extends DataSink { +public interface AsyncHttpServerResponse extends DataSink, CompletedCallback { public void end(); public void send(String contentType, String string); public void send(String string); @@ -18,4 +19,8 @@ public interface AsyncHttpServerResponse extends DataSink { public void writeHead(); public void setContentType(String contentType); public void redirect(String location); + /** + * Alias for end. Used with CompletedEmitters + */ + public void onCompleted(Exception ex); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java index e270978..5aea616 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java @@ -66,7 +66,7 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { } private void writeInternal(ByteBufferList bb) { - Assert.assertTrue(!mCompleted); + Assert.assertTrue(!mEnded); initFirstWrite(); mChunker.write(bb); } @@ -94,11 +94,11 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { public void end() { if (null == mRawHeaders.get("Transfer-Encoding")) { send("text/html", ""); - onCompleted(); + onEnd(); return; } writeInternal(ByteBuffer.wrap(new byte[0])); - onCompleted(); + onEnd(); } private boolean mHeadWritten = false; @@ -127,16 +127,16 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { writeHead(); mSink.write(ByteBuffer.wrap(string.getBytes())); - onCompleted(); + onEnd(); } catch (UnsupportedEncodingException e) { Assert.fail(); } } - boolean mCompleted; - protected void onCompleted() { - mCompleted = true; + boolean mEnded; + protected void onEnd() { + mEnded = true; } protected void report(Exception e) { @@ -184,4 +184,12 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { mRawHeaders.set("Location", location); end(); } + + @Override + public void onCompleted(Exception ex) { + if (ex != null) { + ex.printStackTrace(); + } + end(); + } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java index 60b7104..e9607dd 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java @@ -1,7 +1,6 @@ package com.koushikdutta.async.http.server; import java.nio.ByteBuffer; -import java.util.DuplicateFormatFlagsException; import junit.framework.Assert; @@ -49,9 +48,9 @@ public class BoundaryEmitter extends FilteredDataCallback { @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { // System.out.println(bb.getString()); - System.out.println("chunk: " + bb.remaining()); +// System.out.println("chunk: " + bb.remaining()); - System.out.println("state: " + state); +// System.out.println("state: " + state); // if we were in the middle of a potential match, let's throw that // at the beginning of the buffer and process it too. @@ -92,7 +91,7 @@ public class BoundaryEmitter extends FilteredDataCallback { // len can be -1 on the first boundary Assert.assertEquals(-2, len); } - System.out.println("bstart"); +// System.out.println("bstart"); onBoundaryStart(); } else if (buf[i] == '-') { @@ -119,7 +118,7 @@ public class BoundaryEmitter extends FilteredDataCallback { ByteBufferList list = new ByteBufferList(); list.add(b); super.onDataAvailable(emitter, list); - System.out.println("bend"); +// System.out.println("bend"); onBoundaryEnd(); } else { @@ -153,8 +152,8 @@ public class BoundaryEmitter extends FilteredDataCallback { } if (last < buf.length) { - System.out.println("amount left at boundary: " + (buf.length - last)); - System.out.println(state); +// System.out.println("amount left at boundary: " + (buf.length - last)); +// System.out.println(state); int keep = Math.max(state, 0); ByteBuffer b = ByteBuffer.wrap(buf, last, buf.length - last - keep); ByteBufferList list = new ByteBufferList(); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java index b4e0d1b..af463d0 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java @@ -27,8 +27,8 @@ public class WebSocketImpl implements WebSocket { private AsyncSocket mSocket; BufferedDataSink mSink; - public WebSocketImpl(AsyncHttpServerRequestImpl request, AsyncHttpServerResponse response) { - mSocket = request.mSocket; + public WebSocketImpl(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { + mSocket = request.getSocket(); mSink = new BufferedDataSink(mSocket); mSocket.setClosedCallback(new ClosedCallback() { diff --git a/AndroidAsync/src/com/koushikdutta/test/TestActivity.java b/AndroidAsync/src/com/koushikdutta/test/TestActivity.java index a93036f..89be215 100644 --- a/AndroidAsync/src/com/koushikdutta/test/TestActivity.java +++ b/AndroidAsync/src/com/koushikdutta/test/TestActivity.java @@ -84,7 +84,8 @@ public class TestActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - AsyncHttpServer server = new AsyncHttpServer(3000); + AsyncHttpServer server = new AsyncHttpServer(); + server.listen(3000); server.get("/", new HttpServerRequestCallback() { @Override public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { diff --git a/AndroidAsyncSample/gen/com/koushikdutta/async/R.java b/AndroidAsyncSample/gen/com/koushikdutta/async/R.java index 48d7fcd..07e6084 100644 --- a/AndroidAsyncSample/gen/com/koushikdutta/async/R.java +++ b/AndroidAsyncSample/gen/com/koushikdutta/async/R.java @@ -4,38 +4,11 @@ * aapt tool from the resource data it found. It * should not be modified by hand. */ - package com.koushikdutta.async; public final class R { - public static final class attr { - } - public static final class drawable { - public static final int ic_action_search=0x7f020000; - public static final int ic_launcher=0x7f020001; - } - public static final class id { - public static final int chart=0x7f070004; - public static final int desksms=0x7f070002; - public static final int go=0x7f070000; - public static final int menu_settings=0x7f070005; - public static final int rommanager=0x7f070001; - public static final int tether=0x7f070003; - } - public static final class layout { - public static final int activity_main=0x7f030000; - } - public static final class menu { - public static final int activity_main=0x7f060000; - } - public static final class string { - public static final int app_name=0x7f040000; - public static final int download=0x7f040004; - public static final int hello_world=0x7f040001; - public static final int menu_settings=0x7f040002; - public static final int title_activity_main=0x7f040003; - } - public static final class style { - public static final int AppTheme=0x7f050000; - } + public static final class drawable { + public static final int ic_launcher = 0x7f020001; + public static final int ic_action_search = 0x7f020000; + } } diff --git a/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java b/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java index a335726..f9f1a0e 100644 --- a/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java +++ b/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java @@ -21,6 +21,10 @@ import com.koushikdutta.async.http.AsyncHttpClient; import com.koushikdutta.async.http.AsyncHttpPost; import com.koushikdutta.async.http.AsyncHttpResponse; import com.koushikdutta.async.http.UrlEncodedFormBody; +import com.koushikdutta.async.http.server.AsyncHttpServer; +import com.koushikdutta.async.http.server.WebSocket; +import com.koushikdutta.async.http.server.WebSocket.StringCallback; +import com.koushikdutta.async.http.server.WebSocketCallback; public class MainActivity extends Activity { ImageView rommanager; @@ -45,7 +49,21 @@ public class MainActivity extends Activity { tether = (ImageView)findViewById(R.id.tether); desksms = (ImageView)findViewById(R.id.desksms); chart = (ImageView)findViewById(R.id.chart); + + server.listen(4500); + server.websocket("/", new WebSocketCallback() { + @Override + public void onConnected(WebSocket webSocket) { + webSocket.setStringCallback(new StringCallback() { + @Override + public void onStringAvailable(String s) { + System.out.println("String: " + s); + } + }); + } + }); } + AsyncHttpServer server = new AsyncHttpServer(); @Override public boolean onCreateOptionsMenu(Menu menu) { |