package com.mopub.common; import android.content.Context; import android.net.http.AndroidHttpClient; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.webkit.WebView; import com.mopub.common.logging.MoPubLog; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.HttpClientParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import static com.mopub.common.util.ResponseHeader.USER_AGENT; public class HttpClient { private static final int CONNECTION_TIMEOUT = 10000; private static final int SOCKET_TIMEOUT = 10000; private static final String DEFAULT_USER_AGENT = System.getProperty("http.agent"); private static String sWebViewUserAgent; public static AndroidHttpClient getHttpClient() { final String userAgent = getWebViewUserAgent(DEFAULT_USER_AGENT); AndroidHttpClient httpClient = AndroidHttpClient.newInstance(userAgent); HttpParams params = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT); HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT); HttpClientParams.setRedirecting(params, true); return httpClient; } public static HttpGet initializeHttpGet(@NonNull final String url) { return initializeHttpGet(url, null); } public static HttpGet initializeHttpGet(@NonNull String url, @Nullable final Context context) { Preconditions.checkNotNull(url); // Try to encode url. If this fails, then fallback on the original url String getUrl; try { getUrl = urlEncode(url); } catch (Exception e) { getUrl = url; } final HttpGet httpGet = new HttpGet(getUrl); if (getWebViewUserAgent() == null && context != null) { // Memoize the user agent since creating WebViews is expensive setWebViewUserAgent(new WebView(context).getSettings().getUserAgentString()); } final String webViewUserAgent = getWebViewUserAgent(); if (webViewUserAgent != null) { httpGet.addHeader(USER_AGENT.getKey(), webViewUserAgent); } return httpGet; } /** * This method constructs a properly encoded and valid URI adhering to legal characters for * each component. See Android docs on these classes for reference. */ public static String urlEncode(@NonNull final String url) throws Exception { Preconditions.checkNotNull(url); // If the URL is improperly encoded, then fail if (isUrlImproperlyEncoded(url)) { throw new UnsupportedEncodingException("URL is improperly encoded: " + url); } // If the url is unencoded, then encode it. Otherwise it is already properly encoded // and leave it as is. URI uri; if (isUrlUnencoded(url)) { uri = encodeUrl(url); } else { uri = new URI(url); } return uri.toURL().toString(); } /** * This method tries to decode the URL and returns false if it can't due to improper encoding. */ static boolean isUrlImproperlyEncoded(@NonNull String url) { try { URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { MoPubLog.w("Url is improperly encoded: " + url); return true; } return false; } /** * This method tries to construct a URI and returns true if it can't due to illegal characters * in the url. */ static boolean isUrlUnencoded(@NonNull String url) { try { new URI(url); } catch (URISyntaxException e) { return true; } return false; } /** * This method encodes each component of the URL into a valid URI. */ static URI encodeUrl(@NonNull String urlString) throws Exception { URI uri; try { URL url = new URL(urlString); uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); } catch (Exception e) { MoPubLog.w("Failed to encode url: " + urlString); throw e; } return uri; } /** * @param defaultUserAgent the String to return if the WebView user agent hasn't been generated. * @return the user agent of an Android WebView, or {@code defaultUserAgent} */ public synchronized static String getWebViewUserAgent(String defaultUserAgent) { if (TextUtils.isEmpty(sWebViewUserAgent)) { return defaultUserAgent; } return sWebViewUserAgent; } /** * @return the user agent of an Android WebView or {@code null} */ public synchronized static String getWebViewUserAgent() { return getWebViewUserAgent(null); } public synchronized static void setWebViewUserAgent(final String userAgent) { sWebViewUserAgent = userAgent; } }