package be.digitalia.fosdem.utils;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v4.content.LocalBroadcastManager;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
/**
* Utility class to perform HTTP requests.
*
* @author Christophe Beyls
*/
public class HttpUtils {
private static final int DEFAULT_TIMEOUT = 10000;
private static final int BUFFER_SIZE = 8192;
static {
// HTTP connection reuse was buggy pre-froyo
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
// Bypass hostname verification on older devices
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
}
public static class HttpResult {
// Will be null when the local content is up-to-date
public InputStream inputStream;
public String lastModified;
}
public static InputStream get(Context context, String path) throws IOException {
return get(context, new URL(path), null, null, null).inputStream;
}
public static HttpResult get(Context context, String path, String lastModified,
String progressAction, String progressExtra) throws IOException {
return get(context, new URL(path), lastModified, progressAction, progressExtra);
}
public static HttpResult get(final Context context, URL url, String lastModified,
final String progressAction, final String progressExtra) throws IOException {
HttpResult result = new HttpResult();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(DEFAULT_TIMEOUT);
connection.setConnectTimeout(DEFAULT_TIMEOUT);
// We handle gzip manually to avoid EOFException bug in many Android versions when server returns HTTP 304
connection.addRequestProperty("Accept-Encoding", "gzip");
if (lastModified != null) {
connection.addRequestProperty("If-Modified-Since", lastModified);
}
connection.connect();
String contentEncoding = connection.getHeaderField("Content-Encoding");
result.lastModified = connection.getHeaderField("Last-Modified");
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
connection.disconnect();
if ((responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) && (lastModified != null)) {
// Cached result is still valid; return an empty response
return result;
}
throw new IOException("Server returned response code: " + responseCode);
}
final int length = connection.getContentLength();
result.inputStream = connection.getInputStream();
if ((progressAction != null) && (length != -1)) {
// Broadcast the progression in percents, with a precision of 1/10 of the total file size
result.inputStream = new ByteCountInputStream(result.inputStream,
new ByteCountInputStream.ByteCountListener() {
private final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
@Override
public void onNewCount(int byteCount) {
// Cap percent to 100
int percent = (byteCount >= length) ? 100 : byteCount * 100 / length;
lbm.sendBroadcast(new Intent(progressAction).putExtra(progressExtra, percent));
}
}, length / 10);
}
if ("gzip".equals(contentEncoding)) {
result.inputStream = new GZIPInputStream(result.inputStream, BUFFER_SIZE);
} else {
result.inputStream = new BufferedInputStream(result.inputStream, BUFFER_SIZE);
}
return result;
}
}