/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsProtocolProxyService.h" #include "nsIServiceManager.h" #include "nsXPIDLString.h" #include "nsIProxyAutoConfig.h" #include "nsAutoLock.h" #include "nsIIOService.h" #include "nsIEventQueueService.h" #include "nsIProtocolHandler.h" #include "nsIDNSService.h" #include "nsIPrefService.h" #include "nsIPrefBranchInternal.h" #include "nsReadableUtils.h" #include "nsString.h" #include "nsNetUtil.h" #include "nsCRT.h" #include "prnetdb.h" #include "nsEventQueueUtils.h" #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t') // // apply mask to address (zeros out excluded bits). // // NOTE: we do the byte swapping here to minimize overall swapping. // static void proxy_MaskIPv6Addr(PRIPv6Addr &addr, PRUint16 mask_len) { if (mask_len == 128) return; if (mask_len > 96) { addr.pr_s6_addr32[3] = PR_htonl( PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); } else if (mask_len > 64) { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = PR_htonl( PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); } else if (mask_len > 32) { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = 0; addr.pr_s6_addr32[1] = PR_htonl( PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); } else { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = 0; addr.pr_s6_addr32[1] = 0; addr.pr_s6_addr32[0] = PR_htonl( PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); } } static void proxy_GetStringPref(nsIPrefBranch *aPrefBranch, const char *aPref, nsCString &aResult) { nsXPIDLCString temp; nsresult rv = aPrefBranch->GetCharPref(aPref, getter_Copies(temp)); if (NS_FAILED(rv)) aResult.Truncate(); else { aResult.Assign(temp); // all of our string prefs are hostnames, so we should remove any // whitespace characters that the user might have unknowingly entered. aResult.StripWhitespace(); } } static void proxy_GetIntPref(nsIPrefBranch *aPrefBranch, const char *aPref, PRInt32 &aResult) { PRInt32 temp; nsresult rv = aPrefBranch->GetIntPref(aPref, &temp); if (NS_FAILED(rv)) aResult = -1; else aResult = temp; } NS_IMPL_THREADSAFE_ISUPPORTS3(nsProtocolProxyService, nsIProtocolProxyService, nsIDNSListener, nsIObserver) NS_IMPL_THREADSAFE_ISUPPORTS1(nsProtocolProxyService::nsProxyInfo, nsIProxyInfo) nsProtocolProxyService::nsProtocolProxyService() : mUseProxy(0) , mHTTPProxyPort(-1) , mFTPProxyPort(-1) , mGopherProxyPort(-1) , mHTTPSProxyPort(-1) , mSOCKSProxyPort(-1) , mSOCKSProxyVersion(4) { } nsProtocolProxyService::~nsProtocolProxyService() { if (mFiltersArray.Count() > 0) { mFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); mFiltersArray.Clear(); } } // nsProtocolProxyService methods nsresult nsProtocolProxyService::Init() { // failure to access prefs is non-fatal nsCOMPtr prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefBranch) { // monitor proxy prefs prefBranch->AddObserver("network.proxy", this, PR_FALSE); // read all prefs PrefsChanged(prefBranch, nsnull); } return NS_OK; } NS_IMETHODIMP nsProtocolProxyService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { nsCOMPtr prefs = do_QueryInterface(aSubject); if (prefs) PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get()); return NS_OK; } void nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, const char *pref) { nsresult rv = NS_OK; PRBool reloadPAC = PR_FALSE; nsXPIDLCString tempString; if (!pref || !strcmp(pref, "network.proxy.type")) { PRInt32 type = -1; rv = prefBranch->GetIntPref("network.proxy.type",&type); if (NS_SUCCEEDED(rv)) { // bug 115720 - type 3 is the same as 0 (no proxy), // for ns4.x backwards compatability if (type == 3) { type = 0; // Reset the type so that the dialog looks correct, and we // don't have to handle this case everywhere else // I'm paranoid about a loop of some sort - only do this // if we're enumerating all prefs, and ignore any error if (!pref) prefBranch->SetIntPref("network.proxy.type", 0); } mUseProxy = type; // type == 2 is fixed PAC URL, 4 is WPAD reloadPAC = PR_TRUE; } } if (!pref || !strcmp(pref, "network.proxy.http")) proxy_GetStringPref(prefBranch, "network.proxy.http", mHTTPProxyHost); if (!pref || !strcmp(pref, "network.proxy.http_port")) proxy_GetIntPref(prefBranch, "network.proxy.http_port", mHTTPProxyPort); if (!pref || !strcmp(pref, "network.proxy.ssl")) proxy_GetStringPref(prefBranch, "network.proxy.ssl", mHTTPSProxyHost); if (!pref || !strcmp(pref, "network.proxy.ssl_port")) proxy_GetIntPref(prefBranch, "network.proxy.ssl_port", mHTTPSProxyPort); if (!pref || !strcmp(pref, "network.proxy.ftp")) proxy_GetStringPref(prefBranch, "network.proxy.ftp", mFTPProxyHost); if (!pref || !strcmp(pref, "network.proxy.ftp_port")) proxy_GetIntPref(prefBranch, "network.proxy.ftp_port", mFTPProxyPort); if (!pref || !strcmp(pref, "network.proxy.gopher")) proxy_GetStringPref(prefBranch, "network.proxy.gopher", mGopherProxyHost); if (!pref || !strcmp(pref, "network.proxy.gopher_port")) proxy_GetIntPref(prefBranch, "network.proxy.gopher_port", mGopherProxyPort); if (!pref || !strcmp(pref, "network.proxy.socks")) proxy_GetStringPref(prefBranch, "network.proxy.socks", mSOCKSProxyHost); if (!pref || !strcmp(pref, "network.proxy.socks_port")) proxy_GetIntPref(prefBranch, "network.proxy.socks_port", mSOCKSProxyPort); if (!pref || !strcmp(pref, "network.proxy.socks_version")) { PRInt32 version; proxy_GetIntPref(prefBranch, "network.proxy.socks_version", version); // make sure this preference value remains sane if (version == 5) mSOCKSProxyVersion = 5; else mSOCKSProxyVersion = 4; } if (!pref || !strcmp(pref, "network.proxy.no_proxies_on")) { rv = prefBranch->GetCharPref("network.proxy.no_proxies_on", getter_Copies(tempString)); if (NS_SUCCEEDED(rv)) LoadFilters(tempString.get()); } if ((!pref || !strcmp(pref, "network.proxy.autoconfig_url") || reloadPAC) && (mUseProxy == 2)) { rv = prefBranch->GetCharPref("network.proxy.autoconfig_url", getter_Copies(tempString)); if (NS_SUCCEEDED(rv) && (!reloadPAC || strcmp(tempString.get(), mPACURL.get()))) ConfigureFromPAC(tempString); } if ((!pref || reloadPAC) && (mUseProxy == 4)) ConfigureFromWPAD(); } // this is the main ui thread calling us back, load the pac now void* PR_CALLBACK nsProtocolProxyService::HandlePACLoadEvent(PLEvent* aEvent) { nsresult rv = NS_OK; nsProtocolProxyService *pps = (nsProtocolProxyService *) PL_GetEventOwner(aEvent); if (!pps) { NS_ERROR("HandlePACLoadEvent owner is null"); return NULL; } // create pac js component pps->mPAC = do_CreateInstance(NS_PROXYAUTOCONFIG_CONTRACTID, &rv); if (!pps->mPAC || NS_FAILED(rv)) { NS_ERROR("Cannot load PAC js component"); return NULL; } if (pps->mPACURL.IsEmpty()) { NS_ERROR("HandlePACLoadEvent: js PACURL component is empty"); return NULL; } nsCOMPtr pIOService(do_GetIOService(&rv)); if (!pIOService || NS_FAILED(rv)) { NS_ERROR("Cannot get IO Service"); return NULL; } nsCOMPtr pURI; rv = pIOService->NewURI(pps->mPACURL, nsnull, nsnull, getter_AddRefs(pURI)); if (NS_FAILED(rv)) { NS_ERROR("New URI failed"); return NULL; } rv = pps->mPAC->LoadPACFromURI(pURI, pIOService); if (NS_FAILED(rv)) { NS_ERROR("Load PAC failed"); return NULL; } return NULL; } void PR_CALLBACK nsProtocolProxyService::DestroyPACLoadEvent(PLEvent* aEvent) { nsProtocolProxyService *pps = (nsProtocolProxyService*) PL_GetEventOwner(aEvent); NS_IF_RELEASE(pps); delete aEvent; } PRBool nsProtocolProxyService::CanUseProxy(nsIURI *aURI, PRInt32 defaultPort) { if (mFiltersArray.Count() == 0) return PR_TRUE; PRInt32 port; nsCAutoString host; nsresult rv = aURI->GetAsciiHost(host); if (NS_FAILED(rv) || host.IsEmpty()) return PR_FALSE; rv = aURI->GetPort(&port); if (NS_FAILED(rv)) return PR_FALSE; if (port == -1) port = defaultPort; PRNetAddr addr; PRBool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS); PRIPv6Addr ipv6; if (is_ipaddr) { // convert parsed address to IPv6 if (addr.raw.family == PR_AF_INET) { // convert to IPv4-mapped address PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6); } else if (addr.raw.family == PR_AF_INET6) { // copy the address memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr)); } else { NS_WARNING("unknown address family"); return PR_TRUE; // allow proxying } } PRInt32 index = -1; while (++index < mFiltersArray.Count()) { HostInfo *hinfo = (HostInfo *) mFiltersArray[index]; if (is_ipaddr != hinfo->is_ipaddr) continue; if (hinfo->port && hinfo->port != port) continue; if (is_ipaddr) { // generate masked version of target IPv6 address PRIPv6Addr masked; memcpy(&masked, &ipv6, sizeof(PRIPv6Addr)); proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len); // check for a match if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0) return PR_FALSE; // proxy disallowed } else { PRUint32 host_len = host.Length(); PRUint32 filter_host_len = hinfo->name.host_len; if (host_len >= filter_host_len) { // // compare last |filter_host_len| bytes of target hostname. // const char *host_tail = host.get() + host_len - filter_host_len; if (!PL_strncasecmp(host_tail, hinfo->name.host, filter_host_len)) return PR_FALSE; // proxy disallowed } } } return PR_TRUE; } static const char kProxyType_HTTP[] = "http"; static const char kProxyType_PROXY[] = "proxy"; static const char kProxyType_SOCKS[] = "socks"; static const char kProxyType_SOCKS4[] = "socks4"; static const char kProxyType_SOCKS5[] = "socks5"; static const char kProxyType_DIRECT[] = "direct"; const char * nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, nsProxyInfo **result) { // see BNF in nsIProxyAutoConfig.idl *result = nsnull; // find end of proxy info delimiter const char *end = start; while (*end && *end != ';') ++end; // find end of proxy type delimiter const char *sp = start; while (sp < end && *sp != ' ' && *sp != '\t') ++sp; PRUint32 len = sp - start; const char *type = nsnull; switch (len) { case 5: if (permitHttp && PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) type = kProxyType_HTTP; else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) type = kProxyType_SOCKS4; // assume v4 for 4x compat break; case 6: if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0) type = kProxyType_DIRECT; else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0) type = kProxyType_SOCKS4; else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0) // map "SOCKS5" to "socks" to match contract-id of registered // SOCKS-v5 socket provider. type = kProxyType_SOCKS; break; } if (type) { const char *host = nsnull, *hostEnd = nsnull; PRInt32 port = -1; // extract host:port start = sp; while ((*start == ' ' || *start == '\t') && start < end) start++; if (start < end) { host = start; hostEnd = strchr(host, ':'); if (!hostEnd || hostEnd > end) { hostEnd = end; // no port, so assume default if (type == kProxyType_HTTP) port = 80; else port = 1080; } else port = atoi(hostEnd + 1); } nsProxyInfo *pi = new nsProxyInfo; if (pi) { pi->mType = type; // YES, it is ok to specify a null proxy host. if (host) { pi->mHost = PL_strndup(host, hostEnd - host); pi->mPort = port; } NS_ADDREF(*result = pi); } } while (*end == ';' || *end == ' ' || *end == '\t') ++end; return end; } // nsIProtocolProxyService NS_IMETHODIMP nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult) { nsresult rv = NS_OK; NS_ASSERTION(aURI, "need a uri folks."); *aResult = nsnull; nsCAutoString scheme; rv = aURI->GetScheme(scheme); if (NS_FAILED(rv)) return rv; PRUint32 flags; PRInt32 defaultPort; rv = GetProtocolInfo(scheme.get(), flags, defaultPort); if (NS_FAILED(rv)) return rv; if (!(flags & nsIProtocolHandler::ALLOWS_PROXY)) return NS_OK; // Can't proxy this // if proxies are enabled and this host:port combo is // supposed to use a proxy, check for a proxy. if (0 == mUseProxy || (1 == mUseProxy && !CanUseProxy(aURI, defaultPort))) return NS_OK; // proxy info values const char *type = nsnull; char *host = nsnull; PRInt32 port = -1; // Proxy auto config magic... if (2 == mUseProxy || 4 == mUseProxy) { if (!mPAC) { NS_ERROR("ERROR: PAC js component is null, assuming DIRECT"); return NS_OK; // assume DIRECT connection for now } nsCAutoString proxyStr; rv = mPAC->GetProxyForURI(aURI, proxyStr); if (NS_SUCCEEDED(rv)) { PRBool permitHttp = (flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP); nsProxyInfo *pi, *last = nsnull; const char *p = proxyStr.get(); while (*p) { p = ExtractProxyInfo(p, permitHttp, &pi); if (pi) { if (last) last->mNext = pi; else NS_ADDREF(*aResult = pi); last = pi; } } // if only DIRECT was specified then return no proxy info. if (last && *aResult == last && last->mType == kProxyType_DIRECT) NS_RELEASE(*aResult); } return NS_OK; } if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 && scheme.Equals(NS_LITERAL_CSTRING("http"))) { host = ToNewCString(mHTTPProxyHost); type = kProxyType_HTTP; port = mHTTPProxyPort; } else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 && scheme.Equals(NS_LITERAL_CSTRING("https"))) { host = ToNewCString(mHTTPSProxyHost); type = kProxyType_HTTP; port = mHTTPSProxyPort; } else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 && scheme.Equals(NS_LITERAL_CSTRING("ftp"))) { host = ToNewCString(mFTPProxyHost); type = kProxyType_HTTP; port = mFTPProxyPort; } else if (!mGopherProxyHost.IsEmpty() && mGopherProxyPort > 0 && scheme.Equals(NS_LITERAL_CSTRING("gopher"))) { host = ToNewCString(mGopherProxyHost); type = kProxyType_HTTP; port = mGopherProxyPort; } else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { host = ToNewCString(mSOCKSProxyHost); if (mSOCKSProxyVersion == 4) type = kProxyType_SOCKS4; else type = kProxyType_SOCKS; port = mSOCKSProxyPort; } if (type) return NewProxyInfo_Internal(type, host, port, aResult); return NS_OK; } NS_IMETHODIMP nsProtocolProxyService::NewProxyInfo(const char *aType, const char *aHost, PRInt32 aPort, nsIProxyInfo **aResult) { static const char *types[] = { kProxyType_HTTP, kProxyType_SOCKS, kProxyType_SOCKS4 }; // resolve type; this allows us to avoid copying the type string into each // proxy info instance. we just reference the string literals directly :) const char *type = nsnull; for (PRUint32 i=0; i eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID); if (!eqs) { NS_ERROR("Failed to get EventQueue service"); return rv; } // get ui thread's event queue nsCOMPtr eq = nsnull; rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq)); if (NS_FAILED(rv) || !eqs) { NS_ERROR("Failed to get UI EventQueue"); return rv; } // create an event PLEvent* event = new PLEvent; // AddRef this because it is being placed in the PLEvent struct // It will be Released when DestroyPACLoadEvent is called NS_ADDREF_THIS(); PL_InitEvent(event, this, nsProtocolProxyService::HandlePACLoadEvent, nsProtocolProxyService::DestroyPACLoadEvent); // post the event into the ui event queue rv = eq->PostEvent(event); if (NS_FAILED(rv)) { NS_ERROR("Failed to post PAC load event to UI EventQueue"); PL_DestroyEvent(event); } return rv; } NS_IMETHODIMP nsProtocolProxyService::GetProxyEnabled(PRBool *enabled) { NS_ENSURE_ARG_POINTER(enabled); *enabled = mUseProxy; return NS_OK; } PRBool PR_CALLBACK nsProtocolProxyService::CleanupFilterArray(void *aElement, void *aData) { if (aElement) delete (HostInfo *) aElement; return PR_TRUE; } void nsProtocolProxyService::LoadFilters(const char *filters) { // check to see the owners flag? /!?/ TODO if (mFiltersArray.Count() > 0) { mFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); mFiltersArray.Clear(); } if (!filters) return; // fail silently... // // filter = ( host | domain | ipaddr ["/" mask] ) [":" port] // filters = filter *( "," LWS filter) // while (*filters) { // skip over spaces and , while (*filters && (*filters == ',' || IS_ASCII_SPACE(*filters))) filters++; const char *starthost = filters; const char *endhost = filters + 1; // at least that... const char *portLocation = 0; const char *maskLocation = 0; // // XXX this needs to be fixed to support IPv6 address literals, // which in this context will need to be []-escaped. // while (*endhost && (*endhost != ',' && !IS_ASCII_SPACE(*endhost))) { if (*endhost == ':') portLocation = endhost; else if (*endhost == '/') maskLocation = endhost; endhost++; } filters = endhost; // advance iterator up front HostInfo *hinfo = new HostInfo(); if (!hinfo) return; // fail silently hinfo->port = portLocation ? atoi(portLocation + 1) : 0; // locate end of host const char *end = maskLocation ? maskLocation : portLocation ? portLocation : endhost; nsCAutoString str(starthost, end - starthost); PRNetAddr addr; if (PR_StringToNetAddr(str.get(), &addr) == PR_SUCCESS) { hinfo->is_ipaddr = PR_TRUE; hinfo->ip.family = PR_AF_INET6; // we always store address as IPv6 hinfo->ip.mask_len = maskLocation ? atoi(maskLocation + 1) : 128; if (hinfo->ip.mask_len == 0) { NS_WARNING("invalid mask"); goto loser; } if (addr.raw.family == PR_AF_INET) { // convert to IPv4-mapped address PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr); // adjust mask_len accordingly if (hinfo->ip.mask_len <= 32) hinfo->ip.mask_len += 96; } else if (addr.raw.family == PR_AF_INET6) { // copy the address memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr)); } else { NS_WARNING("unknown address family"); goto loser; } // apply mask to IPv6 address proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len); } else { PRUint32 startIndex, endIndex; if (str.First() == '*') startIndex = 1; // *.domain -> .domain else startIndex = 0; endIndex = (portLocation ? portLocation : endhost) - starthost; hinfo->is_ipaddr = PR_FALSE; hinfo->name.host = ToNewCString(Substring(str, startIndex, endIndex)); if (!hinfo->name.host) goto loser; hinfo->name.host_len = endIndex - startIndex; } //#define DEBUG_DUMP_FILTERS #ifdef DEBUG_DUMP_FILTERS printf("loaded filter[%u]:\n", mFiltersArray.Count()); printf(" is_ipaddr = %u\n", hinfo->is_ipaddr); printf(" port = %u\n", hinfo->port); if (hinfo->is_ipaddr) { printf(" ip.family = %x\n", hinfo->ip.family); printf(" ip.mask_len = %u\n", hinfo->ip.mask_len); PRNetAddr netAddr; PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr); memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr)); char buf[256]; PR_NetAddrToString(&netAddr, buf, sizeof(buf)); printf(" ip.addr = %s\n", buf); } else { printf(" name.host = %s\n", hinfo->name.host); } #endif mFiltersArray.AppendElement(hinfo); hinfo = NULL; loser: if (hinfo) delete hinfo; } } nsresult nsProtocolProxyService::GetProtocolInfo(const char *aScheme, PRUint32 &aFlags, PRInt32 &defaultPort) { nsresult rv; if (!mIOService) { mIOService = do_GetIOService(&rv); if (NS_FAILED(rv)) return rv; } nsCOMPtr handler; rv = mIOService->GetProtocolHandler(aScheme, getter_AddRefs(handler)); if (NS_FAILED(rv)) return rv; rv = handler->GetProtocolFlags(&aFlags); if (NS_FAILED(rv)) return rv; return handler->GetDefaultPort(&defaultPort); } nsresult nsProtocolProxyService::NewProxyInfo_Internal(const char *aType, char *aHost, PRInt32 aPort, nsIProxyInfo **aResult) { nsProxyInfo *proxyInfo = nsnull; NS_NEWXPCOM(proxyInfo, nsProxyInfo); if (!proxyInfo) return NS_ERROR_OUT_OF_MEMORY; proxyInfo->mType = aType; proxyInfo->mHost = aHost; proxyInfo->mPort = aPort; NS_ADDREF(*aResult = proxyInfo); return NS_OK; } void nsProtocolProxyService::ConfigureFromWPAD() { nsCOMPtr dnsService = do_GetService(NS_DNSSERVICE_CONTRACTID); if (!dnsService) { NS_ERROR("Can't run WPAD: no DNS service?"); return; } // Asynchronously resolve "wpad", configuring from PAC if we find one (in our // OnLookupComplete method). // // We diverge from the WPAD spec here in that we don't walk the hosts's // FQDN, stripping components until we hit a TLD. Doing so is dangerous in // the face of an incomplete list of TLDs, and TLDs get added over time. We // could consider doing only a single substitution of the first component, // if that proves to help compatibility. nsresult rv; nsCOMPtr curQ; rv = NS_GetCurrentEventQ(getter_AddRefs(curQ)); if (NS_FAILED(rv)) { NS_ERROR("Can't run WPAD: can't get event queue for async resolve!"); return; } nsCOMPtr request; rv = dnsService->AsyncResolve(NS_LITERAL_CSTRING("wpad"), nsIDNSService::RESOLVE_BYPASS_CACHE, this, curQ, getter_AddRefs(request)); if (NS_FAILED(rv)) { NS_ERROR("Can't run WPAD: AsyncResolve failed"); } } NS_IMETHODIMP nsProtocolProxyService::OnLookupComplete(nsIDNSRequest *aRequest, nsIDNSRecord *aRecord, nsresult aStatus) { if (aRecord) ConfigureFromPAC("http://wpad/wpad.dat"); return NS_OK; }