com.baasbox.android.HttpUrlConnectionClient.java Source code

Java tutorial

Introduction

Here is the source code for com.baasbox.android.HttpUrlConnectionClient.java

Source

/*
 * Copyright (C) 2014. BaasBox
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

package com.baasbox.android;

import android.content.Context;
import android.os.Build;
import com.baasbox.android.impl.Logger;
import com.baasbox.android.net.HttpRequest;
import com.baasbox.android.net.RestClient;
import com.squareup.okhttp.internal.http.RetryableSink;

import org.apache.http.*;
import org.apache.http.conn.scheme.HostNameResolver;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;

import okio.Buffer;

/**
 * Created by eto on 23/12/13.
 */
class HttpUrlConnectionClient implements RestClient {
    // ------------------------------ FIELDS ------------------------------

    private static final long HTTP_CACHE_SIZE = 10 * 1024 * 1024;
    private static final HostnameVerifier ACCEPT_ALL = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    private static final TrustManager[] TRUST_MANAGERS = new TrustManager[] { new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    } };

    private BaasBox.Config config;
    private SSLSocketFactory mSSLSocketFactory;
    private HostnameVerifier mHostVerifier;

    // --------------------------- CONSTRUCTORS ---------------------------
    HttpUrlConnectionClient() {
    }

    @Override
    public void init(Context context, BaasBox.Config config) {
        this.config = config;
        if (config.useHttps) {

        }
        disableReuseConnectionIfNecessary(config.useHttps);
        enableHttpCacheIfAvailable(context, HTTP_CACHE_SIZE);
    }

    private static SSLSocketFactory createSocketFactory(Context context, int certStoreId, String certPassword) {
        TrustManagerFactory tmf;
        InputStream in = null;
        try {
            in = context.getResources().openRawResource(certStoreId);
            KeyStore keyStore = KeyStore.getInstance("BKS");
            keyStore.load(in, certPassword.toCharArray());

            tmf = TrustManagerFactory.getInstance("X509");
            tmf.init(keyStore);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);

            return sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new BaasRuntimeException(e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // swallow
                }
            }
        }
    }

    private void disableReuseConnectionIfNecessary(boolean https) {
        if (https || Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
        }
    }

    private void enableHttpCacheIfAvailable(Context context, long cacheSize) {
        File httpCacheDir = new File(context.getCacheDir(), "baashttpcache");
        try {
            Class.forName("android.net.http.HttpResponseCache").getMethod("install", File.class, long.class)
                    .invoke(null, httpCacheDir, cacheSize);
            Logger.debug("Installed http cache");
        } catch (Exception e) {
            Logger.debug("HttpResponseCache not available");
        }
    }

    // ------------------------ INTERFACE METHODS ------------------------

    // --------------------- Interface RestClient ---------------------

    @Override
    public HttpResponse execute(HttpRequest request) throws BaasException {
        try {
            HttpURLConnection connection = openConnection(request.url);

            for (String name : request.headers.keySet()) {
                connection.addRequestProperty(name, request.headers.get(name));
            }
            setupConnectionForRequest(connection, request);
            connection.connect();

            int responseCode = -1;
            try {
                responseCode = connection.getResponseCode();
            } catch (IOException e) {
                responseCode = connection.getResponseCode();
            }
            Logger.info("Connection response received");
            if (responseCode == -1) {
                throw new IOException("Connection failed");
            }
            StatusLine line = new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), responseCode,
                    connection.getResponseMessage());
            BasicHttpResponse response = new BasicHttpResponse(line);
            response.setEntity(asEntity(connection));
            for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
                if (header.getKey() != null) {
                    Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                    response.addHeader(h);
                }
            }
            return response;
        } catch (IOException e) {
            throw new BaasIOException(e);
        }
    }

    // -------------------------- OTHER METHODS --------------------------

    private HttpEntity asEntity(HttpURLConnection connection) {
        BasicHttpEntity entity = new BasicHttpEntity();
        InputStream in;
        try {
            in = connection.getInputStream();
        } catch (IOException e) {
            in = connection.getErrorStream();
        }
        entity.setContent(in);
        entity.setContentLength(connection.getContentLength());
        entity.setContentEncoding(connection.getContentEncoding());
        entity.setContentType(connection.getContentType());
        return entity;
    }

    private HttpURLConnection openConnection(String urlString) throws BaasIOException, IOException {
        URL url = null;
        try {
            url = new URL(urlString);
        } catch (MalformedURLException e) {
            throw new BaasIOException("Error while parsing url " + urlString, e);
        }
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(config.httpConnectionTimeout);
        connection.setReadTimeout(config.httpSocketTimeout);
        connection.setInstanceFollowRedirects(true);
        connection.setDoInput(true);

        return connection;
    }

    private void setupConnectionForRequest(HttpURLConnection connection, HttpRequest request) throws IOException {
        try {
            switch (request.method) {
            case HttpRequest.GET:
                connection.setRequestMethod("GET");
                break;
            case HttpRequest.POST:
                connection.setRequestMethod("POST");
                addBody(request, connection);
                break;
            case HttpRequest.PUT:
                connection.setRequestMethod("PUT");
                addBody(request, connection);
                break;
            case HttpRequest.DELETE:
                connection.setRequestMethod("DELETE");
                addBody(request, connection);
                break;
            case HttpRequest.PATCH:
                connection.setRequestMethod("PATCH");
                addBody(request, connection);
                break;
            }
        } catch (ProtocolException e) {
            throw new Error("Got a protocol exception while setting http method", e);
        }
    }

    private static void addBody(HttpRequest request, HttpURLConnection connection) throws IOException {
        InputStream in = request.body;
        if (in != null) {
            connection.setDoOutput(true);
            copyStream(in, connection.getOutputStream());
        }
    }

    private static void copyStream(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int reads;
        try {
            while ((reads = in.read(buffer)) != -1) {
                out.write(buffer, 0, reads);
            }
            out.flush();
        } finally {
            in.close();
            out.close();
        }
    }
}