aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoushik Dutta <koushd@gmail.com>2012-09-13 17:24:04 -0700
committerKoushik Dutta <koushd@gmail.com>2012-09-13 17:24:04 -0700
commit8c346e2671eb647abd1d5f4cca1126d44dd1c673 (patch)
tree5867559516dcbf456d33dffefeca031c434e8b8d
parente8f4540ccfad8a3031703bc4d0531119933ecaea (diff)
downloadAndroidAsync-8c346e2671eb647abd1d5f4cca1126d44dd1c673.tar.gz
AndroidAsync-8c346e2671eb647abd1d5f4cca1126d44dd1c673.tar.bz2
AndroidAsync-8c346e2671eb647abd1d5f4cca1126d44dd1c673.zip
add support for hosting static content out of the /assets directory.
-rw-r--r--AndroidAsync/gen/com/koushikdutta/async/R.java6
-rw-r--r--AndroidAsync/project.properties2
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/Util.java55
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java71
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java3
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequestImpl.java8
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java4
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/WebSocketImpl.java8
-rw-r--r--AndroidAsync/src/com/koushikdutta/test/TestActivity.java27
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();