LCOV - code coverage report
Current view: directory - netwerk/base/src - nsProtocolProxyService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 696 547 78.6 %
Date: 2012-06-02 Functions: 52 50 96.2 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim:set ts=4 sw=4 sts=4 et: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *  Malcolm Smith <malsmith@cs.rmit.edu.au>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "mozilla/Util.h"
      41                 : 
      42                 : #include "nsProtocolProxyService.h"
      43                 : #include "nsProxyInfo.h"
      44                 : #include "nsIClassInfoImpl.h"
      45                 : #include "nsIServiceManager.h"
      46                 : #include "nsXPIDLString.h"
      47                 : #include "nsIProxyAutoConfig.h"
      48                 : #include "nsIIOService.h"
      49                 : #include "nsIObserverService.h"
      50                 : #include "nsIProtocolHandler.h"
      51                 : #include "nsIProtocolProxyCallback.h"
      52                 : #include "nsICancelable.h"
      53                 : #include "nsIDNSService.h"
      54                 : #include "nsIPrefService.h"
      55                 : #include "nsIPrefBranch.h"
      56                 : #include "nsReadableUtils.h"
      57                 : #include "nsThreadUtils.h"
      58                 : #include "nsString.h"
      59                 : #include "nsNetUtil.h"
      60                 : #include "nsNetCID.h"
      61                 : #include "nsCRT.h"
      62                 : #include "prnetdb.h"
      63                 : #include "nsPACMan.h"
      64                 : 
      65                 : //----------------------------------------------------------------------------
      66                 : 
      67                 : using namespace mozilla;
      68                 : 
      69                 : #include "prlog.h"
      70                 : #if defined(PR_LOGGING)
      71            1464 : static PRLogModuleInfo *sLog = PR_NewLogModule("proxy");
      72                 : #endif
      73                 : #define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
      74                 : 
      75                 : //----------------------------------------------------------------------------
      76                 : 
      77                 : #define PROXY_PREF_BRANCH  "network.proxy"
      78                 : #define PROXY_PREF(x)      PROXY_PREF_BRANCH "." x
      79                 : 
      80                 : #define WPAD_URL "http://wpad/wpad.dat"
      81                 : 
      82                 : //----------------------------------------------------------------------------
      83                 : 
      84                 : // This structure is intended to be allocated on the stack
      85            7152 : struct nsProtocolInfo {
      86                 :     nsCAutoString scheme;
      87                 :     PRUint32 flags;
      88                 :     PRInt32 defaultPort;
      89                 : };
      90                 : 
      91                 : //----------------------------------------------------------------------------
      92                 : 
      93                 : class nsAsyncResolveRequest : public nsIRunnable
      94                 :                             , public nsPACManCallback 
      95                 :                             , public nsICancelable
      96              12 : {
      97                 : public:
      98                 :     NS_DECL_ISUPPORTS
      99                 : 
     100              12 :     nsAsyncResolveRequest(nsProtocolProxyService *pps, nsIURI *uri,
     101                 :                           PRUint32 aResolveFlags,
     102                 :                           nsIProtocolProxyCallback *callback)
     103                 :         : mStatus(NS_OK)
     104                 :         , mDispatched(false)
     105                 :         , mResolveFlags(0)
     106                 :         , mPPS(pps)
     107                 :         , mURI(uri)
     108              12 :         , mCallback(callback)
     109                 :     {
     110              12 :         NS_ASSERTION(mCallback, "null callback");
     111              12 :     }
     112                 : 
     113               2 :     void SetResult(nsresult status, nsIProxyInfo *pi)
     114                 :     {
     115               2 :         mStatus = status;
     116               2 :         mProxyInfo = pi;
     117               2 :     }
     118                 : 
     119               2 :     NS_IMETHOD Run()
     120                 :     {
     121               2 :         if (mCallback)
     122               2 :             DoCallback();
     123               2 :         return NS_OK;
     124                 :     }
     125                 : 
     126               1 :     NS_IMETHOD Cancel(nsresult reason)
     127                 :     {
     128               1 :         NS_ENSURE_ARG(NS_FAILED(reason));
     129                 : 
     130                 :         // If we've already called DoCallback then, nothing more to do.
     131               1 :         if (!mCallback)
     132               0 :             return NS_OK;
     133                 : 
     134               1 :         SetResult(reason, nsnull);
     135               1 :         return DispatchCallback();
     136                 :     }
     137                 : 
     138               2 :     nsresult DispatchCallback()
     139                 :     {
     140               2 :         if (mDispatched)  // Only need to dispatch once
     141               0 :             return NS_OK;
     142                 : 
     143               2 :         nsresult rv = NS_DispatchToCurrentThread(this);
     144               2 :         if (NS_FAILED(rv))
     145               0 :             NS_WARNING("unable to dispatch callback event");
     146                 :         else {
     147               2 :             mDispatched = true;
     148               2 :             return NS_OK;
     149                 :         }
     150                 : 
     151               0 :         mCallback = nsnull;  // break possible reference cycle
     152               0 :         return rv;
     153                 :     }
     154                 : 
     155                 : private:
     156                 : 
     157                 :     // Called asynchronously, so we do not need to post another PLEvent
     158                 :     // before calling DoCallback.
     159              11 :     void OnQueryComplete(nsresult status, const nsCString &pacString)
     160                 :     {
     161                 :         // If we've already called DoCallback then, nothing more to do.
     162              11 :         if (!mCallback)
     163               1 :             return;
     164                 : 
     165                 :         // Provided we haven't been canceled...
     166              10 :         if (mStatus == NS_OK) {
     167              10 :             mStatus = status;
     168              10 :             mPACString = pacString;
     169                 :         }
     170                 : 
     171                 :         // In the cancelation case, we may still have another PLEvent in
     172                 :         // the queue that wants to call DoCallback.  No need to wait for
     173                 :         // it, just run the callback now.
     174              10 :         DoCallback();
     175                 :     }
     176                 : 
     177              12 :     void DoCallback()
     178                 :     {
     179                 :         // Generate proxy info from the PAC string if appropriate
     180              12 :         if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty())
     181                 :             mPPS->ProcessPACString(mPACString, mResolveFlags,
     182              10 :                                    getter_AddRefs(mProxyInfo));
     183                 : 
     184                 :         // Now apply proxy filters
     185              12 :         if (NS_SUCCEEDED(mStatus)) {
     186              22 :             nsProtocolInfo info;
     187              11 :             mStatus = mPPS->GetProtocolInfo(mURI, &info);
     188              11 :             if (NS_SUCCEEDED(mStatus))
     189              11 :                 mPPS->ApplyFilters(mURI, info, mProxyInfo);
     190                 :             else
     191               0 :                 mProxyInfo = nsnull;
     192                 :         }
     193                 : 
     194              12 :         mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus);
     195              12 :         mCallback = nsnull;  // in case the callback holds an owning ref to us
     196              12 :     }
     197                 : 
     198                 : private:
     199                 : 
     200                 :     nsresult  mStatus;
     201                 :     nsCString mPACString;
     202                 :     bool      mDispatched;
     203                 :     PRUint32  mResolveFlags;
     204                 : 
     205                 :     nsRefPtr<nsProtocolProxyService>   mPPS;
     206                 :     nsCOMPtr<nsIURI>                   mURI;
     207                 :     nsCOMPtr<nsIProtocolProxyCallback> mCallback;
     208                 :     nsCOMPtr<nsIProxyInfo>             mProxyInfo;
     209                 : };
     210                 : 
     211             149 : NS_IMPL_ISUPPORTS2(nsAsyncResolveRequest, nsICancelable, nsIRunnable)
     212                 : 
     213                 : //----------------------------------------------------------------------------
     214                 : 
     215                 : #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t')
     216                 : 
     217                 : //
     218                 : // apply mask to address (zeros out excluded bits).
     219                 : //
     220                 : // NOTE: we do the byte swapping here to minimize overall swapping.
     221                 : //
     222                 : static void
     223             277 : proxy_MaskIPv6Addr(PRIPv6Addr &addr, PRUint16 mask_len)
     224                 : {
     225             277 :     if (mask_len == 128)
     226             277 :         return;
     227                 : 
     228               0 :     if (mask_len > 96) {
     229                 :         addr.pr_s6_addr32[3] = PR_htonl(
     230               0 :                 PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len)));
     231                 :     }
     232               0 :     else if (mask_len > 64) {
     233               0 :         addr.pr_s6_addr32[3] = 0;
     234                 :         addr.pr_s6_addr32[2] = PR_htonl(
     235               0 :                 PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len)));
     236                 :     }
     237               0 :     else if (mask_len > 32) {
     238               0 :         addr.pr_s6_addr32[3] = 0;
     239               0 :         addr.pr_s6_addr32[2] = 0;
     240                 :         addr.pr_s6_addr32[1] = PR_htonl(
     241               0 :                 PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len)));
     242                 :     }
     243                 :     else {
     244               0 :         addr.pr_s6_addr32[3] = 0;
     245               0 :         addr.pr_s6_addr32[2] = 0;
     246               0 :         addr.pr_s6_addr32[1] = 0;
     247                 :         addr.pr_s6_addr32[0] = PR_htonl(
     248               0 :                 PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len)));
     249                 :     }
     250                 : }
     251                 : 
     252                 : static void
     253            1116 : proxy_GetStringPref(nsIPrefBranch *aPrefBranch,
     254                 :                     const char    *aPref,
     255                 :                     nsCString     &aResult)
     256                 : {
     257            2232 :     nsXPIDLCString temp;
     258            1116 :     nsresult rv = aPrefBranch->GetCharPref(aPref, getter_Copies(temp));
     259            1116 :     if (NS_FAILED(rv))
     260               0 :         aResult.Truncate();
     261                 :     else {
     262            1116 :         aResult.Assign(temp);
     263                 :         // all of our string prefs are hostnames, so we should remove any
     264                 :         // whitespace characters that the user might have unknowingly entered.
     265            1116 :         aResult.StripWhitespace();
     266                 :     }
     267            1116 : }
     268                 : 
     269                 : static void
     270            1672 : proxy_GetIntPref(nsIPrefBranch *aPrefBranch,
     271                 :                  const char    *aPref,
     272                 :                  PRInt32       &aResult)
     273                 : {
     274                 :     PRInt32 temp;
     275            1672 :     nsresult rv = aPrefBranch->GetIntPref(aPref, &temp);
     276            1672 :     if (NS_FAILED(rv)) 
     277               0 :         aResult = -1;
     278                 :     else
     279            1672 :         aResult = temp;
     280            1672 : }
     281                 : 
     282                 : static void
     283             278 : proxy_GetBoolPref(nsIPrefBranch *aPrefBranch,
     284                 :                  const char    *aPref,
     285                 :                  bool          &aResult)
     286                 : {
     287                 :     bool temp;
     288             278 :     nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
     289             278 :     if (NS_FAILED(rv)) 
     290               0 :         aResult = false;
     291                 :     else
     292             278 :         aResult = temp;
     293             278 : }
     294                 : 
     295                 : //----------------------------------------------------------------------------
     296                 : 
     297                 : static const PRInt32 PROXYCONFIG_DIRECT4X = 3;
     298                 : static const PRInt32 PROXYCONFIG_COUNT = 6;
     299                 : 
     300            3155 : NS_IMPL_ADDREF(nsProtocolProxyService)
     301            3433 : NS_IMPL_RELEASE(nsProtocolProxyService)
     302                 : NS_IMPL_CLASSINFO(nsProtocolProxyService, NULL, nsIClassInfo::SINGLETON,
     303                 :                   NS_PROTOCOLPROXYSERVICE_CID)
     304             895 : NS_IMPL_QUERY_INTERFACE3_CI(nsProtocolProxyService,
     305                 :                             nsIProtocolProxyService,
     306                 :                             nsIProtocolProxyService2,
     307               1 :                             nsIObserver)
     308               1 : NS_IMPL_CI_INTERFACE_GETTER2(nsProtocolProxyService,
     309                 :                              nsIProtocolProxyService,
     310               1 :                              nsIProtocolProxyService2)
     311                 : 
     312             278 : nsProtocolProxyService::nsProtocolProxyService()
     313                 :     : mFilterLocalHosts(false)
     314                 :     , mFilters(nsnull)
     315                 :     , mProxyConfig(PROXYCONFIG_DIRECT)
     316                 :     , mHTTPProxyPort(-1)
     317                 :     , mFTPProxyPort(-1)
     318                 :     , mHTTPSProxyPort(-1)
     319                 :     , mSOCKSProxyPort(-1)
     320                 :     , mSOCKSProxyVersion(4)
     321                 :     , mSOCKSProxyRemoteDNS(false)
     322                 :     , mPACMan(nsnull)
     323             278 :     , mSessionStart(PR_Now())
     324             556 :     , mFailedProxyTimeout(30 * 60) // 30 minute default
     325                 : {
     326             278 : }
     327                 : 
     328             556 : nsProtocolProxyService::~nsProtocolProxyService()
     329                 : {
     330                 :     // These should have been cleaned up in our Observe method.
     331             278 :     NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters == nsnull &&
     332                 :                  mPACMan == nsnull, "what happened to xpcom-shutdown?");
     333             278 : }
     334                 : 
     335                 : // nsProtocolProxyService methods
     336                 : nsresult
     337             278 : nsProtocolProxyService::Init()
     338                 : {
     339             278 :     if (!mFailedProxies.Init())
     340               0 :         return NS_ERROR_OUT_OF_MEMORY;
     341                 : 
     342                 :     // failure to access prefs is non-fatal
     343                 :     nsCOMPtr<nsIPrefBranch> prefBranch =
     344             556 :             do_GetService(NS_PREFSERVICE_CONTRACTID);
     345             278 :     if (prefBranch) {
     346                 :         // monitor proxy prefs
     347             278 :         prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false);
     348                 : 
     349                 :         // read all prefs
     350             278 :         PrefsChanged(prefBranch, nsnull);
     351                 :     }
     352                 : 
     353                 :     // register for shutdown notification so we can clean ourselves up properly.
     354             556 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     355             278 :     if (obs)
     356             278 :         obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     357                 : 
     358             278 :     return NS_OK;
     359                 : }
     360                 : 
     361                 : NS_IMETHODIMP
     362             304 : nsProtocolProxyService::Observe(nsISupports     *aSubject,
     363                 :                                 const char      *aTopic,
     364                 :                                 const PRUnichar *aData)
     365                 : {
     366             304 :     if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     367                 :         // cleanup
     368             278 :         if (mHostFiltersArray.Length() > 0) {
     369             276 :             mHostFiltersArray.Clear();
     370                 :         }
     371             278 :         if (mFilters) {
     372               0 :             delete mFilters;
     373               0 :             mFilters = nsnull;
     374                 :         }
     375             278 :         if (mPACMan) {
     376              10 :             mPACMan->Shutdown();
     377              10 :             mPACMan = nsnull;
     378                 :         }
     379                 :     }
     380                 :     else {
     381              26 :         NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
     382                 :                      "what is this random observer event?");
     383              52 :         nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
     384              26 :         if (prefs)
     385              26 :             PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get());
     386                 :     }
     387             304 :     return NS_OK;
     388                 : }
     389                 : 
     390                 : void
     391             304 : nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
     392                 :                                      const char    *pref)
     393                 : {
     394             304 :     nsresult rv = NS_OK;
     395             304 :     bool reloadPAC = false;
     396             608 :     nsXPIDLCString tempString;
     397                 : 
     398             304 :     if (!pref || !strcmp(pref, PROXY_PREF("type"))) {
     399             287 :         PRInt32 type = -1;
     400             287 :         rv = prefBranch->GetIntPref(PROXY_PREF("type"), &type);
     401             287 :         if (NS_SUCCEEDED(rv)) {
     402                 :             // bug 115720 - for ns4.x backwards compatibility
     403             287 :             if (type == PROXYCONFIG_DIRECT4X) {
     404               0 :                 type = PROXYCONFIG_DIRECT;
     405                 :                 // Reset the type so that the dialog looks correct, and we
     406                 :                 // don't have to handle this case everywhere else
     407                 :                 // I'm paranoid about a loop of some sort - only do this
     408                 :                 // if we're enumerating all prefs, and ignore any error
     409               0 :                 if (!pref)
     410               0 :                     prefBranch->SetIntPref(PROXY_PREF("type"), type);
     411             287 :             } else if (type >= PROXYCONFIG_COUNT) {
     412               0 :                 LOG(("unknown proxy type: %lu; assuming direct\n", type));
     413               0 :                 type = PROXYCONFIG_DIRECT;
     414                 :             }
     415             287 :             mProxyConfig = type;
     416             287 :             reloadPAC = true;
     417                 :         }
     418                 : 
     419             287 :         if (mProxyConfig == PROXYCONFIG_SYSTEM) {
     420             273 :             mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID);
     421             273 :             if (!mSystemProxySettings)
     422               0 :                 mProxyConfig = PROXYCONFIG_DIRECT;
     423                 :         } else {
     424              14 :             mSystemProxySettings = nsnull;
     425                 :         }
     426                 :     }
     427                 : 
     428             304 :     if (!pref || !strcmp(pref, PROXY_PREF("http")))
     429             281 :         proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost);
     430                 : 
     431             304 :     if (!pref || !strcmp(pref, PROXY_PREF("http_port")))
     432             281 :         proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort);
     433                 : 
     434             304 :     if (!pref || !strcmp(pref, PROXY_PREF("ssl")))
     435             278 :         proxy_GetStringPref(prefBranch, PROXY_PREF("ssl"), mHTTPSProxyHost);
     436                 : 
     437             304 :     if (!pref || !strcmp(pref, PROXY_PREF("ssl_port")))
     438             278 :         proxy_GetIntPref(prefBranch, PROXY_PREF("ssl_port"), mHTTPSProxyPort);
     439                 : 
     440             304 :     if (!pref || !strcmp(pref, PROXY_PREF("ftp")))
     441             278 :         proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost);
     442                 : 
     443             304 :     if (!pref || !strcmp(pref, PROXY_PREF("ftp_port")))
     444             278 :         proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort);
     445                 : 
     446             304 :     if (!pref || !strcmp(pref, PROXY_PREF("socks")))
     447             279 :         proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyHost);
     448                 :     
     449             304 :     if (!pref || !strcmp(pref, PROXY_PREF("socks_port")))
     450             279 :         proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort);
     451                 : 
     452             304 :     if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) {
     453                 :         PRInt32 version;
     454             278 :         proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version);
     455                 :         // make sure this preference value remains sane
     456             278 :         if (version == 5)
     457             278 :             mSOCKSProxyVersion = 5;
     458                 :         else
     459               0 :             mSOCKSProxyVersion = 4;
     460                 :     }
     461                 : 
     462             304 :     if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns")))
     463                 :         proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"),
     464             278 :                           mSOCKSProxyRemoteDNS);
     465                 : 
     466             304 :     if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout")))
     467                 :         proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"),
     468             278 :                          mFailedProxyTimeout);
     469                 : 
     470             304 :     if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) {
     471                 :         rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"),
     472             281 :                                      getter_Copies(tempString));
     473             281 :         if (NS_SUCCEEDED(rv))
     474             281 :             LoadHostFilters(tempString.get());
     475                 :     }
     476                 : 
     477                 :     // We're done if not using something that could give us a PAC URL
     478                 :     // (PAC, WPAD or System)
     479             304 :     if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
     480                 :         mProxyConfig != PROXYCONFIG_SYSTEM)
     481                 :         return;
     482                 : 
     483                 :     // OK, we need to reload the PAC file if:
     484                 :     //  1) network.proxy.type changed, or
     485                 :     //  2) network.proxy.autoconfig_url changed and PAC is configured
     486                 : 
     487             286 :     if (!pref || !strcmp(pref, PROXY_PREF("autoconfig_url")))
     488             283 :         reloadPAC = true;
     489                 : 
     490             286 :     if (reloadPAC) {
     491             286 :         tempString.Truncate();
     492             286 :         if (mProxyConfig == PROXYCONFIG_PAC) {
     493                 :             prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"),
     494              13 :                                     getter_Copies(tempString));
     495             273 :         } else if (mProxyConfig == PROXYCONFIG_WPAD) {
     496                 :             // We diverge from the WPAD spec here in that we don't walk the
     497                 :             // hosts's FQDN, stripping components until we hit a TLD.  Doing so
     498                 :             // is dangerous in the face of an incomplete list of TLDs, and TLDs
     499                 :             // get added over time.  We could consider doing only a single
     500                 :             // substitution of the first component, if that proves to help
     501                 :             // compatibility.
     502               0 :             tempString.AssignLiteral(WPAD_URL);
     503             273 :         } else if (mSystemProxySettings) {
     504                 :             // Get System Proxy settings if available
     505             273 :             mSystemProxySettings->GetPACURI(tempString);
     506                 :         }
     507             286 :         if (!tempString.IsEmpty())
     508              11 :             ConfigureFromPAC(tempString, false);
     509                 :     }
     510                 : }
     511                 : 
     512                 : bool
     513              32 : nsProtocolProxyService::CanUseProxy(nsIURI *aURI, PRInt32 defaultPort) 
     514                 : {
     515              32 :     if (mHostFiltersArray.Length() == 0)
     516               7 :         return true;
     517                 : 
     518                 :     PRInt32 port;
     519              50 :     nsCAutoString host;
     520                 :  
     521              25 :     nsresult rv = aURI->GetAsciiHost(host);
     522              25 :     if (NS_FAILED(rv) || host.IsEmpty())
     523               0 :         return false;
     524                 : 
     525              25 :     rv = aURI->GetPort(&port);
     526              25 :     if (NS_FAILED(rv))
     527               0 :         return false;
     528              25 :     if (port == -1)
     529              25 :         port = defaultPort;
     530                 : 
     531                 :     PRNetAddr addr;
     532              25 :     bool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS);
     533                 : 
     534                 :     PRIPv6Addr ipv6;
     535              25 :     if (is_ipaddr) {
     536                 :         // convert parsed address to IPv6
     537               0 :         if (addr.raw.family == PR_AF_INET) {
     538                 :             // convert to IPv4-mapped address
     539               0 :             PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6);
     540                 :         }
     541               0 :         else if (addr.raw.family == PR_AF_INET6) {
     542                 :             // copy the address
     543               0 :             memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
     544                 :         }
     545                 :         else {
     546               0 :             NS_WARNING("unknown address family");
     547               0 :             return true; // allow proxying
     548                 :         }
     549                 :     }
     550                 :     
     551                 :     // Don't use proxy for local hosts (plain hostname, no dots)
     552              25 :     if (!is_ipaddr && mFilterLocalHosts && (kNotFound == host.FindChar('.'))) {
     553               0 :         LOG(("Not using proxy for this local host [%s]!\n", host.get()));
     554               0 :         return false; // don't allow proxying
     555                 :     }
     556                 : 
     557              25 :     PRInt32 index = -1;
     558              91 :     while (++index < PRInt32(mHostFiltersArray.Length())) {
     559              56 :         HostInfo *hinfo = mHostFiltersArray[index];
     560                 : 
     561              56 :         if (is_ipaddr != hinfo->is_ipaddr)
     562               3 :             continue;
     563              53 :         if (hinfo->port && hinfo->port != port)
     564               0 :             continue;
     565                 : 
     566              53 :         if (is_ipaddr) {
     567                 :             // generate masked version of target IPv6 address
     568                 :             PRIPv6Addr masked;
     569               0 :             memcpy(&masked, &ipv6, sizeof(PRIPv6Addr));
     570               0 :             proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len);
     571                 : 
     572                 :             // check for a match
     573               0 :             if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0)
     574               0 :                 return false; // proxy disallowed
     575                 :         }
     576                 :         else {
     577              53 :             PRUint32 host_len = host.Length();
     578              53 :             PRUint32 filter_host_len = hinfo->name.host_len;
     579                 : 
     580              53 :             if (host_len >= filter_host_len) {
     581                 :                 //
     582                 :                 // compare last |filter_host_len| bytes of target hostname.
     583                 :                 //
     584              53 :                 const char *host_tail = host.get() + host_len - filter_host_len;
     585              53 :                 if (!PL_strncasecmp(host_tail, hinfo->name.host, filter_host_len))
     586              15 :                     return false; // proxy disallowed
     587                 :             }
     588                 :         }
     589                 :     }
     590              10 :     return true;
     591                 : }
     592                 : 
     593                 : static const char kProxyType_HTTP[]    = "http";
     594                 : static const char kProxyType_PROXY[]   = "proxy";
     595                 : static const char kProxyType_SOCKS[]   = "socks";
     596                 : static const char kProxyType_SOCKS4[]  = "socks4";
     597                 : static const char kProxyType_SOCKS5[]  = "socks5";
     598                 : static const char kProxyType_DIRECT[]  = "direct";
     599                 : static const char kProxyType_UNKNOWN[] = "unknown";
     600                 : 
     601                 : const char *
     602            3516 : nsProtocolProxyService::ExtractProxyInfo(const char *start,
     603                 :                                          PRUint32 aResolveFlags,
     604                 :                                          nsProxyInfo **result)
     605                 : {
     606            3516 :     *result = nsnull;
     607            3516 :     PRUint32 flags = 0;
     608                 : 
     609                 :     // see BNF in nsIProxyAutoConfig.idl
     610                 : 
     611                 :     // find end of proxy info delimiter
     612            3516 :     const char *end = start;
     613            3516 :     while (*end && *end != ';') ++end;
     614                 : 
     615                 :     // find end of proxy type delimiter
     616            3516 :     const char *sp = start;
     617            3516 :     while (sp < end && *sp != ' ' && *sp != '\t') ++sp;
     618                 : 
     619            3516 :     PRUint32 len = sp - start;
     620            3516 :     const char *type = nsnull;
     621            3516 :     switch (len) {
     622                 :     case 5:
     623              10 :         if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0)
     624              10 :             type = kProxyType_HTTP;
     625               0 :         else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0)
     626               0 :             type = kProxyType_SOCKS4; // assume v4 for 4x compat
     627              10 :         break;
     628                 :     case 6:
     629            3506 :         if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0)
     630            3506 :             type = kProxyType_DIRECT;
     631               0 :         else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0)
     632               0 :             type = kProxyType_SOCKS4;
     633               0 :         else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0)
     634                 :             // map "SOCKS5" to "socks" to match contract-id of registered
     635                 :             // SOCKS-v5 socket provider.
     636               0 :             type = kProxyType_SOCKS;
     637            3506 :         break;
     638                 :     }
     639            3516 :     if (type) {
     640            3516 :         const char *host = nsnull, *hostEnd = nsnull;
     641            3516 :         PRInt32 port = -1;
     642                 : 
     643                 :         // If it's a SOCKS5 proxy, do name resolution on the server side.
     644                 :         // We could use this with SOCKS4a servers too, but they might not
     645                 :         // support it.
     646            3516 :         if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS)
     647               0 :             flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
     648                 : 
     649                 :         // extract host:port
     650            3516 :         start = sp;
     651            7042 :         while ((*start == ' ' || *start == '\t') && start < end)
     652              10 :             start++;
     653            3516 :         if (start < end) {
     654              10 :             host = start;
     655              10 :             hostEnd = strchr(host, ':');
     656              10 :             if (!hostEnd || hostEnd > end) {
     657               0 :                 hostEnd = end;
     658                 :                 // no port, so assume default
     659               0 :                 if (type == kProxyType_HTTP)
     660               0 :                     port = 80;
     661                 :                 else
     662               0 :                     port = 1080;
     663                 :             }
     664                 :             else
     665              10 :                 port = atoi(hostEnd + 1);
     666                 :         }
     667            3516 :         nsProxyInfo *pi = new nsProxyInfo;
     668            3516 :         if (pi) {
     669            3516 :             pi->mType = type;
     670            3516 :             pi->mFlags = flags;
     671            3516 :             pi->mResolveFlags = aResolveFlags;
     672            3516 :             pi->mTimeout = mFailedProxyTimeout;
     673                 :             // YES, it is ok to specify a null proxy host.
     674            3516 :             if (host) {
     675              10 :                 pi->mHost.Assign(host, hostEnd - host);
     676              10 :                 pi->mPort = port;
     677                 :             }
     678            3516 :             NS_ADDREF(*result = pi);
     679                 :         }
     680                 :     }
     681                 : 
     682            7042 :     while (*end == ';' || *end == ' ' || *end == '\t')
     683              10 :         ++end;
     684            3516 :     return end;
     685                 : }
     686                 : 
     687                 : void
     688           10650 : nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key)
     689                 : {
     690           10650 :     key.AssignASCII(pi->mType);
     691           10650 :     if (!pi->mHost.IsEmpty()) {
     692              95 :         key.Append(' ');
     693              95 :         key.Append(pi->mHost);
     694              95 :         key.Append(':');
     695              95 :         key.AppendInt(pi->mPort);
     696                 :     }
     697           10650 : } 
     698                 : 
     699                 : PRUint32
     700               2 : nsProtocolProxyService::SecondsSinceSessionStart()
     701                 : {
     702               2 :     PRTime now = PR_Now();
     703                 : 
     704                 :     // get time elapsed since session start
     705                 :     PRInt64 diff;
     706               2 :     LL_SUB(diff, now, mSessionStart);
     707                 : 
     708                 :     // convert microseconds to seconds
     709                 :     PRTime ups;
     710               2 :     LL_I2L(ups, PR_USEC_PER_SEC);
     711               2 :     LL_DIV(diff, diff, ups);
     712                 : 
     713                 :     // convert to 32 bit value
     714                 :     PRUint32 dsec;
     715               2 :     LL_L2UI(dsec, diff);
     716                 : 
     717               2 :     return dsec;
     718                 : }
     719                 : 
     720                 : void
     721            3552 : nsProtocolProxyService::EnableProxy(nsProxyInfo *pi)
     722                 : {
     723            7104 :     nsCAutoString key;
     724            3552 :     GetProxyKey(pi, key);
     725            3552 :     mFailedProxies.Remove(key);
     726            3552 : }
     727                 : 
     728                 : void
     729               2 : nsProtocolProxyService::DisableProxy(nsProxyInfo *pi)
     730                 : {
     731               4 :     nsCAutoString key;
     732               2 :     GetProxyKey(pi, key);
     733                 : 
     734               2 :     PRUint32 dsec = SecondsSinceSessionStart();
     735                 : 
     736                 :     // Add timeout to interval (this is the time when the proxy can
     737                 :     // be tried again).
     738               2 :     dsec += pi->mTimeout;
     739                 : 
     740                 :     // NOTE: The classic codebase would increase the timeout value
     741                 :     //       incrementally each time a subsequent failure occurred.
     742                 :     //       We could do the same, but it would require that we not
     743                 :     //       remove proxy entries in IsProxyDisabled or otherwise
     744                 :     //       change the way we are recording disabled proxies.
     745                 :     //       Simpler is probably better for now, and at least the
     746                 :     //       user can tune the timeout setting via preferences.
     747                 : 
     748               2 :     LOG(("DisableProxy %s %d\n", key.get(), dsec));
     749                 : 
     750                 :     // If this fails, oh well... means we don't have enough memory
     751                 :     // to remember the failed proxy.
     752               2 :     mFailedProxies.Put(key, dsec);
     753               2 : }
     754                 : 
     755                 : bool
     756            7096 : nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
     757                 : {
     758           14192 :     nsCAutoString key;
     759            7096 :     GetProxyKey(pi, key);
     760                 : 
     761                 :     PRUint32 val;
     762            7096 :     if (!mFailedProxies.Get(key, &val))
     763            7096 :         return false;
     764                 : 
     765               0 :     PRUint32 dsec = SecondsSinceSessionStart();
     766                 : 
     767                 :     // if time passed has exceeded interval, then try proxy again.
     768               0 :     if (dsec > val) {
     769               0 :         mFailedProxies.Remove(key);
     770               0 :         return false;
     771                 :     }
     772                 : 
     773               0 :     return true;
     774                 : }
     775                 : 
     776                 : nsresult
     777             102 : nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec,
     778                 :                                          bool forceReload)
     779                 : {
     780             102 :     if (!mPACMan) {
     781              10 :         mPACMan = new nsPACMan();
     782              10 :         if (!mPACMan)
     783               0 :             return NS_ERROR_OUT_OF_MEMORY;
     784                 :     }
     785                 : 
     786             204 :     nsCOMPtr<nsIURI> pacURI;
     787             102 :     nsresult rv = NS_NewURI(getter_AddRefs(pacURI), spec);
     788             102 :     if (NS_FAILED(rv))
     789               0 :         return rv;
     790                 : 
     791             102 :     if (mPACMan->IsPACURI(pacURI) && !forceReload)
     792              92 :         return NS_OK;
     793                 : 
     794              10 :     mFailedProxies.Clear();
     795                 : 
     796              10 :     return mPACMan->LoadPACFromURI(pacURI);
     797                 : }
     798                 : 
     799                 : void
     800            3511 : nsProtocolProxyService::ProcessPACString(const nsCString &pacString,
     801                 :                                          PRUint32 aResolveFlags,
     802                 :                                          nsIProxyInfo **result)
     803                 : {
     804            3511 :     if (pacString.IsEmpty()) {
     805               0 :         *result = nsnull;
     806               0 :         return;
     807                 :     }
     808                 : 
     809            3511 :     const char *proxies = pacString.get();
     810                 : 
     811            3511 :     nsProxyInfo *pi = nsnull, *first = nsnull, *last = nsnull;
     812           10538 :     while (*proxies) {
     813            3516 :         proxies = ExtractProxyInfo(proxies, aResolveFlags, &pi);
     814            3516 :         if (pi) {
     815            3516 :             if (last) {
     816               5 :                 NS_ASSERTION(last->mNext == nsnull, "leaking nsProxyInfo");
     817               5 :                 last->mNext = pi;
     818                 :             }
     819                 :             else
     820            3511 :                 first = pi;
     821            3516 :             last = pi;
     822                 :         }
     823                 :     }
     824            3511 :     *result = first;
     825                 : }
     826                 : 
     827                 : // nsIProtocolProxyService2
     828                 : NS_IMETHODIMP
     829               6 : nsProtocolProxyService::ReloadPAC()
     830                 : {
     831              12 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     832               6 :     if (!prefs)
     833               0 :         return NS_OK;
     834                 : 
     835                 :     PRInt32 type;
     836               6 :     nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
     837               6 :     if (NS_FAILED(rv))
     838               0 :         return NS_OK;
     839                 : 
     840              12 :     nsXPIDLCString pacSpec;
     841               6 :     if (type == PROXYCONFIG_PAC)
     842               0 :         prefs->GetCharPref(PROXY_PREF("autoconfig_url"), getter_Copies(pacSpec));
     843               6 :     else if (type == PROXYCONFIG_WPAD)
     844               0 :         pacSpec.AssignLiteral(WPAD_URL);
     845                 : 
     846               6 :     if (!pacSpec.IsEmpty())
     847               0 :         ConfigureFromPAC(pacSpec, true);
     848               6 :     return NS_OK;
     849                 : }
     850                 : 
     851                 : // nsIProtocolProxyService
     852                 : NS_IMETHODIMP
     853            3553 : nsProtocolProxyService::Resolve(nsIURI *uri, PRUint32 flags,
     854                 :                                 nsIProxyInfo **result)
     855                 : {
     856            7106 :     nsProtocolInfo info;
     857            3553 :     nsresult rv = GetProtocolInfo(uri, &info);
     858            3553 :     if (NS_FAILED(rv))
     859               0 :         return rv;
     860                 : 
     861                 :     bool usePAC;
     862            3553 :     rv = Resolve_Internal(uri, info, flags, &usePAC, result);
     863            3553 :     if (NS_FAILED(rv)) {
     864               0 :         LOG(("Resolve_Internal returned rv(0x%08x)\n", rv));
     865               0 :         return rv;
     866                 :     }
     867                 : 
     868            3553 :     if (usePAC && mPACMan) {
     869              96 :         NS_ASSERTION(*result == nsnull, "we should not have a result yet");
     870                 : 
     871                 :         // If the caller didn't want us to invoke PAC, then error out.
     872              96 :         if (flags & RESOLVE_NON_BLOCKING)
     873               1 :             return NS_BASE_STREAM_WOULD_BLOCK;
     874                 : 
     875                 :         // Query the PAC file synchronously.
     876             190 :         nsCString pacString;
     877              95 :         rv = mPACMan->GetProxyForURI(uri, pacString);
     878              95 :         if (NS_SUCCEEDED(rv))
     879              84 :             ProcessPACString(pacString, flags, result);
     880              11 :         else if (rv == NS_ERROR_IN_PROGRESS) {
     881                 :             // Construct a special UNKNOWN proxy entry that informs the caller
     882                 :             // that the proxy info is yet to be determined.
     883              11 :             rv = NewProxyInfo_Internal(kProxyType_UNKNOWN, EmptyCString(), -1,
     884              11 :                                        0, 0, nsnull, flags, result);
     885              11 :             if (NS_FAILED(rv))
     886               0 :                 return rv;
     887                 :         }
     888                 :         else
     889               0 :             NS_WARNING("failed querying PAC file; trying DIRECT");
     890                 :     }
     891                 : 
     892            3552 :     ApplyFilters(uri, info, result);
     893            3552 :     return NS_OK;
     894                 : }
     895                 : 
     896                 : NS_IMETHODIMP
     897              12 : nsProtocolProxyService::AsyncResolve(nsIURI *uri, PRUint32 flags,
     898                 :                                      nsIProtocolProxyCallback *callback,
     899                 :                                      nsICancelable **result)
     900                 : {
     901                 :     nsRefPtr<nsAsyncResolveRequest> ctx =
     902              24 :         new nsAsyncResolveRequest(this, uri, flags, callback);
     903              12 :     if (!ctx)
     904               0 :         return NS_ERROR_OUT_OF_MEMORY;
     905                 : 
     906              24 :     nsProtocolInfo info;
     907              12 :     nsresult rv = GetProtocolInfo(uri, &info);
     908              12 :     if (NS_FAILED(rv))
     909               0 :         return rv;
     910                 : 
     911                 :     bool usePAC;
     912              24 :     nsCOMPtr<nsIProxyInfo> pi;
     913              12 :     rv = Resolve_Internal(uri, info, flags, &usePAC, getter_AddRefs(pi));
     914              12 :     if (NS_FAILED(rv))
     915               0 :         return rv;
     916                 : 
     917              12 :     if (!usePAC || !mPACMan) {
     918               1 :         ApplyFilters(uri, info, pi);
     919                 : 
     920               1 :         ctx->SetResult(NS_OK, pi);
     921               1 :         return ctx->DispatchCallback();
     922                 :     }
     923                 : 
     924                 :     // else kick off a PAC query
     925              11 :     rv = mPACMan->AsyncGetProxyForURI(uri, ctx);
     926              11 :     if (NS_SUCCEEDED(rv)) {
     927              11 :         *result = ctx;
     928              11 :         NS_ADDREF(*result);
     929                 :     }
     930              11 :     return rv;
     931                 : }
     932                 : 
     933                 : NS_IMETHODIMP
     934               9 : nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
     935                 :                                      const nsACString &aHost,
     936                 :                                      PRInt32 aPort,
     937                 :                                      PRUint32 aFlags,
     938                 :                                      PRUint32 aFailoverTimeout,
     939                 :                                      nsIProxyInfo *aFailoverProxy,
     940                 :                                      nsIProxyInfo **aResult)
     941                 : {
     942                 :     static const char *types[] = {
     943                 :         kProxyType_HTTP,
     944                 :         kProxyType_SOCKS,
     945                 :         kProxyType_SOCKS4,
     946                 :         kProxyType_DIRECT,
     947                 :         kProxyType_UNKNOWN
     948                 :     };
     949                 : 
     950                 :     // resolve type; this allows us to avoid copying the type string into each
     951                 :     // proxy info instance.  we just reference the string literals directly :)
     952               9 :     const char *type = nsnull;
     953              18 :     for (PRUint32 i=0; i<ArrayLength(types); ++i) {
     954              18 :         if (aType.LowerCaseEqualsASCII(types[i])) {
     955               9 :             type = types[i];
     956               9 :             break;
     957                 :         }
     958                 :     }
     959               9 :     NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG);
     960                 : 
     961               9 :     if (aPort <= 0)
     962               3 :         aPort = -1;
     963                 : 
     964                 :     return NewProxyInfo_Internal(type, aHost, aPort, aFlags, aFailoverTimeout,
     965               9 :                                  aFailoverProxy, 0, aResult);
     966                 : }
     967                 : 
     968                 : NS_IMETHODIMP
     969               2 : nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo  *aProxy,
     970                 :                                             nsIURI        *aURI,
     971                 :                                             nsresult       aStatus,
     972                 :                                             nsIProxyInfo **aResult)
     973                 : {
     974                 :     // We only support failover when a PAC file is configured, either
     975                 :     // directly or via system settings
     976               2 :     if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
     977                 :         mProxyConfig != PROXYCONFIG_SYSTEM)
     978               0 :         return NS_ERROR_NOT_AVAILABLE;
     979                 : 
     980                 :     // Verify that |aProxy| is one of our nsProxyInfo objects.
     981               4 :     nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
     982               2 :     NS_ENSURE_ARG(pi);
     983                 :     // OK, the QI checked out.  We can proceed.
     984                 : 
     985                 :     // Remember that this proxy is down.
     986               2 :     DisableProxy(pi);
     987                 : 
     988                 :     // NOTE: At this point, we might want to prompt the user if we have
     989                 :     //       not already tried going DIRECT.  This is something that the
     990                 :     //       classic codebase supported; however, IE6 does not prompt.
     991                 : 
     992               2 :     if (!pi->mNext)
     993               0 :         return NS_ERROR_NOT_AVAILABLE;
     994                 : 
     995               2 :     LOG(("PAC failover from %s %s:%d to %s %s:%d\n",
     996                 :         pi->mType, pi->mHost.get(), pi->mPort,
     997                 :         pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort));
     998                 : 
     999               2 :     NS_ADDREF(*aResult = pi->mNext);
    1000               2 :     return NS_OK;
    1001                 : }
    1002                 : 
    1003                 : NS_IMETHODIMP
    1004               4 : nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter,
    1005                 :                                        PRUint32 position)
    1006                 : {
    1007               4 :     UnregisterFilter(filter);  // remove this filter if we already have it
    1008                 : 
    1009               4 :     FilterLink *link = new FilterLink(position, filter);
    1010               4 :     if (!link)
    1011               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1012                 : 
    1013               4 :     if (!mFilters) {
    1014               2 :         mFilters = link;
    1015               2 :         return NS_OK;
    1016                 :     }
    1017                 : 
    1018                 :     // insert into mFilters in sorted order
    1019               2 :     FilterLink *last = nsnull;
    1020               3 :     for (FilterLink *iter = mFilters; iter; iter = iter->next) {
    1021               2 :         if (position < iter->position) {
    1022               1 :             if (last) {
    1023               0 :                 link->next = last->next;
    1024               0 :                 last->next = link;
    1025                 :             }
    1026                 :             else {
    1027               1 :                 link->next = mFilters;
    1028               1 :                 mFilters = link;
    1029                 :             }
    1030               1 :             return NS_OK;
    1031                 :         }
    1032               1 :         last = iter;
    1033                 :     }
    1034                 :     // our position is equal to or greater than the last link in the list
    1035               1 :     last->next = link;
    1036               1 :     return NS_OK;
    1037                 : }
    1038                 : 
    1039                 : NS_IMETHODIMP
    1040               8 : nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter *filter)
    1041                 : {
    1042                 :     // QI to nsISupports so we can safely test object identity.
    1043              16 :     nsCOMPtr<nsISupports> givenObject = do_QueryInterface(filter);
    1044                 : 
    1045               8 :     FilterLink *last = nsnull;
    1046              11 :     for (FilterLink *iter = mFilters; iter; iter = iter->next) {
    1047              14 :         nsCOMPtr<nsISupports> object = do_QueryInterface(iter->filter);
    1048               7 :         if (object == givenObject) {
    1049               4 :             if (last)
    1050               1 :                 last->next = iter->next;
    1051                 :             else
    1052               3 :                 mFilters = iter->next;
    1053               4 :             iter->next = nsnull;
    1054               4 :             delete iter;
    1055               4 :             return NS_OK;
    1056                 :         }
    1057              10 :         last = iter;
    1058                 :     }
    1059                 : 
    1060                 :     // No need to throw an exception in this case.
    1061               4 :     return NS_OK;
    1062                 : }
    1063                 : 
    1064                 : NS_IMETHODIMP
    1065               0 : nsProtocolProxyService::GetProxyConfigType(PRUint32* aProxyConfigType)
    1066                 : {
    1067               0 :   *aProxyConfigType = mProxyConfig;
    1068               0 :   return NS_OK;
    1069                 : }
    1070                 : 
    1071                 : void
    1072             281 : nsProtocolProxyService::LoadHostFilters(const char *filters)
    1073                 : {
    1074                 :     // check to see the owners flag? /!?/ TODO
    1075             281 :     if (mHostFiltersArray.Length() > 0) {
    1076               3 :         mHostFiltersArray.Clear();
    1077                 :     }
    1078                 : 
    1079             281 :     if (!filters)
    1080               0 :         return; // fail silently...
    1081                 : 
    1082                 :     //
    1083                 :     // filter  = ( host | domain | ipaddr ["/" mask] ) [":" port] 
    1084                 :     // filters = filter *( "," LWS filter)
    1085                 :     //
    1086                 :     // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string
    1087             281 :     mFilterLocalHosts = false;
    1088            1127 :     while (*filters) {
    1089                 :         // skip over spaces and ,
    1090            1702 :         while (*filters && (*filters == ',' || IS_ASCII_SPACE(*filters)))
    1091             572 :             filters++;
    1092                 : 
    1093             565 :         const char *starthost = filters;
    1094             565 :         const char *endhost = filters + 1; // at least that...
    1095             565 :         const char *portLocation = 0; 
    1096             565 :         const char *maskLocation = 0;
    1097                 : 
    1098            5680 :         while (*endhost && (*endhost != ',' && !IS_ASCII_SPACE(*endhost))) {
    1099            4550 :             if (*endhost == ':')
    1100               0 :                 portLocation = endhost;
    1101            4550 :             else if (*endhost == '/')
    1102               0 :                 maskLocation = endhost;
    1103            4550 :             else if (*endhost == ']') // IPv6 address literals
    1104               0 :                 portLocation = 0;
    1105            4550 :             endhost++;
    1106                 :         }
    1107                 : 
    1108             565 :         filters = endhost; // advance iterator up front
    1109                 : 
    1110                 :         // locate end of host
    1111                 :         const char *end = maskLocation ? maskLocation :
    1112                 :                           portLocation ? portLocation :
    1113             565 :                           endhost;
    1114                 : 
    1115            1130 :         nsCAutoString str(starthost, end - starthost);
    1116                 : 
    1117                 :         // If the current host filter is "<local>", then all local (i.e.
    1118                 :         // no dots in the hostname) hosts should bypass the proxy
    1119             565 :         if (str.EqualsIgnoreCase("<local>")) {
    1120               1 :             mFilterLocalHosts = true;
    1121               1 :             LOG(("loaded filter for local hosts "
    1122                 :                  "(plain host names, no dots)\n"));
    1123                 :             // Continue to next host filter;
    1124               1 :             continue;
    1125                 :         }
    1126                 : 
    1127                 :         // For all other host filters, create HostInfo object and add to list
    1128             564 :         HostInfo *hinfo = new HostInfo();
    1129             564 :         hinfo->port = portLocation ? atoi(portLocation + 1) : 0;
    1130                 : 
    1131                 :         PRNetAddr addr;
    1132             564 :         if (PR_StringToNetAddr(str.get(), &addr) == PR_SUCCESS) {
    1133             277 :             hinfo->is_ipaddr   = true;
    1134             277 :             hinfo->ip.family   = PR_AF_INET6; // we always store address as IPv6
    1135             277 :             hinfo->ip.mask_len = maskLocation ? atoi(maskLocation + 1) : 128;
    1136                 : 
    1137             277 :             if (hinfo->ip.mask_len == 0) {
    1138               0 :                 NS_WARNING("invalid mask");
    1139               0 :                 goto loser;
    1140                 :             }
    1141                 : 
    1142             277 :             if (addr.raw.family == PR_AF_INET) {
    1143                 :                 // convert to IPv4-mapped address
    1144             277 :                 PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr);
    1145                 :                 // adjust mask_len accordingly
    1146             277 :                 if (hinfo->ip.mask_len <= 32)
    1147               0 :                     hinfo->ip.mask_len += 96;
    1148                 :             }
    1149               0 :             else if (addr.raw.family == PR_AF_INET6) {
    1150                 :                 // copy the address
    1151               0 :                 memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr));
    1152                 :             }
    1153                 :             else {
    1154               0 :                 NS_WARNING("unknown address family");
    1155               0 :                 goto loser;
    1156                 :             }
    1157                 : 
    1158                 :             // apply mask to IPv6 address
    1159             277 :             proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len);
    1160                 :         }
    1161                 :         else {
    1162                 :             PRUint32 startIndex, endIndex;
    1163             287 :             if (str.First() == '*')
    1164               0 :                 startIndex = 1; // *.domain -> .domain
    1165                 :             else
    1166             287 :                 startIndex = 0;
    1167             287 :             endIndex = (portLocation ? portLocation : endhost) - starthost;
    1168                 : 
    1169             287 :             hinfo->is_ipaddr = false;
    1170             287 :             hinfo->name.host = ToNewCString(Substring(str, startIndex, endIndex));
    1171                 : 
    1172             287 :             if (!hinfo->name.host)
    1173               0 :                 goto loser;
    1174                 : 
    1175             287 :             hinfo->name.host_len = endIndex - startIndex;
    1176                 :         }
    1177                 : 
    1178                 : //#define DEBUG_DUMP_FILTERS
    1179                 : #ifdef DEBUG_DUMP_FILTERS
    1180                 :         printf("loaded filter[%u]:\n", mHostFiltersArray.Length());
    1181                 :         printf("  is_ipaddr = %u\n", hinfo->is_ipaddr);
    1182                 :         printf("  port = %u\n", hinfo->port);
    1183                 :         if (hinfo->is_ipaddr) {
    1184                 :             printf("  ip.family = %x\n", hinfo->ip.family);
    1185                 :             printf("  ip.mask_len = %u\n", hinfo->ip.mask_len);
    1186                 : 
    1187                 :             PRNetAddr netAddr;
    1188                 :             PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr);
    1189                 :             memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr));
    1190                 : 
    1191                 :             char buf[256];
    1192                 :             PR_NetAddrToString(&netAddr, buf, sizeof(buf));
    1193                 : 
    1194                 :             printf("  ip.addr = %s\n", buf);
    1195                 :         }
    1196                 :         else {
    1197                 :             printf("  name.host = %s\n", hinfo->name.host);
    1198                 :         }
    1199                 : #endif
    1200                 : 
    1201             564 :         mHostFiltersArray.AppendElement(hinfo);
    1202             564 :         hinfo = nsnull;
    1203                 : loser:
    1204             564 :         delete hinfo;
    1205                 :     }
    1206                 : }
    1207                 : 
    1208                 : nsresult
    1209            3576 : nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info)
    1210                 : {
    1211                 :     nsresult rv;
    1212                 : 
    1213            3576 :     rv = uri->GetScheme(info->scheme);
    1214            3576 :     if (NS_FAILED(rv))
    1215               0 :         return rv;
    1216                 : 
    1217            7152 :     nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
    1218            3576 :     if (NS_FAILED(rv))
    1219               0 :         return rv;
    1220                 : 
    1221            7152 :     nsCOMPtr<nsIProtocolHandler> handler;
    1222            3576 :     rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler));
    1223            3576 :     if (NS_FAILED(rv))
    1224               0 :         return rv;
    1225                 : 
    1226            3576 :     rv = handler->GetProtocolFlags(&info->flags);
    1227            3576 :     if (NS_FAILED(rv))
    1228               0 :         return rv;
    1229                 : 
    1230            3576 :     rv = handler->GetDefaultPort(&info->defaultPort);
    1231            3576 :     return rv;
    1232                 : }
    1233                 : 
    1234                 : nsresult
    1235              36 : nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
    1236                 :                                               const nsACString &aHost,
    1237                 :                                               PRInt32 aPort,
    1238                 :                                               PRUint32 aFlags,
    1239                 :                                               PRUint32 aFailoverTimeout,
    1240                 :                                               nsIProxyInfo *aFailoverProxy,
    1241                 :                                               PRUint32 aResolveFlags,
    1242                 :                                               nsIProxyInfo **aResult)
    1243                 : {
    1244              72 :     nsCOMPtr<nsProxyInfo> failover;
    1245              36 :     if (aFailoverProxy) {
    1246               3 :         failover = do_QueryInterface(aFailoverProxy);
    1247               3 :         NS_ENSURE_ARG(failover);
    1248                 :     }
    1249                 : 
    1250              36 :     nsProxyInfo *proxyInfo = new nsProxyInfo();
    1251              36 :     if (!proxyInfo)
    1252               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1253                 : 
    1254              36 :     proxyInfo->mType = aType;
    1255              36 :     proxyInfo->mHost = aHost;
    1256              36 :     proxyInfo->mPort = aPort;
    1257              36 :     proxyInfo->mFlags = aFlags;
    1258              36 :     proxyInfo->mResolveFlags = aResolveFlags;
    1259                 :     proxyInfo->mTimeout = aFailoverTimeout == PR_UINT32_MAX
    1260              36 :         ? mFailedProxyTimeout : aFailoverTimeout;
    1261              36 :     failover.swap(proxyInfo->mNext);
    1262                 : 
    1263              36 :     NS_ADDREF(*aResult = proxyInfo);
    1264              36 :     return NS_OK;
    1265                 : }
    1266                 : 
    1267                 : nsresult
    1268            3565 : nsProtocolProxyService::Resolve_Internal(nsIURI *uri,
    1269                 :                                          const nsProtocolInfo &info,
    1270                 :                                          PRUint32 flags,
    1271                 :                                          bool *usePAC,
    1272                 :                                          nsIProxyInfo **result)
    1273                 : {
    1274            3565 :     NS_ENSURE_ARG_POINTER(uri);
    1275                 : 
    1276            3565 :     *usePAC = false;
    1277            3565 :     *result = nsnull;
    1278                 : 
    1279            3565 :     if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
    1280               0 :         return NS_OK;  // Can't proxy this (filters may not override)
    1281                 : 
    1282            3565 :     if (mSystemProxySettings) {
    1283            7032 :         nsCAutoString PACURI;
    1284            7032 :         if (NS_FAILED(mSystemProxySettings->GetPACURI(PACURI)) ||
    1285            3516 :             PACURI.IsEmpty()) {
    1286            6840 :             nsCAutoString proxy;
    1287            3420 :             nsresult rv = mSystemProxySettings->GetProxyForURI(uri, proxy);
    1288            3420 :             if (NS_SUCCEEDED(rv)) {
    1289            3417 :                 ProcessPACString(proxy, flags, result);
    1290            3417 :                 return NS_OK;
    1291                 :             }
    1292                 :             // no proxy, stop search
    1293               3 :             return NS_OK;
    1294                 :         }
    1295                 : 
    1296                 :         // See bug #586908.
    1297                 :         // Avoid endless loop if |uri| is the current PAC-URI. Returning OK
    1298                 :         // here means that we will not use a proxy for this connection.
    1299              96 :         if (mPACMan && mPACMan->IsPACURI(uri))
    1300               5 :             return NS_OK;
    1301                 : 
    1302                 :         // Switch to new PAC file if that setting has changed. If the setting
    1303                 :         // hasn't changed, ConfigureFromPAC will exit early.
    1304              91 :         nsresult rv = ConfigureFromPAC(PACURI, false);
    1305              91 :         if (NS_FAILED(rv))
    1306               0 :             return rv;
    1307                 :     }
    1308                 : 
    1309                 :     // if proxies are enabled and this host:port combo is supposed to use a
    1310                 :     // proxy, check for a proxy.
    1311             172 :     if (mProxyConfig == PROXYCONFIG_DIRECT ||
    1312                 :         (mProxyConfig == PROXYCONFIG_MANUAL &&
    1313              32 :          !CanUseProxy(uri, info.defaultPort)))
    1314              16 :         return NS_OK;
    1315                 : 
    1316                 :     // Proxy auto config magic...
    1317             124 :     if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD ||
    1318                 :         mProxyConfig == PROXYCONFIG_SYSTEM) {
    1319                 :         // Do not query PAC now.
    1320             107 :         *usePAC = true;
    1321             107 :         return NS_OK;
    1322                 :     }
    1323                 : 
    1324                 :     // proxy info values
    1325              17 :     const char *type = nsnull;
    1326              17 :     const nsACString *host = nsnull;
    1327              17 :     PRInt32 port = -1;
    1328                 : 
    1329              17 :     PRUint32 proxyFlags = 0;
    1330                 : 
    1331              17 :     if ((flags & RESOLVE_PREFER_SOCKS_PROXY) &&
    1332               0 :         !mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) {
    1333               0 :       host = &mSOCKSProxyHost;
    1334               0 :       if (mSOCKSProxyVersion == 4) 
    1335               0 :           type = kProxyType_SOCKS4;
    1336                 :       else
    1337               0 :           type = kProxyType_SOCKS;
    1338               0 :       port = mSOCKSProxyPort;
    1339               0 :       if (mSOCKSProxyRemoteDNS)
    1340               0 :           proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
    1341                 :     }
    1342              17 :     else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) &&
    1343               0 :              !mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0) {
    1344               0 :         host = &mHTTPSProxyHost;
    1345               0 :         type = kProxyType_HTTP;
    1346               0 :         port = mHTTPSProxyPort;
    1347                 :     }
    1348              32 :     else if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 &&
    1349                 :              ((flags & RESOLVE_IGNORE_URI_SCHEME) ||
    1350              15 :               info.scheme.EqualsLiteral("http"))) {
    1351              15 :         host = &mHTTPProxyHost;
    1352              15 :         type = kProxyType_HTTP;
    1353              15 :         port = mHTTPProxyPort;
    1354                 :     }
    1355               2 :     else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 &&
    1356               0 :              !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
    1357               0 :              info.scheme.EqualsLiteral("https")) {
    1358               0 :         host = &mHTTPSProxyHost;
    1359               0 :         type = kProxyType_HTTP;
    1360               0 :         port = mHTTPSProxyPort;
    1361                 :     }
    1362               2 :     else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 &&
    1363               0 :              !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
    1364               0 :              info.scheme.EqualsLiteral("ftp")) {
    1365               0 :         host = &mFTPProxyHost;
    1366               0 :         type = kProxyType_HTTP;
    1367               0 :         port = mFTPProxyPort;
    1368                 :     }
    1369               2 :     else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) {
    1370               1 :         host = &mSOCKSProxyHost;
    1371               1 :         if (mSOCKSProxyVersion == 4) 
    1372               0 :             type = kProxyType_SOCKS4;
    1373                 :         else
    1374               1 :             type = kProxyType_SOCKS;
    1375               1 :         port = mSOCKSProxyPort;
    1376               1 :         if (mSOCKSProxyRemoteDNS)
    1377               0 :             proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
    1378                 :     }
    1379                 : 
    1380              17 :     if (type) {
    1381                 :         nsresult rv = NewProxyInfo_Internal(type, *host, port, proxyFlags,
    1382                 :                                             PR_UINT32_MAX, nsnull, flags,
    1383              16 :                                             result);
    1384              16 :         if (NS_FAILED(rv))
    1385               0 :             return rv;
    1386                 :     }
    1387                 : 
    1388              17 :     return NS_OK;
    1389                 : }
    1390                 : 
    1391                 : void
    1392            3564 : nsProtocolProxyService::ApplyFilters(nsIURI *uri, const nsProtocolInfo &info,
    1393                 :                                      nsIProxyInfo **list)
    1394                 : {
    1395            3564 :     if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
    1396               0 :         return;
    1397                 : 
    1398                 :     // We prune the proxy list prior to invoking each filter.  This may be
    1399                 :     // somewhat inefficient, but it seems like a good idea since we want each
    1400                 :     // filter to "see" a valid proxy list.
    1401                 : 
    1402                 :     nsresult rv;
    1403            7128 :     nsCOMPtr<nsIProxyInfo> result;
    1404                 : 
    1405            3570 :     for (FilterLink *iter = mFilters; iter; iter = iter->next) {
    1406               6 :         PruneProxyInfo(info, list);
    1407                 : 
    1408               6 :         rv = iter->filter->ApplyFilter(this, uri, *list,
    1409               6 :                                        getter_AddRefs(result));
    1410               6 :         if (NS_FAILED(rv))
    1411               0 :             continue;
    1412               6 :         result.swap(*list);
    1413                 :     }
    1414                 : 
    1415            3564 :     PruneProxyInfo(info, list);
    1416                 : }
    1417                 : 
    1418                 : void
    1419            3570 : nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info,
    1420                 :                                        nsIProxyInfo **list)
    1421                 : {
    1422            3570 :     if (!*list)
    1423              26 :         return;
    1424            3544 :     nsProxyInfo *head = nsnull;
    1425            3544 :     CallQueryInterface(*list, &head);
    1426            3544 :     if (!head) {
    1427               0 :         NS_NOTREACHED("nsIProxyInfo must QI to nsProxyInfo");
    1428               0 :         return;
    1429                 :     }
    1430            3544 :     NS_RELEASE(*list);
    1431                 : 
    1432                 :     // Pruning of disabled proxies works like this:
    1433                 :     //   - If all proxies are disabled, return the full list
    1434                 :     //   - Otherwise, remove the disabled proxies.
    1435                 :     //
    1436                 :     // Pruning of disallowed proxies works like this:
    1437                 :     //   - If the protocol handler disallows the proxy, then we disallow it.
    1438                 : 
    1439                 :     // Start by removing all disallowed proxies if required:
    1440            3544 :     if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) {
    1441               1 :         nsProxyInfo *last = nsnull, *iter = head; 
    1442               4 :         while (iter) {
    1443               2 :             if (iter->Type() == kProxyType_HTTP) {
    1444                 :                 // reject!
    1445               1 :                 if (last)
    1446               0 :                     last->mNext = iter->mNext;
    1447                 :                 else
    1448               1 :                     head = iter->mNext;
    1449               1 :                 nsProxyInfo *next = iter->mNext;
    1450               1 :                 iter->mNext = nsnull;
    1451               1 :                 iter->Release();
    1452               1 :                 iter = next;
    1453                 :             } else {
    1454               1 :                 last = iter;
    1455               1 :                 iter = iter->mNext;
    1456                 :             }
    1457                 :         }
    1458               1 :         if (!head)
    1459               0 :             return;
    1460                 :     }
    1461                 : 
    1462                 :     // Now, scan to see if all remaining proxies are disabled.  If so, then
    1463                 :     // we'll just bail and return them all.  Otherwise, we'll go and prune the
    1464                 :     // disabled ones.
    1465                 :     
    1466            3544 :     bool allDisabled = true;
    1467                 : 
    1468                 :     nsProxyInfo *iter;
    1469            3544 :     for (iter = head; iter; iter = iter->mNext) {
    1470            3544 :         if (!IsProxyDisabled(iter)) {
    1471            3544 :             allDisabled = false;
    1472            3544 :             break;
    1473                 :         }
    1474                 :     }
    1475                 : 
    1476            3544 :     if (allDisabled)
    1477               0 :         LOG(("All proxies are disabled, so trying all again"));
    1478                 :     else {
    1479                 :         // remove any disabled proxies.
    1480            3544 :         nsProxyInfo *last = nsnull; 
    1481           10640 :         for (iter = head; iter; ) {
    1482            3552 :             if (IsProxyDisabled(iter)) {
    1483                 :                 // reject!
    1484               0 :                 nsProxyInfo *reject = iter;
    1485                 : 
    1486               0 :                 iter = iter->mNext;
    1487               0 :                 if (last)
    1488               0 :                     last->mNext = iter;
    1489                 :                 else
    1490               0 :                     head = iter;
    1491                 : 
    1492               0 :                 reject->mNext = nsnull;
    1493               0 :                 NS_RELEASE(reject);
    1494               0 :                 continue;
    1495                 :             }
    1496                 : 
    1497                 :             // since we are about to use this proxy, make sure it is not on
    1498                 :             // the disabled proxy list.  we'll add it back to that list if
    1499                 :             // we have to (in GetFailoverForProxy).
    1500                 :             //
    1501                 :             // XXX(darin): It might be better to do this as a final pass.
    1502                 :             //
    1503            3552 :             EnableProxy(iter);
    1504                 : 
    1505            3552 :             last = iter;
    1506            3552 :             iter = iter->mNext;
    1507                 :         }
    1508                 :     }
    1509                 : 
    1510                 :     // if only DIRECT was specified then return no proxy info, and we're done.
    1511            3544 :     if (head && !head->mNext && head->mType == kProxyType_DIRECT)
    1512            3504 :         NS_RELEASE(head);
    1513                 : 
    1514            3544 :     *list = head;  // Transfer ownership
    1515            4392 : }

Generated by: LCOV version 1.7