From 754de6bb0449a577d2bb9c28cca6adf0ef9554f6 Mon Sep 17 00:00:00 2001 From: steckbrief Date: Mon, 6 Feb 2017 10:01:13 +0100 Subject: relates FS#241: Implementation of http download based on okhttp --- .../conversationsplus/http/HttpClient.java | 152 ++++++++++++++++++--- 1 file changed, 136 insertions(+), 16 deletions(-) (limited to 'src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java') diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java index 7e12a890..e62be056 100644 --- a/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java +++ b/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java @@ -1,52 +1,101 @@ package de.thedevstack.conversationsplus.http; +import android.support.annotation.NonNull; + import org.apache.http.conn.ssl.StrictHostnameVerifier; +import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.Locale; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; +import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.utils.CryptoHelper; import de.thedevstack.conversationsplus.utils.SSLSocketHelper; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Interceptor; +import okhttp3.MediaType; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; +import okio.ForwardingSource; +import okio.Okio; +import okio.Source; /** - * Created by steckbrief on 22.08.2016. + * */ -public final class HttpClient { +public final class HttpClient implements Http { private static HttpClient INSTANCE; - private boolean interactive = false; - private OkHttpClient client; + private static final String LOGTAG = "http-client"; + + private final OkHttpClient client; - public static void init() { + public static synchronized void init() { INSTANCE = new HttpClient(); } - public static synchronized OkHttpClient getClient(boolean interactive) { - if (INSTANCE.interactive != interactive) { - INSTANCE.interactive = interactive; - INSTANCE.buildClient(); + public static synchronized HttpClient getClient() { + if (null == INSTANCE) { + init(); } - return INSTANCE.client; + return INSTANCE; } - private HttpClient() { - this.buildClient(); + private static OkHttpClient.Builder getBuilder(boolean interactive) { + OkHttpClient.Builder builder = INSTANCE.client.newBuilder(); + INSTANCE.initTrustManager(builder, interactive); + + return builder; + } + + public static synchronized OkHttpClient getOkHttpClient(boolean interactive) { + return getBuilder(interactive).build(); + } + + public static synchronized Call openCancelableAndProgressListenedCall(String url, final ProgressListener progressListener, boolean interactive) { + OkHttpClient.Builder builder = getBuilder(interactive); + OkHttpClient client = builder.addNetworkInterceptor(new Interceptor() { + @Override public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }) + .build(); + + return client.newCall(new Request.Builder().url(url).build()); } - private void buildClient() { + public static void retrieveHead(String url, @NonNull Callback callback) throws IOException { + OkHttpClient client = HttpClient.getOkHttpClient(true); + Request request = new Request.Builder() + .url(url) + //.addHeader(HEADER_NAME_ACCEPT_ENCODING, "") + .head() + .build(); + client.newCall(request).enqueue(callback); + } + + private HttpClient() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); - this.initTrustManager(builder); + builder.addInterceptor(new UserAgentInterceptor()); + builder.addInterceptor(new LoggingInterceptor()); this.client = builder.build(); } - public void initTrustManager(final OkHttpClient.Builder builder) { + private static void initTrustManager(final OkHttpClient.Builder builder, final boolean interactive) { final X509TrustManager trustManager; final HostnameVerifier hostnameVerifier; if (interactive) { @@ -78,4 +127,75 @@ public final class HttpClient { } catch (final KeyManagementException | NoSuchAlgorithmException ignored) { } } + + private static class UserAgentInterceptor implements Interceptor, Http { + + @Override + public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + Request requestWithUserAgent = originalRequest.newBuilder() + .header(USER_AGENT_REQUEST_PROPERTY_NAME, ConversationsPlusApplication.getNameAndVersion()) + .build(); + return chain.proceed(requestWithUserAgent); + } + } + + private static class LoggingInterceptor implements Interceptor { + @Override public Response intercept(Interceptor.Chain chain) throws IOException { + Request request = chain.request(); + + long t1 = System.nanoTime(); + Logging.d(LOGTAG, String.format(Locale.getDefault(), "Sending %s request %s on %s%n%s", + request.method(), request.url(), chain.connection(), request.headers())); + + Response response = chain.proceed(request); + + long t2 = System.nanoTime(); + Logging.d(LOGTAG, String.format(Locale.getDefault(), "Received response for %s request %s in %.1fms%n%s", + response.request().method(), response.request().url(), (t2 - t1) / 1e6d, response.headers())); + + return response; + } + } + + private static class ProgressResponseBody extends ResponseBody { + + private final ResponseBody responseBody; + private final ProgressListener progressListener; + private BufferedSource bufferedSource; + + public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { + this.responseBody = responseBody; + this.progressListener = progressListener; + } + + @Override public MediaType contentType() { + return responseBody.contentType(); + } + + @Override public long contentLength() { + return responseBody.contentLength(); + } + + @Override public BufferedSource source() { + if (bufferedSource == null) { + bufferedSource = Okio.buffer(source(responseBody.source())); + } + return bufferedSource; + } + + private Source source(Source source) { + return new ForwardingSource(source) { + + @Override public long read(Buffer sink, long byteCount) throws IOException { + long bytesRead = super.read(sink, byteCount); + // read() returns the number of bytes read, or -1 if this source is exhausted. + boolean done = bytesRead == -1; + long currentBytesRead = !done ? bytesRead : 0; + progressListener.update(currentBytesRead, responseBody.contentLength(), done); + return bytesRead; + } + }; + } + } } -- cgit v1.2.3