bug 749352 - Firefox fails to connect when a proxy is used r=mfinkle,mossop
authorBrad Lassey <blassey@mozilla.com>
Tue, 13 Nov 2012 11:25:18 -0800
changeset 113154 2fd71029eaa2e5a402b22d3f7d8169594c5dd644
parent 113153 ff8ce0a158677b4e52aff6929d64741d2585bffd
child 113155 6f434302bff32b1fb1bd7bb6d6e91e1d1749a3e8
push id23859
push useremorley@mozilla.com
push dateWed, 14 Nov 2012 14:36:31 +0000
treeherdermozilla-central@87928cd21b40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle, mossop
bugs749352
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 749352 - Firefox fails to connect when a proxy is used r=mfinkle,mossop
mobile/android/base/GeckoAppShell.java
toolkit/Makefile.in
toolkit/library/Makefile.in
toolkit/library/nsStaticXULComponents.cpp
toolkit/system/androidproxy/Makefile.in
toolkit/system/androidproxy/nsAndroidSystemProxySettings.cpp
toolkit/toolkit-makefiles.sh
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -92,16 +92,19 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.SynchronousQueue;
+import java.net.ProxySelector;
+import java.net.Proxy;
+import java.net.URI;
 
 public class GeckoAppShell
 {
     private static final String LOGTAG = "GeckoAppShell";
 
     // static members only
     private GeckoAppShell() { }
 
@@ -2228,9 +2231,49 @@ public class GeckoAppShell
         GeckoProfile profile = GeckoApp.mAppContext.getProfile();
         File lock = profile.getFile(".parentlock");
         if (lock.exists()) {
             lock.delete();
             return true;
         }
         return false;
     }
+
+    public static String getProxyForURI(String spec, String scheme, String host, int port) {
+        URI uri = null;
+        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);
+            }
+        }
+        if (uri != null) {
+            ProxySelector ps = ProxySelector.getDefault();
+            if (ps != null) {
+                List<Proxy> 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;
+                    }
+                }
+            }
+        }
+        return "DIRECT";
+    }
 }
--- a/toolkit/Makefile.in
+++ b/toolkit/Makefile.in
@@ -46,16 +46,20 @@ endif
 ifneq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
 PARALLEL_DIRS += system/osxproxy
 endif
 
 ifneq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
 PARALLEL_DIRS += system/windowsproxy
 endif
 
+ifneq (,$(filter android,$(MOZ_WIDGET_TOOLKIT)))
+PARALLEL_DIRS += system/androidproxy
+endif
+
 ifdef MOZ_CRASHREPORTER
 PARALLEL_DIRS += crashreporter
 endif
 
 DIRS += \
   xre \
   $(NULL)
 
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -210,16 +210,22 @@ endif
 endif
 
 ifneq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
 COMPONENT_LIBS += \
   windowsproxy \
   $(NULL)
 endif
 
+ifneq (,$(filter android,$(MOZ_WIDGET_TOOLKIT)))
+COMPONENT_LIBS += \
+  androidproxy \
+  $(NULL)
+endif
+
 ifdef MOZ_JSDEBUGGER
 DEFINES += -DMOZ_JSDEBUGGER
 COMPONENT_LIBS += \
   jsd \
   $(NULL)
 endif
 
 ifdef MOZ_PREF_EXTENSIONS
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -138,16 +138,22 @@
 #endif
 
 #if defined(XP_WIN)
 #define WINDOWSPROXY_MODULE MODULE(nsWindowsProxyModule)
 #else
 #define WINDOWSPROXY_MODULE
 #endif
 
+#if defined(MOZ_WIDGET_ANDROID)
+#define ANDROIDPROXY_MODULE MODULE(nsAndroidProxyModule)
+#else
+#define ANDROIDPROXY_MODULE
+#endif
+
 #if defined(BUILD_CTYPES)
 #define JSCTYPES_MODULE MODULE(jsctypes)
 #else
 #define JSCTYPES_MODULE
 #endif
 
 #ifndef MOZ_APP_COMPONENT_MODULES
 #if defined(MOZ_APP_COMPONENT_INCLUDE)
@@ -219,16 +225,17 @@
     MODULE(BOOT)                             \
     MODULE(NSS)                              \
     SYSTEMPREF_MODULES                       \
     SPELLCHECK_MODULE                        \
     LAYOUT_DEBUG_MODULE                      \
     UNIXPROXY_MODULE                         \
     OSXPROXY_MODULE                          \
     WINDOWSPROXY_MODULE                      \
+    ANDROIDPROXY_MODULE                      \
     JSCTYPES_MODULE                          \
     MODULE(jsreflect)                        \
     MODULE(jsperf)                           \
     MODULE(identity)                         \
     MODULE(nsServicesCryptoModule)           \
     MOZ_APP_COMPONENT_MODULES                \
     MODULE(nsTelemetryModule)                \
     MODULE(jsinspector)                      \
copy from toolkit/system/windowsproxy/Makefile.in
copy to toolkit/system/androidproxy/Makefile.in
--- a/toolkit/system/windowsproxy/Makefile.in
+++ b/toolkit/system/androidproxy/Makefile.in
@@ -4,23 +4,23 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-MODULE          = windowsproxy
-LIBRARY_NAME    = windowsproxy
+MODULE          = androidproxy
+LIBRARY_NAME    = androidproxy
 
 EXPORT_LIBRARY  = 1
 IS_COMPONENT    = 1
-MODULE_NAME     = nsWindowsProxyModule
+MODULE_NAME     = nsAndroidProxyModule
 GRE_MODULE      = 1
 LIBXUL_LIBRARY  = 1
 
 
 CPPSRCS = \
-        nsWindowsSystemProxySettings.cpp \
+        nsAndroidSystemProxySettings.cpp \
         $(NULL)
 
 include $(topsrcdir)/config/rules.mk
copy from toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp
copy to toolkit/system/androidproxy/nsAndroidSystemProxySettings.cpp
--- a/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp
+++ b/toolkit/system/androidproxy/nsAndroidSystemProxySettings.cpp
@@ -1,312 +1,91 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include <windows.h>
-#include <ras.h>
-#include <wininet.h>
+#include "nsNetUtil.h"
+#include "nsIURI.h"
 
 #include "mozilla/Util.h"
 #include "nsISystemProxySettings.h"
 #include "nsIServiceManager.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsPrintfCString.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIURI.h"
 
-class nsWindowsSystemProxySettings : public nsISystemProxySettings
+#include "AndroidBridge.h"
+
+class nsAndroidSystemProxySettings : public nsISystemProxySettings
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISYSTEMPROXYSETTINGS
 
-    nsWindowsSystemProxySettings() {};
+    nsAndroidSystemProxySettings() {};
     nsresult Init();
 
 private:
-    ~nsWindowsSystemProxySettings() {};
-
-    bool MatchOverride(const nsACString& aHost);
-    bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
+    ~nsAndroidSystemProxySettings() {};
 };
 
-NS_IMPL_THREADSAFE_ISUPPORTS1(nsWindowsSystemProxySettings, nsISystemProxySettings)
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsAndroidSystemProxySettings, nsISystemProxySettings)
 
 NS_IMETHODIMP
-nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
+nsAndroidSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
 {
-  *aMainThreadOnly = false;
+  *aMainThreadOnly = true;
   return NS_OK;
 }
 
 
 nsresult
-nsWindowsSystemProxySettings::Init()
+nsAndroidSystemProxySettings::Init()
 {
     return NS_OK;
 }
 
-static void SetProxyResult(const char* aType, const nsACString& aHostPort,
-                           nsACString& aResult)
-{
-    aResult.AssignASCII(aType);
-    aResult.Append(' ');
-    aResult.Append(aHostPort);
-}
-
-static void SetProxyResultDirect(nsACString& aResult)
-{
-    // For whatever reason, a proxy is not to be used.
-    aResult.AssignASCII("DIRECT");
-}
-
-static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
-                                   nsAString& aValue)
+nsresult
+nsAndroidSystemProxySettings::GetPACURI(nsACString& aResult)
 {
-    DWORD connFlags = 0;
-    WCHAR connName[RAS_MaxEntryName + 1];
-    InternetGetConnectedStateExW(&connFlags, connName,
-                                 mozilla::ArrayLength(connName), 0);
-
-    INTERNET_PER_CONN_OPTIONW options[2];
-    options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI;
-    options[1].dwOption = aOption;
-
-    INTERNET_PER_CONN_OPTION_LISTW list;
-    list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
-    list.pszConnection = connFlags & INTERNET_CONNECTION_MODEM ?
-                         connName : NULL;
-    list.dwOptionCount = mozilla::ArrayLength(options);
-    list.dwOptionError = 0;
-    list.pOptions = options;
-
-    unsigned long size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
-    if (!InternetQueryOptionW(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION,
-                              &list, &size)) {
-        if (GetLastError() != ERROR_INVALID_PARAMETER) {
-            return NS_ERROR_FAILURE;
-        }
-        options[0].dwOption = INTERNET_PER_CONN_FLAGS;
-        size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
-        if (!InternetQueryOptionW(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION,
-                                  &list, &size)) {
-            return NS_ERROR_FAILURE;
-        }
-    }
-
-    aFlags = options[0].Value.dwValue;
-    aValue.Assign(options[1].Value.pszValue);
-    GlobalFree(options[1].Value.pszValue);
-
     return NS_OK;
 }
 
-bool
-nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost)
-{
-    nsresult rv;
-    uint32_t flags = 0;
-    nsAutoString buf;
-
-    rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf);
-    if (NS_FAILED(rv))
-        return false;
-
-    NS_ConvertUTF16toUTF8 cbuf(buf);
-
-    nsAutoCString host(aHost);
-    int32_t start = 0;
-    int32_t end = cbuf.Length();
-
-    // Windows formats its proxy override list in the form:
-    // server;server;server where 'server' is a server name pattern or IP
-    // address, or "<local>". "<local>" must be translated to
-    // "localhost;127.0.0.1".
-    // In a server name pattern, a '*' character matches any substring and
-    // all other characters must match themselves; the whole pattern must match
-    // the whole hostname.
-    while (true) {
-        int32_t delimiter = cbuf.FindCharInSet(" ;", start);
-        if (delimiter == -1)
-            delimiter = end;
-
-        if (delimiter != start) {
-            const nsAutoCString override(Substring(cbuf, start,
-                                                   delimiter - start));
-            if (override.EqualsLiteral("<local>")) {
-                // This override matches local addresses.
-                if (host.EqualsLiteral("localhost") ||
-                    host.EqualsLiteral("127.0.0.1"))
-                    return true;
-            } else if (PatternMatch(host, override)) {
-                return true;
-            }
-        }
-
-        if (delimiter == end)
-            break;
-        start = ++delimiter;
-    }
-
-    return false;
-}
-
-bool
-nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost,
-                                           const nsACString& aOverride)
-{
-    nsAutoCString host(aHost);
-    nsAutoCString override(aOverride);
-    int32_t overrideLength = override.Length();
-    int32_t tokenStart = 0;
-    int32_t offset = 0;
-    bool star = false;
-
-    while (tokenStart < overrideLength) {
-        int32_t tokenEnd = override.FindChar('*', tokenStart);
-        if (tokenEnd == tokenStart) {
-            star = true;
-            tokenStart++;
-            // If the character following the '*' is a '.' character then skip
-            // it so that "*.foo.com" allows "foo.com".
-            if (override.FindChar('.', tokenStart) == tokenStart)
-                tokenStart++;
-        } else {
-            if (tokenEnd == -1)
-                tokenEnd = overrideLength;
-            nsAutoCString token(Substring(override, tokenStart,
-                                          tokenEnd - tokenStart));
-            offset = host.Find(token, offset);
-            if (offset == -1 || (!star && offset))
-                return false;
-            star = false;
-            tokenStart = tokenEnd;
-            offset += token.Length();
-        }
-    }
-
-    return (star || (offset == host.Length()));
-}
-
 nsresult
-nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult)
-{
-    nsresult rv;
-    uint32_t flags = 0;
-    nsAutoString buf;
-
-    rv = ReadInternetOption(INTERNET_PER_CONN_AUTOCONFIG_URL, flags, buf);
-    if (!(flags & PROXY_TYPE_AUTO_PROXY_URL)) {
-        aResult.Truncate();
-        return rv;
-    }
-
-    if (NS_SUCCEEDED(rv))
-        aResult = NS_ConvertUTF16toUTF8(buf);
-    return rv;
-}
-
-nsresult
-nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
+nsAndroidSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
                                              const nsACString & aScheme,
                                              const nsACString & aHost,
                                              const int32_t      aPort,
                                              nsACString & aResult)
 {
-    nsresult rv;
-    uint32_t flags = 0;
-    nsAutoString buf;
-
-    rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf);
-    if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) {
-        SetProxyResultDirect(aResult);
-        return NS_OK;
-    }
-
-    if (MatchOverride(aHost)) {
-        SetProxyResultDirect(aResult);
-        return NS_OK;
-    }
-
-    NS_ConvertUTF16toUTF8 cbuf(buf);
-
-    nsAutoCString prefix;
-    ToLowerCase(aScheme, prefix);
-
-    prefix.Append('=');
-
-    nsAutoCString specificProxy;
-    nsAutoCString defaultProxy;
-    nsAutoCString socksProxy;
-    int32_t start = 0;
-    int32_t end = cbuf.Length();
-
-    while (true) {
-        int32_t delimiter = cbuf.FindCharInSet(" ;", start);
-        if (delimiter == -1)
-            delimiter = end;
-
-        if (delimiter != start) {
-            const nsAutoCString proxy(Substring(cbuf, start,
-                                                delimiter - start));
-            if (proxy.FindChar('=') == -1) {
-                // If a proxy name is listed by itself, it is used as the
-                // default proxy for any protocols that do not have a specific
-                // proxy specified.
-                // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
-                defaultProxy = proxy;
-            } else if (proxy.Find(prefix) == 0) {
-                // To list a proxy for a specific protocol, the string must
-                // follow the format "<protocol>=<protocol>://<proxy_name>".
-                // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
-                specificProxy = Substring(proxy, prefix.Length());
-                break;
-            } else if (proxy.Find("socks=") == 0) {
-                // SOCKS proxy.
-                socksProxy = Substring(proxy, 5); // "socks=" length.
-            }
-        }
-
-        if (delimiter == end)
-            break;
-        start = ++delimiter;
-    }
-
-    if (!specificProxy.IsEmpty())
-        SetProxyResult("PROXY", specificProxy, aResult); // Protocol-specific proxy.
-    else if (!defaultProxy.IsEmpty())
-        SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy.
-    else if (!socksProxy.IsEmpty())
-        SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy.
-    else
-        SetProxyResultDirect(aResult); // Direct connection.
-
-    return NS_OK;
+    return mozilla::AndroidBridge::Bridge()->GetProxyForURI(aSpec, aScheme, aHost, aPort, aResult);
 }
 
-#define NS_WINDOWSSYSTEMPROXYSERVICE_CID  /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\
-    { 0x4e22d3ea, 0xaaa2, 0x436e, \
-        {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } }
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAndroidSystemProxySettings, Init)
 
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init)
-NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID);
+#define NS_ANDROIDSYSTEMPROXYSERVICE_CID                    \
+    {0xf01f0060, 0x3708, 0x478e,                            \
+    {0xb9, 0x35, 0x3e, 0xce, 0x8b, 0xe2, 0x94, 0xb8}}
+
+NS_DEFINE_NAMED_CID(NS_ANDROIDSYSTEMPROXYSERVICE_CID);
+
+void test() {};
 
 static const mozilla::Module::CIDEntry kSysProxyCIDs[] = {
-    { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, NULL, nsWindowsSystemProxySettingsConstructor },
+    { &kNS_ANDROIDSYSTEMPROXYSERVICE_CID, false, NULL, nsAndroidSystemProxySettingsConstructor },
     { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = {
-    { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID },
+    { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_ANDROIDSYSTEMPROXYSERVICE_CID },
     { NULL }
 };
 
 static const mozilla::Module kSysProxyModule = {
     mozilla::Module::kVersion,
     kSysProxyCIDs,
     kSysProxyContracts
 };
 
-NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule;
+NSMODULE_DEFN(nsAndroidProxyModule) = &kSysProxyModule;
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -627,16 +627,17 @@ elif [ "$MOZ_WIDGET_TOOLKIT" = "gtk2" ];
   "
 elif [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
   add_makefiles "
     dom/plugins/base/android/Makefile
     dom/system/android/Makefile
     image/decoders/icon/android/Makefile
     netwerk/system/android/Makefile
     widget/android/Makefile
+    toolkit/system/androidproxy/Makefile
   "
   if [ "$MOZ_BUILD_APP" = "mobile/xul" -o "$MOZ_BUILD_APP" = "b2g" ]; then
     add_makefiles "
       embedding/android/Makefile
       embedding/android/locales/Makefile
     "
   fi
 elif [ "$MOZ_WIDGET_TOOLKIT" = "gonk" ]; then
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -197,16 +197,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
     if (mAPIVersion <= 8 /* Froyo */)
         jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mSurface", "I");
     else /* not Froyo */
         jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mNativeSurface", "I");
 
     jNotifyWakeLockChanged = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
 
     jGetGfxInfoData = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getGfxInfoData", "()Ljava/lang/String;");
+    jGetProxyForURI = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;");
     jRegisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V");
     jUnregisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
 
 #ifdef MOZ_ANDROID_OMTC
     jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()Z");
 
     jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIIIZ)V");
     jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V");
@@ -2394,16 +2395,46 @@ AndroidBridge::GetGfxInfoData(nsACString
         (env->CallStaticObjectMethod(mGeckoAppShellClass, jGetGfxInfoData));
     if (jniFrame.CheckForException())
         return;
 
     nsJNIString jniStr(jstrRet, env);
     CopyUTF16toUTF8(jniStr, aRet);
 }
 
+#define CREATE_JAVA_STRING(name) jstring j##name = NewJavaStringUTF(&jniFrame, nsPromiseFlatCString(a##name).get())
+
+nsresult
+AndroidBridge::GetProxyForURI(const nsACString & aSpec,
+                              const nsACString & aScheme,
+                              const nsACString & aHost,
+                              const int32_t      aPort,
+                              nsACString & aResult)
+{
+    JNIEnv* env = GetJNIEnv();
+    if (!env)
+        return NS_ERROR_FAILURE;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    CREATE_JAVA_STRING(Spec);
+    CREATE_JAVA_STRING(Scheme);
+    CREATE_JAVA_STRING(Host);
+    jstring jstrRet = static_cast<jstring>
+        (env->CallStaticObjectMethod(mGeckoAppShellClass, jGetProxyForURI, jSpec, jScheme, jHost, aPort));
+
+    if (jniFrame.CheckForException())
+        return NS_ERROR_FAILURE;
+
+    nsJNIString jniStr(jstrRet, env);
+    CopyUTF16toUTF8(jniStr, aResult);
+    return NS_OK;
+}
+
+
 /* attribute nsIAndroidBrowserApp browserApp; */
 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
 {
     if (nsAppShell::gAppShell)
         nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
     return NS_OK;
 }
 
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -361,17 +361,21 @@ public:
     int GetAPIVersion() { return mAPIVersion; }
     bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; }
 
     void ScheduleComposite();
     void RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id);
     void UnregisterSurfaceTextureFrameListener(jobject surfaceTexture);
 
     void GetGfxInfoData(nsACString& aRet);
-
+    nsresult GetProxyForURI(const nsACString & aSpec,
+                            const nsACString & aScheme,
+                            const nsACString & aHost,
+                            const int32_t      aPort,
+                            nsACString & aResult);
 protected:
     static AndroidBridge *sBridge;
     static StaticAutoPtr<nsTArray<nsCOMPtr<nsISmsRequest> > > sSmsRequests;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
@@ -461,16 +465,17 @@ protected:
     jmethodID jCheckUriVisited;
     jmethodID jMarkUriVisited;
     jmethodID jAddPluginView;
     jmethodID jRemovePluginView;
     jmethodID jCreateSurface;
     jmethodID jShowSurface;
     jmethodID jHideSurface;
     jmethodID jDestroySurface;
+    jmethodID jGetProxyForURI;
 
     jmethodID jNumberOfMessages;
     jmethodID jSendMessage;
     jmethodID jSaveSentMessage;
     jmethodID jGetMessage;
     jmethodID jDeleteMessage;
     jmethodID jCreateMessageList;
     jmethodID jGetNextMessageinList;