/* * RapidPro Android Channel - Relay SMS messages where MNO connections aren't practical. * Copyright (C) 2014 Nyaruka, UNICEF * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package io.rapidpro.androidchannel.util; import android.net.http.AndroidHttpClient; import android.os.Build; import io.rapidpro.androidchannel.RapidPro; import io.rapidpro.androidchannel.json.JSON; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import java.io.*; /** * HttpWrapper wraps all http interaction to allow for intelligent * caching and shared client settings. * * All HTTP calls pass through this class, which makes sure that caching is done * intelligently. */ public class Http { private static final int TIMEOUT = 120000; private static final String USER_AGENT = "RapidPro/" + Build.VERSION.RELEASE; private DefaultHttpClient m_client; public Http() { initializeClient(); } private void initializeClient() { m_client = new TrustingHttpClient(RapidPro.get()); HttpParams params = m_client.getParams(); params.setParameter("http.connection-manager.timeout", Integer.valueOf(Http.TIMEOUT)); params.setParameter("http.connection.timeout", Integer.valueOf(Http.TIMEOUT)); params.setParameter("http.socket.timeout", Integer.valueOf(TIMEOUT)); params.setParameter("http.headers.user-agent", USER_AGENT); m_client.setParams(params); HttpConnectionParams.setConnectionTimeout(params, TIMEOUT); HttpConnectionParams.setSoTimeout(params, TIMEOUT); } /** * Converts an InputStream to a byte array * @param is * @return * @throws IOException */ public byte[] readStreamFully(InputStream is) throws IOException { ByteArrayOutputStream buffer = null; try{ buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[16384]; while ((nRead = is.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); byte[] output = buffer.toByteArray(); return output; } finally { // close our streams is.close(); buffer.close(); } } /** * Fetch content from the wire, first checking if there is a cached version available. */ public byte[] fetch(HttpRequestBase request) throws IOException { // add that we accept GZIP compressed content request.setHeader("Accept-Encoding", "gzip"); // dump the request to the console if (RapidPro.SHOW_WIRE) { RapidPro.LOG.d(" " + request.getMethod() + " " + request.getURI()); for (Header header : request.getAllHeaders()) { RapidPro.LOG.d(" > " + header.getName() + ": " + header.getValue()); } } long start = System.currentTimeMillis(); try { HttpResponse response = m_client.execute(request); InputStream inputStream = new BufferedInputStream(AndroidHttpClient.getUngzippedContent(response.getEntity())); byte[] content = readStreamFully(inputStream); if (RapidPro.SHOW_WIRE) { String body = new String(content); RapidPro.LOG.d("\n " + response.getStatusLine().toString()); RapidPro.LOG.d(" Received response with " + content.length + " bytes"); for (Header header : response.getAllHeaders()) { RapidPro.LOG.d(" < " + header.getName() + ": " + header.getValue()); } RapidPro.LOG.d(" " + body); RapidPro.LOG.d("\n"); } return content; } catch (IOException e) { request.abort(); // no cached response? throw our exception throw e; } finally { RapidPro.LOG.d("Fetch took: " + (System.currentTimeMillis() - start)); } } public JSON fetchJSON(String url, String postData) throws IOException { HttpPost post = new HttpPost(url); post.addHeader("Content-Type", "application/json; charset=UTF-8"); post.setEntity(new StringEntity(postData, "UTF-8")); // fetch our response, we use a cache if available return new JSON(new String(fetch(post))); } }