From 70b9f2a6ef24bf69016b54e1717caa1f1777a8ac Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Mon, 23 Dec 2013 11:09:25 -0800 Subject: [PATCH] Bug 952799 - GeckoAppShell.getProxyForURI can be expensive during a pageload. r=mfinkle --- mobile/android/base/GeckoAppShell.java | 112 +++++++++++++++++-------- 1 file changed, 79 insertions(+), 33 deletions(-) diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 1fd6091e32a..c63d14f9b20 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -68,6 +68,7 @@ import android.os.MessageQueue; import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; +import android.support.v4.util.LruCache; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; @@ -2662,44 +2663,89 @@ public class GeckoAppShell return false; } + // Holds mappings from hostnames to URIs. + // We only use this for HTTP and HTTPS on default ports (-1), because it's + // simpler to do so while addressing most uses. + private static LruCache httpURIs = new LruCache(10); + private static LruCache httpsURIs = new LruCache(10); + + private static URI getAndCacheURIByParts(String scheme, String host, LruCache cache) { + URI uri = cache.get(host); + if (uri != null) { + return uri; + } + + try { + uri = new URI(scheme, null, host, -1, null, null, null); + } catch (java.net.URISyntaxException uriEx) { + Log.d("GeckoProxy", "Failed to create URI from parts.", uriEx); + return null; + } + + cache.put(host, uri); + return uri; + } + + private static URI getURIByParts(String scheme, String host, int port) { + if (port == -1) { + if (scheme.equals("http")) { + return getAndCacheURIByParts("http", host, httpURIs); + } else if (scheme.equals("https")) { + return getAndCacheURIByParts("https", host, httpsURIs); + } + } + + try { + return new URI(scheme, null, host, port, null, null, null); + } catch (java.net.URISyntaxException uriEx) { + Log.d("GeckoProxy", "Failed to create URI from parts.", uriEx); + } + + return null; + } + @WrapElementForJNI(stubName = "GetProxyForURIWrapper") public static String getProxyForURI(String spec, String scheme, String host, int port) { - URI uri = null; + final ProxySelector ps; try { - uri = new URI(spec); - } catch(java.net.URISyntaxException uriEx) { - try { - uri = new URI(scheme, null, host, port, null, null, null); - } catch(java.net.URISyntaxException uriEx2) { - Log.d("GeckoProxy", "Failed to create uri from spec", uriEx); - Log.d("GeckoProxy", "Failed to create uri from parts", uriEx2); - } + // This is cheap -- just a SecurityManager check and a static + // access inside ProxySelector. + ps = ProxySelector.getDefault(); + } catch (SecurityException ex) { + Log.w(LOGTAG, "Not allowed to use default ProxySelector."); + return "DIRECT"; } - if (uri != null) { - ProxySelector ps = ProxySelector.getDefault(); - if (ps != null) { - List proxies = ps.select(uri); - if (proxies != null && !proxies.isEmpty()) { - Proxy proxy = proxies.get(0); - if (!Proxy.NO_PROXY.equals(proxy)) { - final String proxyStr; - switch (proxy.type()) { - case HTTP: - proxyStr = "PROXY " + proxy.address().toString(); - break; - case SOCKS: - proxyStr = "SOCKS " + proxy.address().toString(); - break; - case DIRECT: - default: - proxyStr = "DIRECT"; - break; - } - return proxyStr; - } - } - } + + if (ps == null) { + return "DIRECT"; } + + // We don't use the whole spec because parsing a URI from a string + // is expensive, and the stock Android proxy behavior looks only at + // the scheme and host. + URI uri = getURIByParts(scheme, host, port); + + if (uri == null) { + return "DIRECT"; + } + + List proxies = ps.select(uri); + if (proxies == null || proxies.isEmpty()) { + return "DIRECT"; + } + + Proxy proxy = proxies.get(0); + if (Proxy.NO_PROXY.equals(proxy)) { + return "DIRECT"; + } + + switch (proxy.type()) { + case HTTP: + return "PROXY " + proxy.address().toString(); + case SOCKS: + return "SOCKS " + proxy.address().toString(); + } + return "DIRECT"; } }