package org.emdev.common.http; import org.ebookdroid.opds.exceptions.OPDSException; import android.annotation.TargetApi; import android.net.http.AndroidHttpClient; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.atomic.AtomicReference; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.emdev.common.log.LogContext; import org.emdev.common.log.LogManager; import org.emdev.utils.LengthUtils; @TargetApi(8) public class BaseHttpClient { private static final LogContext LCTX = LogManager.root().lctx("HTTP"); private final String userAgent; private final AndroidHttpClient client; private final BasicAuthenticator auth; public BaseHttpClient(final String userAgent) { this.userAgent = userAgent; this.client = AndroidHttpClient.newInstance(userAgent); this.auth = new BasicAuthenticator(); } @Override protected void finalize() { close(); } public void close() { client.close(); } public void setAuthorization(final String host, final String username, final String password) { auth.setAuthorization(host, username, password); } protected HttpGet createRequest(final URI uri, final Header... headers) { final HttpGet req = new HttpGet(uri); final String host = uri.getHost(); req.setHeader("Host", host); req.setHeader("User-Agent", userAgent); if (LengthUtils.isNotEmpty(headers)) { for (final Header h : headers) { req.setHeader(h); } } return req; } protected HttpResponse connect(final AtomicReference<URI> uriRef, final Header... headers) throws IOException, URISyntaxException, OPDSException { URI uri = uriRef.get(); HttpGet req = createRequest(uri, headers); onPreAuthentication(req); LCTX.d(Thread.currentThread().getName() + ": Connecting to: " + req.getURI()); HttpResponse resp = client.execute(req); StatusLine statusLine = resp.getStatusLine(); int statusCode = statusLine.getStatusCode(); LCTX.d(Thread.currentThread().getName() + ": Status: " + statusLine); int redirectCount = 5; while (redirectCount > 0 && (statusCode == 401 || statusCode == 301 || statusCode == 302)) { if (statusCode == 401) { final HostCredentials creds = onAuthorizationAsked(req, resp); req = createRequest(uri, headers); req.setHeader(creds.basicAuthorization()); } else { redirectCount--; final String location = getHeaderValue(resp, "Location"); if (LengthUtils.isEmpty(location)) { break; } uri = uri.resolve(new URI(location)); uriRef.set(uri); LCTX.d(Thread.currentThread().getName() + ": Location: " + uri); req = createRequest(uri, headers); onPreAuthentication(req); } LCTX.d(Thread.currentThread().getName() + ": Connecting to: " + req.getURI()); resp = client.execute(req); statusLine = resp.getStatusLine(); statusCode = statusLine.getStatusCode(); LCTX.d(Thread.currentThread().getName() + ": Status: " + statusLine); } return resp; } public void onPreAuthentication(final HttpGet req) { final HostCredentials cred = auth.onPreAuthorization(req); if (cred != null) { req.setHeader(cred.basicAuthorization()); } } protected HostCredentials onAuthorizationAsked(final HttpGet req, final HttpResponse resp) throws OPDSException { String method = "Basic"; final Header authHeader = resp.getFirstHeader("WWW-Authenticate"); if (authHeader != null) { method = LengthUtils.safeString(authHeader.getValue(), method).split(" ")[0]; } if (!"Basic".equalsIgnoreCase(method)) { throw new OPDSException("Required authorization method not supported: " + method); } return auth.onAuthorizationAsked(req); } protected static String getHeaderValue(final HttpResponse resp, final String name) { final Header header = resp.getFirstHeader(name); return header != null ? header.getValue() : ""; } protected static String getHeaderValue(final Header header) { return header != null ? header.getValue() : ""; } }