diff options
9 files changed, 165 insertions, 19 deletions
diff --git a/AndroidAsync/gen/com/koushikdutta/async/R.java b/AndroidAsync/gen/com/koushikdutta/async/R.java index 4f4fe85..7761246 100644 --- a/AndroidAsync/gen/com/koushikdutta/async/R.java +++ b/AndroidAsync/gen/com/koushikdutta/async/R.java @@ -11,10 +11,10 @@ public final class R { public static final class attr { } public static final class drawable { - public static int ic_action_search=0x7f020000; - public static int ic_launcher=0x7f020001; + public static final int ic_action_search=0x7f020000; + public static final int ic_launcher=0x7f020001; } public static final class string { - public static int name=0x7f030000; + public static final int name=0x7f030000; } } diff --git a/AndroidAsync/project.properties b/AndroidAsync/project.properties index dfa4dd0..6eb97ab 100644 --- a/AndroidAsync/project.properties +++ b/AndroidAsync/project.properties @@ -12,4 +12,4 @@ # Project target. target=android-16 -android.library=true +android.library=false diff --git a/AndroidAsync/src/com/koushikdutta/async/Util.java b/AndroidAsync/src/com/koushikdutta/async/Util.java index 7e0b443..53ca1aa 100644 --- a/AndroidAsync/src/com/koushikdutta/async/Util.java +++ b/AndroidAsync/src/com/koushikdutta/async/Util.java @@ -1,10 +1,14 @@ package com.koushikdutta.async; +import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; import junit.framework.Assert; +import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; +import com.koushikdutta.async.callback.WritableCallback; public class Util { public static void emitAllData(DataEmitter emitter, ByteBufferList list) { @@ -19,7 +23,7 @@ public class Util { } Assert.assertEquals(list.remaining(), 0); } - + public static void emitAllData(DataEmitter emitter, ByteBuffer b) { ByteBufferList list = new ByteBufferList(); list.add(b); @@ -28,4 +32,53 @@ public class Util { // so this is safe to clear b.position(b.limit()); } + + public static void pump(final InputStream is, final DataSink ds, final CompletedCallback callback) { + final WritableCallback cb = new WritableCallback() { + private void close() { + try { + is.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + byte[] buffer = new byte[8192]; + ByteBuffer pending = ByteBuffer.wrap(buffer); + { + pending.limit(pending.position()); + } + + @Override + public void onWriteable() { + try { + int remaining; + do { + if (pending.remaining() == 0) { + int read = is.read(buffer); + if (read == -1) { + close(); + callback.onCompleted(null); + return; + } + pending.position(0); + pending.limit(read); + } + + remaining = pending.remaining(); + ds.write(pending); + } + while (remaining != pending.remaining()); + } + catch (Exception e) { + close(); + callback.onCompleted(e); + return; + } + } + }; + ds.setWriteableCallback(cb); + + cb.onWriteable(); + } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java index 131a9b7..95d631d 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java @@ -1,23 +1,24 @@ package com.koushikdutta.async.http.server; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; +import java.io.File; +import java.io.InputStream; import java.util.ArrayList; +import java.util.Enumeration; import java.util.Hashtable; +import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; -import android.util.Base64; +import android.content.Context; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.AsyncSocket; -import com.koushikdutta.async.ByteBufferList; -import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.ExceptionCallback; import com.koushikdutta.async.ExceptionEmitter; -import com.koushikdutta.async.callback.ClosedCallback; -import com.koushikdutta.async.callback.DataCallback; +import com.koushikdutta.async.Util; +import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.ListenCallback; import com.koushikdutta.async.http.libcore.RawHeaders; @@ -43,19 +44,26 @@ public class AsyncHttpServer implements ExceptionEmitter { for (Pair p: pairs) { Matcher m = p.regex.matcher(path); if (m.matches()) { + mMatcher = m; match = p; break; } } } } - AsyncHttpServerResponseImpl res = new AsyncHttpServerResponseImpl(socket); + AsyncHttpServerResponseImpl res = new AsyncHttpServerResponseImpl(socket) { + @Override + protected void onCompleted() { + // reuse the socket for a subsequent request. + onAccepted(socket); + } + }; if (match == null) { res.responseCode(404); res.end(); return; } - + match.callback.onRequest(this, res); } @Override @@ -147,6 +155,49 @@ public class AsyncHttpServer implements ExceptionEmitter { addAction("GET", regex, callback); } + InputStream getAssetStream(final Context context, String asset) { + String apkPath = context.getPackageResourcePath(); + String assetPath = "assets/" + asset; + try { + ZipFile zip = new ZipFile(apkPath); + Enumeration<?> entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + if (entry.getName().equals(assetPath)) { + return zip.getInputStream(entry); + } + } + } + catch (Exception ex) { + } + return null; + } + + + public void directory(Context _context, String regex, final String assetPath) { + final Context context = _context.getApplicationContext(); + addAction("GET", regex, new HttpServerRequestCallback() { + @Override + public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) { + System.out.println(request); + String path = request.getMatcher().replaceAll(""); + InputStream is = getAssetStream(context, assetPath + path); + if (is == null) { + response.responseCode(404); + response.end(); + return; + } + response.responseCode(200); + Util.pump(is, response, new CompletedCallback() { + @Override + public void onCompleted(Exception ex) { + response.end(); + } + }); + } + }); + } + private static Hashtable<Integer, String> mCodes = new Hashtable<Integer, String>(); static { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java index 049f8d9..51e7d38 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java @@ -1,8 +1,11 @@ package com.koushikdutta.async.http.server; +import java.util.regex.Matcher; + import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.http.libcore.RequestHeaders; public interface AsyncHttpServerRequest extends DataEmitter { public RequestHeaders getHeaders(); + public Matcher getMatcher(); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java index a858d0a..a052770 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java @@ -1,5 +1,7 @@ package com.koushikdutta.async.http.server; +import java.util.regex.Matcher; + import com.koushikdutta.async.AsyncSocket; import com.koushikdutta.async.LineEmitter; import com.koushikdutta.async.LineEmitter.StringCallback; @@ -10,6 +12,7 @@ import com.koushikdutta.async.http.libcore.RequestHeaders; public class AsyncHttpServerRequestImpl implements AsyncHttpServerRequest { private RawHeaders mRawHeaders = new RawHeaders(); AsyncSocket mSocket; + Matcher mMatcher; protected void report(Exception e) { } @@ -72,4 +75,9 @@ public class AsyncHttpServerRequestImpl implements AsyncHttpServerRequest { return mSocket.isChunked(); } + @Override + public Matcher getMatcher() { + return mMatcher; + } + } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java index 84e3f90..07c4ade 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java @@ -66,9 +66,11 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { public void end() { if (null == mRawHeaders.get("Transfer-Encoding")) { send("text/html", ""); + onCompleted(); return; } write(ByteBuffer.wrap(new byte[0])); + onCompleted(); } private boolean mHeadWritten = false; @@ -82,7 +84,6 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { private void send(String contentType, String string) { try { Assert.assertTrue(mContentLength < 0); - responseCode(200); byte[] bytes = string.getBytes("UTF-8"); mContentLength = bytes.length; mRawHeaders.set("Content-Length", Integer.toString(bytes.length)); @@ -105,6 +106,7 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { @Override public void send(String string) { + responseCode(200); send("text/html", string); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java index dfa9811..aef1f5a 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java @@ -31,6 +31,14 @@ public class WebSocketImpl implements WebSocket { mSocket = request.mSocket; mSink = new BufferedDataSink(mSocket); + mSocket.setClosedCallback(new ClosedCallback() { + @Override + public void onClosed() { + if (WebSocketImpl.this.mClosedCallback != null) + WebSocketImpl.this.mClosedCallback.onClosed(); + } + }); + String key = request.getHeaders().getHeaders().get("Sec-WebSocket-Key"); String concat = key + MAGIC; String sha1 = SHA1(concat); diff --git a/AndroidAsync/src/com/koushikdutta/test/TestActivity.java b/AndroidAsync/src/com/koushikdutta/test/TestActivity.java index 2058065..ab4fc34 100644 --- a/AndroidAsync/src/com/koushikdutta/test/TestActivity.java +++ b/AndroidAsync/src/com/koushikdutta/test/TestActivity.java @@ -25,6 +25,7 @@ import com.koushikdutta.async.ByteBufferList; import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.PushParser; import com.koushikdutta.async.TapCallback; +import com.koushikdutta.async.callback.ClosedCallback; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.ConnectCallback; import com.koushikdutta.async.callback.DataCallback; @@ -81,7 +82,6 @@ public class TestActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - /* AsyncHttpServer server = new AsyncHttpServer(3000); server.get("/", new HttpServerRequestCallback() { @Override @@ -93,13 +93,18 @@ public class TestActivity extends Activity { response.end(); } }); + + server.directory(this, "/bootstrap/.*?", "bootstrap/"); + server.directory(this, "/site/.*?", "site/"); + server.websocket("/test", new WebSocketCallback() { + Process process; @Override public void onConnected(final WebSocket webSocket) { new Thread() { public void run() { try { - final Process process = Runtime.getRuntime().exec("su -c /system/bin/logcat"); + process = Runtime.getRuntime().exec("su -c /system/bin/logcat"); new Thread() { public void run() { try { @@ -139,9 +144,25 @@ public class TestActivity extends Activity { Log.i(TAG, s); } }); + webSocket.setClosedCallback(new ClosedCallback() { + @Override + public void onClosed() { + try { + process.destroy(); + } + catch (Exception e) { + // destroy will cause some angry noise in logcat and throw, since + // we are trying to destroy a root process. + // the kill succeeds, but it still gets angry. + // i assume it succeeds because the various streams are closed. + } + } + }); } }); - */ + + if (true) + return; // try { // ByteArrayOutputStream bout = new ByteArrayOutputStream(); |