/*************************************************************************** * Copyright 2005-2009 Last.fm Ltd. * * Portions contributed by Casey Link, Lukasz Wisniewski, * * Mike Jennings, and Michael Novak Jr. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ package fm.last.util; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.cert.CertificateException; import java.util.HashMap; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import com.google.android.apps.analytics.GoogleAnalyticsTracker; /** * A collection of utility methods to manipulate URLs. * * @author Mike Jennings */ public class UrlUtil { private static final int REDIRECT_RESPONSE_CODE = 302; private UrlUtil() { } public static String useragent; // always verify the host - dont check for certificate final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; /** * Trust every server - dont check for any certificate */ private static void trustAllHosts() { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[] {}; } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection .setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } /** mainly sets the User-Agent we need */ private static void setUserAgent(HttpURLConnection conn) { if (useragent != null) conn.setRequestProperty("User-Agent", useragent); } public static URL getRedirectedUrl(URL url) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestMethod("GET"); conn.setInstanceFollowRedirects(false); conn.setRequestProperty("connection", "close"); int rc = conn.getResponseCode(); if (rc != REDIRECT_RESPONSE_CODE) { throw new IOException("code " + rc + " '" + conn.getResponseMessage() + "'"); } String location = conn.getHeaderField("Location"); if (location == null) { throw new IOException("No 'Location' header found"); } return new URL(location); } private static void copy(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[512]; int bytesRead = 1; while (bytesRead > 0) { bytesRead = in.read(buf); if (bytesRead > 0) { out.write(buf, 0, bytesRead); } } } private static int copy(InputStream in, OutputStream out, int maxBytes) throws IOException { byte[] buf = new byte[512]; int bytesRead = 1; int totalBytes = 0; while (bytesRead > 0) { bytesRead = in.read(buf, 0, Math.min(512, maxBytes - totalBytes)); if (bytesRead > 0) { out.write(buf, 0, bytesRead); totalBytes += bytesRead; } } return totalBytes; } public static String doFormPost(URL url, String input) throws IOException { return doPost(url, new ByteArrayInputStream(input.getBytes()), "application/x-www-urlencoded"); } public static String doPost(URL url, String input) throws IOException { return doPost(url, new ByteArrayInputStream(input.getBytes())); } public static String doPost(URL url, InputStream stuffToPost) throws IOException { return doPost(url, stuffToPost, null); } public static String doPost(URL url, InputStream stuffToPost, String contentType) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("connection", "close"); if (contentType != null) { conn.setRequestProperty("Content-Type", contentType); } OutputStream ostr = null; try { ostr = conn.getOutputStream(); copy(stuffToPost, ostr); } finally { if (ostr != null) ostr.close(); } BufferedReader reader = null; String response = ""; conn.connect(); try { if(conn.getInputStream() != null) reader = new BufferedReader(new InputStreamReader(conn.getInputStream()), 512); } catch (IOException e) { if(conn.getErrorStream() != null) reader = new BufferedReader(new InputStreamReader(conn.getErrorStream()), 512); } if(reader != null) { response = toString(reader); reader.close(); } // Dispatch any queued Analytics data while we've got the network // open try { GoogleAnalyticsTracker tracker = GoogleAnalyticsTracker.getInstance(); if(tracker != null) tracker.dispatch(); } catch (Exception e1) { //ignore any exceptions thrown by analytics } return response; } public static String doGet(URL url) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestMethod("GET"); conn.setRequestProperty("connection", "close"); BufferedReader reader = null; String response = ""; conn.connect(); try { if(conn.getInputStream() != null) reader = new BufferedReader(new InputStreamReader(conn.getInputStream()), 512); } catch (IOException e) { if(conn.getErrorStream() != null) reader = new BufferedReader(new InputStreamReader(conn.getErrorStream()), 512); } if(reader != null) { response = toString(reader); reader.close(); } return response; } /** * Do a GET request and retrieve up to maxBytes bytes * * @param url * @param maxBytes * @return * @throws IOException */ public static byte[] doGetAndReturnBytes(URL url, int maxBytes) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestMethod("GET"); conn.setRequestProperty("connection", "close"); InputStream istr = null; try { int rc = conn.getResponseCode(); if (rc != 200) { throw new IOException("code " + rc + " '" + conn.getResponseMessage() + "'"); } istr = new BufferedInputStream(conn.getInputStream(), 512); ByteArrayOutputStream baos = new ByteArrayOutputStream(); copy(istr, baos, maxBytes); return baos.toByteArray(); } finally { if (istr != null) { istr.close(); } } } private static String buildUrl(String baseurl, Map<String, String> params) throws IOException { if (params.isEmpty()) { return baseurl; } else { return baseurl + "?" + buildQuery(params); } } public static String buildQuery(Map<String, String> params) { StringBuilder sb = null; for (String key : params.keySet()) { String value = params.get(key); if (sb == null) { sb = new StringBuilder(); sb.append(escape(key)).append('=').append(escape(value)); } else { sb.append("&").append(escape(key)).append('=').append(escape(value)); } } return sb.toString(); } public static String doGet(String baseurl, Map<String, String> params) throws IOException { return doGet(new URL(buildUrl(baseurl, params))); } public static String doPost(String baseurl, Map<String, String> params) throws IOException { return doPost(new URL(baseurl), buildQuery(params)); } private static String escape(String s) { try { return URLEncoder.encode(s, "UTF-8"); } catch (UnsupportedEncodingException e) { Log.e("UrlUtil", "Cannot find UTF-8 encoding - this is not very likely!"); return s; } } public static String getXML(URL url) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestProperty("connection", "close"); conn.setRequestMethod("GET"); BufferedReader reader = null; String output = null; try { reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); output = toString(reader); } finally { if (reader != null) { reader.close(); } } // Dispatch any queued Analytics data while we've got the network // open try { GoogleAnalyticsTracker tracker = GoogleAnalyticsTracker.getInstance(); if(tracker != null) tracker.dispatch(); } catch (Exception e1) { //ignore any exceptions thrown by analytics } return output; } public static Bitmap getImage(URL url) throws IOException { HttpURLConnection conn = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); conn = https; } else { conn = (HttpURLConnection) url.openConnection(); } setUserAgent(conn); conn.setRequestProperty("connection", "close"); conn.setRequestMethod("GET"); return BitmapFactory.decodeStream(conn.getInputStream()); } private static String toString(BufferedReader reader) throws IOException { StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line).append('\n'); } return sb.toString(); } @SuppressWarnings("unused") private static String readString(BufferedReader reader) throws IOException { String line; StringBuilder sb = new StringBuilder(); while ((line = reader.readLine()) != null) { sb.append(line); } return sb.toString(); } @SuppressWarnings("unused") private static Map<String, String> getParams(BufferedReader reader) throws IOException { Map<String, String> params = new HashMap<String, String>(); String line; int eq; while ((line = reader.readLine()) != null) { eq = line.indexOf('='); if (eq > 0) { String key = line.substring(0, eq); String value = line.substring(eq + 1); params.put(key, value); } } return params; } }