├── AndroidAsync
├── res
│ └── .gitignore
├── test
│ ├── assets
│ │ ├── hello.txt
│ │ ├── test.json
│ │ └── 6691924d7d24237d3b3679310157d640
│ ├── res
│ │ ├── raw
│ │ │ └── keystore.bks
│ │ ├── drawable-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-ldpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher.png
│ │ └── values
│ │ │ └── strings.xml
│ └── src
│ │ └── com
│ │ └── koushikdutta
│ │ └── async
│ │ └── test
│ │ ├── TriggerFuture.java
│ │ ├── SanityChecks.java
│ │ ├── BodyTests.java
│ │ ├── ProxyTests.java
│ │ ├── Md5.java
│ │ ├── FileTests.java
│ │ ├── ParserTests.java
│ │ ├── Issue59.java
│ │ ├── SSLTests.java
│ │ ├── ByteUtilTests.java
│ │ ├── RedirectTests.java
│ │ ├── CacheTests.java
│ │ ├── WebSocketTests.java
│ │ ├── DnsTests.java
│ │ └── TimeoutTests.java
├── lint.xml
├── ic_launcher-web.png
├── src
│ └── com
│ │ └── koushikdutta
│ │ └── async
│ │ ├── TapCallback.java
│ │ ├── callback
│ │ ├── WritableCallback.java
│ │ ├── CompletedCallback.java
│ │ ├── ResultCallback.java
│ │ ├── ConnectCallback.java
│ │ ├── ContinuationCallback.java
│ │ ├── DataCallback.java
│ │ └── ListenCallback.java
│ │ ├── future
│ │ ├── DependentFuture.java
│ │ ├── FutureRunnable.java
│ │ ├── DependentCancellable.java
│ │ ├── ConvertFuture.java
│ │ ├── Future.java
│ │ ├── FutureCallback.java
│ │ ├── Cancellable.java
│ │ ├── FutureThread.java
│ │ ├── TransformFuture.java
│ │ ├── HandlerFuture.java
│ │ └── SimpleCancellable.java
│ │ ├── http
│ │ ├── server
│ │ │ ├── MalformedRangeException.java
│ │ │ ├── StreamSkipException.java
│ │ │ ├── HttpServerRequestCallback.java
│ │ │ ├── MimeEncodingException.java
│ │ │ ├── AsyncHttpServerRequest.java
│ │ │ ├── AsyncHttpServerResponse.java
│ │ │ └── UnknownRequestBody.java
│ │ ├── socketio
│ │ │ ├── ReconnectCallback.java
│ │ │ ├── StringCallback.java
│ │ │ ├── ConnectCallback.java
│ │ │ ├── Acknowledge.java
│ │ │ ├── ErrorCallback.java
│ │ │ ├── DisconnectCallback.java
│ │ │ ├── EventCallback.java
│ │ │ ├── ExceptionCallback.java
│ │ │ ├── JSONCallback.java
│ │ │ ├── SocketIOException.java
│ │ │ ├── SocketIORequest.java
│ │ │ ├── transport
│ │ │ │ ├── SocketIOTransport.java
│ │ │ │ └── WebSocketTransport.java
│ │ │ └── EventEmitter.java
│ │ ├── BodyDecoderException.java
│ │ ├── ConnectionFailedException.java
│ │ ├── filter
│ │ │ ├── ChunkedDataException.java
│ │ │ ├── PrematureDataEndException.java
│ │ │ ├── DataRemainingException.java
│ │ │ ├── ChunkedOutputFilter.java
│ │ │ ├── ContentLengthFilter.java
│ │ │ └── InflaterInputFilter.java
│ │ ├── WebSocketHandshakeException.java
│ │ ├── AsyncSSLEngineConfigurator.java
│ │ ├── RedirectLimitExceededException.java
│ │ ├── callback
│ │ │ ├── HttpConnectCallback.java
│ │ │ └── RequestCallback.java
│ │ ├── AsyncHttpHead.java
│ │ ├── ConnectionClosedException.java
│ │ ├── AsyncHttpPost.java
│ │ ├── AsyncHttpGet.java
│ │ ├── body
│ │ │ ├── StringPart.java
│ │ │ ├── AsyncHttpRequestBody.java
│ │ │ ├── FilePart.java
│ │ │ ├── StreamPart.java
│ │ │ ├── FileBody.java
│ │ │ ├── StreamBody.java
│ │ │ ├── JSONArrayBody.java
│ │ │ ├── JSONObjectBody.java
│ │ │ ├── StringBody.java
│ │ │ ├── Part.java
│ │ │ ├── DocumentBody.java
│ │ │ └── UrlEncodedFormBody.java
│ │ ├── AsyncHttpResponse.java
│ │ ├── SimpleMiddleware.java
│ │ ├── WebSocket.java
│ │ ├── libcore
│ │ │ ├── Objects.java
│ │ │ ├── ResponseSource.java
│ │ │ ├── HttpDate.java
│ │ │ └── HeaderParser.java
│ │ ├── AsyncHttpClientMiddleware.java
│ │ └── Multimap.java
│ │ ├── AsyncServerSocket.java
│ │ ├── AsyncSocket.java
│ │ ├── HostnameResolutionException.java
│ │ ├── wrapper
│ │ ├── DataEmitterWrapper.java
│ │ └── AsyncSocketWrapper.java
│ │ ├── AsyncSSLSocket.java
│ │ ├── NullDataCallback.java
│ │ ├── util
│ │ ├── Charsets.java
│ │ ├── UntypedHashtable.java
│ │ ├── FileUtility.java
│ │ ├── Allocator.java
│ │ ├── HashList.java
│ │ └── StreamUtility.java
│ │ ├── DataTrackingEmitter.java
│ │ ├── AsyncSSLException.java
│ │ ├── parser
│ │ ├── AsyncParser.java
│ │ ├── JSONObjectParser.java
│ │ ├── JSONArrayParser.java
│ │ ├── StringParser.java
│ │ ├── DocumentParser.java
│ │ └── ByteBufferListParser.java
│ │ ├── DataEmitter.java
│ │ ├── DataSink.java
│ │ ├── stream
│ │ ├── FileDataSink.java
│ │ ├── ByteBufferListInputStream.java
│ │ ├── OutputStreamDataCallback.java
│ │ └── OutputStreamDataSink.java
│ │ ├── LineEmitter.java
│ │ ├── DataEmitterBase.java
│ │ ├── FilteredDataSink.java
│ │ ├── DataEmitterReader.java
│ │ ├── ThreadQueue.java
│ │ ├── ChannelWrapper.java
│ │ ├── ZipDataSink.java
│ │ ├── SocketChannelWrapper.java
│ │ ├── AsyncDatagramSocket.java
│ │ ├── ServerSocketChannelWrapper.java
│ │ ├── FilteredDataEmitter.java
│ │ ├── DatagramChannelWrapper.java
│ │ ├── SelectorWrapper.java
│ │ ├── AsyncSemaphore.java
│ │ ├── BufferedDataEmitter.java
│ │ ├── FileDataEmitter.java
│ │ └── BufferedDataSink.java
├── AndroidManifest.xml
├── .classpath
├── project.properties
├── Android.mk
├── .project
├── proguard-project.txt
├── build.gradle
└── build.xml
├── tether.png
├── desksms.png
├── rommanager.png
├── AndroidAsyncSample
├── ic_launcher-web.png
├── res
│ ├── values
│ │ ├── styles.xml
│ │ └── strings.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_action_search.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_action_search.png
│ ├── drawable-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_action_search.png
│ ├── menu
│ │ └── activity_main.xml
│ └── layout
│ │ └── activity_main.xml
├── .classpath
├── project.properties
├── proguard-project.txt
├── .project
├── AndroidManifest.xml
├── AndroidAsyncSample.iml
└── build.xml
├── .gitignore
├── .classpath
├── LICENSE
└── .project
/AndroidAsync/res/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/AndroidAsync/test/assets/hello.txt:
--------------------------------------------------------------------------------
1 | hello world
--------------------------------------------------------------------------------
/AndroidAsync/test/assets/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": "bar"
3 | }
--------------------------------------------------------------------------------
/AndroidAsync/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/tether.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/tether.png
--------------------------------------------------------------------------------
/desksms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/desksms.png
--------------------------------------------------------------------------------
/rommanager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/rommanager.png
--------------------------------------------------------------------------------
/AndroidAsync/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/ic_launcher-web.png
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/TapCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 |
4 | public interface TapCallback {
5 | }
6 |
--------------------------------------------------------------------------------
/AndroidAsync/test/res/raw/keystore.bks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/res/raw/keystore.bks
--------------------------------------------------------------------------------
/AndroidAsyncSample/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/ic_launcher-web.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | .settings
3 | local.properties
4 | gen
5 | .gradle
6 | build
7 | .idea/
8 | .DS_Store
9 |
10 | okhttp
11 | okio
12 | libs
13 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/AndroidAsync/test/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsync/test/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsync/test/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsync/test/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidAsync/test/assets/6691924d7d24237d3b3679310157d640:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsync/test/assets/6691924d7d24237d3b3679310157d640
--------------------------------------------------------------------------------
/AndroidAsync/test/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AndroidAsyncTestTest
5 |
6 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-hdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-hdpi/ic_action_search.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-mdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-mdpi/ic_action_search.png
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/drawable-xhdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wordpress-mobile/AndroidAsync/master/AndroidAsyncSample/res/drawable-xhdpi/ic_action_search.png
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/WritableCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | public interface WritableCallback {
4 | public void onWriteable();
5 | }
6 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/DependentFuture.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | public interface DependentFuture extends Future, DependentCancellable {
4 | }
5 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/MalformedRangeException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | public class MalformedRangeException extends Exception {
4 | }
5 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/ReconnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | public interface ReconnectCallback {
4 | public void onReconnect();
5 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncServerSocket.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | public interface AsyncServerSocket {
4 | public void stop();
5 | public int getLocalPort();
6 | }
7 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncSocket.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 |
4 | public interface AsyncSocket extends DataEmitter, DataSink {
5 | public AsyncServer getServer();
6 | }
7 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/CompletedCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | public interface CompletedCallback {
4 | public void onCompleted(Exception ex);
5 | }
6 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/ResultCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | public interface ResultCallback {
4 | public void onCompleted(Exception e, S source, T result);
5 | }
6 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/StringCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | public interface StringCallback {
4 | public void onString(String string, Acknowledge acknowledge);
5 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/FutureRunnable.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | /**
4 | * Created by koush on 12/22/13.
5 | */
6 | public interface FutureRunnable {
7 | T run() throws Exception;
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/ConnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | public interface ConnectCallback {
4 | public void onConnectCompleted(Exception ex, SocketIOClient client);
5 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/Acknowledge.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | import org.json.JSONArray;
4 |
5 | public interface Acknowledge {
6 | void acknowledge(JSONArray arguments);
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/DependentCancellable.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | public interface DependentCancellable extends Cancellable {
4 | public DependentCancellable setParent(Cancellable parent);
5 | }
6 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/ErrorCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | /**
4 | * Created by koush on 7/2/13.
5 | */
6 | public interface ErrorCallback {
7 | void onError(String error);
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/BodyDecoderException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | public class BodyDecoderException extends Exception {
4 | public BodyDecoderException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/DisconnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | /**
4 | * Created by koush on 7/2/13.
5 | */
6 | public interface DisconnectCallback {
7 | void onDisconnect(Exception e);
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/EventCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | import org.json.JSONArray;
4 |
5 | public interface EventCallback {
6 | public void onEvent(JSONArray argument, Acknowledge acknowledge);
7 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/ExceptionCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | /**
4 | * Created by koush on 8/1/13.
5 | */
6 | public interface ExceptionCallback {
7 | public void onException(Exception e);
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/HostnameResolutionException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | public class HostnameResolutionException extends Exception {
4 | public HostnameResolutionException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/StreamSkipException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | public class StreamSkipException extends Exception {
4 | public StreamSkipException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/ConnectionFailedException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | public class ConnectionFailedException extends Exception {
4 | public ConnectionFailedException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedDataException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | public class ChunkedDataException extends Exception {
4 | public ChunkedDataException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/JSONCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | import org.json.JSONObject;
4 |
5 | public interface JSONCallback {
6 | public void onJSON(JSONObject json, Acknowledge acknowledge);
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/wrapper/DataEmitterWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.wrapper;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 |
5 | public interface DataEmitterWrapper extends DataEmitter {
6 | public DataEmitter getDataEmitter();
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/ConnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 |
5 | public interface ConnectCallback {
6 | public void onConnectCompleted(Exception ex, AsyncSocket socket);
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/WebSocketHandshakeException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | public class WebSocketHandshakeException extends Exception {
4 | public WebSocketHandshakeException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/HttpServerRequestCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 |
4 | public interface HttpServerRequestCallback {
5 | public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response);
6 | }
7 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/MimeEncodingException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | public class MimeEncodingException extends Exception {
4 | public MimeEncodingException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLEngineConfigurator.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import javax.net.ssl.SSLEngine;
4 |
5 | public interface AsyncSSLEngineConfigurator {
6 | public void configureEngine(SSLEngine engine, String host, int port);
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/RedirectLimitExceededException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | public class RedirectLimitExceededException extends Exception {
4 | public RedirectLimitExceededException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/PrematureDataEndException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | public class PrematureDataEndException extends Exception {
4 | public PrematureDataEndException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/wrapper/AsyncSocketWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.wrapper;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 |
5 | public interface AsyncSocketWrapper extends AsyncSocket, DataEmitterWrapper {
6 | public AsyncSocket getSocket();
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/TriggerFuture.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.future.SimpleFuture;
4 |
5 | class TriggerFuture extends SimpleFuture {
6 | public void trigger() {
7 | setComplete(2020);
8 | }
9 | }
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/menu/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/DataRemainingException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | public class DataRemainingException extends Exception {
4 | public DataRemainingException(String message, Exception cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/callback/HttpConnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.callback;
2 |
3 |
4 | import com.koushikdutta.async.http.AsyncHttpResponse;
5 |
6 | public interface HttpConnectCallback {
7 | public void onConnectCompleted(Exception ex, AsyncHttpResponse response);
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/ContinuationCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | import com.koushikdutta.async.future.Continuation;
4 |
5 | public interface ContinuationCallback {
6 | public void onContinue(Continuation continuation, CompletedCallback next) throws Exception;
7 | }
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/SocketIOException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | /**
4 | * Created by koush on 8/1/13.
5 | */
6 | public class SocketIOException extends Exception {
7 | public SocketIOException(String error) {
8 | super(error);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/DataCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 |
6 |
7 | public interface DataCallback {
8 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb);
9 | }
10 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocket.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.security.cert.X509Certificate;
4 |
5 | import javax.net.ssl.SSLEngine;
6 |
7 | public interface AsyncSSLSocket extends AsyncSocket {
8 | public X509Certificate[] getPeerCertificates();
9 | public SSLEngine getSSLEngine();
10 | }
11 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/NullDataCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.DataCallback;
4 |
5 | public class NullDataCallback implements DataCallback {
6 | @Override
7 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
8 | bb.recycle();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidAsyncSample
4 | Hello world!
5 | Settings
6 | AndroidAsync Sample
7 | Download Images
8 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/Charsets.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import java.nio.charset.Charset;
4 |
5 | /** From java.nio.charset.Charsets */
6 | public class Charsets {
7 | public static final Charset US_ASCII = Charset.forName("US-ASCII");
8 | public static final Charset UTF_8 = Charset.forName("UTF-8");
9 | }
10 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpHead.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import android.net.Uri;
4 |
5 | /**
6 | * Created by koush on 8/25/13.
7 | */
8 | public class AsyncHttpHead extends AsyncHttpRequest {
9 | public AsyncHttpHead(Uri uri) {
10 | super(uri, METHOD);
11 | }
12 |
13 | public static final String METHOD = "HEAD";
14 | }
15 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/callback/ListenCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.callback;
2 |
3 | import com.koushikdutta.async.AsyncServerSocket;
4 | import com.koushikdutta.async.AsyncSocket;
5 |
6 |
7 | public interface ListenCallback extends CompletedCallback {
8 | public void onAccepted(AsyncSocket socket);
9 | public void onListening(AsyncServerSocket socket);
10 | }
11 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/ConnectionClosedException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | public class ConnectionClosedException extends Exception {
4 | public ConnectionClosedException(String message) {
5 | super(message);
6 | }
7 |
8 | public ConnectionClosedException(String detailMessage, Throwable throwable) {
9 | super(detailMessage, throwable);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpPost.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import android.net.Uri;
4 |
5 | public class AsyncHttpPost extends AsyncHttpRequest {
6 | public static final String METHOD = "POST";
7 |
8 | public AsyncHttpPost(String uri) {
9 | this(Uri.parse(uri));
10 | }
11 |
12 | public AsyncHttpPost(Uri uri) {
13 | super(uri, METHOD);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpGet.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import android.net.Uri;
4 |
5 | public class AsyncHttpGet extends AsyncHttpRequest {
6 | public static final String METHOD = "GET";
7 |
8 | public AsyncHttpGet(String uri) {
9 | super(Uri.parse(uri), METHOD);
10 | }
11 |
12 | public AsyncHttpGet(Uri uri) {
13 | super(uri, METHOD);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/ConvertFuture.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | /**
4 | * Created by koush on 6/21/14.
5 | */
6 | public abstract class ConvertFuture extends TransformFuture {
7 | @Override
8 | protected final void transform(F result) throws Exception {
9 | setComplete(convert(result));
10 | }
11 |
12 | protected abstract Future convert(F result) throws Exception;
13 | }
14 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/SanityChecks.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import junit.framework.TestCase;
4 |
5 | import java.nio.ByteBuffer;
6 | import java.nio.ByteOrder;
7 |
8 | /**
9 | * Created by koush on 5/15/13.
10 | */
11 | public class SanityChecks extends TestCase {
12 | public void testByteOrder() {
13 | assertTrue(ByteBuffer.allocate(0).order().equals(ByteOrder.BIG_ENDIAN));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidAsync/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/Future.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 |
4 | public interface Future extends Cancellable, java.util.concurrent.Future {
5 | /**
6 | * Set a callback to be invoked when this Future completes.
7 | * @param callback
8 | * @return
9 | */
10 | public Future setCallback(FutureCallback callback);
11 | public > C then(C callback);
12 | }
13 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DataTrackingEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | /**
4 | * Created by koush on 5/28/13.
5 | */
6 | public interface DataTrackingEmitter extends DataEmitter {
7 | public interface DataTracker {
8 | void onData(int totalBytesRead);
9 | }
10 | void setDataTracker(DataTracker tracker);
11 | DataTracker getDataTracker();
12 | int getBytesRead();
13 | void setDataEmitter(DataEmitter emitter);
14 | }
15 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/callback/RequestCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.callback;
2 |
3 | import com.koushikdutta.async.callback.ResultCallback;
4 | import com.koushikdutta.async.http.AsyncHttpResponse;
5 |
6 | public interface RequestCallback extends ResultCallback {
7 | public void onConnect(AsyncHttpResponse response);
8 | public void onProgress(AsyncHttpResponse response, long downloaded, long total);
9 | }
10 |
--------------------------------------------------------------------------------
/AndroidAsync/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/FutureCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | /**
4 | * Created by koush on 5/20/13.
5 | */
6 | public interface FutureCallback {
7 | /**
8 | * onCompleted is called by the Future with the result or exception of the asynchronous operation.
9 | * @param e Exception encountered by the operation
10 | * @param result Result returned from the operation
11 | */
12 | public void onCompleted(Exception e, T result);
13 | }
14 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncSSLException.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | public class AsyncSSLException extends Exception {
4 | public AsyncSSLException(Throwable cause) {
5 | super("Peer not trusted by any of the system trust managers.", cause);
6 | }
7 | private boolean mIgnore = false;
8 | public void setIgnore(boolean ignore) {
9 | mIgnore = ignore;
10 | }
11 |
12 | public boolean getIgnore() {
13 | return mIgnore;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/AsyncParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.future.Future;
7 |
8 | /**
9 | * Created by koush on 5/27/13.
10 | */
11 | public interface AsyncParser {
12 | Future parse(DataEmitter emitter);
13 | void write(DataSink sink, T value, CompletedCallback completed);
14 | }
15 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/StringPart.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | public class StringPart extends StreamPart {
8 | String value;
9 | public StringPart(String name, String value) {
10 | super(name, value.getBytes().length, null);
11 | this.value = value;
12 | }
13 |
14 | @Override
15 | protected InputStream getInputStream() throws IOException {
16 | return new ByteArrayInputStream(value.getBytes());
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/BodyTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.test.AndroidTestCase;
4 |
5 | import com.koushikdutta.async.http.Multimap;
6 | import com.koushikdutta.async.http.body.UrlEncodedFormBody;
7 |
8 | /**
9 | * Created by koush on 3/19/14.
10 | */
11 | public class BodyTests extends AndroidTestCase {
12 | public void testNullValue() throws Exception {
13 | Multimap mm = new Multimap();
14 | mm.add("hello", null);
15 | UrlEncodedFormBody body = new UrlEncodedFormBody(mm);
16 |
17 | int length = body.length();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2013 Koushik Dutta (2013)
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/Cancellable.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | public interface Cancellable {
4 | /**
5 | * Check whether this asynchronous operation completed successfully.
6 | * @return
7 | */
8 | boolean isDone();
9 |
10 | /**
11 | * Check whether this asynchronous operation has been cancelled.
12 | * @return
13 | */
14 | boolean isCancelled();
15 |
16 | /**
17 | * Attempt to cancel this asynchronous operation.
18 | * @return The return value is whether the operation cancelled successfully.
19 | */
20 | boolean cancel();
21 | }
22 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/FutureThread.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | /**
4 | * Created by koush on 12/22/13.
5 | */
6 | public class FutureThread extends SimpleFuture {
7 | public FutureThread(final FutureRunnable runnable) {
8 | new Thread(new Runnable() {
9 | @Override
10 | public void run() {
11 | try {
12 | setComplete(runnable.run());
13 | }
14 | catch (Exception e) {
15 | setComplete(e);
16 | }
17 | }
18 | }).start();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/AndroidAsync/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/AsyncHttpRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.http.AsyncHttpRequest;
7 |
8 | public interface AsyncHttpRequestBody {
9 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed);
10 | public void parse(DataEmitter emitter, CompletedCallback completed);
11 | public String getContentType();
12 | public boolean readFullyOnRequest();
13 | public int length();
14 | public T get();
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 | android.library.reference.1=../AndroidAsync
16 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DataEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.DataCallback;
5 |
6 | public interface DataEmitter {
7 | public void setDataCallback(DataCallback callback);
8 | public DataCallback getDataCallback();
9 | public boolean isChunked();
10 | public void pause();
11 | public void resume();
12 | public void close();
13 | public boolean isPaused();
14 | public void setEndCallback(CompletedCallback callback);
15 | public CompletedCallback getEndCallback();
16 | public AsyncServer getServer();
17 | public String charset();
18 | }
19 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponse.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.DataSink;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.http.libcore.ResponseHeaders;
8 |
9 | public interface AsyncHttpResponse extends AsyncSocket {
10 | public void setEndCallback(CompletedCallback handler);
11 | public CompletedCallback getEndCallback();
12 | public ResponseHeaders getHeaders();
13 | public void end();
14 | public AsyncSocket detachSocket();
15 | public AsyncHttpRequest getRequest();
16 | }
17 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/UntypedHashtable.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import java.util.Hashtable;
4 |
5 | public class UntypedHashtable {
6 | private Hashtable hash = new Hashtable();
7 |
8 | public void put(String key, Object value) {
9 | hash.put(key, value);
10 | }
11 |
12 | public void remove(String key) {
13 | hash.remove(key);
14 | }
15 |
16 | public T get(String key, T defaultValue) {
17 | T ret = get(key);
18 | if (ret == null)
19 | return defaultValue;
20 | return ret;
21 | }
22 |
23 | public T get(String key) {
24 | return (T)hash.get(key);
25 | }
26 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.callback.WritableCallback;
7 |
8 | public interface DataSink {
9 | public void write(ByteBuffer bb);
10 | public void write(ByteBufferList bb);
11 | public void setWriteableCallback(WritableCallback handler);
12 | public WritableCallback getWriteableCallback();
13 |
14 | public boolean isOpen();
15 | public void close();
16 | public void end();
17 | public void setClosedCallback(CompletedCallback handler);
18 | public CompletedCallback getClosedCallback();
19 | public AsyncServer getServer();
20 | }
21 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/TransformFuture.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | public abstract class TransformFuture extends SimpleFuture implements FutureCallback {
4 | @Override
5 | public void onCompleted(Exception e, F result) {
6 | if (isCancelled())
7 | return;
8 | if (e != null) {
9 | error(e);
10 | return;
11 | }
12 |
13 | try {
14 | transform(result);
15 | }
16 | catch (Exception ex) {
17 | error(ex);
18 | }
19 | }
20 |
21 | protected void error(Exception e) {
22 | setComplete(e);
23 | }
24 |
25 | protected abstract void transform(F result) throws Exception;
26 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import com.koushikdutta.async.ByteBufferList;
6 | import com.koushikdutta.async.DataSink;
7 | import com.koushikdutta.async.FilteredDataSink;
8 |
9 | public class ChunkedOutputFilter extends FilteredDataSink {
10 | public ChunkedOutputFilter(DataSink sink) {
11 | super(sink);
12 | }
13 |
14 | @Override
15 | public ByteBufferList filter(ByteBufferList bb) {
16 | String chunkLen = Integer.toString(bb.remaining(), 16) + "\r\n";
17 | bb.addFirst(ByteBuffer.wrap(chunkLen.getBytes()));
18 | bb.add(ByteBuffer.wrap("\r\n".getBytes()));
19 | return bb;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerRequest.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
6 | import com.koushikdutta.async.http.Multimap;
7 | import com.koushikdutta.async.http.libcore.RequestHeaders;
8 |
9 | import java.util.regex.Matcher;
10 |
11 | public interface AsyncHttpServerRequest extends DataEmitter {
12 | public RequestHeaders getHeaders();
13 | public Matcher getMatcher();
14 | public AsyncHttpRequestBody getBody();
15 | public AsyncSocket getSocket();
16 | public String getPath();
17 | public Multimap getQuery();
18 | public String getMethod();
19 | }
20 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import com.koushikdutta.async.future.Cancellable;
4 |
5 | public class SimpleMiddleware implements AsyncHttpClientMiddleware {
6 |
7 | @Override
8 | public Cancellable getSocket(GetSocketData data) {
9 | return null;
10 | }
11 |
12 | @Override
13 | public void onSocket(OnSocketData data) {
14 |
15 | }
16 |
17 | @Override
18 | public void onHeadersReceived(OnHeadersReceivedData data) {
19 |
20 | }
21 |
22 | @Override
23 | public void onBodyDecoder(OnBodyData data) {
24 |
25 | }
26 |
27 | @Override
28 | public void onRequestComplete(OnRequestCompleteData data) {
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/FileUtility.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import java.io.File;
4 |
5 | /**
6 | * Created by koush on 4/7/14.
7 | */
8 | public class FileUtility {
9 | static public boolean deleteDirectory(File path) {
10 | if (path.exists()) {
11 | File[] files = path.listFiles();
12 | if (files != null) {
13 | for (int i = 0; i < files.length; i++) {
14 | if (files[i].isDirectory()) {
15 | deleteDirectory(files[i]);
16 | }
17 | else {
18 | files[i].delete();
19 | }
20 | }
21 | }
22 | }
23 | return (path.delete());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/ProxyTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.util.Log;
4 |
5 | import com.koushikdutta.async.http.AsyncHttpClient;
6 | import com.koushikdutta.async.http.AsyncHttpGet;
7 |
8 | import junit.framework.TestCase;
9 |
10 | import java.util.concurrent.TimeUnit;
11 |
12 | /**
13 | * Created by koush on 4/20/14.
14 | */
15 | public class ProxyTests extends TestCase {
16 | private void disabledTestSSLProxy() throws Exception {
17 | AsyncHttpGet get = new AsyncHttpGet("http://yahoo.com");
18 | get.enableProxy("192.168.2.21", 8888);
19 | get.setLogging("SSLProxy", Log.VERBOSE);
20 | String ret = AsyncHttpClient.getDefaultInstance().executeString(get, null).get(5000, TimeUnit.DAYS.MILLISECONDS);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/stream/FileDataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.stream;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 |
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 |
10 | /**
11 | * Created by koush on 2/2/14.
12 | */
13 | public class FileDataSink extends OutputStreamDataSink {
14 | File file;
15 | public FileDataSink(AsyncServer server, File file) {
16 | super(server);
17 | this.file = file;
18 | }
19 |
20 | @Override
21 | public OutputStream getOutputStream() throws IOException {
22 | OutputStream ret = super.getOutputStream();
23 | if (ret == null) {
24 | ret = new FileOutputStream(file);
25 | setOutputStream(ret);
26 | }
27 | return ret;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/AndroidAsync/Android.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2011 The Android Open Source Project
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | LOCAL_PATH := $(call my-dir)
18 |
19 | include $(CLEAR_VARS)
20 |
21 | LOCAL_MODULE := AndroidAsync
22 | LOCAL_SDK_VERSION := 8
23 | LOCAL_SRC_FILES := $(call all-java-files-under, src)
24 |
25 | include $(BUILD_STATIC_JAVA_LIBRARY)
26 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/WebSocket.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 |
5 |
6 | public interface WebSocket extends AsyncSocket {
7 | static public interface StringCallback {
8 | public void onStringAvailable(String s);
9 | }
10 | static public interface PongCallback {
11 | public void onPongReceived(String s);
12 | }
13 |
14 | public void send(byte[] bytes);
15 | public void send(String string);
16 | public void send(byte [] bytes, int offset, int len);
17 | public void ping(String message);
18 |
19 | public void setStringCallback(StringCallback callback);
20 | public StringCallback getStringCallback();
21 |
22 | public void setPongCallback(PongCallback callback);
23 | public PongCallback getPongCallback();
24 |
25 | public boolean isBuffering();
26 |
27 | public AsyncSocket getSocket();
28 | }
29 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidAsync
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidAsync/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidAsync
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/FilePart.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import org.apache.http.NameValuePair;
4 | import org.apache.http.message.BasicNameValuePair;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.util.ArrayList;
11 |
12 | public class FilePart extends StreamPart {
13 | File file;
14 | public FilePart(String name, final File file) {
15 | super(name, (int)file.length(), new ArrayList() {
16 | {
17 | add(new BasicNameValuePair("filename", file.getName()));
18 | }
19 | });
20 |
21 | // getRawHeaders().set("Content-Type", "application/xml");
22 |
23 | this.file = file;
24 | }
25 |
26 | @Override
27 | protected InputStream getInputStream() throws IOException {
28 | return new FileInputStream(file);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/Md5.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 |
5 | import java.math.BigInteger;
6 | import java.nio.ByteBuffer;
7 | import java.security.MessageDigest;
8 | import java.security.NoSuchAlgorithmException;
9 |
10 | public class Md5 {
11 | private MessageDigest digest;
12 | public static Md5 createInstance() throws NoSuchAlgorithmException {
13 | Md5 md5 = new Md5();
14 | md5.digest = MessageDigest.getInstance("MD5");
15 | return md5;
16 | }
17 |
18 | private Md5() {
19 |
20 | }
21 | public void update(ByteBufferList bb) {
22 | while (bb.size() > 0) {
23 | ByteBuffer b = bb.remove();
24 | digest.update(b);
25 | }
26 | }
27 |
28 | public String digest() {
29 | String hash = new BigInteger(digest.digest()).toString(16);
30 | return hash;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidAsyncSample
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidAsync/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
22 | -keep class * extends com.koushikdutta.async.TapCallback {
23 | public protected private *;
24 | }
25 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/SocketIORequest.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | import android.net.Uri;
4 | import android.text.TextUtils;
5 |
6 | import com.koushikdutta.async.http.AsyncHttpPost;
7 |
8 | public class SocketIORequest extends AsyncHttpPost {
9 | public SocketIORequest(String uri) {
10 | this(uri, "");
11 | }
12 |
13 | String endpoint;
14 | public String getEndpoint() {
15 | return endpoint;
16 | }
17 |
18 | String query;
19 | public String getQuery() {
20 | return query;
21 | }
22 |
23 | public SocketIORequest(String uri, String endpoint) {
24 | this(uri, endpoint, null);
25 | }
26 |
27 | public SocketIORequest(String uri, String endpoint, String query) {
28 | super(Uri.parse(uri + (query == null ? "" : "?" + query)).buildUpon().encodedPath("/socket.io/1/").build().toString());
29 | this.endpoint = endpoint;
30 | this.query = query;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/StreamPart.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.util.List;
6 |
7 | import org.apache.http.NameValuePair;
8 |
9 | import com.koushikdutta.async.DataSink;
10 | import com.koushikdutta.async.callback.CompletedCallback;
11 |
12 | public abstract class StreamPart extends Part {
13 | public StreamPart(String name, long length, List contentDisposition) {
14 | super(name, length, contentDisposition);
15 | }
16 |
17 | @Override
18 | public void write(DataSink sink, CompletedCallback callback) {
19 | try {
20 | InputStream is = getInputStream();
21 | com.koushikdutta.async.Util.pump(is, sink, callback);
22 | }
23 | catch (Exception e) {
24 | callback.onCompleted(e);
25 | }
26 | }
27 |
28 | protected abstract InputStream getInputStream() throws IOException;
29 | }
30 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/AndroidAsyncSample.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | MANIFEST_FILE_PATH
8 | RESOURCES_DIR_PATH
9 | ASSETS_DIR_PATH
10 | NATIVE_LIBS_DIR_PATH
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/JSONObjectParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.future.Future;
7 | import com.koushikdutta.async.future.TransformFuture;
8 | import org.json.JSONObject;
9 |
10 | /**
11 | * Created by koush on 5/27/13.
12 | */
13 | public class JSONObjectParser implements AsyncParser {
14 | @Override
15 | public Future parse(DataEmitter emitter) {
16 | return new StringParser().parse(emitter)
17 | .then(new TransformFuture() {
18 | @Override
19 | protected void transform(String result) throws Exception {
20 | setComplete(new JSONObject(result));
21 | }
22 | });
23 | }
24 |
25 | @Override
26 | public void write(DataSink sink, JSONObject value, CompletedCallback completed) {
27 | new StringParser().write(sink, value.toString(), completed);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/stream/ByteBufferListInputStream.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.stream;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 |
8 | /**
9 | * Created by koush on 6/1/13.
10 | */
11 | public class ByteBufferListInputStream extends InputStream {
12 | ByteBufferList bb;
13 | public ByteBufferListInputStream(ByteBufferList bb) {
14 | this.bb = bb;
15 | }
16 |
17 | @Override
18 | public int read() throws IOException {
19 | if (bb.remaining() <= 0)
20 | return -1;
21 | return bb.get();
22 | }
23 |
24 | @Override
25 | public int read(byte[] buffer) throws IOException {
26 | return this.read(buffer, 0, buffer.length);
27 | }
28 |
29 | @Override
30 | public int read(byte[] buffer, int offset, int length) throws IOException {
31 | if (bb.remaining() <= 0)
32 | return -1;
33 | int toRead = Math.min(length, bb.remaining());
34 | bb.get(buffer, offset, toRead);
35 | return toRead;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/JSONArrayParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.future.Future;
7 | import com.koushikdutta.async.future.TransformFuture;
8 |
9 | import org.json.JSONArray;
10 | import org.json.JSONObject;
11 |
12 | /**
13 | * Created by koush on 5/27/13.
14 | */
15 | public class JSONArrayParser implements AsyncParser {
16 | @Override
17 | public Future parse(DataEmitter emitter) {
18 | return new StringParser().parse(emitter)
19 | .then(new TransformFuture() {
20 | @Override
21 | protected void transform(String result) throws Exception {
22 | setComplete(new JSONArray(result));
23 | }
24 | });
25 | }
26 |
27 | @Override
28 | public void write(DataSink sink, JSONArray value, CompletedCallback completed) {
29 | new StringParser().write(sink, value.toString(), completed);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/transport/SocketIOTransport.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio.transport;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 | import com.koushikdutta.async.callback.CompletedCallback;
5 |
6 | /**
7 | * A socket.io transport.
8 | *
9 | * Please, refer to the documentation in https://github.com/LearnBoost/socket.io-spec
10 | */
11 | public interface SocketIOTransport {
12 | static public interface StringCallback {
13 | public void onStringAvailable(String s);
14 | }
15 |
16 | /**
17 | * Send message to the server
18 | * @param string
19 | */
20 | public void send(String string);
21 |
22 | /**
23 | * Close connection
24 | */
25 | public void disconnect();
26 |
27 | public void setStringCallback(StringCallback callback);
28 | public void setClosedCallback(CompletedCallback handler);
29 |
30 | public AsyncServer getServer();
31 | public boolean isConnected();
32 |
33 | /**
34 | * Indicates whether heartbeats are enabled for this transport
35 | * @return
36 | */
37 | public boolean heartbeats();
38 | }
39 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/LineEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.DataCallback;
4 |
5 | public class LineEmitter implements DataCallback {
6 | static public interface StringCallback {
7 | public void onStringAvailable(String s);
8 | }
9 |
10 | StringBuilder data = new StringBuilder();
11 |
12 | StringCallback mLineCallback;
13 | public void setLineCallback(StringCallback callback) {
14 | mLineCallback = callback;
15 | }
16 |
17 | public StringCallback getLineCallback() {
18 | return mLineCallback;
19 | }
20 |
21 | @Override
22 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
23 | while (bb.remaining() > 0) {
24 | byte b = bb.get();
25 | if (b == '\n') {
26 | assert mLineCallback != null;
27 | mLineCallback.onStringAvailable(data.toString());
28 | data = new StringBuilder();
29 | return;
30 | }
31 | else {
32 | data.append((char)b);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/AndroidAsync/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url 'http://repo1.maven.org/maven2' }
4 | }
5 | dependencies {
6 | classpath 'com.android.tools.build:gradle:+'
7 | }
8 | }
9 | apply plugin: 'com.android.library'
10 |
11 | android {
12 | sourceSets {
13 | main {
14 | manifest.srcFile 'AndroidManifest.xml'
15 |
16 | jniLibs.srcDirs = ['libs/']
17 |
18 | java.srcDirs=['src/'
19 | // , '../conscrypt/'
20 | // , '../compat/'
21 | ]
22 | }
23 | androidTest.java.srcDirs=['test/src/']
24 | androidTest.res.srcDirs=['test/res/']
25 | androidTest.assets.srcDirs=['test/assets/']
26 | }
27 |
28 | lintOptions {
29 | abortOnError false
30 | }
31 |
32 | defaultConfig {
33 | minSdkVersion 9
34 | targetSdkVersion 19
35 | }
36 |
37 | compileSdkVersion 19
38 | buildToolsVersion "20.0.0"
39 | }
40 |
41 | // upload to maven task
42 | if (System.getenv().I_AM_KOUSH == 'true') {
43 | apply from: 'https://raw.githubusercontent.com/koush/mvn-repo/master/maven.gradle'
44 | }
45 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/libcore/Objects.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.koushikdutta.async.http.libcore;
18 |
19 | public final class Objects {
20 | private Objects() {}
21 |
22 | /**
23 | * Returns true if two possibly-null objects are equal.
24 | */
25 | public static boolean equal(Object a, Object b) {
26 | return a == b || (a != null && a.equals(b));
27 | }
28 |
29 | public static int hashCode(Object o) {
30 | return (o == null) ? 0 : o.hashCode();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | import java.io.File;
4 | import java.io.InputStream;
5 |
6 | import org.json.JSONObject;
7 |
8 | import com.koushikdutta.async.AsyncSocket;
9 | import com.koushikdutta.async.DataSink;
10 | import com.koushikdutta.async.callback.CompletedCallback;
11 | import com.koushikdutta.async.http.libcore.ResponseHeaders;
12 |
13 | public interface AsyncHttpServerResponse extends DataSink, CompletedCallback {
14 | public void end();
15 | public void send(String contentType, String string);
16 | public void send(String string);
17 | public void send(JSONObject json);
18 | public void sendFile(File file);
19 | public void sendStream(InputStream inputStream, long totalLength);
20 | public void responseCode(int code);
21 | public ResponseHeaders getHeaders();
22 | public void writeHead();
23 | public void setContentType(String contentType);
24 | public void redirect(String location);
25 | /**
26 | * Alias for end. Used with CompletedEmitters
27 | */
28 | public void onCompleted(Exception ex);
29 | public AsyncSocket getSocket();
30 | }
31 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/Allocator.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 |
5 | import java.nio.ByteBuffer;
6 |
7 | /**
8 | * Created by koush on 6/28/14.
9 | */
10 | public class Allocator {
11 | final int maxAlloc;
12 | int currentAlloc = 0;
13 | int minAlloc = 2 << 11;
14 |
15 | public Allocator(int maxAlloc) {
16 | this.maxAlloc = maxAlloc;
17 | }
18 |
19 | public Allocator() {
20 | maxAlloc = ByteBufferList.MAX_ITEM_SIZE;
21 | }
22 |
23 | public ByteBuffer allocate() {
24 | return ByteBufferList.obtain(Math.min(Math.max(currentAlloc, minAlloc), maxAlloc));
25 | }
26 |
27 | public void track(long read) {
28 | currentAlloc = (int)read * 2;
29 | }
30 |
31 | public int getMaxAlloc() {
32 | return maxAlloc;
33 | }
34 |
35 | public void setCurrentAlloc(int currentAlloc) {
36 | this.currentAlloc = currentAlloc;
37 | }
38 |
39 | public int getMinAlloc() {
40 | return minAlloc;
41 | }
42 |
43 | public Allocator setMinAlloc(int minAlloc ) {
44 | this.minAlloc = minAlloc;
45 | return this;
46 | }
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/HandlerFuture.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | /**
7 | * Created by koush on 12/25/13.
8 | */
9 | public class HandlerFuture extends SimpleFuture {
10 | Handler handler;
11 |
12 | public HandlerFuture() {
13 | Looper looper = Looper.myLooper();
14 | if (looper == null)
15 | looper = Looper.getMainLooper();
16 | handler = new Handler(looper);
17 | }
18 |
19 | @Override
20 | public SimpleFuture setCallback(final FutureCallback callback) {
21 | FutureCallback wrapped = new FutureCallback() {
22 | @Override
23 | public void onCompleted(final Exception e, final T result) {
24 | if (Looper.myLooper() == handler.getLooper()) {
25 | callback.onCompleted(e, result);
26 | return;
27 | }
28 |
29 | handler.post(new Runnable() {
30 | @Override
31 | public void run() {
32 | onCompleted(e, result);
33 | }
34 | });
35 | }
36 | };
37 | return super.setCallback(wrapped);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/StringParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.DataSink;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.Future;
8 | import com.koushikdutta.async.future.TransformFuture;
9 |
10 | import java.nio.charset.Charset;
11 |
12 | /**
13 | * Created by koush on 5/27/13.
14 | */
15 | public class StringParser implements AsyncParser {
16 | @Override
17 | public Future parse(DataEmitter emitter) {
18 | final String charset = emitter.charset();
19 | return new ByteBufferListParser().parse(emitter)
20 | .then(new TransformFuture() {
21 | @Override
22 | protected void transform(ByteBufferList result) throws Exception {
23 | setComplete(result.readString(charset != null ? Charset.forName(charset) : null));
24 | }
25 | });
26 | }
27 |
28 | @Override
29 | public void write(DataSink sink, String value, CompletedCallback completed) {
30 | new ByteBufferListParser().write(sink, new ByteBufferList(value.getBytes()), completed);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DataEmitterBase.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.DataCallback;
5 |
6 | /**
7 | * Created by koush on 5/27/13.
8 | */
9 | public abstract class DataEmitterBase implements DataEmitter {
10 | private boolean ended;
11 | protected void resetEnded() {
12 | ended = false;
13 | }
14 | protected void report(Exception e) {
15 | if (ended)
16 | return;
17 | ended = true;
18 | if (getEndCallback() != null)
19 | getEndCallback().onCompleted(e);
20 | }
21 |
22 | @Override
23 | public final void setEndCallback(CompletedCallback callback) {
24 | endCallback = callback;
25 | }
26 |
27 | CompletedCallback endCallback;
28 | @Override
29 | public final CompletedCallback getEndCallback() {
30 | return endCallback;
31 | }
32 |
33 |
34 | DataCallback mDataCallback;
35 | @Override
36 | public void setDataCallback(DataCallback callback) {
37 | mDataCallback = callback;
38 | }
39 |
40 | @Override
41 | public DataCallback getDataCallback() {
42 | return mDataCallback;
43 | }
44 |
45 | @Override
46 | public String charset() {
47 | return null;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/libcore/ResponseSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.koushikdutta.async.http.libcore;
18 |
19 | public enum ResponseSource {
20 |
21 | /**
22 | * Return the response from the cache immediately.
23 | */
24 | CACHE,
25 |
26 | /**
27 | * Make a conditional request to the host, returning the cache response if
28 | * the cache is valid and the network response otherwise.
29 | */
30 | CONDITIONAL_CACHE,
31 |
32 | /**
33 | * Return the response from the network.
34 | */
35 | NETWORK;
36 |
37 | public boolean requiresConnection() {
38 | return this == CONDITIONAL_CACHE || this == NETWORK;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/FileBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.http.AsyncHttpRequest;
8 |
9 | import java.io.File;
10 |
11 | /**
12 | * Created by koush on 10/14/13.
13 | */
14 | public class FileBody implements AsyncHttpRequestBody {
15 | File file;
16 | public FileBody(File file) {
17 | this.file = file;
18 | }
19 |
20 | @Override
21 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) {
22 | Util.pump(file, sink, completed);
23 | }
24 |
25 | @Override
26 | public void parse(DataEmitter emitter, CompletedCallback completed) {
27 | throw new AssertionError("not implemented");
28 | }
29 |
30 | public static final String CONTENT_TYPE = "application/binary";
31 | @Override
32 | public String getContentType() {
33 | return CONTENT_TYPE;
34 | }
35 |
36 | @Override
37 | public boolean readFullyOnRequest() {
38 | throw new AssertionError("not implemented");
39 | }
40 |
41 | @Override
42 | public int length() {
43 | return (int)file.length();
44 | }
45 |
46 | @Override
47 | public File get() {
48 | return file;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/ContentLengthFilter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.FilteredDataEmitter;
6 |
7 | public class ContentLengthFilter extends FilteredDataEmitter {
8 | public ContentLengthFilter(long contentLength) {
9 | this.contentLength = contentLength;
10 | }
11 |
12 | @Override
13 | protected void report(Exception e) {
14 | if (e == null && totalRead != contentLength)
15 | e = new PrematureDataEndException("End of data reached before content length was read");
16 | super.report(e);
17 | }
18 |
19 | long contentLength;
20 | long totalRead;
21 | ByteBufferList transformed = new ByteBufferList();
22 | @Override
23 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
24 | assert totalRead < contentLength;
25 |
26 | int remaining = bb.remaining();
27 | long toRead = Math.min(contentLength - totalRead, remaining);
28 |
29 | bb.get(transformed, (int)toRead);
30 |
31 | int beforeRead = transformed.remaining();
32 |
33 | super.onDataAvailable(emitter, transformed);
34 |
35 | totalRead += (beforeRead - transformed.remaining());
36 | transformed.get(bb);
37 |
38 | if (totalRead == contentLength)
39 | report(null);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/FileTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 | import com.koushikdutta.async.FileDataEmitter;
5 | import com.koushikdutta.async.future.Future;
6 | import com.koushikdutta.async.future.FutureCallback;
7 | import com.koushikdutta.async.parser.StringParser;
8 | import com.koushikdutta.async.util.StreamUtility;
9 |
10 | import junit.framework.TestCase;
11 |
12 | import java.io.File;
13 | import java.util.concurrent.Semaphore;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * Created by koush on 5/22/13.
18 | */
19 | public class FileTests extends TestCase {
20 | public static final long TIMEOUT = 1000L;
21 | public void testFileDataEmitter() throws Exception {
22 | final Semaphore semaphore = new Semaphore(0);
23 | File f = new File("/sdcard/test.txt");
24 | StreamUtility.writeFile(f, "hello world");
25 | FileDataEmitter fdm = new FileDataEmitter(AsyncServer.getDefault(), f);
26 | final Md5 md5 = Md5.createInstance();
27 | Future stringBody = new StringParser().parse(fdm)
28 | .setCallback(new FutureCallback() {
29 | @Override
30 | public void onCompleted(Exception e, String result) {
31 | semaphore.release();
32 | }
33 | });
34 | fdm.resume();
35 |
36 | assertTrue("timeout", semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS));
37 | assertEquals("hello world", stringBody.get());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/DocumentParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.DataSink;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.Future;
8 | import com.koushikdutta.async.future.TransformFuture;
9 | import com.koushikdutta.async.http.body.DocumentBody;
10 | import com.koushikdutta.async.stream.ByteBufferListInputStream;
11 |
12 | import org.w3c.dom.Document;
13 |
14 | import javax.xml.parsers.DocumentBuilder;
15 | import javax.xml.parsers.DocumentBuilderFactory;
16 |
17 | /**
18 | * Created by koush on 8/3/13.
19 | */
20 | public class DocumentParser implements AsyncParser {
21 | @Override
22 | public Future parse(DataEmitter emitter) {
23 | return new ByteBufferListParser().parse(emitter)
24 | .then(new TransformFuture() {
25 | @Override
26 | protected void transform(ByteBufferList result) throws Exception {
27 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
28 | DocumentBuilder db = dbf.newDocumentBuilder();
29 | setComplete(db.parse(new ByteBufferListInputStream(result)));
30 | }
31 | });
32 | }
33 |
34 | @Override
35 | public void write(DataSink sink, Document value, CompletedCallback completed) {
36 | new DocumentBody(value).write(null, sink, completed);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | public class FilteredDataSink extends BufferedDataSink {
6 | public FilteredDataSink(DataSink sink) {
7 | super(sink);
8 | setMaxBuffer(0);
9 | }
10 |
11 | public ByteBufferList filter(ByteBufferList bb) {
12 | return bb;
13 | }
14 |
15 | @Override
16 | public final void write(ByteBuffer bb) {
17 | // don't filter and write if currently buffering, unless we know
18 | // that the buffer can fit the entirety of the filtered result
19 | if (isBuffering() && getMaxBuffer() != Integer.MAX_VALUE)
20 | return;
21 | ByteBufferList list = new ByteBufferList();
22 | byte[] bytes = new byte[bb.remaining()];
23 | bb.get(bytes);
24 | assert bb.remaining() == 0;
25 | list.add(ByteBuffer.wrap(bytes));
26 | ByteBufferList filtered = filter(list);
27 | super.write(filtered, true);
28 | }
29 |
30 | @Override
31 | public final void write(ByteBufferList bb) {
32 | // don't filter and write if currently buffering, unless we know
33 | // that the buffer can fit the entirety of the filtered result
34 | if (isBuffering() && getMaxBuffer() != Integer.MAX_VALUE)
35 | return;
36 | ByteBufferList filtered = filter(bb);
37 | assert bb == null || filtered == bb || bb.isEmpty();
38 | super.write(filtered, true);
39 | if (bb != null)
40 | bb.recycle();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import com.koushikdutta.async.AsyncSocket;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.callback.ConnectCallback;
6 | import com.koushikdutta.async.future.Cancellable;
7 | import com.koushikdutta.async.http.libcore.ResponseHeaders;
8 | import com.koushikdutta.async.util.UntypedHashtable;
9 |
10 | import java.util.Hashtable;
11 |
12 | public interface AsyncHttpClientMiddleware {
13 | public static class GetSocketData {
14 | public UntypedHashtable state = new UntypedHashtable();
15 | public AsyncHttpRequest request;
16 | public ConnectCallback connectCallback;
17 | public Cancellable socketCancellable;
18 | }
19 |
20 | public static class OnSocketData extends GetSocketData {
21 | public AsyncSocket socket;
22 | }
23 |
24 | public static class OnHeadersReceivedData extends OnSocketData {
25 | public ResponseHeaders headers;
26 | }
27 |
28 | public static class OnBodyData extends OnHeadersReceivedData {
29 | public DataEmitter bodyEmitter;
30 | }
31 |
32 | public static class OnRequestCompleteData extends OnBodyData {
33 | public Exception exception;
34 | }
35 |
36 | public Cancellable getSocket(GetSocketData data);
37 | public void onSocket(OnSocketData data);
38 | public void onHeadersReceived(OnHeadersReceivedData data);
39 | public void onBodyDecoder(OnBodyData data);
40 | public void onRequestComplete(OnRequestCompleteData data);
41 | }
42 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/stream/OutputStreamDataCallback.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.stream;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.nio.ByteBuffer;
6 |
7 | import com.koushikdutta.async.ByteBufferList;
8 | import com.koushikdutta.async.DataEmitter;
9 | import com.koushikdutta.async.callback.CompletedCallback;
10 | import com.koushikdutta.async.callback.DataCallback;
11 |
12 | public class OutputStreamDataCallback implements DataCallback, CompletedCallback {
13 | private OutputStream mOutput;
14 | public OutputStreamDataCallback(OutputStream os) {
15 | mOutput = os;
16 | }
17 |
18 | public OutputStream getOutputStream() {
19 | return mOutput;
20 | }
21 |
22 | @Override
23 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
24 | try {
25 | while (bb.size() > 0) {
26 | ByteBuffer b = bb.remove();
27 | mOutput.write(b.array(), b.arrayOffset() + b.position(), b.remaining());
28 | ByteBufferList.reclaim(b);
29 | }
30 | }
31 | catch (Exception ex) {
32 | onCompleted(ex);
33 | }
34 | finally {
35 | bb.recycle();
36 | }
37 | }
38 |
39 | public void close() {
40 | try {
41 | mOutput.close();
42 | }
43 | catch (IOException e) {
44 | onCompleted(e);
45 | }
46 | }
47 |
48 | @Override
49 | public void onCompleted(Exception error) {
50 | error.printStackTrace();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DataEmitterReader.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.DataCallback;
4 |
5 | public class DataEmitterReader implements com.koushikdutta.async.callback.DataCallback {
6 | DataCallback mPendingRead;
7 | int mPendingReadLength;
8 | ByteBufferList mPendingData = new ByteBufferList();
9 |
10 | public void read(int count, DataCallback callback) {
11 | assert mPendingRead == null;
12 | mPendingReadLength = count;
13 | mPendingRead = callback;
14 | assert !mPendingData.hasRemaining();
15 | mPendingData.recycle();
16 | }
17 |
18 | private boolean handlePendingData(DataEmitter emitter) {
19 | if (mPendingReadLength > mPendingData.remaining())
20 | return false;
21 |
22 | DataCallback pendingRead = mPendingRead;
23 | mPendingRead = null;
24 | pendingRead.onDataAvailable(emitter, mPendingData);
25 | assert !mPendingData.hasRemaining();
26 |
27 | return true;
28 | }
29 |
30 | public DataEmitterReader() {
31 | }
32 | @Override
33 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
34 | // if we're registered for data, we must be waiting for a read
35 | assert mPendingRead != null;
36 | do {
37 | int need = Math.min(bb.remaining(), mPendingReadLength - mPendingData.remaining());
38 | bb.get(mPendingData, need);
39 | bb.remaining();
40 | }
41 | while (handlePendingData(emitter) && mPendingRead != null);
42 | bb.remaining();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/StreamBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.http.AsyncHttpRequest;
8 |
9 | import java.io.InputStream;
10 |
11 | public class StreamBody implements AsyncHttpRequestBody {
12 | InputStream stream;
13 | int length;
14 |
15 | /**
16 | * Construct an http body from a stream
17 | * @param stream
18 | * @param length Length of stream to read, or value < 0 to read to end
19 | */
20 | public StreamBody(InputStream stream, int length) {
21 | this.stream = stream;
22 | this.length = length;
23 | }
24 |
25 | @Override
26 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) {
27 | Util.pump(stream, length < 0 ? Integer.MAX_VALUE : length, sink, completed);
28 | }
29 |
30 | @Override
31 | public void parse(DataEmitter emitter, CompletedCallback completed) {
32 | throw new AssertionError("not implemented");
33 | }
34 |
35 | public static final String CONTENT_TYPE = "application/binary";
36 | @Override
37 | public String getContentType() {
38 | return CONTENT_TYPE;
39 | }
40 |
41 | @Override
42 | public boolean readFullyOnRequest() {
43 | throw new AssertionError("not implemented");
44 | }
45 |
46 | @Override
47 | public int length() {
48 | return length;
49 | }
50 |
51 | @Override
52 | public InputStream get() {
53 | return stream;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/ThreadQueue.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.util.LinkedList;
4 | import java.util.WeakHashMap;
5 | import java.util.concurrent.Semaphore;
6 |
7 | public class ThreadQueue extends LinkedList {
8 | final private static WeakHashMap mThreadQueues = new WeakHashMap();
9 |
10 | static ThreadQueue getOrCreateThreadQueue(Thread thread) {
11 | ThreadQueue queue;
12 | synchronized (mThreadQueues) {
13 | queue = mThreadQueues.get(thread);
14 | if (queue == null) {
15 | queue = new ThreadQueue();
16 | mThreadQueues.put(thread, queue);
17 | }
18 | }
19 |
20 | return queue;
21 | }
22 |
23 | static void release(AsyncSemaphore semaphore) {
24 | synchronized (mThreadQueues) {
25 | for (ThreadQueue threadQueue: mThreadQueues.values()) {
26 | if (threadQueue.waiter == semaphore)
27 | threadQueue.queueSemaphore.release();
28 | }
29 | }
30 | }
31 |
32 | AsyncSemaphore waiter;
33 | Semaphore queueSemaphore = new Semaphore(0);
34 |
35 | @Override
36 | public boolean add(Runnable object) {
37 | synchronized (this) {
38 | return super.add(object);
39 | }
40 | }
41 |
42 | @Override
43 | public boolean remove(Object object) {
44 | synchronized (this) {
45 | return super.remove(object);
46 | }
47 | }
48 |
49 | @Override
50 | public Runnable remove() {
51 | synchronized (this) {
52 | if (this.isEmpty())
53 | return null;
54 | return super.remove();
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/ChannelWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.net.Socket;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.ClosedChannelException;
7 | import java.nio.channels.ReadableByteChannel;
8 | import java.nio.channels.ScatteringByteChannel;
9 | import java.nio.channels.SelectionKey;
10 | import java.nio.channels.Selector;
11 | import java.nio.channels.spi.AbstractSelectableChannel;
12 |
13 | abstract class ChannelWrapper implements ReadableByteChannel, ScatteringByteChannel {
14 | private AbstractSelectableChannel mChannel;
15 | ChannelWrapper(AbstractSelectableChannel channel) throws IOException {
16 | channel.configureBlocking(false);
17 | mChannel = channel;
18 | }
19 |
20 | public abstract void shutdownInput();
21 | public abstract void shutdownOutput();
22 |
23 | public abstract boolean isConnected();
24 |
25 | public abstract int write(ByteBuffer src) throws IOException;
26 | public abstract int write(ByteBuffer[] src) throws IOException;
27 |
28 | // register for default events appropriate for this channel
29 | public abstract SelectionKey register(Selector sel) throws ClosedChannelException;
30 |
31 | public SelectionKey register(Selector sel, int ops) throws ClosedChannelException {
32 | return mChannel.register(sel, ops);
33 | }
34 |
35 | public boolean isChunked() {
36 | return false;
37 | }
38 |
39 | @Override
40 | public boolean isOpen() {
41 | return mChannel.isOpen();
42 | }
43 |
44 | @Override
45 | public void close() throws IOException {
46 | mChannel.close();
47 | }
48 |
49 | public abstract int getLocalPort();
50 | public abstract Object getSocket();
51 | }
52 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/EventEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio;
2 |
3 | import com.koushikdutta.async.util.HashList;
4 |
5 | import org.json.JSONArray;
6 |
7 | import java.util.Iterator;
8 | import java.util.List;
9 |
10 | /**
11 | * Created by koush on 7/1/13.
12 | */
13 | public class EventEmitter {
14 | interface OnceCallback extends EventCallback {
15 | }
16 |
17 | HashList callbacks = new HashList();
18 | void onEvent(String event, JSONArray arguments, Acknowledge acknowledge) {
19 | List list = callbacks.get(event);
20 | if (list == null)
21 | return;
22 | Iterator iter = list.iterator();
23 | while (iter.hasNext()) {
24 | EventCallback cb = iter.next();
25 | cb.onEvent(arguments, acknowledge);
26 | if (cb instanceof OnceCallback)
27 | iter.remove();
28 | }
29 | }
30 |
31 | public void addListener(String event, EventCallback callback) {
32 | on(event, callback);
33 | }
34 |
35 | public void once(final String event, final EventCallback callback) {
36 | on(event, new OnceCallback() {
37 | @Override
38 | public void onEvent(JSONArray arguments, Acknowledge acknowledge) {
39 | callback.onEvent(arguments, acknowledge);
40 | }
41 | });
42 | }
43 |
44 | public void on(String event, EventCallback callback) {
45 | callbacks.add(event, callback);
46 | }
47 |
48 | public void removeListener(String event, EventCallback callback) {
49 | List list = callbacks.get(event);
50 | if (list == null)
51 | return;
52 | list.remove(callback);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/JSONArrayBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.FutureCallback;
8 | import com.koushikdutta.async.http.AsyncHttpRequest;
9 | import com.koushikdutta.async.parser.JSONArrayParser;
10 |
11 | import org.json.JSONArray;
12 |
13 | public class JSONArrayBody implements AsyncHttpRequestBody {
14 | public JSONArrayBody() {
15 | }
16 |
17 | byte[] mBodyBytes;
18 | JSONArray json;
19 | public JSONArrayBody(JSONArray json) {
20 | this();
21 | this.json = json;
22 | }
23 |
24 | @Override
25 | public void parse(DataEmitter emitter, final CompletedCallback completed) {
26 | new JSONArrayParser().parse(emitter).setCallback(new FutureCallback() {
27 | @Override
28 | public void onCompleted(Exception e, JSONArray result) {
29 | json = result;
30 | completed.onCompleted(e);
31 | }
32 | });
33 | }
34 |
35 | @Override
36 | public void write(AsyncHttpRequest request, DataSink sink, final CompletedCallback completed) {
37 | Util.writeAll(sink, mBodyBytes, completed);
38 | }
39 |
40 | @Override
41 | public String getContentType() {
42 | return "application/json";
43 | }
44 |
45 | @Override
46 | public boolean readFullyOnRequest() {
47 | return true;
48 | }
49 |
50 | @Override
51 | public int length() {
52 | mBodyBytes = json.toString().getBytes();
53 | return mBodyBytes.length;
54 | }
55 |
56 | public static final String CONTENT_TYPE = "application/json";
57 |
58 | @Override
59 | public JSONArray get() {
60 | return json;
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/JSONObjectBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.FutureCallback;
8 | import com.koushikdutta.async.http.AsyncHttpRequest;
9 | import com.koushikdutta.async.parser.JSONObjectParser;
10 |
11 | import org.json.JSONObject;
12 |
13 | public class JSONObjectBody implements AsyncHttpRequestBody {
14 | public JSONObjectBody() {
15 | }
16 |
17 | byte[] mBodyBytes;
18 | JSONObject json;
19 | public JSONObjectBody(JSONObject json) {
20 | this();
21 | this.json = json;
22 | }
23 |
24 | @Override
25 | public void parse(DataEmitter emitter, final CompletedCallback completed) {
26 | new JSONObjectParser().parse(emitter).setCallback(new FutureCallback() {
27 | @Override
28 | public void onCompleted(Exception e, JSONObject result) {
29 | json = result;
30 | completed.onCompleted(e);
31 | }
32 | });
33 | }
34 |
35 | @Override
36 | public void write(AsyncHttpRequest request, DataSink sink, final CompletedCallback completed) {
37 | Util.writeAll(sink, mBodyBytes, completed);
38 | }
39 |
40 | @Override
41 | public String getContentType() {
42 | return CONTENT_TYPE;
43 | }
44 |
45 | @Override
46 | public boolean readFullyOnRequest() {
47 | return true;
48 | }
49 |
50 | @Override
51 | public int length() {
52 | mBodyBytes = json.toString().getBytes();
53 | return mBodyBytes.length;
54 | }
55 |
56 | public static final String CONTENT_TYPE = "application/json";
57 |
58 | @Override
59 | public JSONObject get() {
60 | return json;
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/parser/ByteBufferListParser.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.parser;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.DataSink;
6 | import com.koushikdutta.async.Util;
7 | import com.koushikdutta.async.callback.CompletedCallback;
8 | import com.koushikdutta.async.callback.DataCallback;
9 | import com.koushikdutta.async.future.Future;
10 | import com.koushikdutta.async.future.SimpleFuture;
11 |
12 | /**
13 | * Created by koush on 5/27/13.
14 | */
15 | public class ByteBufferListParser implements AsyncParser {
16 | @Override
17 | public Future parse(final DataEmitter emitter) {
18 | final ByteBufferList bb = new ByteBufferList();
19 | final SimpleFuture ret = new SimpleFuture() {
20 | @Override
21 | protected void cancelCleanup() {
22 | emitter.close();
23 | }
24 | };
25 | emitter.setDataCallback(new DataCallback() {
26 | @Override
27 | public void onDataAvailable(DataEmitter emitter, ByteBufferList data) {
28 | data.get(bb);
29 | }
30 | });
31 |
32 | emitter.setEndCallback(new CompletedCallback() {
33 | @Override
34 | public void onCompleted(Exception ex) {
35 | if (ex != null) {
36 | ret.setComplete(ex);
37 | return;
38 | }
39 |
40 | try {
41 | ret.setComplete(bb);
42 | }
43 | catch (Exception e) {
44 | ret.setComplete(e);
45 | }
46 | }
47 | });
48 |
49 | return ret;
50 | }
51 |
52 | @Override
53 | public void write(DataSink sink, ByteBufferList value, CompletedCallback completed) {
54 | Util.writeAll(sink, value, completed);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/ParserTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.FilteredDataEmitter;
5 | import com.koushikdutta.async.future.Future;
6 | import com.koushikdutta.async.parser.StringParser;
7 | import com.koushikdutta.async.util.Charsets;
8 |
9 | import junit.framework.TestCase;
10 |
11 | import java.nio.ByteBuffer;
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * Created by koush on 7/10/14.
16 | */
17 | public class ParserTests extends TestCase {
18 | public void testString() throws Exception {
19 | StringParser p = new StringParser();
20 | FilteredDataEmitter f = new FilteredDataEmitter() {
21 | @Override
22 | public boolean isPaused() {
23 | return false;
24 | }
25 | };
26 | Future ret = p.parse(f);
27 | ByteBufferList l = new ByteBufferList();
28 | l.add(ByteBuffer.wrap("foo".getBytes(Charsets.US_ASCII.name())));
29 | f.onDataAvailable(f, l);
30 | f.getEndCallback().onCompleted(null);
31 | String s = ret.get();
32 | assertEquals(s, "foo");
33 | }
34 |
35 | public void testUtf8String() throws Exception {
36 | StringParser p = new StringParser();
37 | FilteredDataEmitter f = new FilteredDataEmitter() {
38 | @Override
39 | public String charset() {
40 | return Charsets.UTF_8.name();
41 | }
42 |
43 | @Override
44 | public boolean isPaused() {
45 | return false;
46 | }
47 | };
48 | Future ret = p.parse(f);
49 | ByteBufferList l = new ByteBufferList();
50 | l.add(ByteBuffer.wrap("æææ".getBytes(Charsets.UTF_8.name())));
51 | f.onDataAvailable(f, l);
52 | f.getEndCallback().onCompleted(null);
53 | String s = ret.get();
54 | assertEquals(s, "æææ");
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/socketio/transport/WebSocketTransport.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.socketio.transport;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 | import com.koushikdutta.async.NullDataCallback;
5 | import com.koushikdutta.async.callback.CompletedCallback;
6 | import com.koushikdutta.async.http.WebSocket;
7 |
8 | public class WebSocketTransport implements SocketIOTransport {
9 | private WebSocket webSocket;
10 | private StringCallback stringCallback;
11 |
12 | public WebSocketTransport(WebSocket webSocket) {
13 | this.webSocket = webSocket;
14 |
15 | this.webSocket.setDataCallback(new NullDataCallback());
16 | }
17 |
18 | @Override
19 | public boolean isConnected() {
20 | return this.webSocket.isOpen();
21 | }
22 |
23 | @Override
24 | public void setClosedCallback(CompletedCallback handler) {
25 | this.webSocket.setClosedCallback(handler);
26 | }
27 |
28 | @Override
29 | public void disconnect() {
30 | this.webSocket.close();
31 | }
32 |
33 | @Override
34 | public AsyncServer getServer() {
35 | return this.webSocket.getServer();
36 | }
37 |
38 | @Override
39 | public void send(String message) {
40 | this.webSocket.send(message);
41 | }
42 |
43 | @Override
44 | public void setStringCallback(final StringCallback callback) {
45 | if (this.stringCallback == callback)
46 | return;
47 |
48 | if (callback == null) {
49 | this.webSocket.setStringCallback(null);
50 | } else {
51 | this.webSocket.setStringCallback(new WebSocket.StringCallback() {
52 | @Override
53 | public void onStringAvailable(String s) {
54 | callback.onStringAvailable(s);
55 | }
56 | });
57 | }
58 |
59 | this.stringCallback = callback;
60 | }
61 |
62 | @Override
63 | public boolean heartbeats() {
64 | return true;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/StringBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.FutureCallback;
8 | import com.koushikdutta.async.http.AsyncHttpRequest;
9 | import com.koushikdutta.async.parser.StringParser;
10 |
11 | public class StringBody implements AsyncHttpRequestBody {
12 | public StringBody() {
13 | }
14 |
15 | byte[] mBodyBytes;
16 | String string;
17 | public StringBody(String string) {
18 | this();
19 | this.string = string;
20 | }
21 |
22 | @Override
23 | public void parse(DataEmitter emitter, final CompletedCallback completed) {
24 | new StringParser().parse(emitter).setCallback(new FutureCallback() {
25 | @Override
26 | public void onCompleted(Exception e, String result) {
27 | string = result;
28 | completed.onCompleted(e);
29 | }
30 | });
31 | }
32 |
33 | public static final String CONTENT_TYPE = "text/plain";
34 |
35 | @Override
36 | public void write(AsyncHttpRequest request, DataSink sink, final CompletedCallback completed) {
37 | if (mBodyBytes == null)
38 | mBodyBytes = string.getBytes();
39 | Util.writeAll(sink, mBodyBytes, completed);
40 | }
41 |
42 | @Override
43 | public String getContentType() {
44 | return "text/plain";
45 | }
46 |
47 | @Override
48 | public boolean readFullyOnRequest() {
49 | return true;
50 | }
51 |
52 | @Override
53 | public int length() {
54 | if (mBodyBytes == null)
55 | mBodyBytes = string.getBytes();
56 | return mBodyBytes.length;
57 | }
58 |
59 | @Override
60 | public String toString() {
61 | return string;
62 | }
63 |
64 | @Override
65 | public String get() {
66 | return toString();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/ZipDataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.nio.ByteBuffer;
6 | import java.util.zip.ZipEntry;
7 | import java.util.zip.ZipOutputStream;
8 |
9 | import com.koushikdutta.async.callback.CompletedCallback;
10 |
11 | public class ZipDataSink extends FilteredDataSink {
12 | public ZipDataSink(DataSink sink) {
13 | super(sink);
14 | }
15 |
16 | ByteArrayOutputStream bout = new ByteArrayOutputStream();
17 | ZipOutputStream zop = new ZipOutputStream(bout);
18 |
19 | public void putNextEntry(ZipEntry ze) throws IOException {
20 | zop.putNextEntry(ze);
21 | }
22 |
23 | public void closeEntry() throws IOException {
24 | zop.closeEntry();
25 | }
26 |
27 | protected void report(Exception e) {
28 | CompletedCallback closed = getClosedCallback();
29 | if (closed != null)
30 | closed.onCompleted(e);
31 | }
32 |
33 | @Override
34 | public void end() {
35 | try {
36 | zop.close();
37 | }
38 | catch (IOException e) {
39 | report(e);
40 | return;
41 | }
42 | setMaxBuffer(Integer.MAX_VALUE);
43 | write(new ByteBufferList());
44 | super.end();
45 | }
46 |
47 | @Override
48 | public ByteBufferList filter(ByteBufferList bb) {
49 | try {
50 | if (bb != null) {
51 | while (bb.size() > 0) {
52 | ByteBuffer b = bb.remove();
53 | ByteBufferList.writeOutputStream(zop, b);
54 | ByteBufferList.reclaim(b);
55 | }
56 | }
57 | ByteBufferList ret = new ByteBufferList(bout.toByteArray());
58 | bout.reset();
59 | return ret;
60 | }
61 | catch (IOException e) {
62 | report(e);
63 | return null;
64 | }
65 | finally {
66 | if (bb != null)
67 | bb.recycle();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/SocketChannelWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.ClosedChannelException;
6 | import java.nio.channels.SelectionKey;
7 | import java.nio.channels.Selector;
8 | import java.nio.channels.SocketChannel;
9 |
10 | class SocketChannelWrapper extends ChannelWrapper {
11 | SocketChannel mChannel;
12 |
13 | @Override
14 | public int getLocalPort() {
15 | return mChannel.socket().getLocalPort();
16 | }
17 |
18 | SocketChannelWrapper(SocketChannel channel) throws IOException {
19 | super(channel);
20 | mChannel = channel;
21 | }
22 | @Override
23 | public int read(ByteBuffer buffer) throws IOException {
24 | return mChannel.read(buffer);
25 | }
26 | @Override
27 | public boolean isConnected() {
28 | return mChannel.isConnected();
29 | }
30 | @Override
31 | public int write(ByteBuffer src) throws IOException {
32 | return mChannel.write(src);
33 | }
34 | @Override
35 | public int write(ByteBuffer[] src) throws IOException {
36 | return (int)mChannel.write(src);
37 | }
38 | @Override
39 | public SelectionKey register(Selector sel) throws ClosedChannelException {
40 | return register(sel, SelectionKey.OP_CONNECT);
41 | }
42 |
43 | @Override
44 | public void shutdownOutput() {
45 | try {
46 | mChannel.socket().shutdownOutput();
47 | }
48 | catch (Exception e) {
49 | }
50 | }
51 |
52 | @Override
53 | public void shutdownInput() {
54 | try {
55 | mChannel.socket().shutdownInput();
56 | }
57 | catch (Exception e) {
58 | }
59 | }
60 |
61 | @Override
62 | public long read(ByteBuffer[] byteBuffers) throws IOException {
63 | return mChannel.read(byteBuffers);
64 | }
65 |
66 | @Override
67 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException {
68 | return mChannel.read(byteBuffers, i, i2);
69 | }
70 |
71 | @Override
72 | public Object getSocket() {
73 | return mChannel.socket();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/server/UnknownRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.server;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.NullDataCallback;
6 | import com.koushikdutta.async.Util;
7 | import com.koushikdutta.async.callback.CompletedCallback;
8 | import com.koushikdutta.async.callback.DataCallback;
9 | import com.koushikdutta.async.http.AsyncHttpRequest;
10 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
11 |
12 | public class UnknownRequestBody implements AsyncHttpRequestBody {
13 | public UnknownRequestBody(String contentType) {
14 | mContentType = contentType;
15 | }
16 |
17 | int length = -1;
18 | public UnknownRequestBody(DataEmitter emitter, String contentType, int length) {
19 | mContentType = contentType;
20 | this.emitter = emitter;
21 | this.length = length;
22 | }
23 |
24 | @Override
25 | public void write(final AsyncHttpRequest request, DataSink sink, final CompletedCallback completed) {
26 | Util.pump(emitter, sink, completed);
27 | if (emitter.isPaused())
28 | emitter.resume();
29 | }
30 |
31 | private String mContentType;
32 | @Override
33 | public String getContentType() {
34 | return mContentType;
35 | }
36 |
37 | @Override
38 | public boolean readFullyOnRequest() {
39 | return false;
40 | }
41 |
42 | @Override
43 | public int length() {
44 | return length;
45 | }
46 |
47 | @Override
48 | public Void get() {
49 | return null;
50 | }
51 |
52 | @Deprecated
53 | public void setCallbacks(DataCallback callback, CompletedCallback endCallback) {
54 | emitter.setEndCallback(endCallback);
55 | emitter.setDataCallback(callback);
56 | }
57 |
58 | public DataEmitter getEmitter() {
59 | return emitter;
60 | }
61 |
62 | DataEmitter emitter;
63 | @Override
64 | public void parse(DataEmitter emitter, CompletedCallback completed) {
65 | this.emitter = emitter;
66 | emitter.setEndCallback(completed);
67 | emitter.setDataCallback(new NullDataCallback());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/future/SimpleCancellable.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.future;
2 |
3 | public class SimpleCancellable implements DependentCancellable {
4 | boolean complete;
5 | @Override
6 | public boolean isDone() {
7 | return complete;
8 | }
9 |
10 | protected void cancelCleanup() {
11 | }
12 |
13 | protected void cleanup() {
14 | }
15 |
16 | protected void completeCleanup() {
17 | }
18 |
19 | public boolean setComplete() {
20 | synchronized (this) {
21 | if (cancelled)
22 | return false;
23 | if (complete) {
24 | // don't allow a Cancellable to complete twice...
25 | assert false;
26 | return true;
27 | }
28 | complete = true;
29 | parent = null;
30 | }
31 | completeCleanup();
32 | cleanup();
33 | return true;
34 | }
35 |
36 | @Override
37 | public boolean cancel() {
38 | Cancellable parent;
39 | synchronized (this) {
40 | if (complete)
41 | return false;
42 | if (cancelled)
43 | return true;
44 | cancelled = true;
45 | parent = this.parent;
46 | // null out the parent to allow garbage collection
47 | this.parent = null;
48 | }
49 | if (parent != null)
50 | parent.cancel();
51 | cancelCleanup();
52 | cleanup();
53 | return true;
54 | }
55 | boolean cancelled;
56 |
57 | private Cancellable parent;
58 | @Override
59 | public SimpleCancellable setParent(Cancellable parent) {
60 | synchronized (this) {
61 | if (!isDone())
62 | this.parent = parent;
63 | }
64 | return this;
65 | }
66 |
67 | @Override
68 | public boolean isCancelled() {
69 | synchronized (this) {
70 | return cancelled || (parent != null && parent.isCancelled());
71 | }
72 | }
73 |
74 | public static final Cancellable COMPLETED = new SimpleCancellable() {
75 | {
76 | setComplete();
77 | }
78 | };
79 |
80 | public Cancellable reset() {
81 | cancel();
82 | complete = false;
83 | cancelled = false;
84 | return this;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncDatagramSocket.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.ByteBuffer;
6 |
7 | public class AsyncDatagramSocket extends AsyncNetworkSocket {
8 | public void disconnect() throws IOException {
9 | socketAddress = null;
10 | ((DatagramChannelWrapper)getChannel()).disconnect();
11 | }
12 |
13 | @Override
14 | public InetSocketAddress getRemoteAddress() {
15 | if (isOpen())
16 | return super.getRemoteAddress();
17 | return ((DatagramChannelWrapper)getChannel()).getRemoteAddress();
18 | }
19 |
20 | public void connect(InetSocketAddress address) throws IOException {
21 | socketAddress = address;
22 | ((DatagramChannelWrapper)getChannel()).mChannel.connect(address);
23 | }
24 |
25 | public void send(final String host, final int port, final ByteBuffer buffer) {
26 | if (getServer().getAffinity() != Thread.currentThread()) {
27 | getServer().run(new Runnable() {
28 | @Override
29 | public void run() {
30 | send(host, port, buffer);
31 | }
32 | });
33 | return;
34 | }
35 |
36 | try {
37 | ((DatagramChannelWrapper)getChannel()).mChannel.send(buffer, new InetSocketAddress(host, port));
38 | }
39 | catch (IOException e) {
40 | // close();
41 | // reportEndPending(e);
42 | // reportClose(e);
43 | }
44 |
45 | }
46 | public void send(final InetSocketAddress address, final ByteBuffer buffer) {
47 | if (getServer().getAffinity() != Thread.currentThread()) {
48 | getServer().run(new Runnable() {
49 | @Override
50 | public void run() {
51 | send(address, buffer);
52 | }
53 | });
54 | return;
55 | }
56 |
57 | try {
58 | int sent = ((DatagramChannelWrapper)getChannel()).mChannel.send(buffer, new InetSocketAddress(address.getHostName(), address.getPort()));
59 | }
60 | catch (IOException e) {
61 | // Log.e("SEND", "send error", e);
62 | // close();
63 | // reportEndPending(e);
64 | // reportClose(e);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/Part.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataSink;
4 | import com.koushikdutta.async.callback.CompletedCallback;
5 | import com.koushikdutta.async.http.Multimap;
6 | import com.koushikdutta.async.http.libcore.RawHeaders;
7 | import org.apache.http.NameValuePair;
8 |
9 | import java.io.File;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | public class Part {
14 | public static final String CONTENT_DISPOSITION = "Content-Disposition";
15 |
16 | RawHeaders mHeaders;
17 | Multimap mContentDisposition;
18 | public Part(RawHeaders headers) {
19 | mHeaders = headers;
20 | mContentDisposition = Multimap.parseHeader(mHeaders, CONTENT_DISPOSITION);
21 | }
22 |
23 | public String getName() {
24 | return mContentDisposition.getString("name");
25 | }
26 |
27 | private long length = -1;
28 | public Part(String name, long length, List contentDisposition) {
29 | this.length = length;
30 | mHeaders = new RawHeaders();
31 | StringBuilder builder = new StringBuilder(String.format("form-data; name=\"%s\"", name));
32 | if (contentDisposition != null) {
33 | for (NameValuePair pair: contentDisposition) {
34 | builder.append(String.format("; %s=\"%s\"", pair.getName(), pair.getValue()));
35 | }
36 | }
37 | mHeaders.set(CONTENT_DISPOSITION, builder.toString());
38 | mContentDisposition = Multimap.parseHeader(mHeaders, CONTENT_DISPOSITION);
39 | }
40 |
41 | public RawHeaders getRawHeaders() {
42 | return mHeaders;
43 | }
44 |
45 | public String getContentType() {
46 | return mHeaders.get("Content-Type");
47 | }
48 |
49 | public void setContentType(String contentType) {
50 | mHeaders.set("Content-Type", contentType);
51 | }
52 |
53 | public String getFilename() {
54 | String file = mContentDisposition.getString("filename");
55 | if (file == null)
56 | return null;
57 | return new File(file).getName();
58 | }
59 |
60 | public boolean isFile() {
61 | return mContentDisposition.containsKey("filename");
62 | }
63 |
64 | public long length() {
65 | return length;
66 | }
67 |
68 | public void write(DataSink sink, CompletedCallback callback) {
69 | assert false;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/HashList.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Hashtable;
5 | import java.util.Set;
6 |
7 | /**
8 | * Created by koush on 5/27/13.
9 | */
10 | public class HashList {
11 | class TaggedList extends ArrayList {
12 | Object tag;
13 | }
14 | Hashtable> internal = new Hashtable>();
15 |
16 | public HashList() {
17 | }
18 |
19 | public Set keySet() {
20 | return internal.keySet();
21 | }
22 |
23 | public synchronized V tag(String key) {
24 | TaggedList list = internal.get(key);
25 | if (list == null)
26 | return null;
27 | return (V)list.tag;
28 | }
29 |
30 | public synchronized void tag(String key, V tag) {
31 | TaggedList list = internal.get(key);
32 | if (list == null) {
33 | list = new TaggedList();
34 | internal.put(key, list);
35 | }
36 | list.tag = tag;
37 | }
38 |
39 | public synchronized ArrayList remove(String key) {
40 | return internal.remove(key);
41 | }
42 |
43 | public synchronized int size() {
44 | return internal.size();
45 | }
46 |
47 | public synchronized ArrayList get(String key) {
48 | return internal.get(key);
49 | }
50 |
51 | synchronized public boolean contains(String key) {
52 | ArrayList check = get(key);
53 | return check != null && check.size() > 0;
54 | }
55 |
56 | synchronized public void add(String key, T value) {
57 | ArrayList ret = get(key);
58 | if (ret == null) {
59 | TaggedList put = new TaggedList();
60 | ret = put;
61 | internal.put(key, put);
62 | }
63 | ret.add(value);
64 | }
65 |
66 | synchronized public T pop(String key) {
67 | TaggedList values = internal.get(key);
68 | if (values == null)
69 | return null;
70 | if (values.size() == 0)
71 | return null;
72 | return values.remove(values.size() - 1);
73 | }
74 |
75 | synchronized public boolean removeItem(String key, T value) {
76 | TaggedList values = internal.get(key);
77 | if (values == null)
78 | return false;
79 |
80 | values.remove(value);
81 | return values.size() == 0;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/ServerSocketChannelWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.ClosedChannelException;
6 | import java.nio.channels.SelectionKey;
7 | import java.nio.channels.Selector;
8 | import java.nio.channels.ServerSocketChannel;
9 |
10 | class ServerSocketChannelWrapper extends ChannelWrapper {
11 | ServerSocketChannel mChannel;
12 |
13 | @Override
14 | public void shutdownOutput() {
15 | }
16 |
17 | @Override
18 | public void shutdownInput() {
19 | }
20 |
21 | @Override
22 | public int getLocalPort() {
23 | return mChannel.socket().getLocalPort();
24 | }
25 |
26 | ServerSocketChannelWrapper(ServerSocketChannel channel) throws IOException {
27 | super(channel);
28 | mChannel = channel;
29 | }
30 |
31 | @Override
32 | public int read(ByteBuffer buffer) throws IOException {
33 | final String msg = "Can't read ServerSocketChannel";
34 | assert false;
35 | throw new IOException(msg);
36 | }
37 |
38 | @Override
39 | public boolean isConnected() {
40 | assert false;
41 | return false;
42 | }
43 |
44 | @Override
45 | public int write(ByteBuffer src) throws IOException {
46 | final String msg = "Can't write ServerSocketChannel";
47 | assert false;
48 | throw new IOException(msg);
49 | }
50 |
51 | @Override
52 | public SelectionKey register(Selector sel) throws ClosedChannelException {
53 | return mChannel.register(sel, SelectionKey.OP_ACCEPT);
54 | }
55 |
56 | @Override
57 | public int write(ByteBuffer[] src) throws IOException {
58 | final String msg = "Can't write ServerSocketChannel";
59 | assert false;
60 | throw new IOException(msg);
61 | }
62 |
63 | @Override
64 | public long read(ByteBuffer[] byteBuffers) throws IOException {
65 | final String msg = "Can't read ServerSocketChannel";
66 | assert false;
67 | throw new IOException(msg);
68 | }
69 |
70 | @Override
71 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException {
72 | final String msg = "Can't read ServerSocketChannel";
73 | assert false;
74 | throw new IOException(msg);
75 | }
76 |
77 | @Override
78 | public Object getSocket() {
79 | return mChannel.socket();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/Issue59.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.util.Log;
4 |
5 | import com.koushikdutta.async.AsyncServer;
6 | import com.koushikdutta.async.Util;
7 | import com.koushikdutta.async.callback.CompletedCallback;
8 | import com.koushikdutta.async.http.AsyncHttpClient;
9 | import com.koushikdutta.async.http.AsyncHttpGet;
10 | import com.koushikdutta.async.http.server.AsyncHttpServer;
11 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
12 | import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
13 | import com.koushikdutta.async.http.server.HttpServerRequestCallback;
14 |
15 | import junit.framework.TestCase;
16 |
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * Created by koush on 8/31/13.
21 | */
22 | public class Issue59 extends TestCase {
23 | public void testIssue() throws Exception {
24 | AsyncHttpServer httpServer = new AsyncHttpServer();
25 | try {
26 | httpServer.get("/", new HttpServerRequestCallback() {
27 | @Override
28 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
29 | // setting this to empty is a hacky way of telling the framework not to use
30 | // transfer-encoding. It will get removed.
31 | response.getHeaders().getHeaders().set("Transfer-Encoding", "");
32 | response.responseCode(200);
33 | Util.writeAll(response, "foobarbeepboop".getBytes(), new CompletedCallback() {
34 | @Override
35 | public void onCompleted(Exception ex) {
36 | response.close();
37 | }
38 | });
39 | }
40 | });
41 |
42 | httpServer.listen(5959);
43 |
44 | AsyncHttpGet get = new AsyncHttpGet("http://localhost:5959/");
45 | get.setLogging("issue59", Log.VERBOSE);
46 | get.getHeaders().getHeaders().removeAll("Connection");
47 | get.getHeaders().getHeaders().removeAll("Accept-Encoding");
48 |
49 | assertEquals("foobarbeepboop", AsyncHttpClient.getDefaultInstance().executeString(get, null).get(1000, TimeUnit.MILLISECONDS));
50 | }
51 | finally {
52 | httpServer.stop();
53 | AsyncServer.getDefault().stop();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/filter/InflaterInputFilter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.filter;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.FilteredDataEmitter;
6 | import com.koushikdutta.async.Util;
7 |
8 | import java.io.IOException;
9 | import java.nio.ByteBuffer;
10 | import java.util.zip.Inflater;
11 |
12 | public class InflaterInputFilter extends FilteredDataEmitter {
13 | private Inflater mInflater;
14 |
15 | @Override
16 | protected void report(Exception e) {
17 | mInflater.end();
18 | if (e != null && mInflater.getRemaining() > 0) {
19 | e = new DataRemainingException("data still remaining in inflater", e);
20 | }
21 | super.report(e);
22 | }
23 |
24 | ByteBufferList transformed = new ByteBufferList();
25 | @Override
26 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
27 | try {
28 | ByteBuffer output = ByteBufferList.obtain(bb.remaining() * 2);
29 | int totalRead = 0;
30 | while (bb.size() > 0) {
31 | ByteBuffer b = bb.remove();
32 | if (b.hasRemaining()) {
33 | totalRead =+ b.remaining();
34 | mInflater.setInput(b.array(), b.arrayOffset() + b.position(), b.remaining());
35 | do {
36 | int inflated = mInflater.inflate(output.array(), output.arrayOffset() + output.position(), output.remaining());
37 | output.position(output.position() + inflated);
38 | if (!output.hasRemaining()) {
39 | output.flip();
40 | transformed.add(output);
41 | assert totalRead != 0;
42 | int newSize = output.capacity() * 2;
43 | output = ByteBufferList.obtain(newSize);
44 | }
45 | }
46 | while (!mInflater.needsInput() && !mInflater.finished());
47 | }
48 | ByteBufferList.reclaim(b);
49 | }
50 | output.flip();
51 | transformed.add(output);
52 |
53 | Util.emitAllData(this, transformed);
54 | }
55 | catch (Exception ex) {
56 | report(ex);
57 | }
58 | }
59 |
60 | public InflaterInputFilter() {
61 | this(new Inflater());
62 | }
63 |
64 | public InflaterInputFilter(Inflater inflater) {
65 | mInflater = inflater;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.DataCallback;
5 | import com.koushikdutta.async.wrapper.DataEmitterWrapper;
6 |
7 | public class FilteredDataEmitter extends DataEmitterBase implements DataEmitter, DataCallback, DataEmitterWrapper, DataTrackingEmitter {
8 | DataEmitter mEmitter;
9 | @Override
10 | public DataEmitter getDataEmitter() {
11 | return mEmitter;
12 | }
13 |
14 | @Override
15 | public void setDataEmitter(DataEmitter emitter) {
16 | if (mEmitter != null) {
17 | mEmitter.setDataCallback(null);
18 | }
19 | mEmitter = emitter;
20 | mEmitter.setDataCallback(this);
21 | mEmitter.setEndCallback(new CompletedCallback() {
22 | @Override
23 | public void onCompleted(Exception ex) {
24 | report(ex);
25 | }
26 | });
27 | }
28 |
29 | @Override
30 | public int getBytesRead() {
31 | return totalRead;
32 | }
33 |
34 | @Override
35 | public DataTracker getDataTracker() {
36 | return tracker;
37 | }
38 |
39 | @Override
40 | public void setDataTracker(DataTracker tracker) {
41 | this.tracker = tracker;
42 | }
43 |
44 | DataTracker tracker;
45 | int totalRead;
46 | @Override
47 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
48 | if (bb != null)
49 | totalRead += bb.remaining();
50 | Util.emitAllData(this, bb);
51 | if (bb != null)
52 | totalRead -= bb.remaining();
53 | if (tracker != null && bb != null)
54 | tracker.onData(totalRead);
55 | // if there's data after the emitting, and it is paused... the underlying implementation
56 | // is obligated to cache the byte buffer list.
57 | }
58 |
59 | @Override
60 | public boolean isChunked() {
61 | return mEmitter.isChunked();
62 | }
63 |
64 | @Override
65 | public void pause() {
66 | mEmitter.pause();
67 | }
68 |
69 | @Override
70 | public void resume() {
71 | mEmitter.resume();
72 | }
73 |
74 | @Override
75 | public boolean isPaused() {
76 | return mEmitter.isPaused();
77 | }
78 |
79 | @Override
80 | public AsyncServer getServer() {
81 | return mEmitter.getServer();
82 | }
83 |
84 | @Override
85 | public void close() {
86 | mEmitter.close();
87 | }
88 |
89 | @Override
90 | public String charset() {
91 | if (mEmitter == null)
92 | return null;
93 | return mEmitter.charset();
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/DatagramChannelWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.ClosedChannelException;
7 | import java.nio.channels.DatagramChannel;
8 | import java.nio.channels.SelectionKey;
9 | import java.nio.channels.Selector;
10 |
11 | class DatagramChannelWrapper extends ChannelWrapper {
12 | DatagramChannel mChannel;
13 |
14 | @Override
15 | public int getLocalPort() {
16 | return mChannel.socket().getLocalPort();
17 | }
18 |
19 | InetSocketAddress address;
20 | public InetSocketAddress getRemoteAddress() {
21 | return address;
22 | }
23 |
24 | public void disconnect() throws IOException {
25 | mChannel.disconnect();
26 | }
27 |
28 | DatagramChannelWrapper(DatagramChannel channel) throws IOException {
29 | super(channel);
30 | mChannel = channel;
31 | }
32 | @Override
33 | public int read(ByteBuffer buffer) throws IOException {
34 | if (!isConnected()) {
35 | int position = buffer.position();
36 | address = (InetSocketAddress)mChannel.receive(buffer);
37 | if (address == null)
38 | return -1;
39 | return buffer.position() - position;
40 | }
41 | address = null;
42 | return mChannel.read(buffer);
43 | }
44 | @Override
45 | public boolean isConnected() {
46 | return mChannel.isConnected();
47 | }
48 | @Override
49 | public int write(ByteBuffer src) throws IOException {
50 | return mChannel.write(src);
51 | }
52 | @Override
53 | public int write(ByteBuffer[] src) throws IOException {
54 | return (int)mChannel.write(src);
55 | }
56 | @Override
57 | public SelectionKey register(Selector sel, int ops) throws ClosedChannelException {
58 | return mChannel.register(sel, ops);
59 | }
60 | @Override
61 | public boolean isChunked() {
62 | return true;
63 | }
64 | @Override
65 | public SelectionKey register(Selector sel) throws ClosedChannelException {
66 | return register(sel, SelectionKey.OP_READ);
67 | }
68 |
69 | @Override
70 | public void shutdownOutput() {
71 | }
72 |
73 | @Override
74 | public void shutdownInput() {
75 | }
76 |
77 | @Override
78 | public long read(ByteBuffer[] byteBuffers) throws IOException {
79 | return mChannel.read(byteBuffers);
80 | }
81 |
82 | @Override
83 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException {
84 | return mChannel.read(byteBuffers, i, i2);
85 | }
86 |
87 | @Override
88 | public Object getSocket() {
89 | return mChannel.socket();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/SelectorWrapper.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.util.Set;
7 | import java.util.concurrent.Semaphore;
8 | import java.util.concurrent.TimeUnit;
9 |
10 | /**
11 | * Created by koush on 2/13/14.
12 | */
13 | public class SelectorWrapper {
14 | private Selector selector;
15 | boolean isWaking;
16 | Semaphore semaphore = new Semaphore(0);
17 | public Selector getSelector() {
18 | return selector;
19 | }
20 |
21 | public SelectorWrapper(Selector selector) {
22 | this.selector = selector;
23 | }
24 |
25 | public int selectNow() throws IOException {
26 | return selector.selectNow();
27 | }
28 |
29 | public void select() throws IOException {
30 | select(0);
31 | }
32 |
33 | public void select(long timeout) throws IOException {
34 | try {
35 | semaphore.drainPermits();
36 | selector.select(timeout);
37 | }
38 | finally {
39 | semaphore.release(Integer.MAX_VALUE);
40 | }
41 | }
42 |
43 | public Set keys() {
44 | return selector.keys();
45 | }
46 |
47 | public Set selectedKeys() {
48 | return selector.selectedKeys();
49 | }
50 |
51 | public void close() throws IOException {
52 | selector.close();
53 | }
54 |
55 | public boolean isOpen() {
56 | return selector.isOpen();
57 | }
58 |
59 | public void wakeupOnce() {
60 | // see if it is selecting, ie, can't acquire a permit
61 | boolean selecting = !semaphore.tryAcquire();
62 | selector.wakeup();
63 | // if it was selecting, then the wakeup definitely worked.
64 | if (selecting)
65 | return;
66 |
67 | // now, we NEED to wait for the select to start to forcibly wake it.
68 | synchronized (this) {
69 | // check if another thread is already waiting
70 | if (isWaking) {
71 | // System.out.println("race wakeup already progressing");
72 | return;
73 | }
74 | isWaking = true;
75 | }
76 |
77 | try {
78 | // System.out.println("performing race wakup");
79 | // try to wake up 10 times
80 | for (int i = 0; i < 100; i++) {
81 | try {
82 | if (semaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) {
83 | // System.out.println("race wakeup success");
84 | return;
85 | }
86 | }
87 | catch (InterruptedException e) {
88 | }
89 | selector.wakeup();
90 | }
91 | }
92 | finally {
93 | synchronized (this) {
94 | isWaking = false;
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/DocumentBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.DataEmitter;
4 | import com.koushikdutta.async.DataSink;
5 | import com.koushikdutta.async.Util;
6 | import com.koushikdutta.async.callback.CompletedCallback;
7 | import com.koushikdutta.async.future.FutureCallback;
8 | import com.koushikdutta.async.http.AsyncHttpRequest;
9 | import com.koushikdutta.async.parser.DocumentParser;
10 |
11 | import org.w3c.dom.Document;
12 |
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.OutputStreamWriter;
15 |
16 | import javax.xml.transform.Transformer;
17 | import javax.xml.transform.TransformerFactory;
18 | import javax.xml.transform.dom.DOMSource;
19 | import javax.xml.transform.stream.StreamResult;
20 |
21 | /**
22 | * Created by koush on 8/30/13.
23 | */
24 | public class DocumentBody implements AsyncHttpRequestBody {
25 | public DocumentBody() {
26 | this(null);
27 | }
28 |
29 | public DocumentBody(Document document) {
30 | this.document = document;
31 | }
32 |
33 | ByteArrayOutputStream bout;
34 | private void prepare() {
35 | if (bout != null)
36 | return;
37 |
38 | try {
39 | DOMSource source = new DOMSource(document);
40 | TransformerFactory tf = TransformerFactory.newInstance();
41 | Transformer transformer = tf.newTransformer();
42 | bout = new ByteArrayOutputStream();
43 | OutputStreamWriter writer = new OutputStreamWriter(bout);
44 | StreamResult result = new StreamResult(writer);
45 | transformer.transform(source, result);
46 | writer.flush();
47 | }
48 | catch (Exception e) {
49 | }
50 | }
51 |
52 | @Override
53 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) {
54 | prepare();
55 | byte[] bytes = bout.toByteArray();
56 | Util.writeAll(sink, bytes, completed);
57 | }
58 |
59 | @Override
60 | public void parse(DataEmitter emitter, final CompletedCallback completed) {
61 | new DocumentParser().parse(emitter).setCallback(new FutureCallback() {
62 | @Override
63 | public void onCompleted(Exception e, Document result) {
64 | document = result;
65 | completed.onCompleted(e);
66 | }
67 | });
68 | }
69 |
70 | public static final String CONTENT_TYPE = "application/xml";
71 |
72 | @Override
73 | public String getContentType() {
74 | return CONTENT_TYPE;
75 | }
76 |
77 | @Override
78 | public boolean readFullyOnRequest() {
79 | return true;
80 | }
81 |
82 | @Override
83 | public int length() {
84 | prepare();
85 | return bout.size();
86 | }
87 |
88 | Document document;
89 | @Override
90 | public Document get() {
91 | return document;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/AsyncSemaphore.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import java.util.concurrent.Semaphore;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | public class AsyncSemaphore {
7 |
8 | Semaphore semaphore = new Semaphore(0);
9 |
10 | public void acquire() throws InterruptedException {
11 | ThreadQueue threadQueue = ThreadQueue.getOrCreateThreadQueue(Thread.currentThread());
12 | AsyncSemaphore last = threadQueue.waiter;
13 | threadQueue.waiter = this;
14 | Semaphore queueSemaphore = threadQueue.queueSemaphore;
15 | try {
16 | if (semaphore.tryAcquire())
17 | return;
18 |
19 | while (true) {
20 | // run the queue
21 | while (true) {
22 | Runnable run = threadQueue.remove();
23 | if (run == null)
24 | break;
25 | // Log.i(LOGTAG, "Pumping for AsyncSemaphore");
26 | run.run();
27 | }
28 |
29 | int permits = Math.max(1, queueSemaphore.availablePermits());
30 | queueSemaphore.acquire(permits);
31 | if (semaphore.tryAcquire())
32 | break;
33 | }
34 | }
35 | finally {
36 | threadQueue.waiter = last;
37 | }
38 | }
39 |
40 | public boolean tryAcquire(long timeout, TimeUnit timeunit) throws InterruptedException {
41 | long timeoutMs = TimeUnit.MILLISECONDS.convert(timeout, timeunit);
42 | ThreadQueue threadQueue = ThreadQueue.getOrCreateThreadQueue(Thread.currentThread());
43 | AsyncSemaphore last = threadQueue.waiter;
44 | threadQueue.waiter = this;
45 | Semaphore queueSemaphore = threadQueue.queueSemaphore;
46 |
47 | try {
48 | if (semaphore.tryAcquire())
49 | return true;
50 |
51 | long start = System.currentTimeMillis();
52 | do {
53 | // run the queue
54 | while (true) {
55 | Runnable run = threadQueue.remove();
56 | if (run == null)
57 | break;
58 | // Log.i(LOGTAG, "Pumping for AsyncSemaphore");
59 | run.run();
60 | }
61 |
62 | int permits = Math.max(1, queueSemaphore.availablePermits());
63 | if (!queueSemaphore.tryAcquire(permits, timeoutMs, TimeUnit.MILLISECONDS))
64 | return false;
65 | if (semaphore.tryAcquire())
66 | return true;
67 | }
68 | while (System.currentTimeMillis() - start < timeoutMs);
69 | return false;
70 | }
71 | finally {
72 | threadQueue.waiter = last;
73 | }
74 | }
75 |
76 | public void release() {
77 | semaphore.release();
78 | ThreadQueue.release(this);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/BufferedDataEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.DataCallback;
5 |
6 | public class BufferedDataEmitter implements DataEmitter, DataCallback {
7 | DataEmitter mEmitter;
8 | public BufferedDataEmitter(DataEmitter emitter) {
9 | mEmitter = emitter;
10 | mEmitter.setDataCallback(this);
11 |
12 | mEmitter.setEndCallback(new CompletedCallback() {
13 | @Override
14 | public void onCompleted(Exception ex) {
15 | mEnded = true;
16 | mEndException = ex;
17 | if (mBuffers.remaining() == 0 && mEndCallback != null)
18 | mEndCallback.onCompleted(ex);
19 | }
20 | });
21 | }
22 |
23 | @Override
24 | public void close() {
25 | mEmitter.close();
26 | }
27 |
28 | boolean mEnded = false;
29 | Exception mEndException;
30 |
31 | public void onDataAvailable() {
32 | if (mDataCallback != null && !mPaused && mBuffers.remaining() > 0)
33 | mDataCallback.onDataAvailable(this, mBuffers);
34 |
35 | if (mEnded && mBuffers.remaining() == 0 && mEndCallback != null)
36 | mEndCallback.onCompleted(mEndException);
37 | }
38 |
39 | ByteBufferList mBuffers = new ByteBufferList();
40 |
41 | DataCallback mDataCallback;
42 | @Override
43 | public void setDataCallback(DataCallback callback) {
44 | mDataCallback = callback;
45 | }
46 |
47 | @Override
48 | public DataCallback getDataCallback() {
49 | return mDataCallback;
50 | }
51 |
52 | @Override
53 | public boolean isChunked() {
54 | return false;
55 | }
56 |
57 | @Override
58 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
59 | bb.get(mBuffers);
60 |
61 | onDataAvailable();
62 | }
63 |
64 | private boolean mPaused;
65 | @Override
66 | public void pause() {
67 | mPaused = true;
68 | }
69 |
70 | @Override
71 | public void resume() {
72 | if (!mPaused)
73 | return;
74 | mPaused = false;
75 | onDataAvailable();
76 | }
77 |
78 | @Override
79 | public boolean isPaused() {
80 | return mPaused;
81 | }
82 |
83 |
84 | CompletedCallback mEndCallback;
85 | @Override
86 | public void setEndCallback(CompletedCallback callback) {
87 | mEndCallback = callback;
88 | }
89 |
90 | @Override
91 | public CompletedCallback getEndCallback() {
92 | return mEndCallback;
93 | }
94 |
95 | @Override
96 | public AsyncServer getServer() {
97 | return mEmitter.getServer();
98 | }
99 |
100 | @Override
101 | public String charset() {
102 | return mEmitter.charset();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/SSLTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.test.AndroidTestCase;
4 |
5 | import com.koushikdutta.async.AsyncServer;
6 | import com.koushikdutta.async.http.AsyncHttpClient;
7 | import com.koushikdutta.async.http.AsyncHttpGet;
8 | import com.koushikdutta.async.http.server.AsyncHttpServer;
9 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
10 | import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
11 | import com.koushikdutta.async.http.server.HttpServerRequestCallback;
12 |
13 | import org.json.JSONObject;
14 |
15 | import java.security.KeyStore;
16 |
17 | import javax.net.ssl.KeyManagerFactory;
18 | import javax.net.ssl.SSLContext;
19 | import javax.net.ssl.TrustManagerFactory;
20 |
21 | /**
22 | * Created by koush on 6/4/13.
23 | */
24 | public class SSLTests extends AndroidTestCase {
25 | public void testKeys() throws Exception {
26 | KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
27 | KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
28 |
29 | ks.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray());
30 | kmf.init(ks, "storepass".toCharArray());
31 |
32 |
33 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
34 | KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
35 | ts.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray());
36 | tmf.init(ts);
37 |
38 | SSLContext sslContext = SSLContext.getInstance("TLS");
39 | sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
40 |
41 | AsyncHttpServer httpServer = new AsyncHttpServer();
42 | httpServer.listenSecure(8888, sslContext);
43 | httpServer.get("/", new HttpServerRequestCallback() {
44 | @Override
45 | public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
46 | response.send("hello");
47 | }
48 | });
49 |
50 | Thread.sleep(1000);
51 |
52 | AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setSSLContext(sslContext);
53 | AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setTrustManagers(tmf.getTrustManagers());
54 | AsyncHttpClient.getDefaultInstance().executeString(new AsyncHttpGet("https://localhost:8888/"), null).get();
55 | }
56 |
57 | public void disabled__testClientCertificateIssue163() throws Exception {
58 | // https://security.springthroughtest.com/hello.json
59 |
60 | AsyncServer server = new AsyncServer();
61 | try {
62 | AsyncHttpClient client = new AsyncHttpClient(server);
63 | JSONObject json = client.executeJSONObject(new AsyncHttpGet("https://security.springthroughtest.com/hello.json"), null).get();
64 |
65 | }
66 | finally {
67 | server.stop();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/ByteUtilTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.FilteredDataEmitter;
5 | import com.koushikdutta.async.NullDataCallback;
6 | import com.koushikdutta.async.PushParser;
7 | import com.koushikdutta.async.TapCallback;
8 | import com.koushikdutta.async.Util;
9 |
10 | import junit.framework.TestCase;
11 |
12 | /**
13 | * Created by koush on 5/17/13.
14 | */
15 | public class ByteUtilTests extends TestCase {
16 | int valRead;
17 | public void testPushParserUntil() {
18 | valRead = 0;
19 | FilteredDataEmitter mock = new FilteredDataEmitter() {
20 | @Override
21 | public boolean isPaused() {
22 | return false;
23 | }
24 | };
25 | new PushParser(mock)
26 | .until((byte)0, new NullDataCallback())
27 | .readInt(new PushParser.ParseCallback() {
28 | public void parsed(Integer arg) {
29 | valRead = arg;
30 | }
31 | });
32 | byte[] bytes = new byte[] { 5, 5, 5, 5, 0, 10, 5, 5, 5 };
33 | Util.emitAllData(mock, new ByteBufferList(bytes));
34 | assertEquals(valRead, 0x0A050505);
35 | }
36 |
37 | public void testPushParserTapUntil() {
38 | valRead = 0;
39 | FilteredDataEmitter mock = new FilteredDataEmitter() {
40 | @Override
41 | public boolean isPaused() {
42 | return false;
43 | }
44 | };
45 | new PushParser(mock)
46 | .until((byte)0, new NullDataCallback())
47 | .readInt()
48 | .tap(new TapCallback() {
49 | public void parsed(int arg) {
50 | valRead = arg;
51 | }
52 | });
53 | byte[] bytes = new byte[] { 5, 5, 5, 5, 0, 10, 5, 5, 5 };
54 | Util.emitAllData(mock, new ByteBufferList(bytes));
55 | assertEquals(valRead, 0x0A050505);
56 | }
57 |
58 | int readInt;
59 | byte readByte;
60 | String readString;
61 |
62 | public void testTapCallback() {
63 | readInt = 0;
64 | readByte = 0;
65 | readString = "";
66 |
67 | FilteredDataEmitter mock = new FilteredDataEmitter() {
68 | @Override
69 | public boolean isPaused() {
70 | return false;
71 | }
72 | };
73 | new PushParser(mock)
74 | .readInt()
75 | .readByte()
76 | .readString()
77 | .tap(new TapCallback() {
78 | void tap(int i, byte b, String s) {
79 | readInt = i;
80 | readByte = b;
81 | readString = s;
82 | }
83 | });
84 |
85 | byte[] bytes = new byte[] { 10, 5, 5, 5, 3, 0, 0, 0, 4, 116, 101, 115, 116 };
86 | Util.emitAllData(mock, new ByteBufferList(bytes));
87 | assertEquals(readInt, 0x0A050505);
88 | assertEquals(readByte, (byte) 3);
89 | assertEquals(readString, "test");
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/FileDataEmitter.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.DataCallback;
5 | import com.koushikdutta.async.util.StreamUtility;
6 |
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.nio.ByteBuffer;
10 | import java.nio.channels.FileChannel;
11 |
12 | /**
13 | * Created by koush on 5/22/13.
14 | */
15 | public class FileDataEmitter extends DataEmitterBase {
16 | AsyncServer server;
17 | File file;
18 | public FileDataEmitter(AsyncServer server, File file) {
19 | this.server = server;
20 | this.file = file;
21 | paused = !server.isAffinityThread();
22 | if (!paused)
23 | doResume();
24 | }
25 |
26 | DataCallback callback;
27 | @Override
28 | public void setDataCallback(DataCallback callback) {
29 | this.callback = callback;
30 | }
31 |
32 | @Override
33 | public DataCallback getDataCallback() {
34 | return callback;
35 | }
36 |
37 | @Override
38 | public boolean isChunked() {
39 | return false;
40 | }
41 |
42 | boolean paused;
43 | @Override
44 | public void pause() {
45 | paused = true;
46 | }
47 |
48 | @Override
49 | public void resume() {
50 | paused = false;
51 | doResume();
52 | }
53 |
54 | @Override
55 | protected void report(Exception e) {
56 | StreamUtility.closeQuietly(channel);
57 | super.report(e);
58 | }
59 |
60 | ByteBufferList pending = new ByteBufferList();
61 | FileChannel channel;
62 | Runnable pumper = new Runnable() {
63 | @Override
64 | public void run() {
65 | try {
66 | if (channel == null)
67 | channel = new FileInputStream(file).getChannel();
68 | if (!pending.isEmpty()) {
69 | Util.emitAllData(FileDataEmitter.this, pending);
70 | if (!pending.isEmpty())
71 | return;
72 | }
73 | ByteBuffer b;
74 | do {
75 | b = ByteBufferList.obtain(8192);
76 | if (-1 == channel.read(b)) {
77 | report(null);
78 | return;
79 | }
80 | b.flip();
81 | pending.add(b);
82 | Util.emitAllData(FileDataEmitter.this, pending);
83 | }
84 | while (pending.remaining() == 0 && !isPaused());
85 | }
86 | catch (Exception e) {
87 | report(e);
88 | }
89 | }
90 | };
91 |
92 | private void doResume() {
93 | server.post(pumper);
94 | }
95 |
96 | @Override
97 | public boolean isPaused() {
98 | return paused;
99 | }
100 |
101 | @Override
102 | public AsyncServer getServer() {
103 | return server;
104 | }
105 |
106 | @Override
107 | public void close() {
108 | try {
109 | channel.close();
110 | }
111 | catch (Exception e) {
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/RedirectTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 | import com.koushikdutta.async.http.AsyncHttpClient;
5 | import com.koushikdutta.async.http.AsyncHttpGet;
6 | import com.koushikdutta.async.http.server.AsyncHttpServer;
7 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
8 | import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
9 | import com.koushikdutta.async.http.server.HttpServerRequestCallback;
10 |
11 | import junit.framework.TestCase;
12 |
13 | /**
14 | * Created by koush on 11/4/13.
15 | */
16 | public class RedirectTests extends TestCase {
17 | @Override
18 | protected void setUp() throws Exception {
19 | super.setUp();
20 | AsyncHttpServer server = new AsyncHttpServer();
21 | server.listen(6003);
22 | server.get("/foo", new HttpServerRequestCallback() {
23 | @Override
24 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
25 | response.redirect("/bar");
26 | }
27 | });
28 | server.get("/bar", new HttpServerRequestCallback() {
29 | @Override
30 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
31 | response.send("BORAT!");
32 | }
33 | });
34 |
35 | server.get("/foo/poo", new HttpServerRequestCallback() {
36 | @Override
37 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
38 | response.redirect("../poo");
39 | }
40 | });
41 | server.get("/poo", new HttpServerRequestCallback() {
42 | @Override
43 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
44 | response.send("SWEET!");
45 | }
46 | });
47 | server.get("/foo/bar", new HttpServerRequestCallback() {
48 | @Override
49 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
50 | response.redirect("baz");
51 | }
52 | });
53 | server.get("/foo/baz", new HttpServerRequestCallback() {
54 | @Override
55 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
56 | response.send("SUCCESS!");
57 | }
58 | });
59 | }
60 |
61 | @Override
62 | protected void tearDown() throws Exception {
63 | super.tearDown();
64 | AsyncServer.getDefault().stop();
65 | }
66 |
67 | public void testRelativeRedirect() throws Exception {
68 | String ret = AsyncHttpClient.getDefaultInstance()
69 | .executeString(new AsyncHttpGet("http://localhost:6003/foo/bar"), null)
70 | .get();
71 |
72 | assertEquals(ret, "SUCCESS!");
73 |
74 | ret = AsyncHttpClient.getDefaultInstance()
75 | .executeString(new AsyncHttpGet("http://localhost:6003/foo"), null)
76 | .get();
77 |
78 | assertEquals(ret, "BORAT!");
79 |
80 | ret = AsyncHttpClient.getDefaultInstance()
81 | .executeString(new AsyncHttpGet("http://localhost:6003/foo/poo"), null)
82 | .get();
83 |
84 | assertEquals(ret, "SWEET!");
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/libcore/HttpDate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.koushikdutta.async.http.libcore;
18 |
19 | import java.text.DateFormat;
20 | import java.text.ParseException;
21 | import java.text.SimpleDateFormat;
22 | import java.util.Date;
23 | import java.util.Locale;
24 | import java.util.TimeZone;
25 |
26 | /**
27 | * Best-effort parser for HTTP dates.
28 | */
29 | public final class HttpDate {
30 |
31 | /**
32 | * Most websites serve cookies in the blessed format. Eagerly create the parser to ensure such
33 | * cookies are on the fast path.
34 | */
35 | private static final ThreadLocal STANDARD_DATE_FORMAT
36 | = new ThreadLocal() {
37 | @Override protected DateFormat initialValue() {
38 | DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
39 | rfc1123.setTimeZone(TimeZone.getTimeZone("UTC"));
40 | return rfc1123;
41 | }
42 | };
43 |
44 | /**
45 | * If we fail to parse a date in a non-standard format, try each of these formats in sequence.
46 | */
47 | private static final String[] BROWSER_COMPATIBLE_DATE_FORMATS = new String[] {
48 | /* This list comes from {@code org.apache.http.impl.cookie.BrowserCompatSpec}. */
49 | "EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 1036
50 | "EEE MMM d HH:mm:ss yyyy", // ANSI C asctime()
51 | "EEE, dd-MMM-yyyy HH:mm:ss z",
52 | "EEE, dd-MMM-yyyy HH-mm-ss z",
53 | "EEE, dd MMM yy HH:mm:ss z",
54 | "EEE dd-MMM-yyyy HH:mm:ss z",
55 | "EEE dd MMM yyyy HH:mm:ss z",
56 | "EEE dd-MMM-yyyy HH-mm-ss z",
57 | "EEE dd-MMM-yy HH:mm:ss z",
58 | "EEE dd MMM yy HH:mm:ss z",
59 | "EEE,dd-MMM-yy HH:mm:ss z",
60 | "EEE,dd-MMM-yyyy HH:mm:ss z",
61 | "EEE, dd-MM-yyyy HH:mm:ss z",
62 |
63 | /* RI bug 6641315 claims a cookie of this format was once served by www.yahoo.com */
64 | "EEE MMM d yyyy HH:mm:ss z",
65 | };
66 |
67 | /**
68 | * Returns the date for {@code value}. Returns null if the value couldn't be
69 | * parsed.
70 | */
71 | public static Date parse(String value) {
72 | try {
73 | return STANDARD_DATE_FORMAT.get().parse(value);
74 | } catch (ParseException ignore) {
75 | }
76 | for (String formatString : BROWSER_COMPATIBLE_DATE_FORMATS) {
77 | try {
78 | return new SimpleDateFormat(formatString, Locale.US).parse(value);
79 | } catch (ParseException ignore) {
80 | }
81 | }
82 | return null;
83 | }
84 |
85 | /**
86 | * Returns the string for {@code value}.
87 | */
88 | public static String format(Date value) {
89 | return STANDARD_DATE_FORMAT.get().format(value);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/CacheTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.os.Environment;
4 |
5 | import com.koushikdutta.async.AsyncServer;
6 | import com.koushikdutta.async.AsyncServerSocket;
7 | import com.koushikdutta.async.http.AsyncHttpClient;
8 | import com.koushikdutta.async.http.AsyncHttpGet;
9 | import com.koushikdutta.async.http.ResponseCacheMiddleware;
10 | import com.koushikdutta.async.http.libcore.HttpDate;
11 | import com.koushikdutta.async.http.server.AsyncHttpServer;
12 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
13 | import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
14 | import com.koushikdutta.async.http.server.HttpServerRequestCallback;
15 |
16 | import junit.framework.TestCase;
17 |
18 | import java.io.File;
19 | import java.util.Date;
20 |
21 | /**
22 | * Created by koush on 6/13/13.
23 | */
24 | public class CacheTests extends TestCase {
25 | public void testMaxAgePrivate() throws Exception {
26 | AsyncHttpClient client = new AsyncHttpClient(AsyncServer.getDefault());
27 | ResponseCacheMiddleware cache = ResponseCacheMiddleware.addCache(client, new File(Environment.getExternalStorageDirectory(), "AndroidAsyncTest"), 1024 * 1024 * 10);
28 | AsyncHttpServer httpServer = new AsyncHttpServer();
29 | try {
30 | httpServer.get("/uname/(.*)", new HttpServerRequestCallback() {
31 | @Override
32 | public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
33 | response.getHeaders().getHeaders().set("Date", HttpDate.format(new Date()));
34 | response.getHeaders().getHeaders().set("Cache-Control", "private, max-age=10000");
35 | response.send(request.getMatcher().group(1));
36 | }
37 | });
38 |
39 | AsyncServerSocket socket = httpServer.listen(AsyncServer.getDefault(), 0);
40 | int port = socket.getLocalPort();
41 | // clear the old cache
42 | cache.clear();
43 |
44 | client.executeString(new AsyncHttpGet("http://localhost:" + port + "/uname/43434"), null).get();
45 |
46 | client.executeString(new AsyncHttpGet("http://localhost:" + port + "/uname/43434"), null).get();
47 |
48 |
49 | assertEquals(cache.getCacheHitCount(), 1);
50 | assertEquals(cache.getNetworkCount(), 1);
51 | }
52 | finally {
53 | AsyncServer.getDefault().stop();
54 | client.getMiddleware().remove(cache);
55 | }
56 | }
57 |
58 | // static public boolean deleteDirectory(File path) {
59 | // if (path.exists()) {
60 | // File[] files = path.listFiles();
61 | // if (files != null) {
62 | // for (int i = 0; i < files.length; i++) {
63 | // if (files[i].isDirectory()) {
64 | // deleteDirectory(files[i]);
65 | // } else {
66 | // files[i].delete();
67 | // }
68 | // }
69 | // }
70 | // }
71 | // return (path.delete());
72 | // }
73 |
74 | // public void testDiskLruCache() throws Exception {
75 | // File dir = new File(Environment.getExternalStorageDirectory(), "AndroidAsyncTest/cache-test");
76 | // deleteDirectory(dir);
77 | // DiskLruCache cache = DiskLruCache.open(dir, 0, 1000, 10000000);
78 | // DiskLruCache.Editor editor = cache.edit("stuff");
79 | //
80 | // DiskLruCache cache2 = DiskLruCache.open(dir, 0, 2, 10000000);
81 | // DiskLruCache.Snapshot snapshot = cache2.get("stuff");
82 | // }
83 | }
84 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/WebSocketTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.AsyncServer;
4 | import com.koushikdutta.async.callback.CompletedCallback;
5 | import com.koushikdutta.async.http.AsyncHttpClient;
6 | import com.koushikdutta.async.http.AsyncHttpClient.WebSocketConnectCallback;
7 | import com.koushikdutta.async.http.WebSocket;
8 | import com.koushikdutta.async.http.WebSocket.StringCallback;
9 | import com.koushikdutta.async.http.libcore.RequestHeaders;
10 | import com.koushikdutta.async.http.server.AsyncHttpServer;
11 | import com.koushikdutta.async.http.server.AsyncHttpServer.WebSocketRequestCallback;
12 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
13 |
14 | import junit.framework.TestCase;
15 |
16 | import java.util.concurrent.Semaphore;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | public class WebSocketTests extends TestCase {
20 | AsyncHttpServer httpServer;
21 |
22 | @Override
23 | protected void setUp() throws Exception {
24 | super.setUp();
25 |
26 | httpServer = new AsyncHttpServer();
27 | httpServer.setErrorCallback(new CompletedCallback() {
28 | @Override
29 | public void onCompleted(Exception ex) {
30 | fail();
31 | }
32 | });
33 | httpServer.listen(AsyncServer.getDefault(), 5000);
34 |
35 |
36 | httpServer.websocket("/ws", new WebSocketRequestCallback() {
37 | @Override
38 | public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) {
39 | webSocket.setStringCallback(new StringCallback() {
40 | @Override
41 | public void onStringAvailable(String s) {
42 | webSocket.send(s);
43 | }
44 | });
45 | }
46 | });
47 | }
48 |
49 | private static final long TIMEOUT = 10000L;
50 | public void testWebSocket() throws Exception {
51 | final Semaphore semaphore = new Semaphore(0);
52 |
53 | AsyncHttpClient.getDefaultInstance().websocket("http://localhost:5000/ws", null, new WebSocketConnectCallback() {
54 | @Override
55 | public void onCompleted(Exception ex, WebSocket webSocket) {
56 | webSocket.send("hello");
57 | webSocket.setStringCallback(new StringCallback() {
58 | @Override
59 | public void onStringAvailable(String s) {
60 | assertEquals(s, "hello");
61 | semaphore.release();
62 | }
63 | });
64 | }
65 | });
66 |
67 | assertTrue(semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS));
68 | }
69 |
70 | // public void testDisconnect() throws Exception {
71 | // final Semaphore semaphore = new Semaphore(0);
72 | //
73 | // AsyncHttpClient.getDefaultInstance().websocket("http://192.168.1.2:3005", null, new WebSocketConnectCallback() {
74 | // @Override
75 | // public void onCompleted(Exception ex, WebSocket webSocket) {
76 | // webSocket.setClosedCallback(new CompletedCallback() {
77 | // @Override
78 | // public void onCompleted(Exception ex) {
79 | // semaphore.release();
80 | // }
81 | // });
82 | // }
83 | // });
84 | //
85 | // assertTrue(semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS));
86 | // }
87 |
88 | @Override
89 | protected void tearDown() throws Exception {
90 | super.tearDown();
91 |
92 | httpServer.stop();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/stream/OutputStreamDataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.stream;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.nio.ByteBuffer;
6 |
7 | import com.koushikdutta.async.AsyncServer;
8 | import com.koushikdutta.async.ByteBufferList;
9 | import com.koushikdutta.async.DataSink;
10 | import com.koushikdutta.async.callback.CompletedCallback;
11 | import com.koushikdutta.async.callback.WritableCallback;
12 |
13 | public class OutputStreamDataSink implements DataSink {
14 | public OutputStreamDataSink(AsyncServer server) {
15 | this(server, null);
16 | }
17 |
18 | @Override
19 | public void end() {
20 | try {
21 | if (mStream != null)
22 | mStream.close();
23 | reportClose(null);
24 | }
25 | catch (IOException e) {
26 | reportClose(e);
27 | }
28 | }
29 |
30 | @Override
31 | public void close() {
32 | end();
33 | }
34 |
35 | AsyncServer server;
36 | public OutputStreamDataSink(AsyncServer server, OutputStream stream) {
37 | this.server = server;
38 | setOutputStream(stream);
39 | }
40 |
41 | OutputStream mStream;
42 | public void setOutputStream(OutputStream stream) {
43 | mStream = stream;
44 | }
45 |
46 | public OutputStream getOutputStream() throws IOException {
47 | return mStream;
48 | }
49 |
50 | @Override
51 | public void write(final ByteBuffer bb) {
52 | try {
53 | getOutputStream().write(bb.array(), bb.arrayOffset() + bb.position(), bb.remaining());
54 | }
55 | catch (IOException e) {
56 | reportClose(e);
57 | }
58 | bb.position(0);
59 | bb.limit(0);
60 | }
61 |
62 | @Override
63 | public void write(final ByteBufferList bb) {
64 | try {
65 | while (bb.size() > 0) {
66 | ByteBuffer b = bb.remove();
67 | getOutputStream().write(b.array(), b.arrayOffset() + b.position(), b.remaining());
68 | ByteBufferList.reclaim(b);
69 | }
70 | }
71 | catch (IOException e) {
72 | reportClose(e);
73 | }
74 | finally {
75 | bb.recycle();
76 | }
77 | }
78 |
79 | WritableCallback mWritable;
80 | @Override
81 | public void setWriteableCallback(WritableCallback handler) {
82 | mWritable = handler;
83 | }
84 |
85 | @Override
86 | public WritableCallback getWriteableCallback() {
87 | return mWritable;
88 | }
89 |
90 | @Override
91 | public boolean isOpen() {
92 | return closeReported;
93 | }
94 |
95 | boolean closeReported;
96 | Exception closeException;
97 | public void reportClose(Exception ex) {
98 | if (closeReported)
99 | return;
100 | closeReported = true;
101 | closeException = ex;
102 |
103 | if (mClosedCallback != null)
104 | mClosedCallback.onCompleted(closeException);
105 | }
106 |
107 | CompletedCallback mClosedCallback;
108 | @Override
109 | public void setClosedCallback(CompletedCallback handler) {
110 | mClosedCallback = handler;
111 | }
112 |
113 | @Override
114 | public CompletedCallback getClosedCallback() {
115 | return mClosedCallback;
116 | }
117 |
118 | @Override
119 | public AsyncServer getServer() {
120 | return server;
121 | }
122 |
123 | WritableCallback outputStreamCallback;
124 | public void setOutputStreamWritableCallback(WritableCallback outputStreamCallback) {
125 | this.outputStreamCallback = outputStreamCallback;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/DnsTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import com.koushikdutta.async.AsyncDatagramSocket;
4 | import com.koushikdutta.async.AsyncServer;
5 | import com.koushikdutta.async.AsyncSocket;
6 | import com.koushikdutta.async.ByteBufferList;
7 | import com.koushikdutta.async.DataEmitter;
8 | import com.koushikdutta.async.callback.ConnectCallback;
9 | import com.koushikdutta.async.callback.DataCallback;
10 | import com.koushikdutta.async.dns.Dns;
11 | import com.koushikdutta.async.dns.DnsResponse;
12 | import com.koushikdutta.async.future.FutureCallback;
13 |
14 | import junit.framework.TestCase;
15 |
16 | import java.net.DatagramPacket;
17 | import java.net.DatagramSocket;
18 | import java.net.Inet4Address;
19 | import java.net.InetAddress;
20 | import java.net.InetSocketAddress;
21 | import java.net.MulticastSocket;
22 | import java.net.UnknownHostException;
23 | import java.nio.channels.DatagramChannel;
24 | import java.util.concurrent.Semaphore;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * Created by koush on 10/20/13.
29 | */
30 | public class DnsTests extends TestCase {
31 | public void testLookup() throws Exception {
32 | // final Semaphore semaphore = new Semaphore(0);
33 | // Dns.lookup("google.com")
34 | // .setCallback(new FutureCallback() {
35 | // @Override
36 | // public void onCompleted(Exception e, DnsResponse result) {
37 | // semaphore.release();
38 | // }
39 | // });
40 | //
41 | // semaphore.tryAcquire(1000000, TimeUnit.MILLISECONDS);
42 | }
43 |
44 | public void testMulticastLookup() throws Exception {
45 | // MulticastSocket socket = new MulticastSocket(5353);
46 | // socket.joinGroup(InetAddress.getByName("224.0.0.251"));
47 | // DatagramChannel channel = socket.getChannel();
48 | // assertNotNull(channel);
49 |
50 | // while (true) {
51 | // DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
52 | // socket.receive(packet);
53 | // System.out.println(new String(packet.getData()));
54 | // }
55 |
56 | // AsyncDatagramSocket dgram = AsyncServer.getDefault().openDatagram(new InetSocketAddress(5353), true);
57 | // ((DatagramSocket)dgram.getSocket()).setReuseAddress(true);
58 | // dgram.setDataCallback(new DataCallback() {
59 | // @Override
60 | // public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
61 | // System.out.println(bb.readString());
62 | // }
63 | // });
64 | // ((DatagramSocket)dgram.getSocket()).setBroadcast(true);
65 |
66 |
67 | // final Semaphore semaphore = new Semaphore(0);
68 | // Dns.multicastLookup("_airplay._tcp.local", new FutureCallback() {
69 | // @Override
70 | // public void onCompleted(Exception e, DnsResponse result) {
71 | //// semaphore.release();
72 | // }
73 | // });
74 | //
75 | // semaphore.tryAcquire(1000000, TimeUnit.MILLISECONDS);
76 | }
77 |
78 | public void testNoDomain() throws Exception {
79 | AsyncServer server = new AsyncServer();
80 |
81 | try {
82 | final Semaphore semaphore = new Semaphore(0);
83 | server.connectSocket("www.clockworkmod-notfound.com", 8080, new ConnectCallback() {
84 | @Override
85 | public void onConnectCompleted(Exception ex, AsyncSocket socket) {
86 | assertTrue(ex instanceof UnknownHostException);
87 | semaphore.release();
88 | }
89 | });
90 | assertTrue(semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS));
91 | }
92 | finally {
93 | server.stop();
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http.body;
2 |
3 | import com.koushikdutta.async.ByteBufferList;
4 | import com.koushikdutta.async.DataEmitter;
5 | import com.koushikdutta.async.DataSink;
6 | import com.koushikdutta.async.Util;
7 | import com.koushikdutta.async.callback.CompletedCallback;
8 | import com.koushikdutta.async.callback.DataCallback;
9 | import com.koushikdutta.async.http.AsyncHttpRequest;
10 | import com.koushikdutta.async.http.Multimap;
11 | import com.koushikdutta.async.util.Charsets;
12 |
13 | import org.apache.http.NameValuePair;
14 |
15 | import java.io.UnsupportedEncodingException;
16 | import java.net.URLEncoder;
17 | import java.util.List;
18 |
19 | public class UrlEncodedFormBody implements AsyncHttpRequestBody {
20 | private Multimap mParameters;
21 | private byte[] mBodyBytes;
22 |
23 | public UrlEncodedFormBody(Multimap parameters) {
24 | mParameters = parameters;
25 | }
26 |
27 | public UrlEncodedFormBody(List parameters) {
28 | mParameters = new Multimap(parameters);
29 | }
30 |
31 | private void buildData() {
32 | boolean first = true;
33 | StringBuilder b = new StringBuilder();
34 | try {
35 | for (NameValuePair pair: mParameters) {
36 | if (pair.getValue() == null)
37 | continue;
38 | if (!first)
39 | b.append('&');
40 | first = false;
41 |
42 | b.append(URLEncoder.encode(pair.getName(), "UTF-8"));
43 | b.append('=');
44 | b.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
45 | }
46 | mBodyBytes = b.toString().getBytes("UTF-8");
47 | }
48 | catch (UnsupportedEncodingException e) {
49 | }
50 | }
51 |
52 | @Override
53 | public void write(AsyncHttpRequest request, final DataSink response, final CompletedCallback completed) {
54 | if (mBodyBytes == null)
55 | buildData();
56 | Util.writeAll(response, mBodyBytes, completed);
57 | }
58 |
59 | public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
60 | @Override
61 | public String getContentType() {
62 | return CONTENT_TYPE + "; charset=utf-8";
63 | }
64 |
65 | @Override
66 | public void parse(DataEmitter emitter, final CompletedCallback completed) {
67 | final ByteBufferList data = new ByteBufferList();
68 | emitter.setDataCallback(new DataCallback() {
69 | @Override
70 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
71 | bb.get(data);
72 | }
73 | });
74 | emitter.setEndCallback(new CompletedCallback() {
75 | @Override
76 | public void onCompleted(Exception ex) {
77 | if (ex != null) {
78 | completed.onCompleted(ex);
79 | return;
80 | }
81 | try {
82 | mParameters = Multimap.parseUrlEncoded(data.readString());
83 | completed.onCompleted(null);
84 | }
85 | catch (Exception e) {
86 | completed.onCompleted(e);
87 | }
88 | }
89 | });
90 | }
91 |
92 | public UrlEncodedFormBody() {
93 | }
94 |
95 | @Override
96 | public boolean readFullyOnRequest() {
97 | return true;
98 | }
99 |
100 | @Override
101 | public int length() {
102 | if (mBodyBytes == null)
103 | buildData();
104 | return mBodyBytes.length;
105 | }
106 |
107 | @Override
108 | public Multimap get() {
109 | return mParameters;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/Multimap.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.http;
2 |
3 | import android.net.Uri;
4 | import com.koushikdutta.async.http.libcore.RawHeaders;
5 | import org.apache.http.NameValuePair;
6 | import org.apache.http.message.BasicNameValuePair;
7 |
8 | import java.net.URLDecoder;
9 | import java.util.ArrayList;
10 | import java.util.Hashtable;
11 | import java.util.Iterator;
12 | import java.util.List;
13 |
14 | /**
15 | * Created by koush on 5/27/13.
16 | */
17 | public class Multimap extends Hashtable> implements Iterable {
18 | public Multimap() {
19 | }
20 |
21 | public String getString(String name) {
22 | List ret = get(name);
23 | if (ret == null || ret.size() == 0)
24 | return null;
25 | return ret.get(0);
26 | }
27 |
28 | public void add(String name, String value) {
29 | List ret = get(name);
30 | if (ret == null) {
31 | ret = new ArrayList();
32 | put(name, ret);
33 | }
34 | ret.add(value);
35 | }
36 |
37 | public void put(String name, String value) {
38 | ArrayList ret = new ArrayList();
39 | ret.add(value);
40 | put(name, ret);
41 | }
42 |
43 | public Multimap(RawHeaders headers) {
44 | headers.toMultimap().putAll(this);
45 | }
46 |
47 | public Multimap(List pairs) {
48 | for (NameValuePair pair: pairs)
49 | add(pair.getName(), pair.getValue());
50 | }
51 |
52 | public static Multimap parseHeader(String header) {
53 | if (header == null)
54 | return null;
55 | Multimap map = new Multimap();
56 | String[] parts = header.split(";");
57 | for (String part: parts) {
58 | String[] pair = part.split("=", 2);
59 | String key = pair[0].trim();
60 | String v = null;
61 | if (pair.length > 1)
62 | v = pair[1];
63 | if (v != null && v.endsWith("\"") && v.startsWith("\""))
64 | v = v.substring(1, v.length() - 1);
65 | map.add(key, v);
66 | }
67 | return map;
68 | }
69 |
70 | public static Multimap parseHeader(RawHeaders headers, String header) {
71 | return parseHeader(headers.get(header));
72 | }
73 |
74 | public static Multimap parseQuery(String query) {
75 | Multimap map = new Multimap();
76 | String[] pairs = query.split("&");
77 | for (String p : pairs) {
78 | String[] pair = p.split("=", 2);
79 | if (pair.length == 0)
80 | continue;
81 | String name = Uri.decode(pair[0]);
82 | String value = null;
83 | if (pair.length == 2)
84 | value = Uri.decode(pair[1]);
85 | map.add(name, value);
86 | }
87 | return map;
88 | }
89 |
90 | public static Multimap parseUrlEncoded(String query) {
91 | Multimap map = new Multimap();
92 | String[] pairs = query.split("&");
93 | for (String p : pairs) {
94 | String[] pair = p.split("=", 2);
95 | if (pair.length == 0)
96 | continue;
97 | String name = URLDecoder.decode(pair[0]);
98 | String value = null;
99 | if (pair.length == 2)
100 | value = URLDecoder.decode(pair[1]);
101 | map.add(name, value);
102 | }
103 | return map;
104 | }
105 |
106 | @Override
107 | public Iterator iterator() {
108 | ArrayList ret = new ArrayList();
109 | for (String name: keySet()) {
110 | List values = get(name);
111 | for (String value: values) {
112 | ret.add(new BasicNameValuePair(name, value));
113 | }
114 | }
115 | return ret.iterator();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/http/libcore/HeaderParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.koushikdutta.async.http.libcore;
18 |
19 | final class HeaderParser {
20 |
21 | public interface CacheControlHandler {
22 | void handle(String directive, String parameter);
23 | }
24 |
25 | /**
26 | * Parse a comma-separated list of cache control header values.
27 | */
28 | public static void parseCacheControl(String value, CacheControlHandler handler) {
29 | int pos = 0;
30 | while (pos < value.length()) {
31 | int tokenStart = pos;
32 | pos = skipUntil(value, pos, "=,");
33 | String directive = value.substring(tokenStart, pos).trim();
34 |
35 | if (pos == value.length() || value.charAt(pos) == ',') {
36 | pos++; // consume ',' (if necessary)
37 | handler.handle(directive, null);
38 | continue;
39 | }
40 |
41 | pos++; // consume '='
42 | pos = skipWhitespace(value, pos);
43 |
44 | String parameter;
45 |
46 | // quoted string
47 | if (pos < value.length() && value.charAt(pos) == '\"') {
48 | pos++; // consume '"' open quote
49 | int parameterStart = pos;
50 | pos = skipUntil(value, pos, "\"");
51 | parameter = value.substring(parameterStart, pos);
52 | pos++; // consume '"' close quote (if necessary)
53 |
54 | // unquoted string
55 | } else {
56 | int parameterStart = pos;
57 | pos = skipUntil(value, pos, ",");
58 | parameter = value.substring(parameterStart, pos).trim();
59 | }
60 |
61 | handler.handle(directive, parameter);
62 | }
63 | }
64 |
65 | /**
66 | * Returns the next index in {@code input} at or after {@code pos} that
67 | * contains a character from {@code characters}. Returns the input length if
68 | * none of the requested characters can be found.
69 | */
70 | private static int skipUntil(String input, int pos, String characters) {
71 | for (; pos < input.length(); pos++) {
72 | if (characters.indexOf(input.charAt(pos)) != -1) {
73 | break;
74 | }
75 | }
76 | return pos;
77 | }
78 |
79 | /**
80 | * Returns the next non-whitespace character in {@code input} that is white
81 | * space. Result is undefined if input contains newline characters.
82 | */
83 | private static int skipWhitespace(String input, int pos) {
84 | for (; pos < input.length(); pos++) {
85 | char c = input.charAt(pos);
86 | if (c != ' ' && c != '\t') {
87 | break;
88 | }
89 | }
90 | return pos;
91 | }
92 |
93 | /**
94 | * Returns {@code value} as a positive integer, or 0 if it is negative, or
95 | * -1 if it cannot be parsed.
96 | */
97 | public static int parseSeconds(String value) {
98 | try {
99 | long seconds = Long.parseLong(value);
100 | if (seconds > Integer.MAX_VALUE) {
101 | return Integer.MAX_VALUE;
102 | } else if (seconds < 0) {
103 | return 0;
104 | } else {
105 | return (int) seconds;
106 | }
107 | } catch (NumberFormatException e) {
108 | return -1;
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/util/StreamUtility.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.util;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.Closeable;
5 | import java.io.DataInputStream;
6 | import java.io.DataOutputStream;
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.io.OutputStream;
13 | import java.nio.ByteBuffer;
14 | import java.nio.channels.Channels;
15 | import java.nio.channels.ReadableByteChannel;
16 | import java.nio.channels.WritableByteChannel;
17 |
18 | public class StreamUtility {
19 | public static void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
20 | final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
21 | while (src.read(buffer) != -1) {
22 | // prepare the buffer to be drained
23 | buffer.flip();
24 | // write to the channel, may block
25 | dest.write(buffer);
26 | // If partial transfer, shift remainder down
27 | // If buffer is empty, same as doing recycle()
28 | buffer.compact();
29 | }
30 | // EOF will leave buffer in fill state
31 | buffer.flip();
32 | // make sure the buffer is fully drained.
33 | while (buffer.hasRemaining()) {
34 | dest.write(buffer);
35 | }
36 | }
37 |
38 | public static void copyStream(InputStream input, OutputStream output) throws IOException
39 | {
40 | final ReadableByteChannel inputChannel = Channels.newChannel(input);
41 | final WritableByteChannel outputChannel = Channels.newChannel(output);
42 | // copy the channels
43 | fastChannelCopy(inputChannel, outputChannel);
44 | }
45 |
46 | public static byte[] readToEndAsArray(InputStream input) throws IOException
47 | {
48 | DataInputStream dis = new DataInputStream(input);
49 | byte[] stuff = new byte[1024];
50 | ByteArrayOutputStream buff = new ByteArrayOutputStream();
51 | int read = 0;
52 | while ((read = dis.read(stuff)) != -1)
53 | {
54 | buff.write(stuff, 0, read);
55 | }
56 | dis.close();
57 | return buff.toByteArray();
58 | }
59 |
60 | public static String readToEnd(InputStream input) throws IOException
61 | {
62 | return new String(readToEndAsArray(input));
63 | }
64 |
65 | static public String readFile(String filename) throws IOException {
66 | return readFile(new File(filename));
67 | }
68 |
69 | static public String readFile(File file) throws IOException {
70 | byte[] buffer = new byte[(int) file.length()];
71 | DataInputStream input = null;
72 | try {
73 | input = new DataInputStream(new FileInputStream(file));
74 | input.readFully(buffer);
75 | } finally {
76 | closeQuietly(input);
77 | }
78 | return new String(buffer);
79 | }
80 |
81 | public static void writeFile(File file, String string) throws IOException {
82 | file.getParentFile().mkdirs();
83 | DataOutputStream dout = new DataOutputStream(new FileOutputStream(file));
84 | dout.write(string.getBytes());
85 | dout.close();
86 | }
87 |
88 | public static void writeFile(String file, String string) throws IOException {
89 | writeFile(new File(file), string);
90 | }
91 |
92 | public static void closeQuietly(Closeable... closeables) {
93 | if (closeables == null)
94 | return;
95 | for (Closeable closeable : closeables) {
96 | if (closeable != null) {
97 | try {
98 | closeable.close();
99 | } catch (IOException e) {
100 | // http://stackoverflow.com/a/156525/9636
101 | }
102 | }
103 | }
104 | }
105 |
106 | public static void eat(InputStream input) throws IOException {
107 | byte[] stuff = new byte[1024];
108 | while (input.read(stuff) != -1);
109 | }
110 | }
111 |
112 |
--------------------------------------------------------------------------------
/AndroidAsync/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/AndroidAsyncSample/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/AndroidAsync/src/com/koushikdutta/async/BufferedDataSink.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async;
2 |
3 | import com.koushikdutta.async.callback.CompletedCallback;
4 | import com.koushikdutta.async.callback.WritableCallback;
5 |
6 | import java.nio.ByteBuffer;
7 |
8 | public class BufferedDataSink implements DataSink {
9 | DataSink mDataSink;
10 | public BufferedDataSink(DataSink datasink) {
11 | setDataSink(datasink);
12 | }
13 |
14 | public boolean isBuffering() {
15 | return mPendingWrites.hasRemaining();
16 | }
17 |
18 | public DataSink getDataSink() {
19 | return mDataSink;
20 | }
21 |
22 | public void setDataSink(DataSink datasink) {
23 | mDataSink = datasink;
24 | mDataSink.setWriteableCallback(new WritableCallback() {
25 | @Override
26 | public void onWriteable() {
27 | writePending();
28 | }
29 | });
30 | }
31 |
32 | private void writePending() {
33 | // Log.i("NIO", "Writing to buffer...");
34 | if (mPendingWrites.hasRemaining()) {
35 | mDataSink.write(mPendingWrites);
36 | if (mPendingWrites.remaining() == 0) {
37 | if (endPending)
38 | mDataSink.end();
39 | }
40 | }
41 | if (!mPendingWrites.hasRemaining() && mWritable != null)
42 | mWritable.onWriteable();
43 | }
44 |
45 | ByteBufferList mPendingWrites = new ByteBufferList();
46 |
47 | @Override
48 | public void write(ByteBuffer bb) {
49 | if (remaining() >= getMaxBuffer())
50 | return;
51 |
52 | boolean needsWrite = true;
53 | if (!mPendingWrites.hasRemaining()) {
54 | needsWrite = false;
55 | mDataSink.write(bb);
56 | }
57 |
58 | if (bb.hasRemaining()) {
59 | ByteBuffer dup = ByteBufferList.obtain(bb.remaining());
60 | dup.put(bb);
61 | dup.flip();
62 | mPendingWrites.add(dup);
63 | if (needsWrite)
64 | mDataSink.write(mPendingWrites);
65 | }
66 | }
67 |
68 | @Override
69 | public void write(ByteBufferList bb) {
70 | write(bb, false);
71 | }
72 |
73 | protected void write(ByteBufferList bb, boolean ignoreBuffer) {
74 | if (!mPendingWrites.hasRemaining())
75 | mDataSink.write(bb);
76 |
77 | if (bb.remaining() > 0) {
78 | int toRead = Math.min(bb.remaining(), mMaxBuffer);
79 | if (ignoreBuffer)
80 | toRead = bb.remaining();
81 | if (toRead > 0) {
82 | bb.get(mPendingWrites, toRead);
83 | }
84 | }
85 | }
86 |
87 | WritableCallback mWritable;
88 | @Override
89 | public void setWriteableCallback(WritableCallback handler) {
90 | mWritable = handler;
91 | }
92 |
93 | @Override
94 | public WritableCallback getWriteableCallback() {
95 | return mWritable;
96 | }
97 |
98 | public int remaining() {
99 | return mPendingWrites.remaining();
100 | }
101 |
102 | int mMaxBuffer = Integer.MAX_VALUE;
103 | public int getMaxBuffer() {
104 | return mMaxBuffer;
105 | }
106 |
107 | public void setMaxBuffer(int maxBuffer) {
108 | assert maxBuffer >= 0;
109 | mMaxBuffer = maxBuffer;
110 | }
111 |
112 | @Override
113 | public boolean isOpen() {
114 | return mDataSink.isOpen();
115 | }
116 |
117 | @Override
118 | public void close() {
119 | mDataSink.close();
120 | }
121 |
122 | boolean endPending;
123 | @Override
124 | public void end() {
125 | if (mPendingWrites.hasRemaining()) {
126 | endPending = true;
127 | return;
128 | }
129 | mDataSink.end();
130 | }
131 |
132 | @Override
133 | public void setClosedCallback(CompletedCallback handler) {
134 | mDataSink.setClosedCallback(handler);
135 | }
136 |
137 | @Override
138 | public CompletedCallback getClosedCallback() {
139 | return mDataSink.getClosedCallback();
140 | }
141 |
142 | @Override
143 | public AsyncServer getServer() {
144 | return mDataSink.getServer();
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/AndroidAsync/test/src/com/koushikdutta/async/test/TimeoutTests.java:
--------------------------------------------------------------------------------
1 | package com.koushikdutta.async.test;
2 |
3 | import android.net.Uri;
4 | import android.util.Log;
5 |
6 | import com.koushikdutta.async.AsyncServer;
7 | import com.koushikdutta.async.DataSink;
8 | import com.koushikdutta.async.callback.CompletedCallback;
9 | import com.koushikdutta.async.http.AsyncHttpClient;
10 | import com.koushikdutta.async.http.AsyncHttpRequest;
11 | import com.koushikdutta.async.http.body.StringBody;
12 | import com.koushikdutta.async.http.server.AsyncHttpServer;
13 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
14 | import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
15 | import com.koushikdutta.async.http.server.HttpServerRequestCallback;
16 |
17 | import junit.framework.TestCase;
18 |
19 | import java.net.URI;
20 | import java.util.concurrent.TimeoutException;
21 |
22 | /**
23 | * Created by koush on 7/11/13.
24 | */
25 | public class TimeoutTests extends TestCase {
26 | public TimeoutTests() {
27 | server.get("/3", new HttpServerRequestCallback() {
28 | @Override
29 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
30 | // never respond
31 | AsyncServer.getDefault().postDelayed(new Runnable() {
32 | @Override
33 | public void run() {
34 | response.send("3");
35 | }
36 | }, 1000);
37 | }
38 | });
39 |
40 | server.post("/now", new HttpServerRequestCallback() {
41 | @Override
42 | public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
43 | StringBody body = (StringBody)request.getBody();
44 | response.send(body.get());
45 | }
46 | });
47 | }
48 | AsyncHttpServer server = new AsyncHttpServer();
49 |
50 | @Override
51 | protected void setUp() throws Exception {
52 | super.setUp();
53 | server.listen(AsyncServer.getDefault(), 5000);
54 | }
55 |
56 | @Override
57 | protected void tearDown() throws Exception {
58 | super.tearDown();
59 | server.stop();
60 | AsyncServer.getDefault().stop();
61 | }
62 |
63 | public void testTimeout() throws Exception {
64 | AsyncHttpRequest req = new AsyncHttpRequest(Uri.parse("http://localhost:5000/3"), "GET");
65 | req.setTimeout(1000);
66 | try {
67 | AsyncHttpClient.getDefaultInstance().executeString(req, null).get();
68 | fail();
69 | }
70 | catch (Exception e) {
71 | Log.d("timeout", "error", e);
72 | assertTrue(e.getCause() instanceof TimeoutException);
73 | }
74 |
75 | req = new AsyncHttpRequest(Uri.parse("http://localhost:5000/3"), "GET");
76 | assertEquals("3", AsyncHttpClient.getDefaultInstance().executeString(req, null).get());
77 | }
78 |
79 | public void testSlowBody() throws Exception {
80 | AsyncHttpRequest req = new AsyncHttpRequest(Uri.parse("http://localhost:5000/now"), "POST");
81 | req.setTimeout(1000);
82 | req.setLogging("slowbody", Log.VERBOSE);
83 | req.setBody(new DelayedStringBody("foo"));
84 | assertEquals("foo", AsyncHttpClient.getDefaultInstance().executeString(req, null).get());
85 |
86 | req = new AsyncHttpRequest(Uri.parse("http://localhost:5000/3"), "GET");
87 | req.setLogging("slowbody", Log.VERBOSE);
88 | req.setTimeout(100);
89 | req.setBody(new DelayedStringBody("foo"));
90 | try {
91 | AsyncHttpClient.getDefaultInstance().executeString(req, null).get();
92 | fail();
93 | }
94 | catch (Exception e) {
95 | Log.d("timeout", "error", e);
96 | assertTrue(e.getCause() instanceof TimeoutException);
97 | }
98 | }
99 |
100 | class DelayedStringBody extends StringBody {
101 | public DelayedStringBody(String value) {
102 | super(value);
103 | }
104 | @Override
105 | public void write(final AsyncHttpRequest request, final DataSink sink, final CompletedCallback completed) {
106 | AsyncServer.getDefault().postDelayed(new Runnable() {
107 | @Override
108 | public void run() {
109 | DelayedStringBody.super.write(request, sink, completed);
110 | }
111 | }, 1000);
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------