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 117794 2fd71029eaa2e5a402b22d3f7d8169594c5dd644
parent 117793 ff8ce0a158677b4e52aff6929d64741d2585bffd
child 117795 6f434302bff32b1fb1bd7bb6d6e91e1d1749a3e8
push idunknown
push userunknown
push dateunknown
reviewersmfinkle, mossop
bugs749352
milestone19.0a1
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;