package sexy.code; import android.os.Build; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; class HttpEngine { private final HttpConfig config; HttpEngine(final HttpConfig config) { this.config = config; } public Response execute(final Request request) throws IOException { final URL httpUrl = request.url().url(); final HttpURLConnection urlConnection = (HttpURLConnection) httpUrl.openConnection(); urlConnection.setRequestMethod(request.method()); urlConnection.setReadTimeout(config.readTimeout); urlConnection.setConnectTimeout(config.connectTimeout); urlConnection.setDoInput(true); final Map<String, String> headers = request.headers(); if (headers != null && !headers.isEmpty()) { addRequestProperties(urlConnection, headers); } if (isOutput(request)) { doOutput(urlConnection, request.body()); } urlConnection.connect(); final int statusCode = urlConnection.getResponseCode(); final String message = urlConnection.getResponseMessage(); final Map<String, List<String>> responseHeaders = urlConnection.getHeaderFields(); final ResponseBody body = doInput(urlConnection); return new Response(request, statusCode, message, responseHeaders, body); } public Executor httpExecutor() { return config.httpExecutor; } public Executor callbackExecutor() { return config.callbackExecutor; } private static void addRequestProperties(final HttpURLConnection urlConnection, final Map<String, String> headers) { for (final Map.Entry<String, String> entry : headers.entrySet()) { final String value = entry.getValue(); if (value != null) { urlConnection.addRequestProperty(entry.getKey(), value); } } } private static boolean isOutput(final Request request) { if (request.body() == null) { return false; } final String method = request.method(); return Request.METHOD_POST.equals(method) || Request.METHOD_PUT.equals(method); } private static void doOutput(final HttpURLConnection urlConnection, final RequestBody body) throws IOException { urlConnection.setDoOutput(true); final String contentType = body.contentType().toString(); if (contentType != null) { urlConnection.addRequestProperty("Content-Type", contentType); } final long contentLength = body.contentLength(); if (contentLength > 0) { setFixedLengthStreamingMode(urlConnection, contentLength); urlConnection.addRequestProperty("Content-Length", Long.toString(contentLength)); } else { urlConnection.setChunkedStreamingMode(0); } BufferedOutputStream os = null; try { os = new BufferedOutputStream(urlConnection.getOutputStream()); body.writeTo(os); } finally { Util.closeQuietly(os); } } private static ResponseBody doInput(final HttpURLConnection urlConnection) throws IOException { final String contentType = urlConnection.getContentType(); final long contentLength = urlConnection.getContentLength(); return new ResponseBody(contentType, contentLength, new BufferedInputStream(getResponseStream(urlConnection)), urlConnection); } private static InputStream getResponseStream(final HttpURLConnection urlConnection) { try { return urlConnection.getInputStream(); } catch (final IOException e) { return urlConnection.getErrorStream(); } } private static void setFixedLengthStreamingMode(final HttpURLConnection urlConnection, final long contentLength) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { urlConnection.setFixedLengthStreamingMode(contentLength); } else { urlConnection.setFixedLengthStreamingMode((int) contentLength); } } }