I'm using "com.loopj.android:android-async-http:1.4.5" in my Android app. The setup is that there is one instance of the below HttpDataSource class per API endpoint (eg: http://myhost.com/some/service/{pathParam}); thus there are multiple instances of AsyncHttpClient (and in turn Apache HttpClient); which might be causing my problems.
import java.io.IOException;
import java.net.URI;
import android.util.Log;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
public class HttpDataSource {
private final AsyncHttpClient asyncHttpClient;
public HttpDataSource() {
asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.setUserAgent(UserAgentFactory.createUserAgent());
asyncHttpClient.setEnableRedirects(true);
addRedirectListener();
}
protected void get(final String url, final RequestParams requestParams, final HttpResponseHandler responseHandler) {
// Method not important; constructs headers for conditional GETs
final Header[] headers = checkForMetaData(url);
asyncHttpClient.get(null, url, headers, requestParams, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(final int statusCode, final Header[] headers, final byte[] responseBody) {
// we do some work then pass on to the responseHandler
responseHandler.onSuccess(statusCode, headers, responseBody);
}
@Override
public void onFailure(final int statusCode, final Header[] headers, final byte[] responseBody,
final Throwable error) {
// we do some work then pass on to the responseHandler
responseHandler.onFailure(statusCode, headers, responseBody, error);
}
});
}
private void addRedirectListener() {
getHttpClient().addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(final HttpResponse httpResponse, final HttpContext httpContext)
throws HttpException, IOException {
if (httpResponse.getStatusLine().getStatusCode() == 302) {
final URI reqUri = ((HttpUriRequest) httpContext.getAttribute(ExecutionContext.HTTP_REQUEST)).getURI();
final HttpHost currentHost = (HttpHost) httpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
final String url = (reqUri.isAbsolute()) ? reqUri.toString() : (currentHost.toURI() + reqUri.getPath());
Log.e("HttpDataSource", "Got 302 for '" + url + "'");
}
}
});
}
private DefaultHttpClient getHttpClient() {
return ((DefaultHttpClient) asyncHttpClient.getHttpClient());
}
}
When I make concurrent GETs to different URLs (eg: http://myhost.com/some/service/bar, http://myhost.com/some/service/foo) the redirect listener fires twice, but with the same HttpContext object, which is wrong I think. The logs are:
HttpDataSource﹕ Got 302 for 'http://myhost.com/some/service/foo'
HttpDataSource﹕ Got 302 for 'http://myhost.com/some/service/foo'
I suspect that the issue is with the Apache HttpClient, not Loop4J's AsyncHttpClient as the AsyncHttpClient has an instance of HttpClient which you would hope would be "instance safe".
How can I get the correct HttpContext object for a URL that returns a 302 when concurrent requests are being fired?