├── .github └── FUNDING.yml ├── .gitignore ├── AndroidAsync-Kotlin ├── .gitignore ├── README.md ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── koushikdutta │ │ └── async │ │ └── kotlin │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── koushikdutta │ │ └── async │ │ └── kotlin │ │ └── FutureExtensions.kt │ └── test │ └── java │ └── com │ └── koushikdutta │ └── async │ └── kotlin │ └── ExampleUnitTest.kt ├── AndroidAsync ├── .classpath ├── Android.mk ├── AndroidManifest.xml ├── build.gradle ├── ic_launcher-web.png ├── lint.xml ├── maven.gradle ├── proguard-project.txt ├── project.properties ├── res │ └── .gitignore ├── src │ └── com │ │ └── koushikdutta │ │ └── async │ │ ├── AsyncDatagramSocket.java │ │ ├── AsyncNetworkSocket.java │ │ ├── AsyncSSLException.java │ │ ├── AsyncSSLServerSocket.java │ │ ├── AsyncSSLSocket.java │ │ ├── AsyncSSLSocketWrapper.java │ │ ├── AsyncSemaphore.java │ │ ├── AsyncServer.java │ │ ├── AsyncServerSocket.java │ │ ├── AsyncSocket.java │ │ ├── BufferedDataSink.java │ │ ├── ByteBufferList.java │ │ ├── ChannelWrapper.java │ │ ├── DataEmitter.java │ │ ├── DataEmitterBase.java │ │ ├── DataEmitterReader.java │ │ ├── DataSink.java │ │ ├── DataTrackingEmitter.java │ │ ├── DatagramChannelWrapper.java │ │ ├── FileDataEmitter.java │ │ ├── FilteredDataEmitter.java │ │ ├── FilteredDataSink.java │ │ ├── HostnameResolutionException.java │ │ ├── LineEmitter.java │ │ ├── PushParser.java │ │ ├── SelectorWrapper.java │ │ ├── ServerSocketChannelWrapper.java │ │ ├── SocketChannelWrapper.java │ │ ├── TapCallback.java │ │ ├── ThreadQueue.java │ │ ├── Util.java │ │ ├── ZipDataSink.java │ │ ├── callback │ │ ├── CompletedCallback.java │ │ ├── ConnectCallback.java │ │ ├── ContinuationCallback.java │ │ ├── DataCallback.java │ │ ├── ListenCallback.java │ │ ├── ResultCallback.java │ │ ├── SocketCreateCallback.java │ │ ├── ValueCallback.java │ │ ├── ValueFunction.java │ │ └── WritableCallback.java │ │ ├── dns │ │ ├── Dns.java │ │ └── DnsResponse.java │ │ ├── future │ │ ├── Cancellable.java │ │ ├── Continuation.java │ │ ├── Converter.java │ │ ├── DependentCancellable.java │ │ ├── DependentFuture.java │ │ ├── DoneCallback.java │ │ ├── FailCallback.java │ │ ├── FailConvertCallback.java │ │ ├── FailRecoverCallback.java │ │ ├── Future.java │ │ ├── FutureCallback.java │ │ ├── FutureRunnable.java │ │ ├── FutureThread.java │ │ ├── Futures.java │ │ ├── HandlerFuture.java │ │ ├── MultiFuture.java │ │ ├── MultiTransformFuture.java │ │ ├── SimpleCancellable.java │ │ ├── SimpleFuture.java │ │ ├── SuccessCallback.java │ │ ├── ThenCallback.java │ │ ├── ThenFutureCallback.java │ │ ├── TransformFuture.java │ │ └── TypeConverter.java │ │ ├── http │ │ ├── AsyncHttpClient.java │ │ ├── AsyncHttpClientMiddleware.java │ │ ├── AsyncHttpDelete.java │ │ ├── AsyncHttpGet.java │ │ ├── AsyncHttpHead.java │ │ ├── AsyncHttpPost.java │ │ ├── AsyncHttpPut.java │ │ ├── AsyncHttpRequest.java │ │ ├── AsyncHttpResponse.java │ │ ├── AsyncHttpResponseImpl.java │ │ ├── AsyncSSLEngineConfigurator.java │ │ ├── AsyncSSLSocketMiddleware.java │ │ ├── AsyncSocketMiddleware.java │ │ ├── BasicNameValuePair.java │ │ ├── BodyDecoderException.java │ │ ├── ConnectionClosedException.java │ │ ├── ConnectionFailedException.java │ │ ├── Headers.java │ │ ├── HttpDate.java │ │ ├── HttpTransportMiddleware.java │ │ ├── HttpUtil.java │ │ ├── HybiParser.java │ │ ├── Multimap.java │ │ ├── NameValuePair.java │ │ ├── Protocol.java │ │ ├── ProtocolVersion.java │ │ ├── RedirectLimitExceededException.java │ │ ├── RequestLine.java │ │ ├── SSLEngineSNIConfigurator.java │ │ ├── SimpleMiddleware.java │ │ ├── WebSocket.java │ │ ├── WebSocketHandshakeException.java │ │ ├── WebSocketImpl.java │ │ ├── body │ │ │ ├── AsyncHttpRequestBody.java │ │ │ ├── ByteBufferListRequestBody.java │ │ │ ├── DocumentBody.java │ │ │ ├── FileBody.java │ │ │ ├── FilePart.java │ │ │ ├── JSONArrayBody.java │ │ │ ├── JSONObjectBody.java │ │ │ ├── MultipartFormDataBody.java │ │ │ ├── Part.java │ │ │ ├── StreamBody.java │ │ │ ├── StreamPart.java │ │ │ ├── StringBody.java │ │ │ ├── StringPart.java │ │ │ └── UrlEncodedFormBody.java │ │ ├── cache │ │ │ ├── HeaderParser.java │ │ │ ├── Objects.java │ │ │ ├── RawHeaders.java │ │ │ ├── RequestHeaders.java │ │ │ ├── ResponseCacheMiddleware.java │ │ │ ├── ResponseHeaders.java │ │ │ ├── ResponseSource.java │ │ │ └── StrictLineReader.java │ │ ├── callback │ │ │ ├── HttpConnectCallback.java │ │ │ └── RequestCallback.java │ │ ├── filter │ │ │ ├── ChunkedDataException.java │ │ │ ├── ChunkedInputFilter.java │ │ │ ├── ChunkedOutputFilter.java │ │ │ ├── ContentLengthFilter.java │ │ │ ├── DataRemainingException.java │ │ │ ├── GZIPInputFilter.java │ │ │ ├── InflaterInputFilter.java │ │ │ └── PrematureDataEndException.java │ │ └── server │ │ │ ├── AsyncHttpRequestBodyProvider.java │ │ │ ├── AsyncHttpServer.java │ │ │ ├── AsyncHttpServerRequest.java │ │ │ ├── AsyncHttpServerRequestImpl.java │ │ │ ├── AsyncHttpServerResponse.java │ │ │ ├── AsyncHttpServerResponseImpl.java │ │ │ ├── AsyncHttpServerRouter.java │ │ │ ├── AsyncProxyServer.java │ │ │ ├── BoundaryEmitter.java │ │ │ ├── HttpServerRequestCallback.java │ │ │ ├── MalformedRangeException.java │ │ │ ├── MimeEncodingException.java │ │ │ ├── RouteMatcher.java │ │ │ ├── StreamSkipException.java │ │ │ └── UnknownRequestBody.java │ │ ├── parser │ │ ├── AsyncParser.java │ │ ├── ByteBufferListParser.java │ │ ├── DocumentParser.java │ │ ├── JSONArrayParser.java │ │ ├── JSONObjectParser.java │ │ └── StringParser.java │ │ ├── stream │ │ ├── ByteBufferListInputStream.java │ │ ├── FileDataSink.java │ │ ├── InputStreamDataEmitter.java │ │ ├── OutputStreamDataCallback.java │ │ └── OutputStreamDataSink.java │ │ ├── util │ │ ├── Allocator.java │ │ ├── ArrayDeque.java │ │ ├── Charsets.java │ │ ├── Deque.java │ │ ├── FileCache.java │ │ ├── FileUtility.java │ │ ├── HashList.java │ │ ├── IdleTimeout.java │ │ ├── LruCache.java │ │ ├── StreamUtility.java │ │ ├── TaggedList.java │ │ ├── ThrottleTimeout.java │ │ ├── TimeoutBase.java │ │ └── UntypedHashtable.java │ │ └── wrapper │ │ ├── AsyncSocketWrapper.java │ │ └── DataEmitterWrapper.java └── test │ ├── assets │ ├── 6691924d7d24237d3b3679310157d640 │ ├── hello.txt │ └── test.json │ ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-ldpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── raw │ │ └── keystore.bks │ └── values │ │ └── strings.xml │ └── src │ └── com │ └── koushikdutta │ └── async │ └── test │ ├── BodyTests.java │ ├── ByteUtilTests.java │ ├── CacheTests.java │ ├── CallbackTests.java │ ├── ConscryptTests.java │ ├── ConvertTests.java │ ├── DnsTests.java │ ├── FileCacheTests.java │ ├── FileTests.java │ ├── FutureTests.java │ ├── HttpClientTests.java │ ├── HttpServerTests.java │ ├── Issue59.java │ ├── IssueWithWebSocketFuturesTests.java │ ├── LineEmitterTests.java │ ├── Md5.java │ ├── MultipartTests.java │ ├── ParserTests.java │ ├── ProxyTests.java │ ├── RedirectTests.java │ ├── SSLTests.java │ ├── SanityChecks.java │ ├── TimeoutTests.java │ ├── TriggerFuture.java │ └── WebSocketTests.java ├── AndroidAsyncSample ├── AndroidManifest.xml ├── build.gradle ├── ic_launcher-web.png ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable-hdpi │ │ ├── ic_action_search.png │ │ └── ic_launcher.png │ ├── drawable-ldpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ ├── ic_action_search.png │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ ├── ic_action_search.png │ │ └── ic_launcher.png │ ├── layout │ │ └── activity_main.xml │ ├── menu │ │ └── activity_main.xml │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── koushikdutta │ └── async │ └── sample │ ├── MainActivity.java │ └── middleware │ ├── BasicAuthMiddleware.java │ └── CacheOverrideMiddleware.java ├── LICENSE ├── README.md ├── build.gradle ├── gradlew ├── gradlew.bat └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: koush 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | .settings 3 | local.properties 4 | gen 5 | .gradle 6 | build 7 | .idea/ 8 | .DS_Store 9 | okhttp/ 10 | okio/ 11 | libs 12 | *.iml 13 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/README.md: -------------------------------------------------------------------------------- 1 | # Support for Kotlin Coroutines in AndroidAsync and Ion 2 | 3 | Adds coroutines support to AndroidAsync and [Ion](https://github.com/koush/ion). 4 | 5 | Maven: 6 | ```xml 7 | 8 | com.koushikdutta.async 9 | androidasync-kotlin 10 | (insert latest version) 11 | 12 | ``` 13 | 14 | Gradle: 15 | ```groovy 16 | dependencies { 17 | compile 'com.koushikdutta.async:androidasync-kotlin:' 18 | } 19 | ``` 20 | 21 | Since AndroidAsync and Ion operations all returned futures, you can simply call await() on them within a Kotlin suspend function. 22 | 23 | ```kotlin 24 | suspend fun getTheRobotsTxt() { 25 | val googleRobots = Ion.with(context) 26 | .load("https://google.com/robots.txt") 27 | .asString() 28 | .await() 29 | 30 | val githubRobots = Ion.with(context) 31 | .load("https://github.com/robots.txt") 32 | .asString() 33 | .await() 34 | 35 | return googleRobots + githubRobots 36 | } 37 | ``` 38 | 39 | That's it! 40 | 41 | But remember that the await() suspends, so if you want to fetch both robots.txt at the same time: 42 | 43 | ```kotlin 44 | suspend fun getTheRobotsTxt() { 45 | val googleRobots = Ion.with(context) 46 | .load("https://google.com/robots.txt") 47 | .asString() 48 | 49 | val githubRobots = Ion.with(context) 50 | .load("https://github.com/robots.txt") 51 | .asString() 52 | 53 | return googleRobots.await() + githubRobots.await() 54 | } 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | buildscript { 6 | ext.kotlin_version = '1.3.61' 7 | repositories { 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | } 13 | } 14 | 15 | android { 16 | compileSdkVersion 29 17 | buildToolsVersion "29.0.2" 18 | 19 | kotlinOptions { 20 | apiVersion = "1.3" 21 | languageVersion = "1.3" 22 | } 23 | 24 | compileOptions { 25 | sourceCompatibility 1.8 26 | targetCompatibility 1.8 27 | } 28 | 29 | defaultConfig { 30 | minSdkVersion 14 31 | targetSdkVersion 29 32 | 33 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 34 | consumerProguardFiles 'consumer-rules.pro' 35 | } 36 | 37 | buildTypes { 38 | release { 39 | minifyEnabled false 40 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 41 | } 42 | } 43 | 44 | } 45 | 46 | dependencies { 47 | implementation fileTree(dir: 'libs', include: ['*.jar']) 48 | api project(':AndroidAsync:AndroidAsync') 49 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 50 | 51 | 52 | testImplementation 'junit:junit:4.12' 53 | testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.3.61' 54 | androidTestImplementation 'androidx.test:runner:1.2.0' 55 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 56 | } 57 | 58 | // upload to maven task 59 | if (false && System.getenv().I_AM_KOUSH == 'true') { 60 | apply from: '/Users/koush/cfg/maven.gradle' 61 | } 62 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync-Kotlin/consumer-rules.pro -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/src/androidTest/java/com/koushikdutta/async/kotlin/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.kotlin 2 | 3 | 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import androidx.test.runner.AndroidJUnit4 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | 10 | /** 11 | * Instrumented test, which will execute on an Android device. 12 | * 13 | * See [testing documentation](http://d.android.com/tools/testing). 14 | */ 15 | @RunWith(AndroidJUnit4::class) 16 | class ExampleInstrumentedTest { 17 | @Test 18 | fun useAppContext() { 19 | // Context of the app under test. 20 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 21 | assertEquals("com.koushikdutta.async.kotlin.test", appContext.packageName) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/src/main/java/com/koushikdutta/async/kotlin/FutureExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.kotlin 2 | 3 | import com.koushikdutta.async.future.Future 4 | import kotlin.coroutines.resume 5 | import kotlin.coroutines.resumeWithException 6 | import kotlin.coroutines.suspendCoroutine 7 | 8 | suspend fun Future.await(): T { 9 | return suspendCoroutine { 10 | this.setCallback { e, result -> 11 | if (e != null) 12 | it.resumeWithException(e) 13 | else 14 | it.resume(result) 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /AndroidAsync-Kotlin/src/test/java/com/koushikdutta/async/kotlin/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.kotlin 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AndroidAsync/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /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/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidAsync/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | sourceSets { 5 | main { 6 | manifest.srcFile 'AndroidManifest.xml' 7 | 8 | jniLibs.srcDirs = ['libs/'] 9 | 10 | java.srcDirs=['src/' 11 | // , '../conscrypt/' 12 | // , '../compat/' 13 | ] 14 | } 15 | androidTest.java.srcDirs=['test/src/'] 16 | androidTest.res.srcDirs=['test/res/'] 17 | androidTest.assets.srcDirs=['test/assets/'] 18 | } 19 | 20 | lintOptions { 21 | abortOnError false 22 | } 23 | 24 | defaultConfig { 25 | targetSdkVersion 30 26 | minSdkVersion 21 27 | 28 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 29 | } 30 | 31 | compileOptions { 32 | sourceCompatibility 1.8 33 | targetCompatibility 1.8 34 | } 35 | 36 | compileSdkVersion 30 37 | buildToolsVersion '30.0.2' 38 | 39 | dependencies { 40 | // this is only necessary to get compilation working for self signed certificates. dependency isn't added. 41 | compileOnly group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.60' 42 | compileOnly group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.60' 43 | 44 | 45 | testImplementation 'junit:junit:4.12' 46 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 47 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 48 | // for when i wanna test this against gms conscrypt 49 | androidTestImplementation 'com.google.android.gms:play-services-base:17.0.0' 50 | } 51 | } 52 | 53 | apply from: 'maven.gradle' 54 | -------------------------------------------------------------------------------- /AndroidAsync/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/ic_launcher-web.png -------------------------------------------------------------------------------- /AndroidAsync/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /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/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/res/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/res/.gitignore -------------------------------------------------------------------------------- /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/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/AsyncSSLServerSocket.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.security.PrivateKey; 4 | import java.security.cert.Certificate; 5 | 6 | public interface AsyncSSLServerSocket extends AsyncServerSocket { 7 | PrivateKey getPrivateKey(); 8 | Certificate getCertificate(); 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/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/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/ChannelWrapper.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 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 InetAddress getLocalAddress(); 51 | public abstract Object getSocket(); 52 | } 53 | -------------------------------------------------------------------------------- /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 | void setDataCallback(DataCallback callback); 8 | DataCallback getDataCallback(); 9 | boolean isChunked(); 10 | void pause(); 11 | void resume(); 12 | void close(); 13 | boolean isPaused(); 14 | void setEndCallback(CompletedCallback callback); 15 | CompletedCallback getEndCallback(); 16 | AsyncServer getServer(); 17 | String charset(); 18 | } 19 | -------------------------------------------------------------------------------- /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 report(Exception e) { 12 | if (ended) 13 | return; 14 | ended = true; 15 | if (getEndCallback() != null) 16 | getEndCallback().onCompleted(e); 17 | } 18 | 19 | @Override 20 | public final void setEndCallback(CompletedCallback callback) { 21 | endCallback = callback; 22 | } 23 | 24 | CompletedCallback endCallback; 25 | @Override 26 | public final CompletedCallback getEndCallback() { 27 | return endCallback; 28 | } 29 | 30 | 31 | DataCallback mDataCallback; 32 | @Override 33 | public void setDataCallback(DataCallback callback) { 34 | mDataCallback = callback; 35 | } 36 | 37 | @Override 38 | public DataCallback getDataCallback() { 39 | return mDataCallback; 40 | } 41 | 42 | @Override 43 | public String charset() { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /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 | mPendingReadLength = count; 12 | mPendingRead = callback; 13 | mPendingData.recycle(); 14 | } 15 | 16 | private boolean handlePendingData(DataEmitter emitter) { 17 | if (mPendingReadLength > mPendingData.remaining()) 18 | return false; 19 | 20 | DataCallback pendingRead = mPendingRead; 21 | mPendingRead = null; 22 | pendingRead.onDataAvailable(emitter, mPendingData); 23 | 24 | return true; 25 | } 26 | 27 | public DataEmitterReader() { 28 | } 29 | @Override 30 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { 31 | // if we're registered for data, we must be waiting for a read 32 | do { 33 | int need = Math.min(bb.remaining(), mPendingReadLength - mPendingData.remaining()); 34 | bb.get(mPendingData, need); 35 | bb.remaining(); 36 | } 37 | while (handlePendingData(emitter) && mPendingRead != null); 38 | bb.remaining(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/DataSink.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import com.koushikdutta.async.callback.CompletedCallback; 4 | import com.koushikdutta.async.callback.WritableCallback; 5 | 6 | public interface DataSink { 7 | public void write(ByteBufferList bb); 8 | public void setWriteableCallback(WritableCallback handler); 9 | public WritableCallback getWriteableCallback(); 10 | 11 | public boolean isOpen(); 12 | public void end(); 13 | public void setClosedCallback(CompletedCallback handler); 14 | public CompletedCallback getClosedCallback(); 15 | public AsyncServer getServer(); 16 | } 17 | -------------------------------------------------------------------------------- /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 | 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/DatagramChannelWrapper.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.net.InetSocketAddress; 6 | import java.nio.ByteBuffer; 7 | import java.nio.channels.ClosedChannelException; 8 | import java.nio.channels.DatagramChannel; 9 | import java.nio.channels.SelectionKey; 10 | import java.nio.channels.Selector; 11 | 12 | class DatagramChannelWrapper extends ChannelWrapper { 13 | DatagramChannel mChannel; 14 | 15 | @Override 16 | public InetAddress getLocalAddress() { 17 | return mChannel.socket().getLocalAddress(); 18 | } 19 | 20 | @Override 21 | public int getLocalPort() { 22 | return mChannel.socket().getLocalPort(); 23 | } 24 | 25 | InetSocketAddress address; 26 | public InetSocketAddress getRemoteAddress() { 27 | return address; 28 | } 29 | 30 | public void disconnect() throws IOException { 31 | mChannel.disconnect(); 32 | } 33 | 34 | DatagramChannelWrapper(DatagramChannel channel) throws IOException { 35 | super(channel); 36 | mChannel = channel; 37 | } 38 | @Override 39 | public int read(ByteBuffer buffer) throws IOException { 40 | if (!isConnected()) { 41 | int position = buffer.position(); 42 | address = (InetSocketAddress)mChannel.receive(buffer); 43 | if (address == null) 44 | return -1; 45 | return buffer.position() - position; 46 | } 47 | address = null; 48 | return mChannel.read(buffer); 49 | } 50 | @Override 51 | public boolean isConnected() { 52 | return mChannel.isConnected(); 53 | } 54 | @Override 55 | public int write(ByteBuffer src) throws IOException { 56 | return mChannel.write(src); 57 | } 58 | @Override 59 | public int write(ByteBuffer[] src) throws IOException { 60 | return (int)mChannel.write(src); 61 | } 62 | @Override 63 | public SelectionKey register(Selector sel, int ops) throws ClosedChannelException { 64 | return mChannel.register(sel, ops); 65 | } 66 | @Override 67 | public boolean isChunked() { 68 | return true; 69 | } 70 | @Override 71 | public SelectionKey register(Selector sel) throws ClosedChannelException { 72 | return register(sel, SelectionKey.OP_READ); 73 | } 74 | 75 | @Override 76 | public void shutdownOutput() { 77 | } 78 | 79 | @Override 80 | public void shutdownInput() { 81 | } 82 | 83 | @Override 84 | public long read(ByteBuffer[] byteBuffers) throws IOException { 85 | return mChannel.read(byteBuffers); 86 | } 87 | 88 | @Override 89 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException { 90 | return mChannel.read(byteBuffers, i, i2); 91 | } 92 | 93 | @Override 94 | public Object getSocket() { 95 | return mChannel.socket(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/FileDataEmitter.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import com.koushikdutta.async.callback.DataCallback; 4 | import com.koushikdutta.async.util.StreamUtility; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.nio.ByteBuffer; 9 | import java.nio.channels.FileChannel; 10 | 11 | /** 12 | * Created by koush on 5/22/13. 13 | */ 14 | public class FileDataEmitter extends DataEmitterBase { 15 | AsyncServer server; 16 | File file; 17 | public FileDataEmitter(AsyncServer server, File file) { 18 | this.server = server; 19 | this.file = file; 20 | paused = !server.isAffinityThread(); 21 | if (!paused) 22 | doResume(); 23 | } 24 | 25 | DataCallback callback; 26 | @Override 27 | public void setDataCallback(DataCallback callback) { 28 | this.callback = callback; 29 | } 30 | 31 | @Override 32 | public DataCallback getDataCallback() { 33 | return callback; 34 | } 35 | 36 | @Override 37 | public boolean isChunked() { 38 | return false; 39 | } 40 | 41 | boolean paused; 42 | @Override 43 | public void pause() { 44 | paused = true; 45 | } 46 | 47 | @Override 48 | public void resume() { 49 | paused = false; 50 | doResume(); 51 | } 52 | 53 | @Override 54 | protected void report(Exception e) { 55 | StreamUtility.closeQuietly(channel); 56 | super.report(e); 57 | } 58 | 59 | ByteBufferList pending = new ByteBufferList(); 60 | FileChannel channel; 61 | Runnable pumper = new Runnable() { 62 | @Override 63 | public void run() { 64 | try { 65 | if (channel == null) 66 | channel = new FileInputStream(file).getChannel(); 67 | if (!pending.isEmpty()) { 68 | Util.emitAllData(FileDataEmitter.this, pending); 69 | if (!pending.isEmpty()) 70 | return; 71 | } 72 | ByteBuffer b; 73 | do { 74 | b = ByteBufferList.obtain(8192); 75 | if (-1 == channel.read(b)) { 76 | report(null); 77 | return; 78 | } 79 | b.flip(); 80 | pending.add(b); 81 | Util.emitAllData(FileDataEmitter.this, pending); 82 | } 83 | while (pending.remaining() == 0 && !isPaused()); 84 | } 85 | catch (Exception e) { 86 | report(e); 87 | } 88 | } 89 | }; 90 | 91 | private void doResume() { 92 | server.post(pumper); 93 | } 94 | 95 | @Override 96 | public boolean isPaused() { 97 | return paused; 98 | } 99 | 100 | @Override 101 | public AsyncServer getServer() { 102 | return server; 103 | } 104 | 105 | @Override 106 | public void close() { 107 | try { 108 | channel.close(); 109 | } 110 | catch (Exception e) { 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /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 | private 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 | private DataTracker tracker; 45 | private int totalRead; 46 | @Override 47 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { 48 | if (closed) { 49 | // this emitter was closed but for some reason data is still being spewed... 50 | // eat it, nom nom. 51 | bb.recycle(); 52 | return; 53 | } 54 | if (bb != null) 55 | totalRead += bb.remaining(); 56 | Util.emitAllData(this, bb); 57 | if (bb != null) 58 | totalRead -= bb.remaining(); 59 | if (tracker != null && bb != null) 60 | tracker.onData(totalRead); 61 | // if there's data after the emitting, and it is paused... the underlying implementation 62 | // is obligated to cache the byte buffer list. 63 | } 64 | 65 | @Override 66 | public boolean isChunked() { 67 | return mEmitter.isChunked(); 68 | } 69 | 70 | @Override 71 | public void pause() { 72 | mEmitter.pause(); 73 | } 74 | 75 | @Override 76 | public void resume() { 77 | mEmitter.resume(); 78 | } 79 | 80 | @Override 81 | public boolean isPaused() { 82 | return mEmitter.isPaused(); 83 | } 84 | 85 | @Override 86 | public AsyncServer getServer() { 87 | return mEmitter.getServer(); 88 | } 89 | 90 | boolean closed; 91 | @Override 92 | public void close() { 93 | closed = true; 94 | if (mEmitter != null) 95 | mEmitter.close(); 96 | } 97 | 98 | @Override 99 | public String charset() { 100 | if (mEmitter == null) 101 | return null; 102 | return mEmitter.charset(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/FilteredDataSink.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | public class FilteredDataSink extends BufferedDataSink { 4 | public FilteredDataSink(DataSink sink) { 5 | super(sink); 6 | setMaxBuffer(0); 7 | } 8 | 9 | public ByteBufferList filter(ByteBufferList bb) { 10 | return bb; 11 | } 12 | 13 | @Override 14 | protected void onDataAccepted(ByteBufferList bb) { 15 | ByteBufferList filtered = filter(bb); 16 | // filtering may return the same byte buffer, so watch for that. 17 | if (filtered != bb) { 18 | bb.recycle(); 19 | filtered.get(bb); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /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/LineEmitter.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import com.koushikdutta.async.callback.DataCallback; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.nio.charset.Charset; 7 | 8 | public class LineEmitter implements DataCallback { 9 | public interface StringCallback { 10 | void onStringAvailable(String s); 11 | } 12 | 13 | public LineEmitter() { 14 | this(null); 15 | } 16 | 17 | public LineEmitter(Charset charset) { 18 | this.charset = charset; 19 | } 20 | 21 | Charset charset; 22 | 23 | ByteBufferList data = new ByteBufferList(); 24 | 25 | StringCallback mLineCallback; 26 | public void setLineCallback(StringCallback callback) { 27 | mLineCallback = callback; 28 | } 29 | 30 | public StringCallback getLineCallback() { 31 | return mLineCallback; 32 | } 33 | 34 | @Override 35 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { 36 | ByteBuffer buffer = ByteBuffer.allocate(bb.remaining()); 37 | while (bb.remaining() > 0) { 38 | byte b = bb.get(); 39 | if (b == '\n') { 40 | buffer.flip(); 41 | data.add(buffer); 42 | mLineCallback.onStringAvailable(data.readString(charset)); 43 | data = new ByteBufferList(); 44 | return; 45 | } 46 | else { 47 | buffer.put(b); 48 | } 49 | } 50 | buffer.flip(); 51 | data.add(buffer); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/SelectorWrapper.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | import java.nio.channels.SelectionKey; 6 | import java.nio.channels.Selector; 7 | import java.util.Set; 8 | import java.util.concurrent.Semaphore; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | /** 13 | * Created by koush on 2/13/14. 14 | */ 15 | class SelectorWrapper implements Closeable { 16 | private Selector selector; 17 | public AtomicBoolean isWaking = new AtomicBoolean(false); 18 | Semaphore semaphore = new Semaphore(0); 19 | public Selector getSelector() { 20 | return selector; 21 | } 22 | 23 | public SelectorWrapper(Selector selector) { 24 | this.selector = selector; 25 | } 26 | 27 | public int selectNow() throws IOException { 28 | return selector.selectNow(); 29 | } 30 | 31 | public void select() throws IOException { 32 | select(0); 33 | } 34 | 35 | public void select(long timeout) throws IOException { 36 | try { 37 | semaphore.drainPermits(); 38 | selector.select(timeout); 39 | } 40 | finally { 41 | semaphore.release(Integer.MAX_VALUE); 42 | } 43 | } 44 | 45 | public Set keys() { 46 | return selector.keys(); 47 | } 48 | 49 | public Set selectedKeys() { 50 | return selector.selectedKeys(); 51 | } 52 | 53 | @Override 54 | public void close() throws IOException { 55 | selector.close(); 56 | } 57 | 58 | public boolean isOpen() { 59 | return selector.isOpen(); 60 | } 61 | 62 | public void wakeupOnce() { 63 | // see if it is selecting, ie, can't acquire a permit 64 | boolean selecting = !semaphore.tryAcquire(); 65 | selector.wakeup(); 66 | // if it was selecting, then the wakeup definitely worked. 67 | if (selecting) 68 | return; 69 | 70 | // now, we NEED to wait for the select to start to forcibly wake it. 71 | if (isWaking.getAndSet(true)) { 72 | selector.wakeup(); 73 | return; 74 | } 75 | 76 | try { 77 | waitForSelect(); 78 | selector.wakeup(); 79 | } finally { 80 | isWaking.set(false); 81 | } 82 | } 83 | 84 | public boolean waitForSelect() { 85 | // try to wake up 10 times 86 | for (int i = 0; i < 100; i++) { 87 | try { 88 | if (semaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) { 89 | // successfully acquiring means the selector is NOT selecting, since select 90 | // will drain all permits. 91 | continue; 92 | } 93 | } catch (InterruptedException e) { 94 | // an InterruptedException means the acquire failed a select is in progress, 95 | // since it holds all permits 96 | return true; 97 | } 98 | } 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/ServerSocketChannelWrapper.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.ClosedChannelException; 7 | import java.nio.channels.SelectionKey; 8 | import java.nio.channels.Selector; 9 | import java.nio.channels.ServerSocketChannel; 10 | 11 | class ServerSocketChannelWrapper extends ChannelWrapper { 12 | ServerSocketChannel mChannel; 13 | 14 | @Override 15 | public void shutdownOutput() { 16 | } 17 | 18 | @Override 19 | public void shutdownInput() { 20 | } 21 | 22 | @Override 23 | public InetAddress getLocalAddress() { 24 | return mChannel.socket().getInetAddress(); 25 | } 26 | 27 | @Override 28 | public int getLocalPort() { 29 | return mChannel.socket().getLocalPort(); 30 | } 31 | 32 | ServerSocketChannelWrapper(ServerSocketChannel channel) throws IOException { 33 | super(channel); 34 | mChannel = channel; 35 | } 36 | 37 | @Override 38 | public int read(ByteBuffer buffer) throws IOException { 39 | final String msg = "Can't read ServerSocketChannel"; 40 | throw new IOException(msg); 41 | } 42 | 43 | @Override 44 | public boolean isConnected() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public int write(ByteBuffer src) throws IOException { 50 | final String msg = "Can't write ServerSocketChannel"; 51 | throw new IOException(msg); 52 | } 53 | 54 | @Override 55 | public SelectionKey register(Selector sel) throws ClosedChannelException { 56 | return mChannel.register(sel, SelectionKey.OP_ACCEPT); 57 | } 58 | 59 | @Override 60 | public int write(ByteBuffer[] src) throws IOException { 61 | final String msg = "Can't write ServerSocketChannel"; 62 | throw new IOException(msg); 63 | } 64 | 65 | @Override 66 | public long read(ByteBuffer[] byteBuffers) throws IOException { 67 | final String msg = "Can't read ServerSocketChannel"; 68 | throw new IOException(msg); 69 | } 70 | 71 | @Override 72 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException { 73 | final String msg = "Can't read ServerSocketChannel"; 74 | throw new IOException(msg); 75 | } 76 | 77 | @Override 78 | public Object getSocket() { 79 | return mChannel.socket(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/SocketChannelWrapper.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.ClosedChannelException; 7 | import java.nio.channels.SelectionKey; 8 | import java.nio.channels.Selector; 9 | import java.nio.channels.SocketChannel; 10 | 11 | class SocketChannelWrapper extends ChannelWrapper { 12 | SocketChannel mChannel; 13 | 14 | @Override 15 | public InetAddress getLocalAddress() { 16 | return mChannel.socket().getLocalAddress(); 17 | } 18 | 19 | @Override 20 | public int getLocalPort() { 21 | return mChannel.socket().getLocalPort(); 22 | } 23 | 24 | SocketChannelWrapper(SocketChannel channel) throws IOException { 25 | super(channel); 26 | mChannel = channel; 27 | } 28 | @Override 29 | public int read(ByteBuffer buffer) throws IOException { 30 | return mChannel.read(buffer); 31 | } 32 | @Override 33 | public boolean isConnected() { 34 | return mChannel.isConnected(); 35 | } 36 | @Override 37 | public int write(ByteBuffer src) throws IOException { 38 | return mChannel.write(src); 39 | } 40 | @Override 41 | public int write(ByteBuffer[] src) throws IOException { 42 | return (int)mChannel.write(src); 43 | } 44 | @Override 45 | public SelectionKey register(Selector sel) throws ClosedChannelException { 46 | return register(sel, SelectionKey.OP_CONNECT); 47 | } 48 | 49 | @Override 50 | public void shutdownOutput() { 51 | try { 52 | mChannel.socket().shutdownOutput(); 53 | } 54 | catch (Exception e) { 55 | } 56 | } 57 | 58 | @Override 59 | public void shutdownInput() { 60 | try { 61 | mChannel.socket().shutdownInput(); 62 | } 63 | catch (Exception e) { 64 | } 65 | } 66 | 67 | @Override 68 | public long read(ByteBuffer[] byteBuffers) throws IOException { 69 | return mChannel.read(byteBuffers); 70 | } 71 | 72 | @Override 73 | public long read(ByteBuffer[] byteBuffers, int i, int i2) throws IOException { 74 | return mChannel.read(byteBuffers, i, i2); 75 | } 76 | 77 | @Override 78 | public Object getSocket() { 79 | return mChannel.socket(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/TapCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async; 2 | 3 | 4 | public interface TapCallback { 5 | } 6 | -------------------------------------------------------------------------------- /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 | 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/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/callback/CompletedCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.callback; 2 | 3 | public interface CompletedCallback { 4 | public class NullCompletedCallback implements CompletedCallback { 5 | @Override 6 | public void onCompleted(Exception ex) { 7 | 8 | } 9 | } 10 | 11 | public void onCompleted(Exception ex); 12 | } 13 | -------------------------------------------------------------------------------- /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/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/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 class NullDataCallback implements DataCallback { 9 | @Override 10 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { 11 | bb.recycle(); 12 | } 13 | } 14 | 15 | public void onDataAvailable(DataEmitter emitter, ByteBufferList bb); 16 | } 17 | -------------------------------------------------------------------------------- /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/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/callback/SocketCreateCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.callback; 2 | 3 | import com.koushikdutta.async.AsyncNetworkSocket; 4 | 5 | public interface SocketCreateCallback { 6 | void onSocketCreated(int localPort); 7 | } 8 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/callback/ValueCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.callback; 2 | 3 | /** 4 | * Created by koush on 7/5/16. 5 | */ 6 | public interface ValueCallback { 7 | void onResult(T value); 8 | } 9 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/callback/ValueFunction.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.callback; 2 | 3 | public interface ValueFunction { 4 | T getValue() throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /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/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/DependentCancellable.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface DependentCancellable extends Cancellable { 4 | boolean setParent(Cancellable parent); 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/future/DoneCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface DoneCallback { 4 | void done(Exception e, T result) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/FailCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface FailCallback { 4 | /** 5 | * Callback that is invoked when a future completes with an error. 6 | * The error should be rethrown to pass it along. 7 | * @param e 8 | * @throws Exception 9 | */ 10 | void fail(Exception e) throws Exception; 11 | } 12 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/FailConvertCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface FailConvertCallback { 4 | /** 5 | * Callback that is invoked when a future completes with an error. 6 | * The error should be rethrown, or a new value should be returned. 7 | * @param e 8 | * @return 9 | * @throws Exception 10 | */ 11 | T fail(Exception e) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/FailRecoverCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface FailRecoverCallback { 4 | /** 5 | * Callback that is invoked when a future completes with an error. 6 | * The error should be rethrown, or a new future value should be returned. 7 | * @param e 8 | * @return 9 | * @throws Exception 10 | */ 11 | Future fail(Exception e) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/Future.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | 4 | import java.util.concurrent.Executor; 5 | 6 | public interface Future extends Cancellable, java.util.concurrent.Future { 7 | /** 8 | * Set a callback to be invoked when this Future completes. 9 | * @param callback 10 | * @return 11 | */ 12 | void setCallback(FutureCallback callback); 13 | 14 | /** 15 | * Set a callback to be invoked when the Future completes 16 | * with an error or a result. 17 | * The existing error or result will be passed down the chain, or a new error 18 | * may be thrown. 19 | * @param done 20 | * @return 21 | */ 22 | Future done(DoneCallback done); 23 | 24 | /** 25 | * Set a callback to be invoked when this Future completes successfully. 26 | * @param callback 27 | * @return A future that will resolve once the success callback completes, 28 | * which may contain any errors thrown by the success callback. 29 | */ 30 | Future success(SuccessCallback callback); 31 | 32 | /** 33 | * Set a callback to be invoked when this Future completes successfully. 34 | * @param then 35 | * @param 36 | * @return A future containing all exceptions that happened prior or during 37 | * the callback, or the successful result. 38 | */ 39 | Future then(ThenFutureCallback then); 40 | 41 | /** 42 | * Set a callback to be invoked when this Future completes successfully. 43 | * @param then 44 | * @param 45 | * @return A future containing all exceptions that happened prior or during 46 | * the callback, or the successful result. 47 | */ 48 | Future thenConvert(ThenCallback then); 49 | 50 | /** 51 | * Set a callback to be invoked when this future completes with a failure. 52 | * The failure can be observered and rethrown, otherwise it is considered handled. 53 | * The exception will be nulled for subsequent callbacks in the chain. 54 | * @param fail 55 | * @return 56 | */ 57 | Future fail(FailCallback fail); 58 | 59 | /** 60 | * Set a callback to be invoked when this future completes with a failure. 61 | * The failure can be observered and rethrown, or handled by returning 62 | * a new fallback value of the same type. 63 | * @param fail 64 | * @return 65 | */ 66 | Future failConvert(FailConvertCallback fail); 67 | 68 | /** 69 | * Set a callback to be invoked when this future completes with a failure. 70 | * The failure should be observered and rethrown, or handled by returning 71 | * a new future of the same type. 72 | * @param fail 73 | * @return 74 | */ 75 | Future failRecover(FailRecoverCallback fail); 76 | 77 | /** 78 | * Get the result, if any. Returns null if still in progress. 79 | * @return 80 | */ 81 | T tryGet(); 82 | 83 | /** 84 | * Get the exception, if any. Returns null if still in progress. 85 | * @return 86 | */ 87 | Exception tryGetException(); 88 | 89 | /** 90 | * Get the result on the executor thread. 91 | * @param executor 92 | * @return 93 | */ 94 | default Future executorThread(Executor executor) { 95 | SimpleFuture ret = new SimpleFuture<>(); 96 | executor.execute(() -> ret.setComplete(Future.this)); 97 | return ret; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /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/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/future/FutureThread.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | 5 | /** 6 | * Created by koush on 12/22/13. 7 | */ 8 | public class FutureThread extends SimpleFuture { 9 | public FutureThread(final FutureRunnable runnable) { 10 | this(runnable, "FutureThread"); 11 | } 12 | 13 | public FutureThread(final ExecutorService pool, final FutureRunnable runnable) { 14 | pool.submit(new Runnable() { 15 | @Override 16 | public void run() { 17 | try { 18 | setComplete(runnable.run()); 19 | } 20 | catch (Exception e) { 21 | setComplete(e); 22 | } 23 | } 24 | }); 25 | } 26 | 27 | public FutureThread(final FutureRunnable runnable, String name) { 28 | new Thread(new Runnable() { 29 | @Override 30 | public void run() { 31 | try { 32 | setComplete(runnable.run()); 33 | } 34 | catch (Exception e) { 35 | setComplete(e); 36 | } 37 | } 38 | }, name).start(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/Futures.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | 9 | public class Futures { 10 | public static Future> waitAll(final List> futures) { 11 | final ArrayList results = new ArrayList<>(); 12 | final SimpleFuture> ret = new SimpleFuture<>(); 13 | 14 | if (futures.isEmpty()) { 15 | ret.setComplete(results); 16 | return ret; 17 | } 18 | 19 | FutureCallback cb = new FutureCallback() { 20 | int count = 0; 21 | 22 | @Override 23 | public void onCompleted(Exception e, T result) { 24 | results.add(result); 25 | count++; 26 | if (count < futures.size()) 27 | futures.get(count).setCallback(this); 28 | else 29 | ret.setComplete(results); 30 | } 31 | }; 32 | 33 | futures.get(0).setCallback(cb); 34 | 35 | return ret; 36 | } 37 | 38 | public static Future> waitAll(final Future... futures) { 39 | return waitAll(Arrays.asList(futures)); 40 | } 41 | 42 | 43 | private static void loopUntil(final Iterator values, ThenFutureCallback callback, SimpleFuture ret, Exception lastException) { 44 | while (values.hasNext()) { 45 | try { 46 | callback.then(values.next()) 47 | .success(ret::setComplete) 48 | .fail(e -> loopUntil(values, callback, ret, e)); 49 | return; 50 | } catch (Exception e) { 51 | lastException = e; 52 | } 53 | } 54 | 55 | if (lastException == null) 56 | ret.setComplete(new Exception("empty list")); 57 | else 58 | ret.setComplete(lastException); 59 | } 60 | 61 | public static Future loopUntil(final Iterable values, ThenFutureCallback callback) { 62 | SimpleFuture ret = new SimpleFuture<>(); 63 | loopUntil(values.iterator(), callback, ret, null); 64 | return ret; 65 | } 66 | 67 | public static Future loopUntil(final F[] values, ThenFutureCallback callback) { 68 | return loopUntil(Arrays.asList(values), callback); 69 | } 70 | } -------------------------------------------------------------------------------- /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 void 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 | super.setCallback(wrapped); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/MultiFuture.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by koush on 2/25/14. 7 | */ 8 | public class MultiFuture extends SimpleFuture { 9 | private ArrayList> internalCallbacks; 10 | 11 | public MultiFuture() { 12 | } 13 | 14 | public MultiFuture(T value) { 15 | super(value); 16 | } 17 | 18 | public MultiFuture(Exception e) { 19 | super(e); 20 | } 21 | 22 | public MultiFuture(Future future) { 23 | super(future); 24 | } 25 | 26 | private final FutureCallbackInternal internalCallback = (e, result, callsite) -> { 27 | ArrayList> callbacks; 28 | synchronized (MultiFuture.this) { 29 | callbacks = MultiFuture.this.internalCallbacks; 30 | MultiFuture.this.internalCallbacks = null; 31 | } 32 | 33 | if (callbacks == null) 34 | return; 35 | for (FutureCallbackInternal cb : callbacks) { 36 | cb.onCompleted(e, result, callsite); 37 | } 38 | }; 39 | 40 | @Override 41 | protected void setCallbackInternal(FutureCallsite callsite, FutureCallbackInternal internalCallback) { 42 | synchronized (this) { 43 | if (internalCallback != null) { 44 | if (internalCallbacks == null) 45 | internalCallbacks = new ArrayList<>(); 46 | internalCallbacks.add(internalCallback); 47 | } 48 | } 49 | // so, there is a race condition where this internal callback could get 50 | // executed twice, if two callbacks are added at the same time. 51 | // however, it doesn't matter, as the actual retrieval and nulling 52 | // of the callback list is done in another sync block. 53 | // one of the invocations will actually invoke all the callbacks, 54 | // while the other will not get a list back. 55 | 56 | // race: 57 | // 1-ADD 58 | // 2-ADD 59 | // 1-INVOKE LIST 60 | // 2-INVOKE NULL 61 | 62 | super.setCallbackInternal(callsite, this.internalCallback); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/MultiTransformFuture.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public abstract class MultiTransformFuture extends MultiFuture 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/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 | return false; 26 | } 27 | complete = true; 28 | parent = null; 29 | } 30 | completeCleanup(); 31 | cleanup(); 32 | return true; 33 | } 34 | 35 | @Override 36 | public boolean cancel() { 37 | Cancellable parent; 38 | synchronized (this) { 39 | if (complete) 40 | return false; 41 | if (cancelled) 42 | return true; 43 | cancelled = true; 44 | parent = this.parent; 45 | // null out the parent to allow garbage collection 46 | this.parent = null; 47 | } 48 | if (parent != null) 49 | parent.cancel(); 50 | cancelCleanup(); 51 | cleanup(); 52 | return true; 53 | } 54 | boolean cancelled; 55 | 56 | private Cancellable parent; 57 | @Override 58 | public boolean setParent(Cancellable parent) { 59 | synchronized (this) { 60 | if (isDone()) 61 | return false; 62 | this.parent = parent; 63 | return true; 64 | } 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 static final Cancellable CANCELLED = new SimpleCancellable() { 81 | { 82 | cancel(); 83 | } 84 | }; 85 | 86 | public Cancellable reset() { 87 | cancel(); 88 | complete = false; 89 | cancelled = false; 90 | return this; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/SuccessCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface SuccessCallback { 4 | void success(T value) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/ThenCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface ThenCallback { 4 | /** 5 | * Callback that is invoked when Future.then completes, 6 | * and converts a value F to value T. 7 | * @param from 8 | * @return 9 | * @throws Exception 10 | */ 11 | T then(F from) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/ThenFutureCallback.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface ThenFutureCallback { 4 | /** 5 | * Callback that is invoked when Future.then completes, 6 | * and converts a value F to a Future. 7 | * @param from 8 | * @return 9 | * @throws Exception 10 | */ 11 | Future then(F from) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /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 | public TransformFuture(F from) { 5 | onCompleted(null, from); 6 | } 7 | 8 | public TransformFuture() { 9 | } 10 | 11 | @Override 12 | public void onCompleted(Exception e, F result) { 13 | if (isCancelled()) 14 | return; 15 | if (e != null) { 16 | error(e); 17 | return; 18 | } 19 | 20 | try { 21 | transform(result); 22 | } 23 | catch (Exception ex) { 24 | error(ex); 25 | } 26 | } 27 | 28 | protected void error(Exception e) { 29 | setComplete(e); 30 | } 31 | 32 | protected abstract void transform(F result) throws Exception; 33 | } -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/future/TypeConverter.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.future; 2 | 3 | public interface TypeConverter { 4 | Future convert(F from, String fromMime) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpDelete.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http; 2 | 3 | import android.net.Uri; 4 | 5 | public class AsyncHttpDelete extends AsyncHttpRequest { 6 | public static final String METHOD = "DELETE"; 7 | 8 | public AsyncHttpDelete(String uri) { 9 | this(Uri.parse(uri)); 10 | } 11 | 12 | public AsyncHttpDelete(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/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 | @Override 14 | public boolean hasBody() { 15 | return false; 16 | } 17 | 18 | public static final String METHOD = "HEAD"; 19 | } 20 | -------------------------------------------------------------------------------- /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/AsyncHttpPut.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http; 2 | 3 | import android.net.Uri; 4 | 5 | public class AsyncHttpPut extends AsyncHttpRequest { 6 | public static final String METHOD = "PUT"; 7 | 8 | public AsyncHttpPut(String uri) { 9 | this(Uri.parse(uri)); 10 | } 11 | 12 | public AsyncHttpPut(Uri uri) { 13 | super(uri, METHOD); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /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.callback.CompletedCallback; 6 | 7 | public interface AsyncHttpResponse extends DataEmitter { 8 | public String protocol(); 9 | public String message(); 10 | public int code(); 11 | public Headers headers(); 12 | public AsyncSocket detachSocket(); 13 | public AsyncHttpRequest getRequest(); 14 | } 15 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLEngineConfigurator.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http; 2 | 3 | import javax.net.ssl.SSLContext; 4 | import javax.net.ssl.SSLEngine; 5 | 6 | public interface AsyncSSLEngineConfigurator { 7 | SSLEngine createEngine(SSLContext sslContext, String peerHost, int peerPort); 8 | void configureEngine(SSLEngine engine, AsyncHttpClientMiddleware.GetSocketData data, String host, int port); 9 | } 10 | -------------------------------------------------------------------------------- /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/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/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/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; 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 | if (value == null) 73 | return null; 74 | try { 75 | return STANDARD_DATE_FORMAT.get().parse(value); 76 | } catch (ParseException ignore) { 77 | } 78 | for (String formatString : BROWSER_COMPATIBLE_DATE_FORMATS) { 79 | try { 80 | return new SimpleDateFormat(formatString, Locale.US).parse(value); 81 | } catch (ParseException ignore) { 82 | } 83 | } 84 | return null; 85 | } 86 | 87 | /** 88 | * Returns the string for {@code value}. 89 | */ 90 | public static String format(Date value) { 91 | return STANDARD_DATE_FORMAT.get().format(value); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /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/RequestLine.java: -------------------------------------------------------------------------------- 1 | /* 2 | * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/RequestLine.java $ 3 | * $Revision: 573864 $ 4 | * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $ 5 | * 6 | * ==================================================================== 7 | * Licensed to the Apache Software Foundation (ASF) under one 8 | * or more contributor license agreements. See the NOTICE file 9 | * distributed with this work for additional information 10 | * regarding copyright ownership. The ASF licenses this file 11 | * to you under the Apache License, Version 2.0 (the 12 | * "License"); you may not use this file except in compliance 13 | * with the License. You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, 18 | * software distributed under the License is distributed on an 19 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 | * KIND, either express or implied. See the License for the 21 | * specific language governing permissions and limitations 22 | * under the License. 23 | * ==================================================================== 24 | * 25 | * This software consists of voluntary contributions made by many 26 | * individuals on behalf of the Apache Software Foundation. For more 27 | * information on the Apache Software Foundation, please see 28 | * . 29 | * 30 | */ 31 | 32 | package com.koushikdutta.async.http; 33 | 34 | /** 35 | * The first line of an {@link HttpRequest HttpRequest}. 36 | * It contains the method, URI, and HTTP version of the request. 37 | * For details, see RFC 2616. 38 | * 39 | * @author Oleg Kalnichevski 40 | * 41 | * @version $Revision: 573864 $ 42 | * 43 | * @since 4.0 44 | */ 45 | public interface RequestLine { 46 | 47 | String getMethod(); 48 | 49 | ProtocolVersion getProtocolVersion(); 50 | 51 | String getUri(); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/SSLEngineSNIConfigurator.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http; 2 | 3 | import android.os.Build; 4 | 5 | import java.lang.reflect.Field; 6 | import java.util.Hashtable; 7 | 8 | import javax.net.ssl.SSLContext; 9 | import javax.net.ssl.SSLEngine; 10 | 11 | /** 12 | * Created by koush on 12/8/14. 13 | */ 14 | public class SSLEngineSNIConfigurator implements AsyncSSLEngineConfigurator { 15 | private static class EngineHolder implements AsyncSSLEngineConfigurator { 16 | Field peerHost; 17 | Field peerPort; 18 | Field sslParameters; 19 | Field useSni; 20 | boolean skipReflection; 21 | 22 | @Override 23 | public SSLEngine createEngine(SSLContext sslContext, String peerHost, int peerPort) { 24 | return null; 25 | } 26 | 27 | public EngineHolder(Class engineClass) { 28 | try { 29 | peerHost = engineClass.getSuperclass().getDeclaredField("peerHost"); 30 | peerHost.setAccessible(true); 31 | 32 | peerPort = engineClass.getSuperclass().getDeclaredField("peerPort"); 33 | peerPort.setAccessible(true); 34 | 35 | sslParameters = engineClass.getDeclaredField("sslParameters"); 36 | sslParameters.setAccessible(true); 37 | 38 | useSni = sslParameters.getType().getDeclaredField("useSni"); 39 | useSni.setAccessible(true); 40 | } 41 | catch (NoSuchFieldException e) { 42 | } 43 | } 44 | 45 | @Override 46 | public void configureEngine(SSLEngine engine, AsyncHttpClientMiddleware.GetSocketData data, String host, int port) { 47 | if (useSni == null || skipReflection) 48 | return; 49 | try { 50 | peerHost.set(engine, host); 51 | peerPort.set(engine, port); 52 | Object sslp = sslParameters.get(engine); 53 | useSni.set(sslp, true); 54 | } 55 | catch (IllegalAccessException e) { 56 | } 57 | } 58 | } 59 | 60 | Hashtable holders = new Hashtable(); 61 | 62 | @Override 63 | public SSLEngine createEngine(SSLContext sslContext, String peerHost, int peerPort) { 64 | // pre M, must use reflection to enable SNI, otherwise createSSLEngine(peerHost, peerPort) works. 65 | SSLEngine engine; 66 | boolean skipReflection = "GmsCore_OpenSSL".equals(sslContext.getProvider().getName()) || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; 67 | if (skipReflection) 68 | engine = sslContext.createSSLEngine(peerHost, peerPort); 69 | else 70 | engine = sslContext.createSSLEngine(); 71 | // ensureHolder(engine).skipReflection = skipReflection; 72 | return engine; 73 | } 74 | 75 | EngineHolder ensureHolder(SSLEngine engine) { 76 | String name = engine.getClass().getCanonicalName(); 77 | EngineHolder holder = holders.get(name); 78 | if (holder == null) { 79 | holder = new EngineHolder(engine.getClass()); 80 | holders.put(name, holder); 81 | } 82 | return holder; 83 | } 84 | 85 | @Override 86 | public void configureEngine(SSLEngine engine, AsyncHttpClientMiddleware.GetSocketData data, String host, int port) { 87 | EngineHolder holder = ensureHolder(engine); 88 | holder.configureEngine(engine, data, host, port); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /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 | @Override 7 | public void onRequest(OnRequestData data) { 8 | } 9 | 10 | @Override 11 | public Cancellable getSocket(GetSocketData data) { 12 | return null; 13 | } 14 | 15 | @Override 16 | public boolean exchangeHeaders(OnExchangeHeaderData data) { 17 | return false; 18 | } 19 | 20 | @Override 21 | public void onRequestSent(OnRequestSentData data) { 22 | } 23 | 24 | @Override 25 | public void onHeadersReceived(OnHeadersReceivedData data) { 26 | } 27 | 28 | @Override 29 | public void onBodyDecoder(OnBodyDecoderData data) { 30 | } 31 | 32 | @Override 33 | public AsyncHttpRequest onResponseReady(OnResponseReadyData data) { 34 | return null; 35 | } 36 | 37 | @Override 38 | public void onResponseComplete(OnResponseCompleteData data) { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/WebSocket.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http; 2 | 3 | import com.koushikdutta.async.AsyncSocket; 4 | 5 | public interface WebSocket extends AsyncSocket { 6 | interface StringCallback { 7 | void onStringAvailable(String s); 8 | } 9 | interface PingCallback { 10 | void onPingReceived(String s); 11 | } 12 | interface PongCallback { 13 | void onPongReceived(String s); 14 | } 15 | 16 | void send(byte[] bytes); 17 | void send(String string); 18 | void send(byte [] bytes, int offset, int len); 19 | void ping(String message); 20 | void pong(String message); 21 | 22 | void setStringCallback(StringCallback callback); 23 | StringCallback getStringCallback(); 24 | 25 | void setPingCallback(PingCallback callback); 26 | 27 | void setPongCallback(PongCallback callback); 28 | PongCallback getPongCallback(); 29 | 30 | boolean isBuffering(); 31 | String getProtocol(); 32 | 33 | AsyncSocket getSocket(); 34 | } 35 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/body/ByteBufferListRequestBody.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.http.AsyncHttpRequest; 9 | import com.koushikdutta.async.parser.ByteBufferListParser; 10 | 11 | public class ByteBufferListRequestBody implements AsyncHttpRequestBody { 12 | public ByteBufferListRequestBody() { 13 | } 14 | 15 | ByteBufferList bb; 16 | public ByteBufferListRequestBody(ByteBufferList bb) { 17 | this.bb = bb; 18 | } 19 | @Override 20 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) { 21 | Util.writeAll(sink, bb, completed); 22 | } 23 | 24 | @Override 25 | public void parse(DataEmitter emitter, CompletedCallback completed) { 26 | new ByteBufferListParser().parse(emitter).setCallback((e, result) -> { 27 | bb = result; 28 | completed.onCompleted(e); 29 | }); 30 | } 31 | 32 | public static String CONTENT_TYPE = "application/binary"; 33 | 34 | @Override 35 | public String getContentType() { 36 | return CONTENT_TYPE; 37 | } 38 | 39 | @Override 40 | public boolean readFullyOnRequest() { 41 | return true; 42 | } 43 | 44 | @Override 45 | public int length() { 46 | return bb.remaining(); 47 | } 48 | 49 | @Override 50 | public ByteBufferList get() { 51 | return bb; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /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 | import com.koushikdutta.async.util.Charsets; 11 | 12 | import org.w3c.dom.Document; 13 | 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.OutputStreamWriter; 16 | 17 | import javax.xml.transform.Transformer; 18 | import javax.xml.transform.TransformerFactory; 19 | import javax.xml.transform.dom.DOMSource; 20 | import javax.xml.transform.stream.StreamResult; 21 | 22 | /** 23 | * Created by koush on 8/30/13. 24 | */ 25 | public class DocumentBody implements AsyncHttpRequestBody { 26 | public DocumentBody() { 27 | this(null); 28 | } 29 | 30 | public DocumentBody(Document document) { 31 | this.document = document; 32 | } 33 | 34 | ByteArrayOutputStream bout; 35 | private void prepare() { 36 | if (bout != null) 37 | return; 38 | 39 | try { 40 | DOMSource source = new DOMSource(document); 41 | TransformerFactory tf = TransformerFactory.newInstance(); 42 | Transformer transformer = tf.newTransformer(); 43 | bout = new ByteArrayOutputStream(); 44 | OutputStreamWriter writer = new OutputStreamWriter(bout, Charsets.UTF_8); 45 | StreamResult result = new StreamResult(writer); 46 | transformer.transform(source, result); 47 | writer.flush(); 48 | } 49 | catch (Exception e) { 50 | } 51 | } 52 | 53 | @Override 54 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) { 55 | prepare(); 56 | byte[] bytes = bout.toByteArray(); 57 | Util.writeAll(sink, bytes, completed); 58 | } 59 | 60 | @Override 61 | public void parse(DataEmitter emitter, final CompletedCallback completed) { 62 | new DocumentParser().parse(emitter).setCallback(new FutureCallback() { 63 | @Override 64 | public void onCompleted(Exception e, Document result) { 65 | document = result; 66 | completed.onCompleted(e); 67 | } 68 | }); 69 | } 70 | 71 | public static final String CONTENT_TYPE = "application/xml"; 72 | 73 | @Override 74 | public String getContentType() { 75 | return CONTENT_TYPE; 76 | } 77 | 78 | @Override 79 | public boolean readFullyOnRequest() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public int length() { 85 | prepare(); 86 | return bout.size(); 87 | } 88 | 89 | Document document; 90 | @Override 91 | public Document get() { 92 | return document; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /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 | public static final String CONTENT_TYPE = "application/binary"; 16 | 17 | File file; 18 | String contentType = CONTENT_TYPE; 19 | 20 | public FileBody(File file) { 21 | this.file = file; 22 | } 23 | 24 | public FileBody(File file, String contentType) { 25 | this.file = file; 26 | this.contentType = contentType; 27 | } 28 | 29 | @Override 30 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) { 31 | Util.pump(file, sink, completed); 32 | } 33 | 34 | @Override 35 | public void parse(DataEmitter emitter, CompletedCallback completed) { 36 | throw new AssertionError("not implemented"); 37 | } 38 | 39 | @Override 40 | public String getContentType() { 41 | return contentType; 42 | } 43 | 44 | public void setContentType(String contentType) { 45 | this.contentType = contentType; 46 | } 47 | 48 | @Override 49 | public boolean readFullyOnRequest() { 50 | throw new AssertionError("not implemented"); 51 | } 52 | 53 | @Override 54 | public int length() { 55 | return (int)file.length(); 56 | } 57 | 58 | @Override 59 | public File get() { 60 | return file; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/body/FilePart.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.body; 2 | 3 | import com.koushikdutta.async.http.BasicNameValuePair; 4 | import com.koushikdutta.async.http.NameValuePair; 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 | @Override 32 | public String toString() { 33 | return getName(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /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/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.Headers; 6 | import com.koushikdutta.async.http.Multimap; 7 | import com.koushikdutta.async.http.NameValuePair; 8 | 9 | import java.io.File; 10 | import java.util.List; 11 | import java.util.Locale; 12 | 13 | public class Part { 14 | public static final String CONTENT_DISPOSITION = "Content-Disposition"; 15 | 16 | Headers mHeaders; 17 | Multimap mContentDisposition; 18 | public Part(Headers headers) { 19 | mHeaders = headers; 20 | mContentDisposition = Multimap.parseSemicolonDelimited(mHeaders.get(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 Headers(); 31 | StringBuilder builder = new StringBuilder(String.format(Locale.ENGLISH, "form-data; name=\"%s\"", name)); 32 | if (contentDisposition != null) { 33 | for (NameValuePair pair: contentDisposition) { 34 | builder.append(String.format(Locale.ENGLISH, "; %s=\"%s\"", pair.getName(), pair.getValue())); 35 | } 36 | } 37 | mHeaders.set(CONTENT_DISPOSITION, builder.toString()); 38 | mContentDisposition = Multimap.parseSemicolonDelimited(mHeaders.get(CONTENT_DISPOSITION)); 39 | } 40 | 41 | public Headers 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 | } 70 | } 71 | -------------------------------------------------------------------------------- /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 | String contentType = CONTENT_TYPE; 15 | 16 | /** 17 | * Construct an http body from a stream 18 | * @param stream 19 | * @param length Length of stream to read, or value < 0 to read to end 20 | */ 21 | public StreamBody(InputStream stream, int length) { 22 | this.stream = stream; 23 | this.length = length; 24 | } 25 | 26 | @Override 27 | public void write(AsyncHttpRequest request, DataSink sink, CompletedCallback completed) { 28 | Util.pump(stream, length < 0 ? Integer.MAX_VALUE : length, sink, completed); 29 | } 30 | 31 | @Override 32 | public void parse(DataEmitter emitter, CompletedCallback completed) { 33 | throw new AssertionError("not implemented"); 34 | } 35 | 36 | public static final String CONTENT_TYPE = "application/binary"; 37 | @Override 38 | public String getContentType() { 39 | return contentType; 40 | } 41 | public StreamBody setContentType(String contentType) { 42 | this.contentType = contentType; 43 | return this; 44 | } 45 | 46 | @Override 47 | public boolean readFullyOnRequest() { 48 | throw new AssertionError("not implemented"); 49 | } 50 | 51 | @Override 52 | public int length() { 53 | return length; 54 | } 55 | 56 | @Override 57 | public InputStream get() { 58 | return stream; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /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 com.koushikdutta.async.DataSink; 8 | import com.koushikdutta.async.callback.CompletedCallback; 9 | import com.koushikdutta.async.http.NameValuePair; 10 | 11 | public abstract class StreamPart extends Part { 12 | public StreamPart(String name, long length, List contentDisposition) { 13 | super(name, length, contentDisposition); 14 | } 15 | 16 | @Override 17 | public void write(DataSink sink, CompletedCallback callback) { 18 | try { 19 | InputStream is = getInputStream(); 20 | com.koushikdutta.async.Util.pump(is, sink, callback); 21 | } 22 | catch (Exception e) { 23 | callback.onCompleted(e); 24 | } 25 | } 26 | 27 | protected abstract InputStream getInputStream() throws IOException; 28 | } 29 | -------------------------------------------------------------------------------- /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/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 | public String getValue() { 20 | return value; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/cache/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.cache; 18 | 19 | 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/cache/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.cache; 18 | 19 | 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/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/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/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/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 | @Override 23 | public void end() { 24 | setMaxBuffer(Integer.MAX_VALUE); 25 | ByteBufferList fin = new ByteBufferList(); 26 | write(fin); 27 | setMaxBuffer(0); 28 | // do NOT call through to super.end, as chunking is a framing protocol. 29 | // we don't want to close the underlying transport. 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /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: " + totalRead + "/" + contentLength + " Paused: " + isPaused()); 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 | int remaining = bb.remaining(); 25 | long toRead = Math.min(contentLength - totalRead, remaining); 26 | 27 | bb.get(transformed, (int)toRead); 28 | 29 | int beforeRead = transformed.remaining(); 30 | 31 | super.onDataAvailable(emitter, transformed); 32 | 33 | totalRead += (beforeRead - transformed.remaining()); 34 | transformed.get(bb); 35 | 36 | if (totalRead == contentLength) 37 | report(null); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /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/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 | int newSize = output.capacity() * 2; 42 | output = ByteBufferList.obtain(newSize); 43 | } 44 | } 45 | while (!mInflater.needsInput() && !mInflater.finished()); 46 | } 47 | ByteBufferList.reclaim(b); 48 | } 49 | output.flip(); 50 | transformed.add(output); 51 | 52 | Util.emitAllData(this, transformed); 53 | } 54 | catch (Exception ex) { 55 | report(ex); 56 | } 57 | } 58 | 59 | public InflaterInputFilter() { 60 | this(new Inflater()); 61 | } 62 | 63 | public InflaterInputFilter(Inflater inflater) { 64 | mInflater = inflater; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /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/http/server/AsyncHttpRequestBodyProvider.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.server; 2 | 3 | import com.koushikdutta.async.http.Headers; 4 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody; 5 | 6 | public interface AsyncHttpRequestBodyProvider { 7 | AsyncHttpRequestBody getBody(Headers headers); 8 | } 9 | -------------------------------------------------------------------------------- /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.Headers; 6 | import com.koushikdutta.async.http.Multimap; 7 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody; 8 | 9 | import java.util.Map; 10 | import java.util.regex.Matcher; 11 | 12 | public interface AsyncHttpServerRequest extends DataEmitter { 13 | Headers getHeaders(); 14 | Matcher getMatcher(); 15 | void setMatcher(Matcher matcher); 16 | T getBody(); 17 | AsyncSocket getSocket(); 18 | String getPath(); 19 | Multimap getQuery(); 20 | String getMethod(); 21 | String getUrl(); 22 | 23 | String get(String name); 24 | Map getState(); 25 | } 26 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponse.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.server; 2 | 3 | import com.koushikdutta.async.AsyncSocket; 4 | import com.koushikdutta.async.ByteBufferList; 5 | import com.koushikdutta.async.DataSink; 6 | import com.koushikdutta.async.callback.CompletedCallback; 7 | import com.koushikdutta.async.http.AsyncHttpResponse; 8 | import com.koushikdutta.async.http.Headers; 9 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody; 10 | import com.koushikdutta.async.parser.AsyncParser; 11 | 12 | import org.json.JSONArray; 13 | import org.json.JSONObject; 14 | 15 | import java.io.File; 16 | import java.io.InputStream; 17 | import java.nio.ByteBuffer; 18 | 19 | public interface AsyncHttpServerResponse extends DataSink, CompletedCallback { 20 | void end(); 21 | void send(String contentType, byte[] bytes); 22 | void send(String contentType, ByteBufferList bb); 23 | void send(String contentType, ByteBuffer bb); 24 | void send(String contentType, String string); 25 | void send(String string); 26 | void send(JSONObject json); 27 | void send(JSONArray jsonArray); 28 | void sendFile(File file); 29 | void sendStream(InputStream inputStream, long totalLength); 30 | void sendBody(AsyncParser body, T value); 31 | AsyncHttpServerResponse code(int code); 32 | int code(); 33 | Headers getHeaders(); 34 | void writeHead(); 35 | void setContentType(String contentType); 36 | void redirect(String location); 37 | AsyncHttpServerRequest getRequest(); 38 | String getHttpVersion(); 39 | void setHttpVersion(String httpVersion); 40 | 41 | // NOT FINAL 42 | void proxy(AsyncHttpResponse response); 43 | 44 | /** 45 | * Alias for end. Used with CompletedEmitters 46 | */ 47 | void onCompleted(Exception ex); 48 | AsyncSocket getSocket(); 49 | void setSocket(AsyncSocket socket); 50 | } 51 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/http/server/AsyncProxyServer.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.server; 2 | 3 | import android.net.Uri; 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.AsyncHttpRequest; 10 | import com.koushikdutta.async.http.AsyncHttpResponse; 11 | import com.koushikdutta.async.http.callback.HttpConnectCallback; 12 | 13 | /** 14 | * Created by koush on 7/22/14. 15 | */ 16 | public class AsyncProxyServer extends AsyncHttpServer { 17 | AsyncHttpClient proxyClient; 18 | public AsyncProxyServer(AsyncServer server) { 19 | proxyClient = new AsyncHttpClient(server); 20 | } 21 | 22 | @Override 23 | protected void onRequest(HttpServerRequestCallback callback, AsyncHttpServerRequest request, final AsyncHttpServerResponse response) { 24 | super.onRequest(callback, request, response); 25 | 26 | if (callback != null) 27 | return; 28 | 29 | try { 30 | Uri uri; 31 | 32 | try { 33 | uri = Uri.parse(request.getPath()); 34 | if (uri.getScheme() == null) 35 | throw new Exception("no host or full uri provided"); 36 | } 37 | catch (Exception e) { 38 | String host = request.getHeaders().get("Host"); 39 | int port = 80; 40 | if (host != null) { 41 | String[] splits = host.split(":", 2); 42 | if (splits.length == 2) { 43 | host = splits[0]; 44 | port = Integer.parseInt(splits[1]); 45 | } 46 | } 47 | uri = Uri.parse("http://" + host + ":" + port + request.getPath()); 48 | } 49 | 50 | proxyClient.execute(new AsyncHttpRequest(uri, request.getMethod(), request.getHeaders()), new HttpConnectCallback() { 51 | @Override 52 | public void onConnectCompleted(Exception ex, AsyncHttpResponse remoteResponse) { 53 | if (ex != null) { 54 | response.code(500); 55 | response.send(ex.getMessage()); 56 | return; 57 | } 58 | response.proxy(remoteResponse); 59 | } 60 | }); 61 | } 62 | catch (Exception e) { 63 | response.code(500); 64 | response.send(e.getMessage()); 65 | } 66 | } 67 | 68 | @Override 69 | protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /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/MalformedRangeException.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.server; 2 | 3 | public class MalformedRangeException extends Exception { 4 | } 5 | -------------------------------------------------------------------------------- /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/server/RouteMatcher.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.http.server; 2 | 3 | public interface RouteMatcher { 4 | AsyncHttpServerRouter.RouteMatch route(String method, String path); 5 | } -------------------------------------------------------------------------------- /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/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.Util; 6 | import com.koushikdutta.async.callback.CompletedCallback; 7 | import com.koushikdutta.async.callback.DataCallback; 8 | import com.koushikdutta.async.http.AsyncHttpRequest; 9 | import com.koushikdutta.async.http.body.AsyncHttpRequestBody; 10 | 11 | public class UnknownRequestBody implements AsyncHttpRequestBody { 12 | public UnknownRequestBody(String contentType) { 13 | mContentType = contentType; 14 | } 15 | 16 | int length = -1; 17 | public UnknownRequestBody(DataEmitter emitter, String contentType, int length) { 18 | mContentType = contentType; 19 | this.emitter = emitter; 20 | this.length = length; 21 | } 22 | 23 | @Override 24 | public void write(final AsyncHttpRequest request, DataSink sink, final CompletedCallback completed) { 25 | Util.pump(emitter, sink, completed); 26 | if (emitter.isPaused()) 27 | emitter.resume(); 28 | } 29 | 30 | private String mContentType; 31 | @Override 32 | public String getContentType() { 33 | return mContentType; 34 | } 35 | 36 | @Override 37 | public boolean readFullyOnRequest() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public int length() { 43 | return length; 44 | } 45 | 46 | @Override 47 | public Void get() { 48 | return null; 49 | } 50 | 51 | @Deprecated 52 | public void setCallbacks(DataCallback callback, CompletedCallback endCallback) { 53 | emitter.setEndCallback(endCallback); 54 | emitter.setDataCallback(callback); 55 | } 56 | 57 | public DataEmitter getEmitter() { 58 | return emitter; 59 | } 60 | 61 | DataEmitter emitter; 62 | @Override 63 | public void parse(DataEmitter emitter, CompletedCallback completed) { 64 | this.emitter = emitter; 65 | emitter.setEndCallback(completed); 66 | emitter.setDataCallback(new DataCallback.NullDataCallback()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /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 | import java.lang.reflect.Type; 9 | 10 | /** 11 | * Created by koush on 5/27/13. 12 | */ 13 | public interface AsyncParser { 14 | Future parse(DataEmitter emitter); 15 | void write(DataSink sink, T value, CompletedCallback completed); 16 | Type getType(); 17 | String getMime(); 18 | } 19 | -------------------------------------------------------------------------------- /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 | import java.lang.reflect.Type; 13 | 14 | /** 15 | * Created by koush on 5/27/13. 16 | */ 17 | public class ByteBufferListParser implements AsyncParser { 18 | @Override 19 | public Future parse(final DataEmitter emitter) { 20 | final ByteBufferList bb = new ByteBufferList(); 21 | final SimpleFuture ret = new SimpleFuture() { 22 | @Override 23 | protected void cancelCleanup() { 24 | emitter.close(); 25 | } 26 | }; 27 | emitter.setDataCallback(new DataCallback() { 28 | @Override 29 | public void onDataAvailable(DataEmitter emitter, ByteBufferList data) { 30 | data.get(bb); 31 | } 32 | }); 33 | 34 | emitter.setEndCallback(new CompletedCallback() { 35 | @Override 36 | public void onCompleted(Exception ex) { 37 | if (ex != null) { 38 | ret.setComplete(ex); 39 | return; 40 | } 41 | 42 | try { 43 | ret.setComplete(bb); 44 | } 45 | catch (Exception e) { 46 | ret.setComplete(e); 47 | } 48 | } 49 | }); 50 | 51 | return ret; 52 | } 53 | 54 | @Override 55 | public void write(DataSink sink, ByteBufferList value, CompletedCallback completed) { 56 | Util.writeAll(sink, value, completed); 57 | } 58 | 59 | @Override 60 | public Type getType() { 61 | return ByteBufferList.class; 62 | } 63 | 64 | @Override 65 | public String getMime() { 66 | return null; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/parser/DocumentParser.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.http.body.DocumentBody; 8 | import com.koushikdutta.async.stream.ByteBufferListInputStream; 9 | 10 | import org.w3c.dom.Document; 11 | 12 | import java.lang.reflect.Type; 13 | 14 | import javax.xml.parsers.DocumentBuilderFactory; 15 | 16 | /** 17 | * Created by koush on 8/3/13. 18 | */ 19 | public class DocumentParser implements AsyncParser { 20 | @Override 21 | public Future parse(DataEmitter emitter) { 22 | return new ByteBufferListParser().parse(emitter) 23 | .thenConvert(from -> DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteBufferListInputStream(from))); 24 | } 25 | 26 | @Override 27 | public void write(DataSink sink, Document value, CompletedCallback completed) { 28 | new DocumentBody(value).write(null, sink, completed); 29 | } 30 | 31 | @Override 32 | public Type getType() { 33 | return Document.class; 34 | } 35 | 36 | @Override 37 | public String getMime() { 38 | return "text/xml"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /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 | 8 | import org.json.JSONArray; 9 | 10 | import java.lang.reflect.Type; 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 | .thenConvert(JSONArray::new); 20 | } 21 | 22 | @Override 23 | public void write(DataSink sink, JSONArray value, CompletedCallback completed) { 24 | new StringParser().write(sink, value.toString(), completed); 25 | } 26 | 27 | @Override 28 | public Type getType() { 29 | return JSONArray.class; 30 | } 31 | 32 | @Override 33 | public String getMime() { 34 | return "application/json"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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 | 8 | import org.json.JSONObject; 9 | 10 | import java.lang.reflect.Type; 11 | 12 | /** 13 | * Created by koush on 5/27/13. 14 | */ 15 | public class JSONObjectParser implements AsyncParser { 16 | @Override 17 | public Future parse(DataEmitter emitter) { 18 | return new StringParser().parse(emitter).thenConvert(JSONObject::new); 19 | } 20 | 21 | @Override 22 | public void write(DataSink sink, JSONObject value, CompletedCallback completed) { 23 | new StringParser().write(sink, value.toString(), completed); 24 | } 25 | 26 | @Override 27 | public Type getType() { 28 | return JSONObject.class; 29 | } 30 | 31 | @Override 32 | public String getMime() { 33 | return "application/json"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /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 | 9 | import java.lang.reflect.Type; 10 | import java.nio.charset.Charset; 11 | 12 | /** 13 | * Created by koush on 5/27/13. 14 | */ 15 | public class StringParser implements AsyncParser { 16 | Charset forcedCharset; 17 | 18 | public StringParser() { 19 | } 20 | 21 | public StringParser(Charset charset) { 22 | this.forcedCharset = charset; 23 | } 24 | 25 | @Override 26 | public Future parse(DataEmitter emitter) { 27 | final String charset = emitter.charset(); 28 | return new ByteBufferListParser().parse(emitter) 29 | .thenConvert(from -> { 30 | Charset charsetToUse = forcedCharset; 31 | if (charsetToUse == null && charset != null) 32 | charsetToUse = Charset.forName(charset); 33 | return from.readString(charsetToUse); 34 | }); 35 | } 36 | 37 | @Override 38 | public void write(DataSink sink, String value, CompletedCallback completed) { 39 | new ByteBufferListParser().write(sink, new ByteBufferList(value.getBytes()), completed); 40 | } 41 | 42 | @Override 43 | public Type getType() { 44 | return String.class; 45 | } 46 | 47 | @Override 48 | public String getMime() { 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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 (int)bb.get() & 0x000000ff; 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/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 | file.getParentFile().mkdirs(); 25 | ret = new FileOutputStream(file); 26 | setOutputStream(ret); 27 | } 28 | return ret; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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/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 | AsyncServer server; 31 | public OutputStreamDataSink(AsyncServer server, OutputStream stream) { 32 | this.server = server; 33 | setOutputStream(stream); 34 | } 35 | 36 | OutputStream mStream; 37 | public void setOutputStream(OutputStream stream) { 38 | mStream = stream; 39 | } 40 | 41 | public OutputStream getOutputStream() throws IOException { 42 | return mStream; 43 | } 44 | 45 | @Override 46 | public void write(final ByteBufferList bb) { 47 | try { 48 | while (bb.size() > 0) { 49 | ByteBuffer b = bb.remove(); 50 | getOutputStream().write(b.array(), b.arrayOffset() + b.position(), b.remaining()); 51 | ByteBufferList.reclaim(b); 52 | } 53 | } 54 | catch (IOException e) { 55 | reportClose(e); 56 | } 57 | finally { 58 | bb.recycle(); 59 | } 60 | } 61 | 62 | WritableCallback mWritable; 63 | @Override 64 | public void setWriteableCallback(WritableCallback handler) { 65 | mWritable = handler; 66 | } 67 | 68 | @Override 69 | public WritableCallback getWriteableCallback() { 70 | return mWritable; 71 | } 72 | 73 | @Override 74 | public boolean isOpen() { 75 | return closeReported; 76 | } 77 | 78 | boolean closeReported; 79 | Exception closeException; 80 | public void reportClose(Exception ex) { 81 | if (closeReported) 82 | return; 83 | closeReported = true; 84 | closeException = ex; 85 | 86 | if (mClosedCallback != null) 87 | mClosedCallback.onCompleted(closeException); 88 | } 89 | 90 | CompletedCallback mClosedCallback; 91 | @Override 92 | public void setClosedCallback(CompletedCallback handler) { 93 | mClosedCallback = handler; 94 | } 95 | 96 | @Override 97 | public CompletedCallback getClosedCallback() { 98 | return mClosedCallback; 99 | } 100 | 101 | @Override 102 | public AsyncServer getServer() { 103 | return server; 104 | } 105 | 106 | WritableCallback outputStreamCallback; 107 | public void setOutputStreamWritableCallback(WritableCallback outputStreamCallback) { 108 | this.outputStreamCallback = outputStreamCallback; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /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 allocate(currentAlloc); 25 | } 26 | 27 | public ByteBuffer allocate(int currentAlloc) { 28 | return ByteBufferList.obtain(Math.min(Math.max(currentAlloc, minAlloc), maxAlloc)); 29 | } 30 | 31 | public void track(long read) { 32 | currentAlloc = (int)read * 2; 33 | } 34 | 35 | public int getMaxAlloc() { 36 | return maxAlloc; 37 | } 38 | 39 | public void setCurrentAlloc(int currentAlloc) { 40 | this.currentAlloc = currentAlloc; 41 | } 42 | 43 | public int getMinAlloc() { 44 | return minAlloc; 45 | } 46 | 47 | public Allocator setMinAlloc(int minAlloc ) { 48 | this.minAlloc = Math.max(0, minAlloc); 49 | return this; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /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 | public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 10 | } 11 | -------------------------------------------------------------------------------- /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/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 | Hashtable> internal = new Hashtable>(); 12 | 13 | public HashList() { 14 | } 15 | 16 | public Set keySet() { 17 | return internal.keySet(); 18 | } 19 | 20 | public synchronized V tag(String key) { 21 | TaggedList list = internal.get(key); 22 | if (list == null) 23 | return null; 24 | return list.tag(); 25 | } 26 | 27 | public synchronized void tag(String key, V tag) { 28 | TaggedList list = internal.get(key); 29 | if (list == null) { 30 | list = new TaggedList(); 31 | internal.put(key, list); 32 | } 33 | list.tag(tag); 34 | } 35 | 36 | public synchronized ArrayList remove(String key) { 37 | return internal.remove(key); 38 | } 39 | 40 | public synchronized int size() { 41 | return internal.size(); 42 | } 43 | 44 | public synchronized ArrayList get(String key) { 45 | return internal.get(key); 46 | } 47 | 48 | synchronized public boolean contains(String key) { 49 | ArrayList check = get(key); 50 | return check != null && check.size() > 0; 51 | } 52 | 53 | synchronized public void add(String key, T value) { 54 | ArrayList ret = get(key); 55 | if (ret == null) { 56 | TaggedList put = new TaggedList(); 57 | ret = put; 58 | internal.put(key, put); 59 | } 60 | ret.add(value); 61 | } 62 | 63 | synchronized public T pop(String key) { 64 | TaggedList values = internal.get(key); 65 | if (values == null) 66 | return null; 67 | if (values.size() == 0) 68 | return null; 69 | return values.remove(values.size() - 1); 70 | } 71 | 72 | synchronized public boolean removeItem(String key, T value) { 73 | TaggedList values = internal.get(key); 74 | if (values == null) 75 | return false; 76 | 77 | values.remove(value); 78 | return values.size() == 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/util/IdleTimeout.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.util; 2 | 3 | import android.os.Handler; 4 | 5 | import com.koushikdutta.async.AsyncServer; 6 | 7 | public class IdleTimeout extends TimeoutBase { 8 | Runnable callback; 9 | 10 | public IdleTimeout(AsyncServer server, long delay) { 11 | super(server, delay); 12 | 13 | } 14 | 15 | public IdleTimeout(Handler handler, long delay) { 16 | super(handler, delay); 17 | } 18 | 19 | public void setTimeout(Runnable callback) { 20 | this.callback = callback; 21 | } 22 | 23 | Object cancellable; 24 | public void reset() { 25 | handlerish.removeAllCallbacks(cancellable); 26 | cancellable = handlerish.postDelayed(callback, delay); 27 | } 28 | 29 | public void cancel() { 30 | // must post this, so that when it runs it removes everything in the queue, 31 | // preventing any rescheduling. 32 | // posting gaurantees there is not a reschedule in progress. 33 | handlerish.post(() -> handlerish.removeAllCallbacks(cancellable)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/util/TaggedList.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.util; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class TaggedList extends ArrayList { 6 | private Object tag; 7 | 8 | public synchronized V tag() { 9 | return (V)tag; 10 | } 11 | 12 | public synchronized void tag(V tag) { 13 | this.tag = tag; 14 | } 15 | 16 | public synchronized void tagNull(V tag) { 17 | if (this.tag == null) 18 | this.tag = tag; 19 | } 20 | } -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/util/ThrottleTimeout.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.util; 2 | 3 | import android.os.Handler; 4 | 5 | import com.koushikdutta.async.AsyncServer; 6 | import com.koushikdutta.async.callback.ValueCallback; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by koush on 7/19/16. 13 | */ 14 | public class ThrottleTimeout extends TimeoutBase { 15 | ValueCallback> callback; 16 | ArrayList values = new ArrayList<>(); 17 | ThrottleMode throttleMode = ThrottleMode.Collect; 18 | 19 | public enum ThrottleMode { 20 | /** 21 | * The timeout will keep resetting until it expires, at which point all 22 | * the collected values will be invoked on the callback. 23 | */ 24 | Collect, 25 | /** 26 | * The callback will be invoked immediately with the first, but future values will be 27 | * metered until it expires. 28 | */ 29 | Meter, 30 | } 31 | 32 | 33 | public ThrottleTimeout(final AsyncServer server, long delay, ValueCallback> callback) { 34 | super(server, delay); 35 | this.callback = callback; 36 | } 37 | 38 | public ThrottleTimeout(final Handler handler, long delay, ValueCallback> callback) { 39 | super(handler, delay); 40 | this.callback = callback; 41 | } 42 | 43 | public void setCallback(ValueCallback> callback) { 44 | this.callback = callback; 45 | } 46 | 47 | private void runCallback() { 48 | cancellable = null; 49 | ArrayList v = new ArrayList<>(values); 50 | values.clear(); 51 | callback.onResult(v); 52 | } 53 | 54 | Object cancellable; 55 | public synchronized void postThrottled(final T value) { 56 | handlerish.post(() -> { 57 | values.add(value); 58 | 59 | if (throttleMode == ThrottleMode.Collect) { 60 | // cancel the existing, schedule a new one, and wait. 61 | handlerish.removeAllCallbacks(cancellable); 62 | cancellable = handlerish.postDelayed(this::runCallback, delay); 63 | } 64 | else { 65 | // nothing is pending, so this can be fired off immediately 66 | if (cancellable == null) { 67 | runCallback(); 68 | 69 | // meter future invocations 70 | cancellable = handlerish.postDelayed(this::runCallback, delay); 71 | } 72 | } 73 | }); 74 | } 75 | 76 | public void setThrottleMode(ThrottleMode throttleMode) { 77 | this.throttleMode = throttleMode; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AndroidAsync/src/com/koushikdutta/async/util/TimeoutBase.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.util; 2 | 3 | import android.os.Handler; 4 | 5 | import com.koushikdutta.async.AsyncServer; 6 | import com.koushikdutta.async.future.Cancellable; 7 | 8 | public class TimeoutBase { 9 | protected Handlerish handlerish; 10 | protected long delay; 11 | 12 | interface Handlerish { 13 | void post(Runnable r); 14 | Object postDelayed(Runnable r, long delay); 15 | void removeAllCallbacks(Object cancellable); 16 | } 17 | 18 | protected void onCallback() { 19 | 20 | } 21 | 22 | public TimeoutBase(final AsyncServer server, long delay) { 23 | this.delay = delay; 24 | this.handlerish = new Handlerish() { 25 | @Override 26 | public void post(Runnable r) { 27 | server.post(r); 28 | } 29 | 30 | @Override 31 | public Object postDelayed(Runnable r, long delay) { 32 | return server.postDelayed(r, delay); 33 | } 34 | 35 | @Override 36 | public void removeAllCallbacks(Object cancellable) { 37 | if (cancellable == null) 38 | return; 39 | ((Cancellable)cancellable).cancel(); 40 | } 41 | }; 42 | } 43 | 44 | public TimeoutBase(final Handler handler, long delay) { 45 | this.delay = delay; 46 | this.handlerish = new Handlerish() { 47 | @Override 48 | public void post(Runnable r) { 49 | handler.post(r); 50 | } 51 | 52 | @Override 53 | public Object postDelayed(Runnable r, long delay) { 54 | handler.postDelayed(r, delay); 55 | return r; 56 | } 57 | 58 | @Override 59 | public void removeAllCallbacks(Object cancellable) { 60 | if (cancellable == null) 61 | return; 62 | handler.removeCallbacks((Runnable)cancellable); 63 | } 64 | }; 65 | } 66 | 67 | public void setDelay(long delay) { 68 | this.delay = delay; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /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/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/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/test/assets/6691924d7d24237d3b3679310157d640: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/assets/6691924d7d24237d3b3679310157d640 -------------------------------------------------------------------------------- /AndroidAsync/test/assets/hello.txt: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /AndroidAsync/test/assets/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } -------------------------------------------------------------------------------- /AndroidAsync/test/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsync/test/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsync/test/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsync/test/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsync/test/res/raw/keystore.bks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsync/test/res/raw/keystore.bks -------------------------------------------------------------------------------- /AndroidAsync/test/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AndroidAsyncTestTest 5 | 6 | -------------------------------------------------------------------------------- /AndroidAsync/test/src/com/koushikdutta/async/test/BodyTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | import androidx.test.runner.AndroidJUnit4; 4 | 5 | import com.koushikdutta.async.http.Multimap; 6 | import com.koushikdutta.async.http.body.UrlEncodedFormBody; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Created by koush on 3/19/14. 13 | */ 14 | @RunWith(AndroidJUnit4.class) 15 | public class BodyTests { 16 | @Test 17 | public void testNullValue() throws Exception { 18 | Multimap mm = new Multimap(); 19 | mm.add("hello", null); 20 | UrlEncodedFormBody body = new UrlEncodedFormBody(mm); 21 | 22 | int length = body.length(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /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.PushParser; 6 | import com.koushikdutta.async.TapCallback; 7 | import com.koushikdutta.async.Util; 8 | import com.koushikdutta.async.callback.DataCallback; 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 DataCallback.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 DataCallback.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/test/src/com/koushikdutta/async/test/ConvertTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | import androidx.test.runner.AndroidJUnit4; 4 | 5 | import com.koushikdutta.async.future.SimpleFuture; 6 | 7 | import org.json.JSONObject; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import java.nio.ByteBuffer; 12 | 13 | import static com.koushikdutta.async.future.Converter.convert; 14 | import static org.junit.Assert.assertEquals; 15 | 16 | @RunWith(AndroidJUnit4.class) 17 | public class ConvertTests { 18 | @Test 19 | public void testConvert() throws Exception { 20 | ByteBuffer buf = convert(new SimpleFuture<>(new JSONObject())) 21 | .to(ByteBuffer.class) 22 | .get(); 23 | 24 | assertEquals(buf.remaining(), 2); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /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/test/src/com/koushikdutta/async/test/FileTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | 4 | import androidx.test.runner.AndroidJUnit4; 5 | 6 | import com.koushikdutta.async.AsyncServer; 7 | import com.koushikdutta.async.FileDataEmitter; 8 | import com.koushikdutta.async.future.Future; 9 | import com.koushikdutta.async.future.FutureCallback; 10 | import com.koushikdutta.async.parser.StringParser; 11 | import com.koushikdutta.async.util.StreamUtility; 12 | 13 | import org.junit.runner.RunWith; 14 | 15 | import java.io.File; 16 | import java.util.concurrent.Semaphore; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import static androidx.test.InstrumentationRegistry.getContext; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | /** 24 | * Created by koush on 5/22/13. 25 | */ 26 | @RunWith(AndroidJUnit4.class) 27 | public class FileTests { 28 | public static final long TIMEOUT = 1000L; 29 | public void testFileDataEmitter() throws Exception { 30 | final Semaphore semaphore = new Semaphore(0); 31 | File f = getContext().getFileStreamPath("test.txt"); 32 | StreamUtility.writeFile(f, "hello world"); 33 | FileDataEmitter fdm = new FileDataEmitter(AsyncServer.getDefault(), f); 34 | final Md5 md5 = Md5.createInstance(); 35 | Future stringBody = new StringParser().parse(fdm); 36 | stringBody 37 | .setCallback(new FutureCallback() { 38 | @Override 39 | public void onCompleted(Exception e, String result) { 40 | semaphore.release(); 41 | } 42 | }); 43 | fdm.resume(); 44 | 45 | assertTrue("timeout", semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)); 46 | assertEquals("hello world", stringBody.get()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /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.ByteBufferList; 7 | import com.koushikdutta.async.Util; 8 | import com.koushikdutta.async.callback.CompletedCallback; 9 | import com.koushikdutta.async.http.AsyncHttpClient; 10 | import com.koushikdutta.async.http.AsyncHttpGet; 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.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * Created by koush on 8/31/13. 22 | */ 23 | public class Issue59 extends TestCase { 24 | public void testIssue() throws Exception { 25 | AsyncHttpServer httpServer = new AsyncHttpServer(); 26 | try { 27 | httpServer.get("/", new HttpServerRequestCallback() { 28 | @Override 29 | public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) { 30 | // setting this to empty is a hacky way of telling the framework not to use 31 | // transfer-encoding. It will get removed. 32 | response.getHeaders().set("Transfer-Encoding", ""); 33 | response.code(200); 34 | Util.writeAll(response, "foobarbeepboop".getBytes(), new CompletedCallback() { 35 | @Override 36 | public void onCompleted(Exception ex) { 37 | response.end(); 38 | } 39 | }); 40 | } 41 | }); 42 | 43 | httpServer.listen(5959); 44 | 45 | AsyncHttpGet get = new AsyncHttpGet("http://localhost:5959/"); 46 | get.setLogging("issue59", Log.VERBOSE); 47 | get.getHeaders().removeAll("Connection"); 48 | get.getHeaders().removeAll("Accept-Encoding"); 49 | 50 | assertEquals("foobarbeepboop", AsyncHttpClient.getDefaultInstance().executeString(get, null).get(1000, TimeUnit.MILLISECONDS)); 51 | } 52 | finally { 53 | httpServer.stop(); 54 | AsyncServer.getDefault().stop(); 55 | } 56 | } 57 | 58 | public void testIon428() throws Exception { 59 | ByteBufferList bb = AsyncHttpClient.getDefaultInstance().executeByteBufferList(new AsyncHttpGet("https://cdn2.vox-cdn.com/thumbor/KxtZNw37jKNfxdA0hX5edHvbTBE=/0x0:2039x1359/800x536/cdn0.vox-cdn.com/uploads/chorus_image/image/44254028/lg-g-watch.0.0.jpg"), null) 60 | .get(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AndroidAsync/test/src/com/koushikdutta/async/test/IssueWithWebSocketFuturesTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | import com.koushikdutta.async.future.Future; 4 | import com.koushikdutta.async.http.AsyncHttpClient; 5 | import com.koushikdutta.async.http.WebSocket; 6 | import com.koushikdutta.async.http.server.AsyncHttpServer; 7 | import com.koushikdutta.async.http.server.AsyncHttpServerRequest; 8 | 9 | import junit.framework.TestCase; 10 | 11 | import java.util.concurrent.CountDownLatch; 12 | 13 | 14 | public class IssueWithWebSocketFuturesTests extends TestCase { 15 | 16 | //testing that websocket callback gets called with the correct parameters. 17 | public void testWebSocketFutureWithHandshakeFailureCallback() throws Exception { 18 | 19 | //creating a faulty server! 20 | AsyncHttpServer httpServer = new AsyncHttpServer(); 21 | httpServer.websocket(".*", new AsyncHttpServer.WebSocketRequestCallback() { 22 | @Override 23 | public void onConnected(WebSocket webSocket, AsyncHttpServerRequest request) { 24 | 25 | } 26 | }); 27 | httpServer.listen(6666); 28 | 29 | 30 | 31 | final Exception[] callbackException = {null}; 32 | final WebSocket[] callbackWs = {null}; 33 | final CountDownLatch countDownLatch = new CountDownLatch(1); 34 | 35 | 36 | //for some reason, it fails with a WebSocketHandshakeException. 37 | //But in general, if the handshake fails, the callback must be called with an exception. 38 | Future wsFuture = AsyncHttpClient.getDefaultInstance().websocket("ws://127.0.0.1:6666", "ws", new AsyncHttpClient.WebSocketConnectCallback() { 39 | @Override 40 | public void onCompleted(Exception ex, WebSocket webSocket) { 41 | callbackException[0] = ex; 42 | callbackWs[0] = webSocket; 43 | countDownLatch.countDown(); 44 | } 45 | }); 46 | 47 | 48 | //wait for the future to complete 49 | countDownLatch.await(); 50 | 51 | //exactly one mut be null 52 | assertTrue(callbackWs[0] == null ^ callbackException[0] == null); 53 | 54 | //callback parameters must be the same as the future's result 55 | assertEquals(wsFuture.tryGet(), callbackWs[0]); 56 | assertEquals(wsFuture.tryGetException(), callbackException[0]); 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AndroidAsync/test/src/com/koushikdutta/async/test/LineEmitterTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | import com.koushikdutta.async.ByteBufferList; 4 | import com.koushikdutta.async.LineEmitter; 5 | import com.koushikdutta.async.util.Charsets; 6 | 7 | import junit.framework.TestCase; 8 | 9 | import java.nio.ByteBuffer; 10 | import java.nio.charset.Charset; 11 | import java.util.concurrent.Semaphore; 12 | 13 | /** 14 | * Created by koush on 6/9/16. 15 | */ 16 | public class LineEmitterTests extends TestCase { 17 | public void testFunnyCharacter() { 18 | final String stuff = "é\n"; 19 | LineEmitter emitter = new LineEmitter(Charsets.UTF_8); 20 | emitter.setLineCallback(new LineEmitter.StringCallback() { 21 | @Override 22 | public void onStringAvailable(String s) { 23 | assertEquals(s + '\n', stuff); 24 | } 25 | }); 26 | 27 | 28 | assertEquals(stuff.charAt(0), 233); 29 | ByteBufferList bb = new ByteBufferList(ByteBuffer.wrap(stuff.getBytes(Charsets.UTF_8))); 30 | emitter.onDataAvailable(null, bb); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.DocumentParser; 7 | import com.koushikdutta.async.parser.StringParser; 8 | import com.koushikdutta.async.util.Charsets; 9 | 10 | import junit.framework.TestCase; 11 | 12 | import org.w3c.dom.Document; 13 | 14 | import java.nio.ByteBuffer; 15 | import java.nio.charset.Charset; 16 | 17 | /** 18 | * Created by koush on 7/10/14. 19 | */ 20 | public class ParserTests extends TestCase { 21 | public void testString() throws Exception { 22 | StringParser p = new StringParser(); 23 | FilteredDataEmitter f = new FilteredDataEmitter() { 24 | @Override 25 | public boolean isPaused() { 26 | return false; 27 | } 28 | }; 29 | Future ret = p.parse(f); 30 | ByteBufferList l = new ByteBufferList(); 31 | l.add(ByteBuffer.wrap("foo".getBytes(Charsets.US_ASCII.name()))); 32 | f.onDataAvailable(f, l); 33 | f.getEndCallback().onCompleted(null); 34 | String s = ret.get(); 35 | assertEquals(s, "foo"); 36 | } 37 | 38 | public void testUtf8String() throws Exception { 39 | StringParser p = new StringParser(); 40 | FilteredDataEmitter f = new FilteredDataEmitter() { 41 | @Override 42 | public String charset() { 43 | return Charsets.UTF_8.name(); 44 | } 45 | 46 | @Override 47 | public boolean isPaused() { 48 | return false; 49 | } 50 | }; 51 | Future ret = p.parse(f); 52 | ByteBufferList l = new ByteBufferList(); 53 | l.add(ByteBuffer.wrap("æææ".getBytes(Charsets.UTF_8.name()))); 54 | f.onDataAvailable(f, l); 55 | f.getEndCallback().onCompleted(null); 56 | String s = ret.get(); 57 | assertEquals(s, "æææ"); 58 | } 59 | 60 | public void testAsyncParserBase() throws Exception { 61 | DocumentParser parser = new DocumentParser(); 62 | assertEquals(parser.getType(), Document.class); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /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/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/test/src/com/koushikdutta/async/test/SSLTests.java: -------------------------------------------------------------------------------- 1 | package com.koushikdutta.async.test; 2 | 3 | import androidx.test.runner.AndroidJUnit4; 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 | import org.junit.runner.RunWith; 15 | 16 | import java.security.KeyStore; 17 | 18 | import javax.net.ssl.KeyManagerFactory; 19 | import javax.net.ssl.SSLContext; 20 | import javax.net.ssl.TrustManagerFactory; 21 | 22 | import static androidx.test.InstrumentationRegistry.getContext; 23 | 24 | /** 25 | * Created by koush on 6/4/13. 26 | */ 27 | @RunWith(AndroidJUnit4.class) 28 | public class SSLTests { 29 | public void testKeys() throws Exception { 30 | KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); 31 | KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 32 | 33 | ks.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray()); 34 | kmf.init(ks, "storepass".toCharArray()); 35 | 36 | 37 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 38 | KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType()); 39 | ts.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray()); 40 | tmf.init(ts); 41 | 42 | SSLContext sslContext = SSLContext.getInstance("TLS"); 43 | sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 44 | 45 | AsyncHttpServer httpServer = new AsyncHttpServer(); 46 | httpServer.listenSecure(8888, sslContext); 47 | httpServer.get("/", new HttpServerRequestCallback() { 48 | @Override 49 | public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { 50 | response.send("hello"); 51 | } 52 | }); 53 | 54 | Thread.sleep(1000); 55 | 56 | AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setSSLContext(sslContext); 57 | AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setTrustManagers(tmf.getTrustManagers()); 58 | AsyncHttpClient.getDefaultInstance().executeString(new AsyncHttpGet("https://localhost:8888/"), null).get(); 59 | } 60 | 61 | public void disabled__testClientCertificateIssue163() throws Exception { 62 | // https://security.springthroughtest.com/hello.json 63 | 64 | AsyncServer server = new AsyncServer(); 65 | try { 66 | AsyncHttpClient client = new AsyncHttpClient(server); 67 | JSONObject json = client.executeJSONObject(new AsyncHttpGet("https://security.springthroughtest.com/hello.json"), null).get(); 68 | 69 | } 70 | finally { 71 | server.stop(); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /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.Headers; 8 | import com.koushikdutta.async.http.WebSocket; 9 | import com.koushikdutta.async.http.WebSocket.StringCallback; 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 org.junit.Test; 17 | 18 | import java.util.concurrent.Semaphore; 19 | import java.util.concurrent.TimeUnit; 20 | 21 | public class WebSocketTests extends TestCase { 22 | AsyncHttpServer httpServer; 23 | 24 | @Override 25 | protected void setUp() throws Exception { 26 | super.setUp(); 27 | 28 | httpServer = new AsyncHttpServer(); 29 | httpServer.setErrorCallback(new CompletedCallback() { 30 | @Override 31 | public void onCompleted(Exception ex) { 32 | fail(); 33 | } 34 | }); 35 | httpServer.listen(AsyncServer.getDefault(), 5000); 36 | 37 | 38 | httpServer.websocket("/ws", new WebSocketRequestCallback() { 39 | @Override 40 | public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) { 41 | webSocket.setStringCallback(new StringCallback() { 42 | @Override 43 | public void onStringAvailable(String s) { 44 | webSocket.send(s); 45 | } 46 | }); 47 | } 48 | }); 49 | } 50 | 51 | private static final long TIMEOUT = 60000L; 52 | @Test 53 | public void testWebSocket() throws Exception { 54 | final Semaphore semaphore = new Semaphore(0); 55 | 56 | AsyncHttpClient.getDefaultInstance().websocket("http://localhost:5000/ws", (String)null, new WebSocketConnectCallback() { 57 | @Override 58 | public void onCompleted(Exception ex, WebSocket webSocket) { 59 | webSocket.send("hello"); 60 | webSocket.setStringCallback(new StringCallback() { 61 | @Override 62 | public void onStringAvailable(String s) { 63 | assertEquals(s, "hello"); 64 | semaphore.release(); 65 | } 66 | }); 67 | } 68 | }); 69 | 70 | assertTrue(semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)); 71 | } 72 | 73 | // public void testDisconnect() throws Exception { 74 | // final Semaphore semaphore = new Semaphore(0); 75 | // 76 | // AsyncHttpClient.getDefaultInstance().websocket("http://192.168.1.2:3005", null, new WebSocketConnectCallback() { 77 | // @Override 78 | // public void onCompleted(Exception ex, WebSocket webSocket) { 79 | // webSocket.setClosedCallback(new CompletedCallback() { 80 | // @Override 81 | // public void onCompleted(Exception ex) { 82 | // semaphore.release(); 83 | // } 84 | // }); 85 | // } 86 | // }); 87 | // 88 | // assertTrue(semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)); 89 | // } 90 | 91 | @Override 92 | protected void tearDown() throws Exception { 93 | super.tearDown(); 94 | 95 | httpServer.stop(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AndroidAsyncSample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | 12 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AndroidAsyncSample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | dependencies { 4 | compile project(':AndroidAsync') 5 | } 6 | 7 | android { 8 | sourceSets { 9 | main { 10 | manifest.srcFile 'AndroidManifest.xml' 11 | res.srcDirs = ['res/'] 12 | java.srcDirs = ['src/'] 13 | } 14 | } 15 | 16 | defaultConfig { 17 | targetSdkVersion 24 18 | minSdkVersion 9 19 | } 20 | 21 | compileSdkVersion project.hasProperty('global_compileSdkVersion') ? global_compileSdkVersion : 25 22 | buildToolsVersion project.hasProperty('global_buildToolsVersion') ? global_buildToolsVersion : '25.0.2' 23 | } 24 | 25 | -------------------------------------------------------------------------------- /AndroidAsyncSample/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/ic_launcher-web.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-hdpi/ic_action_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-hdpi/ic_action_search.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-mdpi/ic_action_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-mdpi/ic_action_search.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-xhdpi/ic_action_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-xhdpi/ic_action_search.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koush/AndroidAsync/12f9e20443db5c8e79e7e4d43d9e2b3f4230266b/AndroidAsyncSample/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidAsyncSample/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidAsyncSample/res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /AndroidAsyncSample/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |