Bug 1200802 - Accept RFC1929 SOCKS credentials in proxyInfo. r=michal
authorBen Bucksch <ben.bucksch@beonex.com>
Tue, 24 Nov 2015 22:56:00 +0100
changeset 308333 76cee391a698d2dcea75600b34fc04ddff7ea000
parent 308332 82c89f573e53c851f912e4d8f64278e1a398c87d
child 308334 ebb6fb453ccaf38e34add4fa109dc01bedaaab31
push idunknown
push userunknown
push dateunknown
reviewersmichal
bugs1200802
milestone45.0a1
Bug 1200802 - Accept RFC1929 SOCKS credentials in proxyInfo. r=michal
netwerk/base/nsIProtocolProxyService.idl
netwerk/base/nsIProxyInfo.idl
netwerk/base/nsProtocolProxyService.cpp
netwerk/base/nsProtocolProxyService.h
netwerk/base/nsProxyInfo.cpp
netwerk/base/nsProxyInfo.h
netwerk/base/nsSocketTransport2.cpp
netwerk/base/nsSocketTransport2.h
netwerk/protocol/http/TunnelUtils.cpp
netwerk/protocol/http/nsHttpConnectionInfo.cpp
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/socket/nsISocketProvider.idl
netwerk/socket/nsSOCKSIOLayer.cpp
netwerk/socket/nsSOCKSIOLayer.h
netwerk/socket/nsSOCKSSocketProvider.cpp
netwerk/socket/nsUDPSocketProvider.cpp
security/manager/ssl/nsNSSIOLayer.cpp
security/manager/ssl/nsNSSIOLayer.h
security/manager/ssl/nsSSLSocketProvider.cpp
security/manager/ssl/nsTLSSocketProvider.cpp
--- a/netwerk/base/nsIProtocolProxyService.idl
+++ b/netwerk/base/nsIProtocolProxyService.idl
@@ -13,17 +13,17 @@ interface nsIProtocolProxyChannelFilter;
 interface nsIProxyInfo;
 interface nsIChannel;
 interface nsIURI;
 
 /**
  * nsIProtocolProxyService provides methods to access information about
  * various network proxies.
  */
-[scriptable, uuid(deec8e08-a246-443c-90b6-f655632d1abf)]
+[scriptable, uuid(ef57c8b6-e09d-4cd4-9222-2a5d2402e15d)]
 interface nsIProtocolProxyService : nsISupports
 {
     /** Flag 1 << 0 is unused **/
 
     /**
      * When the proxy configuration is manual this flag may be passed to the
      * resolve and asyncResolve methods to request to prefer the SOCKS proxy
      * to HTTP ones.
@@ -135,16 +135,55 @@ interface nsIProtocolProxyService : nsIS
      *        parameter may be null.
      */
     nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost,
                               in long aPort, in unsigned long aFlags,
                               in unsigned long aFailoverTimeout,
                               in nsIProxyInfo aFailoverProxy);
 
     /**
+     * This method may be called to construct a nsIProxyInfo instance for
+     * with the specified username and password.
+     * Currently implemented for SOCKS proxies only.
+     * @param aType
+     *        The proxy type.  This is a string value that identifies the proxy
+     *        type.  Standard values include:
+     *          "socks"   - specifies a SOCKS version 5 proxy
+     *          "socks4"  - specifies a SOCKS version 4 proxy
+     *        The type name is case-insensitive.  Other string values may be
+     *        possible, and new types may be defined by a future version of
+     *        this interface.
+     * @param aHost
+     *        The proxy hostname or IP address.
+     * @param aPort
+     *        The proxy port.
+     * @param aUsername
+     *        The proxy username
+     * @param aPassword
+     *        The proxy password
+     * @param aFlags
+     *        Flags associated with this connection.  See nsIProxyInfo.idl
+     *        for currently defined flags.
+     * @param aFailoverTimeout
+     *        Specifies the length of time (in seconds) to ignore this proxy if
+     *        this proxy fails.  Pass UINT32_MAX to specify the default
+     *        timeout value, causing nsIProxyInfo::failoverTimeout to be
+     *        assigned the default value.
+     * @param aFailoverProxy
+     *        Specifies the next proxy to try if this proxy fails.  This
+     *        parameter may be null.
+     */
+    nsIProxyInfo newProxyInfoWithAuth(in ACString aType, in AUTF8String aHost,
+                                      in long aPort,
+                                      in ACString aUsername, in ACString aPassword,
+                                      in unsigned long aFlags,
+                                      in unsigned long aFailoverTimeout,
+                                      in nsIProxyInfo aFailoverProxy);
+
+    /**
      * If the proxy identified by aProxyInfo is unavailable for some reason,
      * this method may be called to access an alternate proxy that may be used
      * instead.  As a side-effect, this method may affect future result values
      * from resolve/asyncResolve as well as from getFailoverForProxy.
      *
      * @param aProxyInfo
      *        The proxy that was unavailable.
      * @param aURI
--- a/netwerk/base/nsIProxyInfo.idl
+++ b/netwerk/base/nsIProxyInfo.idl
@@ -3,17 +3,17 @@
  * 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 "nsISupports.idl"
 
 /**
  * This interface identifies a proxy server.
  */
-[scriptable, uuid(9e557d99-7af0-4895-95b7-e6dba28c9ad9)]
+[scriptable, uuid(63fff172-2564-4138-96c6-3ae7d245fbed)]
 interface nsIProxyInfo : nsISupports
 {
   /**
    * This attribute specifies the hostname of the proxy server.
    */
   readonly attribute AUTF8String host;
 
   /**
@@ -46,16 +46,26 @@ interface nsIProxyInfo : nsISupports
 
   /**
    * This attribute specifies flags that were used by nsIProxyProtocolService when
    * creating this ProxyInfo element. 
    */
   readonly attribute unsigned long resolveFlags;
 
   /**
+   * Specifies a proxy username.
+   */
+  readonly attribute ACString username;
+
+  /**
+   * Specifies a proxy password.
+   */
+  readonly attribute ACString password;
+
+  /**
    * This attribute specifies the failover timeout in seconds for this proxy.
    * If a nsIProxyInfo is reported as failed via nsIProtocolProxyService::
    * getFailoverForProxy, then the failed proxy will not be used again for this
    * many seconds.
    */
   readonly attribute unsigned long failoverTimeout;
 
   /**
--- a/netwerk/base/nsProtocolProxyService.cpp
+++ b/netwerk/base/nsProtocolProxyService.cpp
@@ -1374,16 +1374,33 @@ NS_IMETHODIMP
 nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
                                      const nsACString &aHost,
                                      int32_t aPort,
                                      uint32_t aFlags,
                                      uint32_t aFailoverTimeout,
                                      nsIProxyInfo *aFailoverProxy,
                                      nsIProxyInfo **aResult)
 {
+    return NewProxyInfoWithAuth(aType, aHost, aPort,
+                                EmptyCString(), EmptyCString(),
+                                aFlags, aFailoverTimeout,
+                                aFailoverProxy, aResult);
+}
+
+NS_IMETHODIMP
+nsProtocolProxyService::NewProxyInfoWithAuth(const nsACString &aType,
+                                             const nsACString &aHost,
+                                             int32_t aPort,
+                                             const nsACString &aUsername,
+                                             const nsACString &aPassword,
+                                             uint32_t aFlags,
+                                             uint32_t aFailoverTimeout,
+                                             nsIProxyInfo *aFailoverProxy,
+                                             nsIProxyInfo **aResult)
+{
     static const char *types[] = {
         kProxyType_HTTP,
         kProxyType_HTTPS,
         kProxyType_SOCKS,
         kProxyType_SOCKS4,
         kProxyType_DIRECT
     };
 
@@ -1393,20 +1410,26 @@ nsProtocolProxyService::NewProxyInfo(con
     for (uint32_t i = 0; i < ArrayLength(types); ++i) {
         if (aType.LowerCaseEqualsASCII(types[i])) {
             type = types[i];
             break;
         }
     }
     NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG);
 
-    if (aPort <= 0)
-        aPort = -1;
+    // We have only implemented username/password for SOCKS proxies.
+    if ((!aUsername.IsEmpty() || !aPassword.IsEmpty()) &&
+        !aType.LowerCaseEqualsASCII(kProxyType_SOCKS) &&
+        !aType.LowerCaseEqualsASCII(kProxyType_SOCKS4)) {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
 
-    return NewProxyInfo_Internal(type, aHost, aPort, aFlags, aFailoverTimeout,
+    return NewProxyInfo_Internal(type, aHost, aPort,
+                                 aUsername, aPassword,
+                                 aFlags, aFailoverTimeout,
                                  aFailoverProxy, 0, aResult);
 }
 
 NS_IMETHODIMP
 nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo  *aProxy,
                                             nsIURI        *aURI,
                                             nsresult       aStatus,
                                             nsIProxyInfo **aResult)
@@ -1712,35 +1735,42 @@ nsProtocolProxyService::GetProtocolInfo(
     rv = handler->GetDefaultPort(&info->defaultPort);
     return rv;
 }
 
 nsresult
 nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
                                               const nsACString &aHost,
                                               int32_t aPort,
+                                              const nsACString &aUsername,
+                                              const nsACString &aPassword,
                                               uint32_t aFlags,
                                               uint32_t aFailoverTimeout,
                                               nsIProxyInfo *aFailoverProxy,
                                               uint32_t aResolveFlags,
                                               nsIProxyInfo **aResult)
 {
+    if (aPort <= 0)
+        aPort = -1;
+
     nsCOMPtr<nsProxyInfo> failover;
     if (aFailoverProxy) {
         failover = do_QueryInterface(aFailoverProxy);
         NS_ENSURE_ARG(failover);
     }
 
     nsProxyInfo *proxyInfo = new nsProxyInfo();
     if (!proxyInfo)
         return NS_ERROR_OUT_OF_MEMORY;
 
     proxyInfo->mType = aType;
     proxyInfo->mHost = aHost;
     proxyInfo->mPort = aPort;
+    proxyInfo->mUsername = aUsername;
+    proxyInfo->mPassword = aPassword;
     proxyInfo->mFlags = aFlags;
     proxyInfo->mResolveFlags = aResolveFlags;
     proxyInfo->mTimeout = aFailoverTimeout == UINT32_MAX
         ? mFailedProxyTimeout : aFailoverTimeout;
     failover.swap(proxyInfo->mNext);
 
     NS_ADDREF(*aResult = proxyInfo);
     return NS_OK;
@@ -1899,18 +1929,19 @@ nsProtocolProxyService::Resolve_Internal
         else
             type = kProxyType_SOCKS;
         port = mSOCKSProxyPort;
         if (mSOCKSProxyRemoteDNS)
             proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
     }
 
     if (type) {
-        rv = NewProxyInfo_Internal(type, *host, port, proxyFlags,
-                                   UINT32_MAX, nullptr, flags,
+        rv = NewProxyInfo_Internal(type, *host, port,
+                                   EmptyCString(), EmptyCString(),
+                                   proxyFlags, UINT32_MAX, nullptr, flags,
                                    result);
         if (NS_FAILED(rv))
             return rv;
     }
 
     return NS_OK;
 }
 
--- a/netwerk/base/nsProtocolProxyService.h
+++ b/netwerk/base/nsProtocolProxyService.h
@@ -172,30 +172,36 @@ protected:
      * that expects a string literal for the type.
      *
      * @param type
      *        The proxy type.
      * @param host
      *        The proxy host name (UTF-8 ok).
      * @param port
      *        The proxy port number.
+     * @param username
+     *        The username for the proxy (ASCII). May be "", but not null.
+     * @param password
+     *        The password for the proxy (ASCII). May be "", but not null.
      * @param flags
      *        The proxy flags (nsIProxyInfo::flags).
      * @param timeout
      *        The failover timeout for this proxy.
      * @param next
      *        The next proxy to try if this one fails.
      * @param aResolveFlags
      *        The flags passed to resolve (from nsIProtocolProxyService).
      * @param result
      *        The resulting nsIProxyInfo object.
      */
     nsresult NewProxyInfo_Internal(const char *type,
                                                const nsACString &host,
                                                int32_t port,
+                                               const nsACString &username,
+                                               const nsACString &password,
                                                uint32_t flags,
                                                uint32_t timeout,
                                                nsIProxyInfo *next,
                                                uint32_t aResolveFlags,
                                                nsIProxyInfo **result);
 
     /**
      * This method is an internal version of Resolve that does not query PAC.
--- a/netwerk/base/nsProxyInfo.cpp
+++ b/netwerk/base/nsProxyInfo.cpp
@@ -43,16 +43,30 @@ nsProxyInfo::GetFlags(uint32_t *result)
 NS_IMETHODIMP
 nsProxyInfo::GetResolveFlags(uint32_t *result)
 {
   *result = mResolveFlags;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsProxyInfo::GetUsername(nsACString &result)
+{
+  result = mUsername;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsProxyInfo::GetPassword(nsACString &result)
+{
+  result = mPassword;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsProxyInfo::GetFailoverTimeout(uint32_t *result)
 {
   *result = mTimeout;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsProxyInfo::GetFailoverProxy(nsIProxyInfo **result)
--- a/netwerk/base/nsProxyInfo.h
+++ b/netwerk/base/nsProxyInfo.h
@@ -30,16 +30,18 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIPROXYINFO
 
   // Cheap accessors for use within Necko
   const nsCString &Host()  { return mHost; }
   int32_t          Port()  { return mPort; }
   const char      *Type()  { return mType; }
   uint32_t         Flags() { return mFlags; }
+  const nsCString &Username()  { return mUsername; }
+  const nsCString &Password()  { return mPassword; }
 
   bool IsDirect();
   bool IsHTTP();
   bool IsHTTPS();
   bool IsSOCKS();
 
 private:
   friend class nsProtocolProxyService;
@@ -55,16 +57,18 @@ private:
 
   ~nsProxyInfo()
   {
     NS_IF_RELEASE(mNext);
   }
 
   const char  *mType;  // pointer to statically allocated value
   nsCString    mHost;
+  nsCString    mUsername;
+  nsCString    mPassword;
   int32_t      mPort;
   uint32_t     mFlags;
   uint32_t     mResolveFlags;
   uint32_t     mTimeout;
   nsProxyInfo *mNext;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyInfo, NS_PROXYINFO_IID)
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -808,16 +808,17 @@ nsSocketTransport::Init(const char **typ
         mPort = port;
     }
 
     if (proxyInfo) {
         mHttpsProxy = proxyInfo->IsHTTPS();
     }
 
     const char *proxyType = nullptr;
+    mProxyInfo = proxyInfo;
     if (proxyInfo) {
         mProxyPort = proxyInfo->Port();
         mProxyHost = proxyInfo->Host();
         // grab proxy type (looking for "socks" for example)
         proxyType = proxyInfo->Type();
         if (proxyType && (proxyInfo->IsHTTP() ||
                           proxyInfo->IsHTTPS() ||
                           proxyInfo->IsDirect() ||
@@ -1100,18 +1101,17 @@ nsSocketTransport::BuildSocket(PRFileDes
             do_GetService(kSocketProviderServiceCID, &rv);
         if (NS_FAILED(rv)) return rv;
 
         // by setting host to mOriginHost, instead of mHost we send the
         // SocketProvider (e.g. PSM) the origin hostname but can still do DNS
         // on an explicit alternate service host name
         const char *host       = mOriginHost.get();
         int32_t     port       = (int32_t) mOriginPort;
-        const char *proxyHost  = mProxyHost.IsEmpty() ? nullptr : mProxyHost.get();
-        int32_t     proxyPort  = (int32_t) mProxyPort;
+        nsCOMPtr<nsIProxyInfo> proxyInfo = mProxyInfo;
         uint32_t    controlFlags = 0;
 
         uint32_t i;
         for (i=0; i<mTypeCount; ++i) {
             nsCOMPtr<nsISocketProvider> provider;
 
             SOCKET_LOG(("  pushing io layer [%u:%s]\n", i, mTypes[i]));
 
@@ -1135,33 +1135,33 @@ nsSocketTransport::BuildSocket(PRFileDes
             if (i == 0) {
                 // if this is the first type, we'll want the 
                 // service to allocate a new socket
 
                 // when https proxying we want to just connect to the proxy as if
                 // it were the end host (i.e. expect the proxy's cert)
 
                 rv = provider->NewSocket(mNetAddr.raw.family,
-                                         mHttpsProxy ? proxyHost : host,
-                                         mHttpsProxy ? proxyPort : port,
-                                         proxyHost, proxyPort,
+                                         mHttpsProxy ? mProxyHost.get() : host,
+                                         mHttpsProxy ? mProxyPort : port,
+                                         proxyInfo,
                                          controlFlags, &fd,
                                          getter_AddRefs(secinfo));
 
                 if (NS_SUCCEEDED(rv) && !fd) {
                     NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
                     rv = NS_ERROR_UNEXPECTED;
                 }
             }
             else {
                 // the socket has already been allocated, 
                 // so we just want the service to add itself
                 // to the stack (such as pushing an io layer)
                 rv = provider->AddToSocket(mNetAddr.raw.family,
-                                           host, port, proxyHost, proxyPort,
+                                           host, port, proxyInfo,
                                            controlFlags, fd,
                                            getter_AddRefs(secinfo));
             }
             // controlFlags = 0; not used below this point...
             if (NS_FAILED(rv))
                 break;
 
             // if the service was ssl or starttls, we want to hold onto the socket info
@@ -1181,18 +1181,17 @@ nsSocketTransport::BuildSocket(PRFileDes
                     secCtrl->SetNotificationCallbacks(callbacks);
                 // remember if socket type is SSL so we can ProxyStartSSL if need be.
                 usingSSL = isSSL;
             }
             else if ((strcmp(mTypes[i], "socks") == 0) ||
                      (strcmp(mTypes[i], "socks4") == 0)) {
                 // since socks is transparent, any layers above
                 // it do not have to worry about proxy stuff
-                proxyHost = nullptr;
-                proxyPort = -1;
+                proxyInfo = nullptr;
                 proxyTransparent = true;
             }
         }
 
         if (NS_FAILED(rv)) {
             SOCKET_LOG(("  error pushing io layer [%u:%s rv=%x]\n", i, mTypes[i], rv));
             if (fd) {
                 PR_Close(fd);
--- a/netwerk/base/nsSocketTransport2.h
+++ b/netwerk/base/nsSocketTransport2.h
@@ -281,16 +281,17 @@ private:
 
     // socket type info:
     char       **mTypes;
     uint32_t     mTypeCount;
     nsCString    mHost;
     nsCString    mProxyHost;
     nsCString    mOriginHost;
     uint16_t     mPort;
+    nsCOMPtr<nsIProxyInfo> mProxyInfo;
     uint16_t     mProxyPort;
     uint16_t     mOriginPort;
     bool mProxyTransparent;
     bool mProxyTransparentResolvesHost;
     bool mHttpsProxy;
     uint32_t     mConnectionFlags;
     
     uint16_t         SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -73,17 +73,17 @@ TLSFilterTransaction::TLSFilterTransacti
     sLayerMethodsPtr = &sLayerMethods;
   }
 
   mFD = PR_CreateIOLayerStub(sLayerIdentity, &sLayerMethods);
 
   if (provider && mFD) {
     mFD->secret = reinterpret_cast<PRFilePrivate *>(this);
     provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr,
-                          0, 0, mFD, getter_AddRefs(mSecInfo));
+                          0, mFD, getter_AddRefs(mSecInfo));
   }
 
   if (mTransaction) {
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
     mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
     nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
     if (secCtrl) {
       secCtrl->SetNotificationCallbacks(callbacks);
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -11,16 +11,40 @@
 #undef LOG
 #define LOG(args) LOG5(args)
 #undef LOG_ENABLED
 #define LOG_ENABLED() LOG5_ENABLED()
 
 #include "nsHttpConnectionInfo.h"
 #include "mozilla/net/DNS.h"
 #include "prnetdb.h"
+#include "nsICryptoHash.h"
+
+static nsresult
+SHA256(const char* aPlainText, nsAutoCString& aResult)
+{
+  static nsICryptoHash* hasher = nullptr;
+  nsresult rv;
+  if (!hasher) {
+    rv = CallCreateInstance("@mozilla.org/security/hash;1", &hasher);
+    if (NS_FAILED(rv)) {
+      LOG(("nsHttpDigestAuth: no crypto hash!\n"));
+      return rv;
+    }
+  }
+
+  rv = hasher->Init(nsICryptoHash::SHA256);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = hasher->Update((unsigned char*) aPlainText, strlen(aPlainText));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = hasher->Finish(false, aResult);
+  return rv;
+}
 
 namespace mozilla {
 namespace net {
 
 nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
                                            int32_t originPort,
                                            const nsACString &npnToken,
                                            const nsACString &username,
@@ -146,25 +170,42 @@ void nsHttpConnectionInfo::BuildHashKey(
     // right protocol even if our proxy preferences change).
     //
     // NOTE: for SSL tunnels add the proxy information to the cache key.
     // We cannot use the proxy as the host parameter (as we do for non SSL)
     // because this is a single host tunnel, but we need to include the proxy
     // information so that a change in proxy config will mean this connection
     // is not reused
 
+    // NOTE: Adding the username and the password provides a means to isolate
+    // keep-alive to the URL bar domain as well: If the username is the URL bar
+    // domain, keep-alive connections are not reused by resources bound to
+    // different URL bar domains as the respective hash keys are not matching.
+
     if ((!mUsingHttpProxy && ProxyHost()) ||
         (mUsingHttpProxy && mUsingConnect)) {
         mHashKey.AppendLiteral(" (");
         mHashKey.Append(ProxyType());
         mHashKey.Append(':');
         mHashKey.Append(ProxyHost());
         mHashKey.Append(':');
         mHashKey.AppendInt(ProxyPort());
         mHashKey.Append(')');
+        mHashKey.Append('[');
+        mHashKey.Append(ProxyUsername());
+        mHashKey.Append(':');
+        const char* password = ProxyPassword();
+        if (strlen(password) > 0) {
+            nsAutoCString digestedPassword;
+            nsresult rv = SHA256(password, digestedPassword);
+            if (rv == NS_OK) {
+                mHashKey.Append(digestedPassword);
+            }
+        }
+        mHashKey.Append(']');
     }
 
     if(!mRoutedHost.IsEmpty()) {
         mHashKey.AppendLiteral(" <ROUTE-via ");
         mHashKey.Append(mRoutedHost);
         mHashKey.Append(':');
         mHashKey.AppendInt(mRoutedPort);
         mHashKey.Append('>');
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -79,16 +79,18 @@ public:
     // OK to treat these as an infalible allocation
     nsHttpConnectionInfo* Clone() const;
     void CloneAsDirectRoute(nsHttpConnectionInfo **outParam);
     nsresult CreateWildCard(nsHttpConnectionInfo **outParam);
 
     const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nullptr; }
     int32_t     ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
     const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nullptr; }
+    const char *ProxyUsername() const { return mProxyInfo ? mProxyInfo->Username().get() : nullptr; }
+    const char *ProxyPassword() const { return mProxyInfo ? mProxyInfo->Password().get() : nullptr; }
 
     // Compare this connection info to another...
     // Two connections are 'equal' if they end up talking the same
     // protocol to the same server. This is needed to properly manage
     // persistent connections to proxies
     // Note that we don't care about transparent proxies -
     // it doesn't matter if we're talking via socks or not, since
     // a request will end up at the same host.
--- a/netwerk/socket/nsISocketProvider.idl
+++ b/netwerk/socket/nsISocketProvider.idl
@@ -1,21 +1,22 @@
 /* -*- 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 "nsISupports.idl"
 
+interface nsIProxyInfo;
 [ptr] native PRFileDescStar(struct PRFileDesc);
 
 /**
  * nsISocketProvider
  */
-[scriptable, uuid(00b3df92-e830-11d8-d48e-0004e22243f8)]
+[scriptable, uuid(508d5469-9e1e-4a08-b5b0-7cfebba1e51a)]
 interface nsISocketProvider : nsISupports
 {
     /**
      * newSocket
      *
      * @param aFamily
      *        The address family for this socket (PR_AF_INET or PR_AF_INET6).
      * @param aHost
@@ -33,18 +34,17 @@ interface nsISocketProvider : nsISupport
      * @param aSecurityInfo
      *        Any security info that should be associated with aFileDesc.  This
      *        object typically implements nsITransportSecurityInfo.
      */
     [noscript]
     void newSocket(in long            aFamily,
                    in string          aHost, 
                    in long            aPort,
-                   in string          aProxyHost,
-                   in long            aProxyPort,
+                   in nsIProxyInfo    aProxy,
                    in unsigned long   aFlags,
                    out PRFileDescStar aFileDesc, 
                    out nsISupports    aSecurityInfo);
 
     /**
      * addToSocket
      *
      * This function is called to allow the socket provider to layer a
@@ -53,18 +53,17 @@ interface nsISocketProvider : nsISupport
      *
      * Parameters are the same as newSocket with the exception of aFileDesc,
      * which is an in-param instead.
      */
     [noscript]
     void addToSocket(in long           aFamily,
                      in string         aHost, 
                      in long           aPort,
-                     in string         aProxyHost,
-                     in long           aProxyPort,
+                     in nsIProxyInfo   aProxy,
                      in unsigned long  aFlags,
                      in PRFileDescStar aFileDesc, 
                      out nsISupports   aSecurityInfo);
 
     /**
      * PROXY_RESOLVES_HOST
      *
      * This flag is set if the proxy is to perform hostname resolution instead
--- a/netwerk/socket/nsSOCKSIOLayer.cpp
+++ b/netwerk/socket/nsSOCKSIOLayer.cpp
@@ -42,39 +42,42 @@ class nsSOCKSSocketInfo : public nsISOCK
         SOCKS_INITIAL,
         SOCKS_DNS_IN_PROGRESS,
         SOCKS_DNS_COMPLETE,
         SOCKS_CONNECTING_TO_PROXY,
         SOCKS4_WRITE_CONNECT_REQUEST,
         SOCKS4_READ_CONNECT_RESPONSE,
         SOCKS5_WRITE_AUTH_REQUEST,
         SOCKS5_READ_AUTH_RESPONSE,
+        SOCKS5_WRITE_USERNAME_REQUEST,
+        SOCKS5_READ_USERNAME_RESPONSE,
         SOCKS5_WRITE_CONNECT_REQUEST,
         SOCKS5_READ_CONNECT_RESPONSE_TOP,
         SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
         SOCKS_CONNECTED,
         SOCKS_FAILED
     };
 
-    // A buffer of 265 bytes should be enough for any request and response
+    // A buffer of 520 bytes should be enough for any request and response
     // in case of SOCKS4 as well as SOCKS5
-    static const uint32_t BUFFER_SIZE = 265;
+    static const uint32_t BUFFER_SIZE = 520;
     static const uint32_t MAX_HOSTNAME_LEN = 255;
+    static const uint32_t MAX_USERNAME_LEN = 255;
+    static const uint32_t MAX_PASSWORD_LEN = 255;
 
 public:
     nsSOCKSSocketInfo();
 
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSISOCKSSOCKETINFO
     NS_DECL_NSIDNSLISTENER
 
     void Init(int32_t version,
               int32_t family,
-              const char *proxyHost,
-              int32_t proxyPort,
+              nsIProxyInfo *proxy,
               const char *destinationHost,
               uint32_t flags);
 
     void SetConnectTimeout(PRIntervalTime to);
     PRStatus DoHandshake(PRFileDesc *fd, int16_t oflags = -1);
     int16_t GetPollFlags() const;
     bool IsConnected() const { return mState == SOCKS_CONNECTED; }
     void ForgetFD() { mFD = nullptr; }
@@ -86,16 +89,18 @@ private:
     PRStatus StartDNS(PRFileDesc *fd);
     PRStatus ConnectToProxy(PRFileDesc *fd);
     void FixupAddressFamily(PRFileDesc *fd, NetAddr *proxy);
     PRStatus ContinueConnectingToProxy(PRFileDesc *fd, int16_t oflags);
     PRStatus WriteV4ConnectRequest();
     PRStatus ReadV4ConnectResponse();
     PRStatus WriteV5AuthRequest();
     PRStatus ReadV5AuthResponse();
+    PRStatus WriteV5UsernameRequest();
+    PRStatus ReadV5UsernameResponse();
     PRStatus WriteV5ConnectRequest();
     PRStatus ReadV5AddrTypeAndLength(uint8_t *type, uint32_t *len);
     PRStatus ReadV5ConnectResponseTop();
     PRStatus ReadV5ConnectResponseBottom();
 
     uint8_t ReadUint8();
     uint16_t ReadUint16();
     uint32_t ReadUint32();
@@ -114,34 +119,33 @@ private:
     uint32_t  mReadOffset;
     uint32_t  mAmountToRead;
     nsCOMPtr<nsIDNSRecord>  mDnsRec;
     nsCOMPtr<nsICancelable> mLookup;
     nsresult                mLookupStatus;
     PRFileDesc             *mFD;
 
     nsCString mDestinationHost;
-    nsCString mProxyHost;
-    int32_t   mProxyPort;
+    nsCOMPtr<nsIProxyInfo> mProxy;
     int32_t   mVersion;   // SOCKS version 4 or 5
     int32_t   mDestinationFamily;
     uint32_t  mFlags;
     NetAddr   mInternalProxyAddr;
     NetAddr   mExternalProxyAddr;
     NetAddr   mDestinationAddr;
     PRIntervalTime mTimeout;
+    nsCString mProxyUsername; // Cache, from mProxy
 };
 
 nsSOCKSSocketInfo::nsSOCKSSocketInfo()
     : mState(SOCKS_INITIAL)
     , mDataIoPtr(nullptr)
     , mDataLength(0)
     , mReadOffset(0)
     , mAmountToRead(0)
-    , mProxyPort(-1)
     , mVersion(-1)
     , mDestinationFamily(AF_INET)
     , mFlags(0)
     , mTimeout(PR_INTERVAL_NO_TIMEOUT)
 {
     mData = new uint8_t[BUFFER_SIZE];
 
     mInternalProxyAddr.raw.family = AF_INET;
@@ -262,24 +266,24 @@ private:
   }
 
   uint8_t* mBuf;
   size_t mLength;
 };
 
 
 void
-nsSOCKSSocketInfo::Init(int32_t version, int32_t family, const char *proxyHost, int32_t proxyPort, const char *host, uint32_t flags)
+nsSOCKSSocketInfo::Init(int32_t version, int32_t family, nsIProxyInfo *proxy, const char *host, uint32_t flags)
 {
     mVersion         = version;
     mDestinationFamily = family;
-    mProxyHost       = proxyHost;
-    mProxyPort       = proxyPort;
+    mProxy           = proxy;
     mDestinationHost = host;
     mFlags           = flags;
+    mProxy->GetUsername(mProxyUsername); // cache
 }
 
 NS_IMPL_ISUPPORTS(nsSOCKSSocketInfo, nsISOCKSSocketInfo, nsIDNSListener)
 
 NS_IMETHODIMP 
 nsSOCKSSocketInfo::GetExternalProxyAddr(NetAddr * *aExternalProxyAddr)
 {
     memcpy(*aExternalProxyAddr, &mExternalProxyAddr, sizeof(NetAddr));
@@ -356,24 +360,27 @@ nsSOCKSSocketInfo::StartDNS(PRFileDesc *
 {
     MOZ_ASSERT(!mDnsRec && mState == SOCKS_INITIAL,
                "Must be in initial state to make DNS Lookup");
 
     nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
     if (!dns)
         return PR_FAILURE;
 
+    nsCString proxyHost;
+    mProxy->GetHost(proxyHost);
+
     mFD  = fd;
-    nsresult rv = dns->AsyncResolve(mProxyHost, 0, this,
+    nsresult rv = dns->AsyncResolve(proxyHost, 0, this,
                                     NS_GetCurrentThread(),
                                     getter_AddRefs(mLookup));
 
     if (NS_FAILED(rv)) {
         LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
-                  mProxyHost.get()));
+                  proxyHost.get()));
         return PR_FAILURE;
     }
     mState = SOCKS_DNS_IN_PROGRESS;
     PR_SetError(PR_IN_PROGRESS_ERROR, 0);
     return PR_FAILURE;
 }
 
 NS_IMETHODIMP
@@ -408,26 +415,31 @@ nsSOCKSSocketInfo::ConnectToProxy(PRFile
     }
 
     // Try socks5 if the destination addrress is IPv6
     if (mVersion == 4 &&
         mDestinationAddr.raw.family == AF_INET6) {
         mVersion = 5;
     }
 
+    int32_t proxyPort;
+    mProxy->GetPort(&proxyPort);
+
     int32_t addresses = 0;
     do {
         if (addresses++)
-            mDnsRec->ReportUnusable(mProxyPort);
+            mDnsRec->ReportUnusable(proxyPort);
         
-        rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
+        rv = mDnsRec->GetNextAddr(proxyPort, &mInternalProxyAddr);
         // No more addresses to try? If so, we'll need to bail
         if (NS_FAILED(rv)) {
+            nsCString proxyHost;
+            mProxy->GetHost(proxyHost);
             LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
-                     mProxyHost.get()));
+                     proxyHost.get()));
             return PR_FAILURE;
         }
 
         if (MOZ_LOG_TEST(gSOCKSLog, LogLevel::Debug)) {
           char buf[kIPv6CStrBufSize];
           NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
           LOGDEBUG(("socks: trying proxy server, %s:%hu",
                    buf, ntohs(mInternalProxyAddr.inet.port)));
@@ -534,16 +546,22 @@ nsSOCKSSocketInfo::ContinueConnectingToP
     if (mVersion == 4)
         return WriteV4ConnectRequest();
     return WriteV5AuthRequest();
 }
 
 PRStatus
 nsSOCKSSocketInfo::WriteV4ConnectRequest()
 {
+    if (mProxyUsername.Length() > MAX_USERNAME_LEN) {
+        LOGERROR(("socks username is too long"));
+        HandshakeFinished(PR_UNKNOWN_ERROR);
+        return PR_FAILURE;
+    }
+
     NetAddr *addr = &mDestinationAddr;
     int32_t proxy_resolve;
 
     MOZ_ASSERT(mState == SOCKS_CONNECTING_TO_PROXY,
                "Invalid state!");
     
     proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
 
@@ -563,28 +581,32 @@ nsSOCKSSocketInfo::WriteV4ConnectRequest
     // use a buffer with no further writes allowed.
     Buffer<0> buf3;
     if (proxy_resolve) {
         // Add the full name, null-terminated, to the request
         // according to SOCKS 4a. A fake IP address, with the first
         // four bytes set to 0 and the last byte set to something other
         // than 0, is used to notify the proxy that this is a SOCKS 4a
         // request. This request type works for Tor and perhaps others.
+        // Passwords not supported by V4.
         auto buf2 = buf.WriteUint32(htonl(0x00000001)) // Fake IP
-                       .WriteUint8(0x00) // Send an emtpy username
+                       .WriteString<MAX_USERNAME_LEN>(mProxyUsername)
+                       .WriteUint8(0x00) // Null-terminate username
                        .WriteString<MAX_HOSTNAME_LEN>(mDestinationHost); // Hostname
         if (!buf2) {
             LOGERROR(("socks4: destination host name is too long!"));
             HandshakeFinished(PR_BAD_ADDRESS_ERROR);
             return PR_FAILURE;
         }
         buf3 = buf2.WriteUint8(0x00);
     } else if (addr->raw.family == AF_INET) {
+        // Passwords not supported by V4.
         buf3 = buf.WriteNetAddr(addr) // Add the IPv4 address
-                  .WriteUint8(0x00); // Send an emtpy username
+                  .WriteString<MAX_USERNAME_LEN>(mProxyUsername)
+                  .WriteUint8(0x00); // Null-terminate username
     } else {
         LOGERROR(("socks: SOCKS 4 can only handle IPv4 addresses!"));
         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
         return PR_FAILURE;
     }
 
     mDataLength = buf3.Written();
     return PR_SUCCESS;
@@ -618,24 +640,26 @@ nsSOCKSSocketInfo::ReadV4ConnectResponse
     return PR_FAILURE;
 }
 
 PRStatus
 nsSOCKSSocketInfo::WriteV5AuthRequest()
 {
     MOZ_ASSERT(mVersion == 5, "SOCKS version must be 5!");
 
+    mDataLength = 0;
     mState = SOCKS5_WRITE_AUTH_REQUEST;
 
     // Send an initial SOCKS 5 greeting
     LOGDEBUG(("socks5: sending auth methods"));
     mDataLength = Buffer<BUFFER_SIZE>(mData)
                   .WriteUint8(0x05) // version -- 5
-                  .WriteUint8(0x01) // # auth methods -- 1
-                  .WriteUint8(0x00) // we don't support authentication
+                  .WriteUint8(0x01) // # of auth methods -- 1
+                  // Use authenticate iff we have a proxy username.
+                  .WriteUint8(mProxyUsername.IsEmpty() ? 0x00 : 0x02)
                   .Written();
 
     return PR_SUCCESS;
 }
 
 PRStatus
 nsSOCKSSocketInfo::ReadV5AuthResponse()
 {
@@ -648,22 +672,91 @@ nsSOCKSSocketInfo::ReadV5AuthResponse()
 
     // Check version number
     if (ReadUint8() != 0x05) {
         LOGERROR(("socks5: unexpected version in the reply"));
         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
         return PR_FAILURE;
     }
 
-    // Make sure our authentication choice was accepted
-    if (ReadUint8() != 0x00) {
+    // Make sure our authentication choice was accepted,
+    // and continue accordingly
+    uint8_t authMethod = ReadUint8();
+    if (mProxyUsername.IsEmpty() && authMethod == 0x00) { // no auth
+        LOGDEBUG(("socks5: server allows connection without authentication"));
+        return WriteV5ConnectRequest();
+    } else if (!mProxyUsername.IsEmpty() && authMethod == 0x02) { // username/pw
+        LOGDEBUG(("socks5: auth method accepted by server"));
+        return WriteV5UsernameRequest();
+    } else { // 0xFF signals error
         LOGERROR(("socks5: server did not accept our authentication method"));
         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
         return PR_FAILURE;
     }
+}
+
+PRStatus
+nsSOCKSSocketInfo::WriteV5UsernameRequest()
+{
+    MOZ_ASSERT(mVersion == 5, "SOCKS version must be 5!");
+
+    if (mProxyUsername.Length() > MAX_USERNAME_LEN) {
+        LOGERROR(("socks username is too long"));
+        HandshakeFinished(PR_UNKNOWN_ERROR);
+        return PR_FAILURE;
+    }
+
+    nsCString password;
+    mProxy->GetPassword(password);
+    if (password.Length() > MAX_PASSWORD_LEN) {
+        LOGERROR(("socks password is too long"));
+        HandshakeFinished(PR_UNKNOWN_ERROR);
+        return PR_FAILURE;
+    }
+
+    mDataLength = 0;
+    mState = SOCKS5_WRITE_USERNAME_REQUEST;
+
+    // RFC 1929 Username/password auth for SOCKS 5
+    LOGDEBUG(("socks5: sending username and password"));
+    mDataLength = Buffer<BUFFER_SIZE>(mData)
+                  .WriteUint8(0x01) // version 1 (not 5)
+                  .WriteUint8(mProxyUsername.Length()) // username length
+                  .WriteString<MAX_USERNAME_LEN>(mProxyUsername) // username
+                  .WriteUint8(password.Length()) // password length
+                  .WriteString<MAX_PASSWORD_LEN>(password) // password. WARNING: Sent unencrypted!
+                  .Written();
+
+    return PR_SUCCESS;
+}
+
+PRStatus
+nsSOCKSSocketInfo::ReadV5UsernameResponse()
+{
+    MOZ_ASSERT(mState == SOCKS5_READ_USERNAME_RESPONSE,
+                      "Handling SOCKS 5 username/password reply in wrong state!");
+
+    MOZ_ASSERT(mDataLength == 2,
+               "SOCKS 5 username reply must be 2 bytes");
+
+    // Check version number, must be 1 (not 5)
+    if (ReadUint8() != 0x01) {
+        LOGERROR(("socks5: unexpected version in the reply"));
+        HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
+        return PR_FAILURE;
+    }
+
+    // Check whether username/password were accepted
+    if (ReadUint8() != 0x00) { // 0 = success
+        LOGERROR(("socks5: username/password not accepted"));
+        HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
+        return PR_FAILURE;
+    }
+
+    LOGDEBUG(("socks5: username/password accepted by server"));
 
     return WriteV5ConnectRequest();
 }
 
 PRStatus
 nsSOCKSSocketInfo::WriteV5ConnectRequest()
 {
     // Send SOCKS 5 connect request
@@ -902,16 +995,26 @@ nsSOCKSSocketInfo::DoHandshake(PRFileDes
                 return PR_FAILURE;
             WantRead(2);
             mState = SOCKS5_READ_AUTH_RESPONSE;
             return PR_SUCCESS;
         case SOCKS5_READ_AUTH_RESPONSE:
             if (ReadFromSocket(fd) != PR_SUCCESS)
                 return PR_FAILURE;
             return ReadV5AuthResponse();
+        case SOCKS5_WRITE_USERNAME_REQUEST:
+            if (WriteToSocket(fd) != PR_SUCCESS)
+                return PR_FAILURE;
+            WantRead(2);
+            mState = SOCKS5_READ_USERNAME_RESPONSE;
+            return PR_SUCCESS;
+        case SOCKS5_READ_USERNAME_RESPONSE:
+            if (ReadFromSocket(fd) != PR_SUCCESS)
+                return PR_FAILURE;
+            return ReadV5UsernameResponse();
         case SOCKS5_WRITE_CONNECT_REQUEST:
             if (WriteToSocket(fd) != PR_SUCCESS)
                 return PR_FAILURE;
 
             // The SOCKS 5 response to the connection request is variable
             // length. First, we'll read enough to tell how long the response
             // is, and will read the rest later.
             WantRead(5);
@@ -946,20 +1049,22 @@ nsSOCKSSocketInfo::GetPollFlags() const
 {
     switch (mState) {
         case SOCKS_DNS_IN_PROGRESS:
         case SOCKS_DNS_COMPLETE:
         case SOCKS_CONNECTING_TO_PROXY:
             return PR_POLL_EXCEPT | PR_POLL_WRITE;
         case SOCKS4_WRITE_CONNECT_REQUEST:
         case SOCKS5_WRITE_AUTH_REQUEST:
+        case SOCKS5_WRITE_USERNAME_REQUEST:
         case SOCKS5_WRITE_CONNECT_REQUEST:
             return PR_POLL_WRITE;
         case SOCKS4_READ_CONNECT_RESPONSE:
         case SOCKS5_READ_AUTH_RESPONSE:
+        case SOCKS5_READ_USERNAME_RESPONSE:
         case SOCKS5_READ_CONNECT_RESPONSE_TOP:
         case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
             return PR_POLL_READ;
         default:
             break;
     }
 
     return 0;
@@ -1264,18 +1369,17 @@ nsSOCKSIOLayerListen(PRFileDesc *fd, int
     return fd->lower->methods->listen(fd->lower, backlog);
 }
 
 // add SOCKS IO layer to an existing socket
 nsresult
 nsSOCKSIOLayerAddToSocket(int32_t family,
                           const char *host, 
                           int32_t port,
-                          const char *proxyHost,
-                          int32_t proxyPort,
+                          nsIProxyInfo *proxy,
                           int32_t socksVersion,
                           uint32_t flags,
                           PRFileDesc *fd, 
                           nsISupports** info)
 {
     NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), NS_ERROR_NOT_INITIALIZED);
 
 
@@ -1327,17 +1431,17 @@ nsSOCKSIOLayerAddToSocket(int32_t family
     {
         // clean up IOLayerStub
         LOGERROR(("Failed to create nsSOCKSSocketInfo()."));
         PR_DELETE(layer);
         return NS_ERROR_FAILURE;
     }
 
     NS_ADDREF(infoObject);
-    infoObject->Init(socksVersion, family, proxyHost, proxyPort, host, flags);
+    infoObject->Init(socksVersion, family, proxy, host, flags);
     layer->secret = (PRFilePrivate*) infoObject;
     rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer);
 
     if (rv == PR_FAILURE) {
         LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv));
         NS_RELEASE(infoObject);
         PR_DELETE(layer);
         return NS_ERROR_FAILURE;
--- a/netwerk/socket/nsSOCKSIOLayer.h
+++ b/netwerk/socket/nsSOCKSIOLayer.h
@@ -4,20 +4,20 @@
  * 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/. */
 
 #ifndef nsSOCKSIOLayer_h__
 #define nsSOCKSIOLayer_h__
 
 #include "prio.h"
 #include "nscore.h"
+#include "nsIProxyInfo.h"
 
 nsresult nsSOCKSIOLayerAddToSocket(int32_t       family,
                                    const char   *host, 
                                    int32_t       port,
-                                   const char   *proxyHost,
-                                   int32_t       proxyPort,
+                                   nsIProxyInfo *proxyInfo,
                                    int32_t       socksVersion,
                                    uint32_t      flags,
                                    PRFileDesc   *fd, 
                                    nsISupports **info);
 
 #endif /* nsSOCKSIOLayer_h__ */
--- a/netwerk/socket/nsSOCKSSocketProvider.cpp
+++ b/netwerk/socket/nsSOCKSSocketProvider.cpp
@@ -39,60 +39,56 @@ nsSOCKSSocketProvider::CreateV5(nsISuppo
         rv = inst->QueryInterface(aIID, aResult); 
     return rv;
 }
 
 NS_IMETHODIMP
 nsSOCKSSocketProvider::NewSocket(int32_t family,
                                  const char *host, 
                                  int32_t port,
-                                 const char *proxyHost,
-                                 int32_t proxyPort,
+                                 nsIProxyInfo *proxy,
                                  uint32_t flags,
                                  PRFileDesc **result,
                                  nsISupports **socksInfo)
 {
     PRFileDesc *sock;
     
     sock = PR_OpenTCPSocket(family);
     if (!sock)
         return NS_ERROR_OUT_OF_MEMORY;
 
     nsresult rv = nsSOCKSIOLayerAddToSocket(family,
                                             host, 
                                             port,
-                                            proxyHost,
-                                            proxyPort,
+                                            proxy,
                                             mVersion,
                                             flags,
                                             sock, 
                                             socksInfo);
     if (NS_SUCCEEDED(rv)) {
         *result = sock;
         return NS_OK;
     }
 
     return NS_ERROR_SOCKET_CREATE_FAILED;
 }
 
 NS_IMETHODIMP
 nsSOCKSSocketProvider::AddToSocket(int32_t family,
                                    const char *host,
                                    int32_t port,
-                                   const char *proxyHost,
-                                   int32_t proxyPort,
+                                   nsIProxyInfo *proxy,
                                    uint32_t flags,
                                    PRFileDesc *sock,
                                    nsISupports **socksInfo)
 {
     nsresult rv = nsSOCKSIOLayerAddToSocket(family,
                                             host, 
                                             port,
-                                            proxyHost,
-                                            proxyPort,
+                                            proxy,
                                             mVersion,
                                             flags,
                                             sock, 
                                             socksInfo);
     
     if (NS_FAILED(rv))
         rv = NS_ERROR_SOCKET_CREATE_FAILED;
     return rv;
--- a/netwerk/socket/nsUDPSocketProvider.cpp
+++ b/netwerk/socket/nsUDPSocketProvider.cpp
@@ -11,18 +11,17 @@ NS_IMPL_ISUPPORTS(nsUDPSocketProvider, n
 nsUDPSocketProvider::~nsUDPSocketProvider()
 {
 }
 
 NS_IMETHODIMP 
 nsUDPSocketProvider::NewSocket(int32_t aFamily,
                                const char *aHost, 
                                int32_t aPort, 
-                               const char *aProxyHost, 
-                               int32_t aProxyPort,
+                               nsIProxyInfo *aProxy,
                                uint32_t aFlags,
                                PRFileDesc * *aFileDesc, 
                                nsISupports **aSecurityInfo)
 {
     NS_ENSURE_ARG_POINTER(aFileDesc);
   
     PRFileDesc* udpFD = PR_OpenUDPSocket(aFamily);
     if (!udpFD)
@@ -31,18 +30,17 @@ nsUDPSocketProvider::NewSocket(int32_t a
     *aFileDesc = udpFD;
     return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsUDPSocketProvider::AddToSocket(int32_t aFamily,
                                  const char *aHost,
                                  int32_t aPort,
-                                 const char *aProxyHost,
-                                 int32_t aProxyPort,
+                                 nsIProxyInfo *aProxy,
                                  uint32_t aFlags,
                                  struct PRFileDesc * aFileDesc,
                                  nsISupports **aSecurityInfo)
 {
     // does not make sense to strap a UDP socket onto an existing socket
     NS_NOTREACHED("Cannot layer UDP socket on an existing socket");
     return NS_ERROR_UNEXPECTED;
 }
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -1812,28 +1812,27 @@ nsSSLIOLayerHelpers::treatUnsafeNegotiat
   MutexAutoLock lock(mutex);
   return mTreatUnsafeNegotiationAsBroken;
 }
 
 nsresult
 nsSSLIOLayerNewSocket(int32_t family,
                       const char* host,
                       int32_t port,
-                      const char* proxyHost,
-                      int32_t proxyPort,
+                      nsIProxyInfo *proxy,
                       PRFileDesc** fd,
                       nsISupports** info,
                       bool forSTARTTLS,
                       uint32_t flags)
 {
 
   PRFileDesc* sock = PR_OpenTCPSocket(family);
   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
 
-  nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
+  nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxy,
                                         sock, info, forSTARTTLS, flags);
   if (NS_FAILED(rv)) {
     PR_Close(sock);
     return rv;
   }
 
   *fd = sock;
   return NS_OK;
@@ -2508,21 +2507,21 @@ loser:
   if (sslSock) {
     PR_Close(sslSock);
   }
   return nullptr;
 }
 
 static nsresult
 nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
-                       const char* proxyHost, const char* host, int32_t port,
+                       bool haveProxy, const char* host, int32_t port,
                        nsNSSSocketInfo* infoObject)
 {
   nsNSSShutDownPreventionLock locker;
-  if (forSTARTTLS || proxyHost) {
+  if (forSTARTTLS || haveProxy) {
     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   SSLVersionRange range;
   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
@@ -2589,18 +2588,17 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
 
   return NS_OK;
 }
 
 nsresult
 nsSSLIOLayerAddToSocket(int32_t family,
                         const char* host,
                         int32_t port,
-                        const char* proxyHost,
-                        int32_t proxyPort,
+                        nsIProxyInfo* proxy,
                         PRFileDesc* fd,
                         nsISupports** info,
                         bool forSTARTTLS,
                         uint32_t providerFlags)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* layer = nullptr;
   PRFileDesc* plaintextLayer = nullptr;
@@ -2612,16 +2610,23 @@ nsSSLIOLayerAddToSocket(int32_t family,
   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
   if (!infoObject) return NS_ERROR_FAILURE;
 
   NS_ADDREF(infoObject);
   infoObject->SetForSTARTTLS(forSTARTTLS);
   infoObject->SetHostName(host);
   infoObject->SetPort(port);
 
+  bool haveProxy = false;
+  if (proxy) {
+    nsCString proxyHost;
+    proxy->GetHost(proxyHost);
+    haveProxy = !proxyHost.IsEmpty();
+  }
+
   // A plaintext observer shim is inserted so we can observe some protocol
   // details without modifying nss
   plaintextLayer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
                                         &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
   if (plaintextLayer) {
     plaintextLayer->secret = (PRFilePrivate*) infoObject;
     stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
     if (stat == PR_FAILURE) {
@@ -2633,17 +2638,17 @@ nsSSLIOLayerAddToSocket(int32_t family,
   PRFileDesc* sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
   if (!sslSock) {
     NS_ASSERTION(false, "NSS: Error importing socket");
     goto loser;
   }
 
   infoObject->SetFileDescPtr(sslSock);
 
-  rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, proxyHost, host, port,
+  rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host, port,
                               infoObject);
 
   if (NS_FAILED(rv))
     goto loser;
 
   // Now, layer ourselves on top of the SSL socket...
   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
@@ -2656,17 +2661,17 @@ nsSSLIOLayerAddToSocket(int32_t family,
   if (stat == PR_FAILURE) {
     goto loser;
   }
 
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Socket set up\n", (void*) sslSock));
   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
 
   // We are going use a clear connection first //
-  if (forSTARTTLS || proxyHost) {
+  if (forSTARTTLS || haveProxy) {
     infoObject->SetHandshakeNotPending();
   }
 
   infoObject->SharedState().NoteSocketCreated();
 
   return NS_OK;
  loser:
   NS_IF_RELEASE(infoObject);
--- a/security/manager/ssl/nsNSSIOLayer.h
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _NSNSSIOLAYER_H
 #define _NSNSSIOLAYER_H
 
 #include "TransportSecurityInfo.h"
 #include "nsISSLSocketControl.h"
 #include "nsIClientAuthDialogs.h"
+#include "nsIProxyInfo.h"
 #include "nsNSSCertificate.h"
 #include "nsDataHashtable.h"
 #include "nsTHashtable.h"
 #include "mozilla/TimeStamp.h"
 #include "sslt.h"
 
 namespace mozilla {
 namespace psm {
@@ -237,28 +238,26 @@ public:
 private:
   mozilla::Mutex mutex;
   nsCOMPtr<nsIObserver> mPrefObserver;
 };
 
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char* host,
                                int32_t port,
-                               const char* proxyHost,
-                               int32_t proxyPort,
+                               nsIProxyInfo *proxy,
                                PRFileDesc** fd,
                                nsISupports** securityInfo,
                                bool forSTARTTLS,
                                uint32_t flags);
 
 nsresult nsSSLIOLayerAddToSocket(int32_t family,
                                  const char* host,
                                  int32_t port,
-                                 const char* proxyHost,
-                                 int32_t proxyPort,
+                                 nsIProxyInfo *proxy,
                                  PRFileDesc* fd,
                                  nsISupports** securityInfo,
                                  bool forSTARTTLS,
                                  uint32_t flags);
 
 nsresult nsSSLIOLayerFreeTLSIntolerantSites();
 nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo* infoObject, int error);
 
--- a/security/manager/ssl/nsSSLSocketProvider.cpp
+++ b/security/manager/ssl/nsSSLSocketProvider.cpp
@@ -17,49 +17,45 @@ nsSSLSocketProvider::~nsSSLSocketProvide
 }
 
 NS_IMPL_ISUPPORTS(nsSSLSocketProvider, nsISocketProvider)
 
 NS_IMETHODIMP
 nsSSLSocketProvider::NewSocket(int32_t family,
                                const char *host,
                                int32_t port,
-                               const char *proxyHost,
-                               int32_t proxyPort,
+                               nsIProxyInfo *proxy,
                                uint32_t flags,
                                PRFileDesc **_result,
                                nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
-                                      proxyHost,
-                                      proxyPort,
+                                      proxy,
                                       _result,
                                       securityInfo,
                                       false,
                                       flags);
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
 
 // Add the SSL IO layer to an existing socket
 NS_IMETHODIMP
 nsSSLSocketProvider::AddToSocket(int32_t family,
                                  const char *host,
                                  int32_t port,
-                                 const char *proxyHost,
-                                 int32_t proxyPort,
+                                 nsIProxyInfo *proxy,
                                  uint32_t flags,
                                  PRFileDesc *aSocket,
                                  nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
-                                        proxyHost,
-                                        proxyPort,
+                                        proxy,
                                         aSocket,
                                         securityInfo,
                                         false,
                                         flags);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
--- a/security/manager/ssl/nsTLSSocketProvider.cpp
+++ b/security/manager/ssl/nsTLSSocketProvider.cpp
@@ -17,50 +17,46 @@ nsTLSSocketProvider::~nsTLSSocketProvide
 }
 
 NS_IMPL_ISUPPORTS(nsTLSSocketProvider, nsISocketProvider)
 
 NS_IMETHODIMP
 nsTLSSocketProvider::NewSocket(int32_t family,
                                const char *host,
                                int32_t port,
-                               const char *proxyHost,
-                               int32_t proxyPort,
+                               nsIProxyInfo *proxy,
                                uint32_t flags,
                                PRFileDesc **_result,
                                nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
-                                      proxyHost,
-                                      proxyPort,
+                                      proxy,
                                       _result,
                                       securityInfo,
                                       true,
                                       flags);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
 
 // Add the SSL IO layer to an existing socket
 NS_IMETHODIMP
 nsTLSSocketProvider::AddToSocket(int32_t family,
                                  const char *host,
                                  int32_t port,
-                                 const char *proxyHost,
-                                 int32_t proxyPort,
+                                 nsIProxyInfo *proxy,
                                  uint32_t flags,
                                  PRFileDesc *aSocket,
                                  nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
-                                        proxyHost,
-                                        proxyPort,
+                                        proxy,
                                         aSocket,
                                         securityInfo,
                                         true,
                                         flags);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }