From 9dfd81423b1868245cc3393bb3fb81423245464e Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 22 Sep 2015 13:39:08 +0200 Subject: [PATCH 1/8] URL typo in changelog, #966 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59efa08fb..09f21beed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ List of closed issues is here [https://github.com/loopj/android-async-http/issue ## 1.4.7 (released 9. 5. 2015) -Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.7](https://github.com/loopj/android-async-http/commits1.4.7) +Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.7](https://github.com/loopj/android-async-http/commits/1.4.7) List of closed issues is here [https://github.com/loopj/android-async-http/issues?milestone=6&state=closed](https://github.com/loopj/android-async-http/issues?milestone=6&state=closed) - Fixed crash when canceling through RequestHandle from UI Thread (NetworkOnMainThreadException) From 1913b2cfdaea2367b5258c0f7d903367f31c3597 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Tue, 22 Sep 2015 15:40:04 -0500 Subject: [PATCH 2/8] Made delete(String, RequestParams, AsyncHttpResponseHandler) return a RequestHandle --- .../src/main/java/com/loopj/android/http/AsyncHttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 8f816adc0..65cac381f 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1414,9 +1414,9 @@ public RequestHandle delete(Context context, String url, Header[] headers, Respo * @param params additional DELETE parameters or files to send with the request. * @param responseHandler the response handler instance that should handle the response. */ - public void delete(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { + public RequestHandle delete(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { final HttpDelete delete = new HttpDelete(getUrlWithQueryString(isUrlEncodingEnabled, url, params)); - sendRequest(httpClient, httpContext, delete, null, responseHandler, null); + return sendRequest(httpClient, httpContext, delete, null, responseHandler, null); } /** From 6256165e7591864d369004f9fe8438a74b4c4c48 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Tue, 22 Sep 2015 15:45:35 -0500 Subject: [PATCH 3/8] Added return to delete(url, params, handler) docs --- .../src/main/java/com/loopj/android/http/AsyncHttpClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 65cac381f..bada27e07 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1413,6 +1413,7 @@ public RequestHandle delete(Context context, String url, Header[] headers, Respo * @param url the URL to send the request to. * @param params additional DELETE parameters or files to send with the request. * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process */ public RequestHandle delete(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { final HttpDelete delete = new HttpDelete(getUrlWithQueryString(isUrlEncodingEnabled, url, params)); From cffb89b13865fe8bfa592ae0567c3a107c169e7e Mon Sep 17 00:00:00 2001 From: Leandro Menezes Date: Fri, 9 Oct 2015 00:42:11 -0300 Subject: [PATCH 4/8] Bearer Authentication Added Bearer Authentication --- .../loopj/android/http/AsyncHttpClient.java | 46 ++++++++++-- .../android/http/BearerAuthSchemeFactory.java | 75 +++++++++++++++++++ .../loopj/android/http/TokenCredentials.java | 28 +++++++ 3 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java create mode 100644 library/src/main/java/com/loopj/android/http/TokenCredentials.java diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index bada27e07..039224e3d 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1,14 +1,13 @@ +package com.loopj.android.http; + /* Android Asynchronous Http Client Copyright (c) 2011 James Smith https://loopj.com - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,9 +15,8 @@ limitations under the License. */ -package com.loopj.android.http; - import android.content.Context; +import android.media.session.MediaSession; import android.os.Looper; import java.io.IOException; @@ -50,6 +48,7 @@ import cz.msebera.android.httpclient.HttpResponse; import cz.msebera.android.httpclient.HttpResponseInterceptor; import cz.msebera.android.httpclient.HttpVersion; +import cz.msebera.android.httpclient.auth.AuthSchemeRegistry; import cz.msebera.android.httpclient.auth.AuthScope; import cz.msebera.android.httpclient.auth.AuthState; import cz.msebera.android.httpclient.auth.Credentials; @@ -76,6 +75,7 @@ import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory; import cz.msebera.android.httpclient.entity.HttpEntityWrapper; import cz.msebera.android.httpclient.impl.auth.BasicScheme; +import cz.msebera.android.httpclient.impl.client.BasicCredentialsProvider; import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; import cz.msebera.android.httpclient.impl.conn.tsccm.ThreadSafeClientConnManager; import cz.msebera.android.httpclient.params.BasicHttpParams; @@ -251,6 +251,11 @@ public void process(HttpResponse response, HttpContext context) { httpClient.addRequestInterceptor(new HttpRequestInterceptor() { @Override public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { + + AuthSchemeRegistry authSchemeRegistry = new AuthSchemeRegistry(); + authSchemeRegistry.register("Bearer", new BearerAuthSchemeFactory()); + context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, authSchemeRegistry); + AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute( ClientContext.CREDS_PROVIDER); @@ -259,7 +264,11 @@ public void process(final HttpRequest request, final HttpContext context) throws if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); - if (creds != null) { + if(creds instanceof TokenCredentials) { + authState.setAuthScheme(new BearerAuthSchemeFactory.BearerAuthScheme()); + authState.setCredentials(creds); + } + else if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } @@ -791,6 +800,29 @@ public void removeHeader(String header) { clientHeaderMap.remove(header); } + /** + * Sets bearer authentication for the request. Uses AuthScope.ANY. This is the same as + * setBearerAuth('token',AuthScope.ANY, false) + * @param token Bearer Token + */ + public void setBearerAuth(String token) { + setBearerAuth(token, AuthScope.ANY, false); + } + + + /** + * Sets bearer authentication for the request. You should pass in your AuthScope for security. It + * should be like this setBearerAuth("token", new AuthScope("host",port,AuthScope.ANY_REALM), false) + * @param token Bearer Token + * @param scope an AuthScope object + * @param preemptive sets authorization in preemptive manner + */ + public void setBearerAuth(String token, AuthScope scope, boolean preemptive) { + TokenCredentials credentials = new TokenCredentials(token); + setCredentials(scope, credentials); + setAuthenticationPreemptive(preemptive); + } + /** * Sets basic authentication for the request. Uses AuthScope.ANY. This is the same as * setBasicAuth('username','password',AuthScope.ANY) @@ -1635,4 +1667,4 @@ public void consumeContent() throws IOException { super.consumeContent(); } } -} +} \ No newline at end of file diff --git a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java new file mode 100644 index 000000000..5db429ebf --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java @@ -0,0 +1,75 @@ +package com.loopj.android.http; + +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpRequest; +import cz.msebera.android.httpclient.auth.AUTH; +import cz.msebera.android.httpclient.auth.AuthScheme; +import cz.msebera.android.httpclient.auth.AuthSchemeFactory; +import cz.msebera.android.httpclient.auth.AuthenticationException; +import cz.msebera.android.httpclient.auth.ContextAwareAuthScheme; +import cz.msebera.android.httpclient.auth.Credentials; +import cz.msebera.android.httpclient.auth.MalformedChallengeException; +import cz.msebera.android.httpclient.message.BufferedHeader; +import cz.msebera.android.httpclient.params.HttpParams; +import cz.msebera.android.httpclient.protocol.HttpContext; +import cz.msebera.android.httpclient.util.CharArrayBuffer; + +/** + * Created by chase on 08/10/2015. + */ +public class BearerAuthSchemeFactory implements AuthSchemeFactory { + + @Override + public AuthScheme newInstance(HttpParams params) { + return new BearerAuthScheme(); + } + + public static class BearerAuthScheme implements ContextAwareAuthScheme { + private boolean complete = false; + + @Override + public void processChallenge(Header header) throws MalformedChallengeException { + this.complete = true; + } + + @Override + public Header authenticate(Credentials credentials, HttpRequest request) throws AuthenticationException { + return authenticate(credentials, request, null); + } + + @Override + public Header authenticate(Credentials credentials, HttpRequest request, HttpContext httpContext) + throws AuthenticationException { + CharArrayBuffer buffer = new CharArrayBuffer(32); + buffer.append(AUTH.WWW_AUTH_RESP); + buffer.append(": Bearer "); + buffer.append(credentials.getUserPrincipal().getName()); + return new BufferedHeader(buffer); + } + + @Override + public String getSchemeName() { + return "Bearer"; + } + + @Override + public String getParameter(String name) { + return null; + } + + @Override + public String getRealm() { + return null; + } + + @Override + public boolean isConnectionBased() { + return false; + } + + @Override + public boolean isComplete() { + return this.complete; + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/loopj/android/http/TokenCredentials.java b/library/src/main/java/com/loopj/android/http/TokenCredentials.java new file mode 100644 index 000000000..10549aa45 --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/TokenCredentials.java @@ -0,0 +1,28 @@ +package com.loopj.android.http; + +/** + * Created by chase on 08/10/2015. + */ +import java.security.Principal; + +import cz.msebera.android.httpclient.auth.BasicUserPrincipal; +import cz.msebera.android.httpclient.auth.Credentials; + +public class TokenCredentials implements Credentials { + private Principal userPrincipal; + + public TokenCredentials(String token) { + this.userPrincipal = new BasicUserPrincipal(token); + } + + @Override + public Principal getUserPrincipal() { + return userPrincipal; + } + + @Override + public String getPassword() { + return null; + } + +} From 2a9b4ef7de68196945920de480880a2b7829ba2a Mon Sep 17 00:00:00 2001 From: Xiaowei Zhao Date: Sun, 8 Nov 2015 23:42:48 +0800 Subject: [PATCH 5/8] Make AsyncHttpResponseHandler.ctor more clear --- .../http/AsyncHttpResponseHandler.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 609cc21a7..20475601f 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -117,13 +117,8 @@ public AsyncHttpResponseHandler() { * @param looper The looper to work with */ public AsyncHttpResponseHandler(Looper looper) { - this.looper = looper == null ? Looper.myLooper() : looper; - - // Use asynchronous mode by default. - setUseSynchronousMode(false); - // Do not use the pool's thread to fire callbacks by default. - setUsePoolThread(false); + this(looper == null ? Looper.myLooper() : looper, false); } /** @@ -133,17 +128,24 @@ public AsyncHttpResponseHandler(Looper looper) { * @param usePoolThread Whether to use the pool's thread to fire callbacks */ public AsyncHttpResponseHandler(boolean usePoolThread) { - // Whether to use the pool's thread to fire callbacks. - setUsePoolThread(usePoolThread); - - // When using the pool's thread, there's no sense in having a looper. - if (!getUsePoolThread()) { - // Use the current thread's looper. - this.looper = Looper.myLooper(); + this(usePoolThread ? null : Looper.myLooper(), usePoolThread); + } - // Use asynchronous mode by default. - setUseSynchronousMode(false); + private AsyncHttpResponseHandler(Looper looper, boolean usePoolThread) { + if (!usePoolThread) { + Utils.asserts(looper != null, "use looper thread, must call Looper.prepare() first!"); + this.looper = looper; + // Create a handler on current thread to submit tasks + this.handler = new ResponderHandler(this, looper); + } else { + Utils.asserts(looper == null, "use pool thread, looper should be null!"); + // If pool thread is to be used, there's no point in keeping a reference + // to the looper and handler. + this.looper = null; + this.handler = null; } + + this.usePoolThread = usePoolThread; } @Override From 4a7ac9db33ae4094584499029cb312eba83ee10f Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 17 Nov 2015 16:49:00 +0100 Subject: [PATCH 6/8] #988 additional changes as of comments in PR --- .../loopj/android/http/AsyncHttpClient.java | 13 ++++++------ .../http/AsyncHttpResponseHandler.java | 2 +- .../android/http/BearerAuthSchemeFactory.java | 20 ++++++++++++++++--- .../loopj/android/http/TokenCredentials.java | 20 ++++++++++++++++--- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 039224e3d..81e89c0f3 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -16,7 +16,6 @@ */ import android.content.Context; -import android.media.session.MediaSession; import android.os.Looper; import java.io.IOException; @@ -75,7 +74,6 @@ import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory; import cz.msebera.android.httpclient.entity.HttpEntityWrapper; import cz.msebera.android.httpclient.impl.auth.BasicScheme; -import cz.msebera.android.httpclient.impl.client.BasicCredentialsProvider; import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; import cz.msebera.android.httpclient.impl.conn.tsccm.ThreadSafeClientConnManager; import cz.msebera.android.httpclient.params.BasicHttpParams; @@ -264,11 +262,10 @@ public void process(final HttpRequest request, final HttpContext context) throws if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); - if(creds instanceof TokenCredentials) { + if (creds instanceof TokenCredentials) { authState.setAuthScheme(new BearerAuthSchemeFactory.BearerAuthScheme()); authState.setCredentials(creds); - } - else if (creds != null) { + } else if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } @@ -803,6 +800,7 @@ public void removeHeader(String header) { /** * Sets bearer authentication for the request. Uses AuthScope.ANY. This is the same as * setBearerAuth('token',AuthScope.ANY, false) + * * @param token Bearer Token */ public void setBearerAuth(String token) { @@ -813,8 +811,9 @@ public void setBearerAuth(String token) { /** * Sets bearer authentication for the request. You should pass in your AuthScope for security. It * should be like this setBearerAuth("token", new AuthScope("host",port,AuthScope.ANY_REALM), false) - * @param token Bearer Token - * @param scope an AuthScope object + * + * @param token Bearer Token + * @param scope an AuthScope object * @param preemptive sets authorization in preemptive manner */ public void setBearerAuth(String token, AuthScope scope, boolean preemptive) { diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 20475601f..88f105a20 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -78,7 +78,7 @@ * }); * */ -@SuppressWarnings("ALL") +@SuppressWarnings("DesignForExtension") public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterface { public static final String DEFAULT_CHARSET = "UTF-8"; diff --git a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java index 5db429ebf..f31065275 100644 --- a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java +++ b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java @@ -1,3 +1,20 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + https://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ package com.loopj.android.http; import cz.msebera.android.httpclient.Header; @@ -14,9 +31,6 @@ import cz.msebera.android.httpclient.protocol.HttpContext; import cz.msebera.android.httpclient.util.CharArrayBuffer; -/** - * Created by chase on 08/10/2015. - */ public class BearerAuthSchemeFactory implements AuthSchemeFactory { @Override diff --git a/library/src/main/java/com/loopj/android/http/TokenCredentials.java b/library/src/main/java/com/loopj/android/http/TokenCredentials.java index 10549aa45..7e8270bbe 100644 --- a/library/src/main/java/com/loopj/android/http/TokenCredentials.java +++ b/library/src/main/java/com/loopj/android/http/TokenCredentials.java @@ -1,8 +1,22 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + https://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ package com.loopj.android.http; -/** - * Created by chase on 08/10/2015. - */ import java.security.Principal; import cz.msebera.android.httpclient.auth.BasicUserPrincipal; From ff9633e3ac00b8aa864570abc640f4bcabf6a5a5 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 17 Nov 2015 17:20:55 +0100 Subject: [PATCH 7/8] Distributing proguard.txt in AAR packages --- library/build.gradle | 1 + library/proguard.txt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 library/proguard.txt diff --git a/library/build.gradle b/library/build.gradle index d463344f6..7a55b32cf 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -7,6 +7,7 @@ android { defaultConfig { minSdkVersion 3 targetSdkVersion 23 + consumerProguardFiles 'proguard.txt' } lintOptions { diff --git a/library/proguard.txt b/library/proguard.txt new file mode 100644 index 000000000..e3ab81252 --- /dev/null +++ b/library/proguard.txt @@ -0,0 +1,2 @@ +-keep class cz.msebera.android.httpclient.** { *; } +-keep class com.loopj.android.http.** { *; } From 9c7b6d41e3b84a5d62dfc914c29536708fc7dcdb Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 17 Nov 2015 17:50:01 +0100 Subject: [PATCH 8/8] Added HTTP OPTIONS call --- .../loopj/android/http/AsyncHttpClient.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 81e89c0f3..6644f5c26 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -58,6 +58,7 @@ import cz.msebera.android.httpclient.client.RedirectHandler; import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase; import cz.msebera.android.httpclient.client.methods.HttpHead; +import cz.msebera.android.httpclient.client.methods.HttpOptions; import cz.msebera.android.httpclient.client.methods.HttpPatch; import cz.msebera.android.httpclient.client.methods.HttpPost; import cz.msebera.android.httpclient.client.methods.HttpPut; @@ -988,6 +989,24 @@ public void cancelRequestsByTAG(Object TAG, boolean mayInterruptIfRunning) { } // [-] HTTP HEAD + // [+] HTTP OPTIONS + + /** + * Perform a HTTP OPTIONS request, without any parameters. + * + * @param url the URL to send the request to. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle options(String url, ResponseHandlerInterface responseHandler) { + return options(null, url, null, responseHandler); + } + + public RequestHandle options(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) { + return sendRequest(httpClient, httpContext, new HttpOptions(getUrlWithQueryString(isUrlEncodingEnabled(), url, params)), null, responseHandler, context); + } + + // [-] HTTP OPTIONS // [+] HTTP GET /**