Skip to content

Commit

Permalink
Save HttpContext between requests (getodk#2594)
Browse files Browse the repository at this point in the history
  • Loading branch information
lognaturel authored and yanokwa committed Sep 28, 2018
1 parent f992554 commit 540ab48
Showing 1 changed file with 25 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,15 @@ public class HttpClientConnection implements OpenRosaHttpInterface {
private static final int UPLOAD_CONNECTION_TIMEOUT = 60000; // it can take up to 27 seconds to spin up an Aggregate
private static final String HTTP_CONTENT_TYPE_TEXT_XML = "text/xml";

private CredentialsProvider credentialsProvider;
private CookieStore cookieStore;
// Retain authentication and cookies between requests. Gets mutated on each call to
// HttpClient.execute).
private HttpContext httpContext;

public HttpClientConnection() {
credentialsProvider = new AgingCredentialsProvider(7 * 60 * 1000);
cookieStore = new BasicCookieStore();
httpContext = new BasicHttpContext();

httpContext.setAttribute(HttpClientContext.COOKIE_STORE, new BasicCookieStore());
httpContext.setAttribute(HttpClientContext.CREDS_PROVIDER, new AgingCredentialsProvider(7 * 60 * 1000));
}

private enum ContentTypeMapping {
Expand Down Expand Up @@ -149,14 +152,13 @@ public static ContentType of(String fileName) {
public @NonNull
HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullable HttpCredentialsInterface credentials) throws Exception {
addCredentialsForHost(uri, credentials);
getCookieStore().clear();
clearCookieStore();

HttpContext localContext = getHttpContext();
HttpClient httpclient = createHttpClient(CONNECTION_TIMEOUT);

// if https then enable preemptive basic auth...
if (uri.getScheme().equals("https")) {
enablePreemptiveBasicAuth(localContext, uri.getHost());
enablePreemptiveBasicAuth(uri.getHost());
}

// set up request...
Expand All @@ -165,14 +167,14 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl

HttpResponse response;

response = httpclient.execute(req, localContext);
response = httpclient.execute(req, httpContext);
int statusCode = response.getStatusLine().getStatusCode();

if (statusCode != HttpStatus.SC_OK) {
discardEntityBytes(response);
if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
// clear the cookies -- should not be necessary?
getCookieStore().clear();
clearCookieStore();
}
String errMsg =
Collect.getInstance().getString(R.string.file_fetch_failed, uri.toString(),
Expand Down Expand Up @@ -233,16 +235,15 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl
@Override
public @NonNull HttpHeadResult head(@NonNull URI uri, @Nullable HttpCredentialsInterface credentials) throws Exception {
addCredentialsForHost(uri, credentials);
getCookieStore().clear();
clearCookieStore();

HttpContext localContext = getHttpContext();
HttpClient httpclient = createHttpClient(CONNECTION_TIMEOUT);
HttpHead httpHead = createOpenRosaHttpHead(uri);
Map<String, String> responseHeaders = new HashMap<>();

// if https then enable preemptive basic auth...
if (uri.getScheme() != null && uri.getScheme().equals("https")) {
enablePreemptiveBasicAuth(localContext, uri.getHost());
enablePreemptiveBasicAuth(uri.getHost());
}

final HttpResponse response;
Expand All @@ -251,11 +252,10 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl
try {
Timber.i("Issuing HEAD request to: %s", uri.toString());

response = httpclient.execute(httpHead, localContext);
response = httpclient.execute(httpHead, httpContext);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
getCookieStore().clear();

clearCookieStore();
} else if (statusCode == HttpStatus.SC_NO_CONTENT) {
for (Header head : response.getAllHeaders()) {
responseHeaders.put(head.getName(), head.getValue());
Expand Down Expand Up @@ -299,15 +299,13 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl
@NonNull URI uri,
@Nullable HttpCredentialsInterface credentials) throws IOException {
addCredentialsForHost(uri, credentials);
getCookieStore().clear();
clearCookieStore();

// get shared HttpContext so that authentication and cookies are retained.
HttpContext localContext = getHttpContext();
HttpClient httpclient = createHttpClient(UPLOAD_CONNECTION_TIMEOUT);

// if https then enable preemptive basic auth...
if (uri.getScheme().equals("https")) {
enablePreemptiveBasicAuth(localContext, uri.getHost());
enablePreemptiveBasicAuth(uri.getHost());
}

ResponseMessageParser messageParser = null;
Expand Down Expand Up @@ -379,7 +377,7 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl

try {
Timber.i("Issuing POST request to: %s", uri.toString());
response = httpclient.execute(httppost, localContext);
response = httpclient.execute(httppost, httpContext);
int responseCode = response.getStatusLine().getStatusCode();
HttpEntity httpEntity = response.getEntity();
Timber.i("Response code:%d", responseCode);
Expand All @@ -392,7 +390,7 @@ HttpGetResult get(@NonNull URI uri, @Nullable final String contentType, @Nullabl
discardEntityBytes(response);

if (responseCode == HttpStatus.SC_UNAUTHORIZED) {
getCookieStore().clear();
clearCookieStore();
}

if (responseCode != HttpStatus.SC_CREATED && responseCode != HttpStatus.SC_ACCEPTED) {
Expand Down Expand Up @@ -425,18 +423,6 @@ private void addCredentialsForHost(@NonNull URI uri, @Nullable HttpCredentialsIn
}
}

private synchronized HttpContext getHttpContext() {

// context holds authentication state machine, so it cannot be
// shared across independent activities.
HttpContext localContext = new BasicHttpContext();

localContext.setAttribute(HttpClientContext.COOKIE_STORE, getCookieStore());
localContext.setAttribute(HttpClientContext.CREDS_PROVIDER, getCredentialsProvider());

return localContext;
}

/**
* Create an httpClient with connection timeouts and other parameters set.
* Save and reuse the connection manager across invocations (this is what
Expand Down Expand Up @@ -474,14 +460,12 @@ private synchronized HttpClient createHttpClient(int timeout) {

}

private void enablePreemptiveBasicAuth(
HttpContext localContext, String host) {
AuthCache ac = (AuthCache) localContext
.getAttribute(HttpClientContext.AUTH_CACHE);
private void enablePreemptiveBasicAuth(String host) {
AuthCache ac = (AuthCache) httpContext.getAttribute(HttpClientContext.AUTH_CACHE);
HttpHost h = new HttpHost(host);
if (ac == null) {
ac = new BasicAuthCache();
localContext.setAttribute(HttpClientContext.AUTH_CACHE, ac);
httpContext.setAttribute(HttpClientContext.AUTH_CACHE, ac);
}
List<AuthScope> asList = buildAuthScopes(host);
for (AuthScope authScope : asList) {
Expand All @@ -503,12 +487,12 @@ private List<AuthScope> buildAuthScopes(String host) {
return asList;
}

private CookieStore getCookieStore() {
return cookieStore;
private void clearCookieStore() {
((CookieStore) httpContext.getAttribute(HttpClientContext.COOKIE_STORE)).clear();
}

private CredentialsProvider getCredentialsProvider() {
return credentialsProvider;
return (CredentialsProvider) httpContext.getAttribute(HttpClientContext.CREDS_PROVIDER);
}

public void clearHostCredentials(String host) {
Expand Down

0 comments on commit 540ab48

Please sign in to comment.