зеркало из https://github.com/mozilla/gecko-dev.git
Bug 356831 - Proxy autodiscovery doesn't check DHCP (option 252) r=bagder,valentin
This patch addresses an issue with Firefox's proxy detection on networks which do not have their a proxy auto-configuration (PAC) file hosted at http://wpad/wpad.dat, and instead make use of DHCP option 252 for broadcasting the address of the PAC file. See https://findproxyforurl.com/wpad-introduction/ for an introduction to the protocol. Prior to this patch, proxy auto-detect missed out the DHCP query stage, and just looked for a PAC file at http://wpad/wpad.dat This patch only addresses the issue for Firefox on Windows, although it defines a DHCP client interface which could be implemented on other platforms. The high-level components of this patch are: * nsIDHCPClient.idl - this is an interface which has been defined for querying the DHCP server. * nsPACMan.cpp - where previously when the PAC URL was simply set to a constant of http://wpad/wpad.dat, it now dispatches an asynchronous command to the proxy thread. The class ExecutePACThreadAction has been augmented to include an instruction to 'ConfigureWPAD' (Configure Web-proxy auto-detect), and a new class, 'ConfigureWPADComplete' has been created to relay the result (the URL of the PAC file) back to the nsPACMan object. * nsProtocolProxyService.cpp Minor changes to reflect the fact that the PAC URL not being set does not always mean there is no PAC to be used; instead it could be in the process of being detected. * TestPACMan.cpp This is a new file, and tests only the DHCP auto-detect functionality. Some tests use multiple threads, as they test the non-blocking proxy detection. * DHCPUtils.cpp A class containing the main logic for querying DHCP. * WindowsNetworkFunctionsWrapper.cpp A very thin wrapper around the Windows API calls needed by DHCPUtils. This class was introduced so it could be mocked out in tests. * nsWindowsDHCPClient.cpp * An implementation of the interface defined in nsIDHCPClient.idl. Fairly thin: most logic is implemented in DHCPUtils. * TestDHCPUtils.cpp Tests for DHCPUtils and nsWindowsDHCPClient MozReview-Commit-ID: HinC1UevOon --HG-- extra : rebase_source : df2b80fcc03948e54f222e11060e1783f3b95421
This commit is contained in:
Родитель
3e8fd2dc07
Коммит
f95f738f4e
|
@ -2164,6 +2164,7 @@ pref("network.cookie.lifetimePolicy", 0); // 0-accept, 1-dontUse 2-acceptF
|
|||
pref("network.cookie.prefsMigrated", false);
|
||||
pref("network.cookie.lifetime.days", 90); // Ignored unless network.cookie.lifetimePolicy is 3.
|
||||
|
||||
pref("network.proxy.enable_wpad_over_dhcp", true);
|
||||
// The PAC file to load. Ignored unless network.proxy.type is 2.
|
||||
pref("network.proxy.autoconfig_url", "");
|
||||
// Strip off paths when sending URLs to PAC scripts
|
||||
|
|
|
@ -38,6 +38,7 @@ XPIDL_SOURCES += [
|
|||
'nsIDashboard.idl',
|
||||
'nsIDashboardEventNotifier.idl',
|
||||
'nsIDeprecationWarner.idl',
|
||||
'nsIDHCPClient.idl',
|
||||
'nsIDivertableChannel.idl',
|
||||
'nsIDownloader.idl',
|
||||
'nsIEncodedChannel.idl',
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* This interface allows the proxy code to access the DHCP Options in a platform-specific way
|
||||
*/
|
||||
[scriptable, uuid(aee75dc0-be1a-46b9-9e0c-31a6899c175c)]
|
||||
interface nsIDHCPClient : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* returns the DHCP Option designated by the option parameter
|
||||
*/
|
||||
ACString getOption(in uint8_t option);
|
||||
};
|
|
@ -5,17 +5,20 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsPACMan.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIAuthPrompt.h"
|
||||
#include "nsIPromptFactory.h"
|
||||
#include "nsIDHCPClient.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIPromptFactory.h"
|
||||
#include "nsIProtocolProxyService.h"
|
||||
#include "nsISystemProxySettings.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -26,6 +29,8 @@ LazyLogModule gProxyLog("proxy");
|
|||
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gProxyLog, LogLevel::Debug, args)
|
||||
#define MOZ_WPAD_URL "http://wpad/wpad.dat"
|
||||
#define MOZ_DHCP_WPAD_OPTION 252
|
||||
|
||||
// The PAC thread does evaluations of both PAC files and
|
||||
// nsISystemProxySettings because they can both block the calling thread and we
|
||||
|
@ -75,6 +80,26 @@ GetExtraJSContextHeapSize()
|
|||
return extraSize < 0 ? 0 : extraSize;
|
||||
}
|
||||
|
||||
// Read network proxy type from preference
|
||||
// Used to verify that the preference is WPAD in nsPACMan::ConfigureWPAD
|
||||
nsresult
|
||||
GetNetworkProxyTypeFromPref(int32_t* type)
|
||||
{
|
||||
*type = 0;
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
|
||||
if (!prefs) {
|
||||
LOG(("Failed to get a preference service object"));
|
||||
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
}
|
||||
nsresult rv = prefs->GetIntPref("network.proxy.type", type);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
LOG(("Failed to retrieve network.proxy.type from prefs"));
|
||||
return rv;
|
||||
}
|
||||
LOG(("network.proxy.type pref retrieved: %d\n", *type));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -92,12 +117,12 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void SetPACString(const nsCString &pacString)
|
||||
void SetPACString(const nsACString &pacString)
|
||||
{
|
||||
mPACString = pacString;
|
||||
}
|
||||
|
||||
void SetPACURL(const nsCString &pacURL)
|
||||
void SetPACURL(const nsACString &pacURL)
|
||||
{
|
||||
mPACURL = pacURL;
|
||||
}
|
||||
|
@ -191,14 +216,43 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
RefPtr<nsPACMan> mPACMan;
|
||||
RefPtr<nsPACMan> mPACMan;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ConfigureWPADComplete allows the PAC thread to tell the main thread that
|
||||
// the URL for the PAC file has been found
|
||||
class ConfigureWPADComplete final : public Runnable
|
||||
{
|
||||
public:
|
||||
ConfigureWPADComplete(nsPACMan *aPACMan, const nsACString &aPACURISpec)
|
||||
: Runnable("net::ConfigureWPADComplete"),
|
||||
mPACMan(aPACMan),
|
||||
mPACURISpec(aPACURISpec)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
mPACMan->AssignPACURISpec(mPACURISpec);
|
||||
mPACMan->ContinueLoadingAfterPACUriKnown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<nsPACMan> mPACMan;
|
||||
nsCString mPACURISpec;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ExecutePACThreadAction is used to proxy actions from the main
|
||||
// thread onto the PAC thread. There are 3 options: process the queue,
|
||||
// cancel the queue, and setup the javascript context with a new PAC file
|
||||
// thread onto the PAC thread. There are 4 options: process the queue,
|
||||
// cancel the queue, query DHCP for the PAC option
|
||||
// and setup the javascript context with a new PAC file
|
||||
|
||||
class ExecutePACThreadAction final : public Runnable
|
||||
{
|
||||
|
@ -211,6 +265,7 @@ public:
|
|||
, mCancelStatus(NS_OK)
|
||||
, mSetupPAC(false)
|
||||
, mExtraHeapSize(0)
|
||||
, mConfigureWPAD(false)
|
||||
{ }
|
||||
|
||||
void CancelQueue (nsresult status)
|
||||
|
@ -221,7 +276,7 @@ public:
|
|||
|
||||
void SetupPAC (const char *text,
|
||||
uint32_t datalen,
|
||||
nsCString &pacURI,
|
||||
const nsACString &pacURI,
|
||||
uint32_t extraHeapSize)
|
||||
{
|
||||
mSetupPAC = true;
|
||||
|
@ -230,6 +285,11 @@ public:
|
|||
mExtraHeapSize = extraHeapSize;
|
||||
}
|
||||
|
||||
void ConfigureWPAD()
|
||||
{
|
||||
mConfigureWPAD = true;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
|
||||
|
@ -254,6 +314,15 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mConfigureWPAD) {
|
||||
nsAutoCString spec;
|
||||
mConfigureWPAD = false;
|
||||
mPACMan->ConfigureWPAD(spec);
|
||||
RefPtr<ConfigureWPADComplete> runnable = new ConfigureWPADComplete(mPACMan, spec);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mPACMan->ProcessPendingQ();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -266,8 +335,9 @@ private:
|
|||
|
||||
bool mSetupPAC;
|
||||
uint32_t mExtraHeapSize;
|
||||
nsCString mSetupPACData;
|
||||
nsCString mSetupPACURI;
|
||||
nsCString mSetupPACData;
|
||||
nsCString mSetupPACURI;
|
||||
bool mConfigureWPAD;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -288,7 +358,7 @@ PendingPACQuery::PendingPACQuery(nsPACMan* pacMan,
|
|||
}
|
||||
|
||||
void
|
||||
PendingPACQuery::Complete(nsresult status, const nsCString &pacString)
|
||||
PendingPACQuery::Complete(nsresult status, const nsACString &pacString)
|
||||
{
|
||||
if (!mCallback)
|
||||
return;
|
||||
|
@ -301,7 +371,7 @@ PendingPACQuery::Complete(nsresult status, const nsCString &pacString)
|
|||
}
|
||||
|
||||
void
|
||||
PendingPACQuery::UseAlternatePACFile(const nsCString &pacURL)
|
||||
PendingPACQuery::UseAlternatePACFile(const nsACString &pacURL)
|
||||
{
|
||||
if (!mCallback)
|
||||
return;
|
||||
|
@ -336,6 +406,9 @@ nsPACMan::nsPACMan(nsIEventTarget *mainThreadEventTarget)
|
|||
, mShutdown(false)
|
||||
, mLoadFailureCount(0)
|
||||
, mInProgress(false)
|
||||
, mAutoDetect(false)
|
||||
, mWPADOverDHCPEnabled(false)
|
||||
, mProxyConfigType(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "pacman must be created on main thread");
|
||||
if (!sThreadLocalSetup){
|
||||
|
@ -395,7 +468,7 @@ nsPACMan::AsyncGetProxyForURI(nsIURI *uri,
|
|||
TimeStamp::Now() > mScheduledReload) {
|
||||
LOG(("nsPACMan::AsyncGetProxyForURI reload as scheduled\n"));
|
||||
|
||||
LoadPACFromURI(EmptyCString());
|
||||
LoadPACFromURI(EmptyCString(), true);
|
||||
}
|
||||
|
||||
RefPtr<PendingPACQuery> query =
|
||||
|
@ -428,16 +501,15 @@ nsPACMan::PostQuery(PendingPACQuery *query)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsPACMan::LoadPACFromURI(const nsCString &spec)
|
||||
nsPACMan::LoadPACFromURI(const nsACString &aSpec, bool aIsScheduledReload)
|
||||
{
|
||||
NS_ENSURE_STATE(!mShutdown);
|
||||
NS_ENSURE_ARG(!spec.IsEmpty() || !mPACURISpec.IsEmpty());
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> loader =
|
||||
do_CreateInstance(NS_STREAMLOADER_CONTRACTID);
|
||||
NS_ENSURE_STATE(loader);
|
||||
|
||||
LOG(("nsPACMan::LoadPACFromURI %s\n", spec.get()));
|
||||
LOG(("nsPACMan::LoadPACFromURI aSpec: %s, aIsScheduledReload:%s\n", aSpec.BeginReading(), aIsScheduledReload? "true" : "false"));
|
||||
// Since we might get called from nsProtocolProxyService::Init, we need to
|
||||
// post an event back to the main thread before we try to use the IO service.
|
||||
//
|
||||
|
@ -458,11 +530,12 @@ nsPACMan::LoadPACFromURI(const nsCString &spec)
|
|||
CancelExistingLoad();
|
||||
|
||||
mLoader = loader;
|
||||
if (!spec.IsEmpty()) {
|
||||
mPACURISpec = spec;
|
||||
if (!aIsScheduledReload) {
|
||||
mPACURIRedirectSpec.Truncate();
|
||||
mNormalPACURISpec.Truncate(); // set at load time
|
||||
mLoadFailureCount = 0; // reset
|
||||
mAutoDetect = aSpec.IsEmpty();
|
||||
mPACURISpec.Assign(aSpec);
|
||||
}
|
||||
|
||||
// reset to Null
|
||||
|
@ -470,6 +543,56 @@ nsPACMan::LoadPACFromURI(const nsCString &spec)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPACMan::GetPACFromDHCP(nsACString &aSpec)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
|
||||
if (!mDHCPClient) {
|
||||
LOG(("nsPACMan::GetPACFromDHCP DHCP option %d query failed because there is no DHCP client available\n", MOZ_DHCP_WPAD_OPTION));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
nsresult rv;
|
||||
rv = mDHCPClient->GetOption(MOZ_DHCP_WPAD_OPTION, aSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsPACMan::GetPACFromDHCP DHCP option %d query failed with result %d\n", MOZ_DHCP_WPAD_OPTION, (uint32_t)rv));
|
||||
} else {
|
||||
LOG(("nsPACMan::GetPACFromDHCP DHCP option %d query succeeded, finding PAC URL %s\n", MOZ_DHCP_WPAD_OPTION, aSpec.BeginReading()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPACMan::ConfigureWPAD(nsACString &aSpec)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
|
||||
|
||||
MOZ_RELEASE_ASSERT(mProxyConfigType == nsIProtocolProxyService::PROXYCONFIG_WPAD,
|
||||
"WPAD is being executed when not selected by user");
|
||||
|
||||
aSpec.Truncate();
|
||||
if (mWPADOverDHCPEnabled) {
|
||||
GetPACFromDHCP(aSpec);
|
||||
}
|
||||
|
||||
if (aSpec.IsEmpty()) {
|
||||
// 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.
|
||||
aSpec.AssignLiteral(MOZ_WPAD_URL);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPACMan::AssignPACURISpec(const nsACString &aSpec)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
mPACURISpec.Assign(aSpec);
|
||||
}
|
||||
|
||||
void
|
||||
nsPACMan::StartLoading()
|
||||
{
|
||||
|
@ -482,6 +605,29 @@ nsPACMan::StartLoading()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mAutoDetect) {
|
||||
GetNetworkProxyTypeFromPref(&mProxyConfigType);
|
||||
RefPtr<ExecutePACThreadAction> wpadConfigurer =
|
||||
new ExecutePACThreadAction(this);
|
||||
wpadConfigurer->ConfigureWPAD();
|
||||
if (mPACThread) {
|
||||
mPACThread->Dispatch(wpadConfigurer, nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
} else {
|
||||
ContinueLoadingAfterPACUriKnown();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPACMan::ContinueLoadingAfterPACUriKnown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
|
||||
// CancelExistingLoad was called...
|
||||
if (!mLoader) {
|
||||
PostCancelPendingQ(NS_ERROR_ABORT);
|
||||
return;
|
||||
}
|
||||
if (NS_SUCCEEDED(mLoader->Init(this, nullptr))) {
|
||||
// Always hit the origin server when loading PAC.
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
||||
|
@ -799,6 +945,8 @@ nsresult
|
|||
nsPACMan::Init(nsISystemProxySettings *systemProxySettings)
|
||||
{
|
||||
mSystemProxySettings = systemProxySettings;
|
||||
mDHCPClient = do_GetService(NS_DHCPCLIENT_CONTRACTID);
|
||||
|
||||
|
||||
nsresult rv =
|
||||
NS_NewNamedThread("ProxyResolution", getter_AddRefs(mPACThread));
|
||||
|
|
|
@ -7,23 +7,24 @@
|
|||
#ifndef nsPACMan_h__
|
||||
#define nsPACMan_h__
|
||||
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "ProxyAutoConfig.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/net/NeckoTargetHolder.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsString.h"
|
||||
#include "ProxyAutoConfig.h"
|
||||
|
||||
class nsISystemProxySettings;
|
||||
class nsIDHCPClient;
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -52,8 +53,8 @@ public:
|
|||
* newPACURL should be 0 length.
|
||||
*/
|
||||
virtual void OnQueryComplete(nsresult status,
|
||||
const nsCString &pacString,
|
||||
const nsCString &newPACURL) = 0;
|
||||
const nsACString &pacString,
|
||||
const nsACString &newPACURL) = 0;
|
||||
};
|
||||
|
||||
class PendingPACQuery final : public Runnable,
|
||||
|
@ -65,8 +66,8 @@ public:
|
|||
bool mainThreadResponse);
|
||||
|
||||
// can be called from either thread
|
||||
void Complete(nsresult status, const nsCString &pacString);
|
||||
void UseAlternatePACFile(const nsCString &pacURL);
|
||||
void Complete(nsresult status, const nsACString &pacString);
|
||||
void UseAlternatePACFile(const nsACString &pacURL);
|
||||
|
||||
nsCString mSpec;
|
||||
nsCString mScheme;
|
||||
|
@ -131,7 +132,7 @@ public:
|
|||
* The non normalized uri spec of this URI used for comparison with
|
||||
* system proxy settings to determine if the PAC uri has changed.
|
||||
*/
|
||||
nsresult LoadPACFromURI(const nsCString &pacSpec);
|
||||
nsresult LoadPACFromURI(const nsACString &aSpec, bool aIsScheduledReload = false);
|
||||
|
||||
/**
|
||||
* Returns true if we are currently loading the PAC file.
|
||||
|
@ -166,6 +167,10 @@ public:
|
|||
return IsPACURI(tmp);
|
||||
}
|
||||
|
||||
bool IsUsingWPAD() {
|
||||
return mAutoDetect;
|
||||
}
|
||||
|
||||
nsresult Init(nsISystemProxySettings *);
|
||||
static nsPACMan *sInstance;
|
||||
|
||||
|
@ -173,6 +178,8 @@ public:
|
|||
void ProcessPendingQ();
|
||||
void CancelPendingQ(nsresult);
|
||||
|
||||
void SetWPADOverDHCPEnabled(bool aValue) { mWPADOverDHCPEnabled = aValue; }
|
||||
|
||||
private:
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
@ -180,8 +187,10 @@ private:
|
|||
|
||||
friend class PendingPACQuery;
|
||||
friend class PACLoadComplete;
|
||||
friend class ConfigureWPADComplete;
|
||||
friend class ExecutePACThreadAction;
|
||||
friend class WaitForThreadShutdown;
|
||||
friend class TestPACMan;
|
||||
|
||||
~nsPACMan();
|
||||
|
||||
|
@ -195,6 +204,11 @@ private:
|
|||
*/
|
||||
void StartLoading();
|
||||
|
||||
/**
|
||||
* Continue loading the PAC file.
|
||||
*/
|
||||
void ContinueLoadingAfterPACUriKnown();
|
||||
|
||||
/**
|
||||
* Reload the PAC file if there is reason to.
|
||||
*/
|
||||
|
@ -212,15 +226,22 @@ private:
|
|||
*/
|
||||
nsresult PostQuery(PendingPACQuery *query);
|
||||
|
||||
// Having found the PAC URI on the PAC thread, copy it to a string which
|
||||
// can be altered on the main thread.
|
||||
void AssignPACURISpec(const nsACString &aSpec);
|
||||
|
||||
// PAC thread operations only
|
||||
void PostProcessPendingQ();
|
||||
void PostCancelPendingQ(nsresult);
|
||||
bool ProcessPending();
|
||||
nsresult GetPACFromDHCP(nsACString &aSpec);
|
||||
nsresult ConfigureWPAD(nsACString &aSpec);
|
||||
|
||||
private:
|
||||
ProxyAutoConfig mPAC;
|
||||
nsCOMPtr<nsIThread> mPACThread;
|
||||
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
|
||||
nsCOMPtr<nsIDHCPClient> mDHCPClient;
|
||||
|
||||
LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */
|
||||
|
||||
|
@ -239,6 +260,9 @@ private:
|
|||
|
||||
bool mInProgress;
|
||||
bool mIncludePath;
|
||||
bool mAutoDetect;
|
||||
bool mWPADOverDHCPEnabled;
|
||||
int32_t mProxyConfigType;
|
||||
};
|
||||
|
||||
extern LazyLogModule gProxyLog;
|
||||
|
|
|
@ -62,7 +62,6 @@ namespace net {
|
|||
#define PROXY_PREF_BRANCH "network.proxy"
|
||||
#define PROXY_PREF(x) PROXY_PREF_BRANCH "." x
|
||||
|
||||
#define WPAD_URL "http://wpad/wpad.dat"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
@ -311,8 +310,8 @@ private:
|
|||
// Called asynchronously, so we do not need to post another PLEvent
|
||||
// before calling DoCallback.
|
||||
void OnQueryComplete(nsresult status,
|
||||
const nsCString &pacString,
|
||||
const nsCString &newPACURL) override
|
||||
const nsACString &pacString,
|
||||
const nsACString &newPACURL) override
|
||||
{
|
||||
// If we've already called DoCallback then, nothing more to do.
|
||||
if (!mCallback)
|
||||
|
@ -821,6 +820,7 @@ nsProtocolProxyService::nsProtocolProxyService()
|
|||
, mSOCKSProxyVersion(4)
|
||||
, mSOCKSProxyRemoteDNS(false)
|
||||
, mProxyOverTLS(true)
|
||||
, mWPADOverDHCPEnabled(false)
|
||||
, mPACMan(nullptr)
|
||||
, mSessionStart(PR_Now())
|
||||
, mFailedProxyTimeout(30 * 60) // 30 minute default
|
||||
|
@ -1087,6 +1087,12 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
|||
mProxyOverTLS);
|
||||
}
|
||||
|
||||
if (!pref || !strcmp(pref, PROXY_PREF("enable_wpad_over_dhcp"))) {
|
||||
proxy_GetBoolPref(prefBranch, PROXY_PREF("enable_wpad_over_dhcp"),
|
||||
mWPADOverDHCPEnabled);
|
||||
reloadPAC = true;
|
||||
}
|
||||
|
||||
if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout")))
|
||||
proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"),
|
||||
mFailedProxyTimeout);
|
||||
|
@ -1119,19 +1125,15 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
|||
ResetPACThread();
|
||||
}
|
||||
} else if (mProxyConfig == PROXYCONFIG_WPAD) {
|
||||
// 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.
|
||||
tempString.AssignLiteral(WPAD_URL);
|
||||
LOG(("Auto-detecting proxy - Reset Pac Thread"));
|
||||
ResetPACThread();
|
||||
} else if (mSystemProxySettings) {
|
||||
// Get System Proxy settings if available
|
||||
AsyncConfigureFromPAC(false, false);
|
||||
}
|
||||
if (!tempString.IsEmpty())
|
||||
ConfigureFromPAC(tempString, false);
|
||||
if (!tempString.IsEmpty() || mProxyConfig == PROXYCONFIG_WPAD) {
|
||||
ConfigureFromPAC(tempString, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1482,9 +1484,7 @@ nsProtocolProxyService::SetupPACThread(nsIEventTarget *mainThreadEventTarget)
|
|||
else {
|
||||
rv = mPACMan->Init(nullptr);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mPACMan->Shutdown();
|
||||
mPACMan = nullptr;
|
||||
}
|
||||
return rv;
|
||||
|
@ -1508,11 +1508,15 @@ nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec,
|
|||
nsresult rv = SetupPACThread();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mPACMan->IsPACURI(spec) && !forceReload)
|
||||
bool autodetect = spec.IsEmpty();
|
||||
if (!forceReload && ((!autodetect && mPACMan->IsPACURI(spec)) ||
|
||||
(autodetect && mPACMan->IsUsingWPAD()))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mFailedProxies.Clear();
|
||||
|
||||
mPACMan->SetWPADOverDHCPEnabled(mWPADOverDHCPEnabled);
|
||||
return mPACMan->LoadPACFromURI(spec);
|
||||
}
|
||||
|
||||
|
@ -1565,8 +1569,6 @@ nsProtocolProxyService::ReloadPAC()
|
|||
nsAutoCString pacSpec;
|
||||
if (type == PROXYCONFIG_PAC)
|
||||
prefs->GetCharPref(PROXY_PREF("autoconfig_url"), pacSpec);
|
||||
else if (type == PROXYCONFIG_WPAD)
|
||||
pacSpec.AssignLiteral(WPAD_URL);
|
||||
else if (type == PROXYCONFIG_SYSTEM) {
|
||||
if (mSystemProxySettings) {
|
||||
AsyncConfigureFromPAC(true, true);
|
||||
|
@ -1575,7 +1577,7 @@ nsProtocolProxyService::ReloadPAC()
|
|||
}
|
||||
}
|
||||
|
||||
if (!pacSpec.IsEmpty())
|
||||
if (!pacSpec.IsEmpty() || type == PROXYCONFIG_WPAD)
|
||||
ConfigureFromPAC(pacSpec, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1599,8 +1601,8 @@ class nsAsyncBridgeRequest final : public nsPACManCallback
|
|||
}
|
||||
|
||||
void OnQueryComplete(nsresult status,
|
||||
const nsCString &pacString,
|
||||
const nsCString &newPACURL) override
|
||||
const nsACString &pacString,
|
||||
const nsACString &newPACURL) override
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mCompleted = true;
|
||||
|
|
|
@ -400,6 +400,7 @@ protected:
|
|||
int32_t mSOCKSProxyVersion;
|
||||
bool mSOCKSProxyRemoteDNS;
|
||||
bool mProxyOverTLS;
|
||||
bool mWPADOverDHCPEnabled;
|
||||
|
||||
RefPtr<nsPACMan> mPACMan; // non-null if we are using PAC
|
||||
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
|
||||
|
|
|
@ -335,6 +335,10 @@
|
|||
#define NS_SYSTEMPROXYSETTINGS_CONTRACTID \
|
||||
"@mozilla.org/system-proxy-settings;1"
|
||||
|
||||
// component implementing nsIDHCPClient.
|
||||
#define NS_DHCPCLIENT_CONTRACTID \
|
||||
"@mozilla.org/dhcp-client;1"
|
||||
|
||||
// service implementing nsIStreamTransportService
|
||||
#define NS_STREAMTRANSPORTSERVICE_CONTRACTID \
|
||||
"@mozilla.org/network/stream-transport-service;1"
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "../../../xpcom/threads/nsThreadManager.h"
|
||||
#include "nsIDHCPClient.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsComponentManager.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "../../base/nsPACMan.h"
|
||||
|
||||
|
||||
#define TEST_WPAD_DHCP_OPTION "http://pac/pac.dat"
|
||||
#define TEST_ASSIGNED_PAC_URL "http://assignedpac/pac.dat"
|
||||
#define WPAD_PREF 4
|
||||
#define NETWORK_PROXY_TYPE_PREF_NAME "network.proxy.type"
|
||||
#define GETTING_NETWORK_PROXY_TYPE_FAILED -1
|
||||
|
||||
nsCString WPADOptionResult;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
nsresult
|
||||
SetNetworkProxyType(int32_t pref)
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
|
||||
if (!prefs) {
|
||||
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
}
|
||||
return prefs->SetIntPref(NETWORK_PROXY_TYPE_PREF_NAME, pref);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetNetworkProxyType(int32_t* pref)
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
|
||||
if (!prefs) {
|
||||
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
}
|
||||
return prefs->GetIntPref(NETWORK_PROXY_TYPE_PREF_NAME, pref);
|
||||
}
|
||||
|
||||
class nsTestDHCPClient final : public nsIDHCPClient
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDHCPCLIENT
|
||||
|
||||
nsTestDHCPClient() {};
|
||||
nsresult Init(){
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
private:
|
||||
~nsTestDHCPClient() {};
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTestDHCPClient::GetOption(uint8_t option, nsACString & _retval)
|
||||
{
|
||||
_retval.Assign(WPADOptionResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsTestDHCPClient, nsIDHCPClient)
|
||||
|
||||
|
||||
#define NS_TESTDHCPCLIENTSERVICE_CID /* {FEBF1D69-4D7D-4891-9524-045AD18B5592} */\
|
||||
{ 0xFEBF1D69, 0x4D7D, 0x4891, \
|
||||
{0x95, 0x24, 0x04, 0x5a, 0xd1, 0x8b, 0x55, 0x92 } }
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsTestDHCPClient, Init)
|
||||
NS_DEFINE_NAMED_CID(NS_TESTDHCPCLIENTSERVICE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kSysDHCPClientCIDs[] = {
|
||||
{ &kNS_TESTDHCPCLIENTSERVICE_CID, false, nullptr, nsTestDHCPClientConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kSysDHCPClientContracts[] = {
|
||||
{ NS_DHCPCLIENT_CONTRACTID, &kNS_TESTDHCPCLIENTSERVICE_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kSysDHCPClientModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kSysDHCPClientCIDs,
|
||||
kSysDHCPClientContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsDHCPClientModule) = &kSysDHCPClientModule;
|
||||
|
||||
void
|
||||
SetOptionResult(const char* result)
|
||||
{
|
||||
WPADOptionResult.Assign(result);
|
||||
}
|
||||
|
||||
class ProcessPendingEventsAction final : public Runnable
|
||||
{
|
||||
public:
|
||||
// by default we just process the queue
|
||||
ProcessPendingEventsAction()
|
||||
: Runnable("net::ProcessPendingEventsAction")
|
||||
{ }
|
||||
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
if (NS_HasPendingEvents(nullptr)) {
|
||||
NS_WARNING("Found pending requests on PAC thread");
|
||||
nsresult rv;
|
||||
rv = NS_ProcessPendingEvents(nullptr);
|
||||
EXPECT_EQ(NS_OK, rv);
|
||||
}
|
||||
NS_WARNING("No pending requests on PAC thread");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class TestPACMan : public ::testing::Test {
|
||||
protected:
|
||||
|
||||
RefPtr<nsPACMan> mPACMan;
|
||||
|
||||
void
|
||||
ProcessAllEvents()
|
||||
{
|
||||
ProcessPendingEventsOnPACThread();
|
||||
nsresult rv;
|
||||
while (NS_HasPendingEvents(nullptr)) {
|
||||
NS_WARNING("Pending events on main thread");
|
||||
rv = NS_ProcessPendingEvents(nullptr);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ProcessPendingEventsOnPACThread();
|
||||
}
|
||||
NS_WARNING("End of pending events on main thread");
|
||||
}
|
||||
|
||||
|
||||
// This method is used to ensure that all pending events on the main thread
|
||||
// and the Proxy thread are processsed.
|
||||
// It iterates over ProcessAllEvents because simply calling ProcessAllEvents once
|
||||
// did not reliably process the events on both threads on all platforms.
|
||||
void
|
||||
ProcessAllEventsTenTimes(){
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ProcessAllEvents();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
SetUp()
|
||||
{
|
||||
ASSERT_EQ(NS_OK, GetNetworkProxyType(&originalNetworkProxyTypePref));
|
||||
nsFactoryEntry* factoryEntry = nsComponentManagerImpl::gComponentManager
|
||||
->GetFactoryEntry(kNS_TESTDHCPCLIENTSERVICE_CID);
|
||||
if (factoryEntry) {
|
||||
nsresult rv = nsComponentManagerImpl::gComponentManager->UnregisterFactory(kNS_TESTDHCPCLIENTSERVICE_CID, factoryEntry->mFactory);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
}
|
||||
nsComponentManagerImpl::gComponentManager->RegisterModule(&kSysDHCPClientModule, nullptr);
|
||||
|
||||
mPACMan = new nsPACMan(nullptr);
|
||||
mPACMan->SetWPADOverDHCPEnabled(true);
|
||||
mPACMan->Init(nullptr);
|
||||
ASSERT_EQ(NS_OK, SetNetworkProxyType(WPAD_PREF));
|
||||
|
||||
}
|
||||
|
||||
virtual void
|
||||
TearDown()
|
||||
{
|
||||
|
||||
mPACMan->Shutdown();
|
||||
if (originalNetworkProxyTypePref != GETTING_NETWORK_PROXY_TYPE_FAILED) {
|
||||
ASSERT_EQ(NS_OK, SetNetworkProxyType(originalNetworkProxyTypePref));
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDHCPClient>
|
||||
GetPACManDHCPCient()
|
||||
{
|
||||
return mPACMan->mDHCPClient;
|
||||
}
|
||||
|
||||
void
|
||||
SetPACManDHCPCient(nsCOMPtr<nsIDHCPClient> aValue)
|
||||
{
|
||||
mPACMan->mDHCPClient = aValue;
|
||||
}
|
||||
|
||||
void
|
||||
AssertPACSpecEqualTo(const char* aExpected)
|
||||
{
|
||||
ASSERT_STREQ(aExpected, mPACMan->mPACURISpec.Data());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int32_t originalNetworkProxyTypePref = GETTING_NETWORK_PROXY_TYPE_FAILED;
|
||||
|
||||
void ProcessPendingEventsOnPACThread(){
|
||||
RefPtr<ProcessPendingEventsAction> action =
|
||||
new ProcessPendingEventsAction();
|
||||
|
||||
mPACMan->mPACThread->Dispatch(action, nsIEventTarget::DISPATCH_SYNC);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
TEST_F(TestPACMan, TestCreateDHCPClientAndGetOption) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
nsCString spec;
|
||||
GetPACManDHCPCient()->GetOption(252, spec);
|
||||
ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, spec.Data());
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, TestCreateDHCPClientAndGetEmptyOption) {
|
||||
SetOptionResult("");
|
||||
nsCString spec;
|
||||
spec.AssignLiteral(TEST_ASSIGNED_PAC_URL);
|
||||
GetPACManDHCPCient()->GetOption(252, spec);
|
||||
ASSERT_TRUE(spec.IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenTheDHCPClientExistsAndDHCPIsNonEmptyDHCPOptionIsUsedAsPACUri) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
|
||||
mPACMan->LoadPACFromURI(EmptyCString());
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data());
|
||||
AssertPACSpecEqualTo(TEST_WPAD_DHCP_OPTION);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenTheDHCPResponseIsEmptyWPADDefaultsToStandardURL) {
|
||||
|
||||
SetOptionResult(EmptyCString().Data());
|
||||
|
||||
mPACMan->LoadPACFromURI(EmptyCString());
|
||||
ASSERT_TRUE(NS_HasPendingEvents(nullptr));
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
ASSERT_STREQ("", WPADOptionResult.Data());
|
||||
AssertPACSpecEqualTo("http://wpad/wpad.dat");
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenThereIsNoDHCPClientWPADDefaultsToStandardURL) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
|
||||
SetPACManDHCPCient(nullptr);
|
||||
|
||||
mPACMan->LoadPACFromURI(EmptyCString());
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data());
|
||||
AssertPACSpecEqualTo("http://wpad/wpad.dat");
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenWPADOverDHCPIsPreffedOffWPADDefaultsToStandardURL) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
|
||||
mPACMan->SetWPADOverDHCPEnabled(false);
|
||||
mPACMan->LoadPACFromURI(EmptyCString());
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data());
|
||||
AssertPACSpecEqualTo("http://wpad/wpad.dat");
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenPACUriIsSetDirectlyItIsUsedRatherThanWPAD) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
|
||||
nsCString spec;
|
||||
spec.AssignLiteral(TEST_ASSIGNED_PAC_URL);
|
||||
|
||||
mPACMan->LoadPACFromURI(spec);
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
AssertPACSpecEqualTo(TEST_ASSIGNED_PAC_URL);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestPACMan, WhenAScheduledReloadOfAssignedPACHappensTheAssignedPACSpecStaysRatherThanReadingFromDHCP) {
|
||||
|
||||
SetOptionResult(TEST_WPAD_DHCP_OPTION);
|
||||
nsCString spec;
|
||||
spec.AssignLiteral(TEST_ASSIGNED_PAC_URL);
|
||||
mPACMan->LoadPACFromURI(spec);
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
mPACMan->LoadPACFromURI(EmptyCString(), true);
|
||||
|
||||
ProcessAllEventsTenTimes();
|
||||
|
||||
AssertPACSpecEqualTo(TEST_ASSIGNED_PAC_URL);
|
||||
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
|
@ -9,6 +9,7 @@ UNIFIED_SOURCES += [
|
|||
'TestHeaders.cpp',
|
||||
'TestHttpAuthUtils.cpp',
|
||||
'TestMozURL.cpp',
|
||||
'TestPACMan.cpp',
|
||||
'TestPartiallySeekableInputStream.cpp',
|
||||
'TestProtocolProxyService.cpp',
|
||||
'TestReadStreamToString.cpp',
|
||||
|
@ -29,3 +30,8 @@ LOCAL_INCLUDES += [
|
|||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'!/xpcom',
|
||||
'/xpcom/components'
|
||||
]
|
||||
|
|
|
@ -40,7 +40,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
|
|||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
DIRS += ['system/osxproxy']
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DIRS += ['system/windowsproxy']
|
||||
DIRS += ['system/windowsproxy',
|
||||
'system/windowsDHCPClient']
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['system/androidproxy']
|
||||
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DHCPUtils.h"
|
||||
#include <vector>
|
||||
#include "mozilla\Logging.h"
|
||||
#include "nsString.h"
|
||||
|
||||
|
||||
#define MOZ_WORKING_BUFFER_SIZE_NETWORK_ADAPTERS 15000
|
||||
#define MOZ_WORKING_BUFFER_SIZE_DHCP_PARAMS 1000
|
||||
#define MOZ_MAX_TRIES 3
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
//
|
||||
// The comments on this page reference the following Microsoft documentation pages (both retrieved 2017-06-27)
|
||||
// [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
|
||||
// [2] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363298(v=vs.85).aspx
|
||||
mozilla::LazyLogModule gDhcpUtilsLog("dhcpUtils");
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gDhcpUtilsLog, LogLevel::Debug, args)
|
||||
|
||||
bool
|
||||
IsCurrentAndHasDHCP(PIP_ADAPTER_ADDRESSES aAddresses)
|
||||
{
|
||||
return aAddresses->OperStatus == 1 &&
|
||||
(aAddresses->Dhcpv4Server.iSockaddrLength ||
|
||||
aAddresses->Dhcpv6Server.iSockaddrLength);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetActiveDHCPNetworkAdapterName(nsACString& aNetworkAdapterName,
|
||||
WindowsNetworkFunctionsWrapper* aWindowsNetworkFunctionsWrapper)
|
||||
{
|
||||
/* Declare and initialize variables */
|
||||
|
||||
uint32_t dwSize = 0;
|
||||
uint32_t dwRetVal = 0;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
// Set the flags to pass to GetAdaptersAddresses
|
||||
uint32_t flags = GAA_FLAG_INCLUDE_PREFIX;
|
||||
|
||||
// default to unspecified address family (both)
|
||||
uint32_t family = AF_UNSPEC;
|
||||
|
||||
// Allocate a 15 KB buffer to start with.
|
||||
uint32_t outBufLen = MOZ_WORKING_BUFFER_SIZE_NETWORK_ADAPTERS;
|
||||
uint32_t iterations = 0;
|
||||
|
||||
aNetworkAdapterName.Truncate();
|
||||
|
||||
// Now we try calling the GetAdaptersAddresses method until the return value
|
||||
// is not ERROR_BUFFER_OVERFLOW. According to [1]
|
||||
//
|
||||
//
|
||||
// > When the return value is ERROR_BUFFER_OVERFLOW, the SizePointer parameter returned
|
||||
// > points to the required size of the buffer to hold the adapter information.
|
||||
// > Note that it is possible for the buffer size required for the IP_ADAPTER_ADDRESSES
|
||||
// > structures pointed to by the AdapterAddresses parameter to change between
|
||||
// > subsequent calls to the GetAdaptersAddresses function if an adapter address
|
||||
// > is added or removed. However, this method of using the GetAdaptersAddresses
|
||||
// > function is strongly discouraged. This method requires calling the
|
||||
// > GetAdaptersAddresses function multiple times.
|
||||
// >
|
||||
// > The recommended method of calling the GetAdaptersAddresses function is
|
||||
// > to pre-allocate a 15KB working buffer pointed to by the AdapterAddresses parameter.
|
||||
// > On typical computers, this dramatically reduces the chances that the
|
||||
// > GetAdaptersAddresses function returns ERROR_BUFFER_OVERFLOW, which would require
|
||||
// > calling GetAdaptersAddresses function multiple times.
|
||||
//
|
||||
//
|
||||
// The possibility of the buffer size changing between calls to
|
||||
// GetAdaptersAddresses is why we allow the following code to be called several times,
|
||||
// rather than just the two that would be neccessary if we could rely on the
|
||||
// value returned in outBufLen being the true size needed.
|
||||
|
||||
std::vector<IP_ADAPTER_ADDRESSES> pAddresses;
|
||||
do {
|
||||
pAddresses.resize(outBufLen/sizeof(IP_ADAPTER_ADDRESSES));
|
||||
|
||||
dwRetVal =
|
||||
aWindowsNetworkFunctionsWrapper->GetAdaptersAddressesWrapped(
|
||||
family, flags, nullptr, pAddresses.data(), (PULONG)&outBufLen);
|
||||
|
||||
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
|
||||
iterations++;
|
||||
}
|
||||
} while (dwRetVal == ERROR_BUFFER_OVERFLOW && iterations < MOZ_MAX_TRIES);
|
||||
|
||||
switch(dwRetVal) {
|
||||
case NO_ERROR:
|
||||
{
|
||||
// set default return value if we don't find a suitable network adapter
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses.data();
|
||||
while (pCurrAddresses) {
|
||||
if (IsCurrentAndHasDHCP(pCurrAddresses)) {
|
||||
rv = NS_OK;
|
||||
aNetworkAdapterName.Assign(pCurrAddresses->AdapterName);
|
||||
break;
|
||||
}
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ERROR_NO_DATA:
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
break;
|
||||
default:
|
||||
MOZ_LOG(gDhcpUtilsLog, mozilla::LogLevel::Warning,
|
||||
("GetAdaptersAddresses returned %d", dwRetVal));
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
IterateDHCPInformRequestsUntilBufferLargeEnough(
|
||||
DHCPCAPI_PARAMS& aDhcpRequestedOptionParams,
|
||||
wchar_t* aWideNetworkAdapterName,
|
||||
std::vector<char>& aBuffer,
|
||||
WindowsNetworkFunctionsWrapper* aWindowsNetworkFunctionsWrapper)
|
||||
{
|
||||
uint32_t iterations = 0;
|
||||
uint32_t outBufLen = MOZ_WORKING_BUFFER_SIZE_DHCP_PARAMS;
|
||||
|
||||
DHCPCAPI_PARAMS_ARRAY RequestParams = {
|
||||
1, // only one option to request
|
||||
&aDhcpRequestedOptionParams
|
||||
};
|
||||
|
||||
// According to [2],
|
||||
// the following is for 'Optional data to be requested,
|
||||
// in addition to the data requested in the RecdParams array.'
|
||||
// We are not requesting anything in addition, so this is empty.
|
||||
DHCPCAPI_PARAMS_ARRAY SendParams = {
|
||||
0,
|
||||
nullptr
|
||||
};
|
||||
|
||||
DWORD winAPIResponse;
|
||||
// Now we try calling the DHCPRequestParams method until the return value
|
||||
// is not ERROR_MORE_DATA. According to [2]:
|
||||
//
|
||||
//
|
||||
// > Note that the required size of Buffer may increase during the time that elapses
|
||||
// > between the initial function call's return and a subsequent call;
|
||||
// > therefore, the required size of Buffer (indicated in pSize)
|
||||
// > provides an indication of the approximate size required of Buffer,
|
||||
// > rather than guaranteeing that subsequent calls will return successfully
|
||||
// > if Buffer is set to the size indicated in pSize.
|
||||
//
|
||||
//
|
||||
// This is why we allow this DHCPRequestParams to be called several times,
|
||||
// rather than just the two that would be neccessary if we could rely on the
|
||||
// value returned in outBufLen being the true size needed.
|
||||
do {
|
||||
aBuffer.resize(outBufLen);
|
||||
|
||||
winAPIResponse = aWindowsNetworkFunctionsWrapper->DhcpRequestParamsWrapped(
|
||||
DHCPCAPI_REQUEST_SYNCHRONOUS, // Flags
|
||||
nullptr, // Reserved
|
||||
aWideNetworkAdapterName, // Adapter Name
|
||||
nullptr, // not using class id
|
||||
SendParams, // sent parameters
|
||||
RequestParams, // requesting params
|
||||
(PBYTE)aBuffer.data(), // buffer for the output of RequestParams
|
||||
(PULONG)&outBufLen, // buffer size
|
||||
nullptr // Request ID for persistent requests - not needed here
|
||||
);
|
||||
|
||||
if (winAPIResponse == ERROR_MORE_DATA) {
|
||||
iterations++;
|
||||
}
|
||||
} while (winAPIResponse == ERROR_MORE_DATA && iterations < MOZ_MAX_TRIES);
|
||||
return winAPIResponse;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RetrieveOption(
|
||||
const nsACString& aAdapterName,
|
||||
uint8_t aOption,
|
||||
std::vector<char>& aOptionValueBuf,
|
||||
uint32_t* aOptionSize,
|
||||
WindowsNetworkFunctionsWrapper* aWindowsNetworkFunctionsWrapper)
|
||||
{
|
||||
|
||||
nsresult rv;
|
||||
nsAutoString wideNetworkAdapterName = NS_ConvertUTF8toUTF16(aAdapterName);
|
||||
|
||||
DHCPCAPI_PARAMS DhcpRequestedOptionParams = {
|
||||
0, // Flags - Reserved, must be set to zero [2]
|
||||
aOption, // OptionId
|
||||
false, // whether this is vendor specific - let's assume not
|
||||
nullptr, // data filled in on return
|
||||
0 // nBytes used by return data
|
||||
};
|
||||
|
||||
std::vector<char> tmpBuffer(MOZ_WORKING_BUFFER_SIZE_DHCP_PARAMS); // a buffer for the DHCP response object
|
||||
DWORD winAPIResponse = IterateDHCPInformRequestsUntilBufferLargeEnough(DhcpRequestedOptionParams,
|
||||
wideNetworkAdapterName.get(),
|
||||
tmpBuffer,
|
||||
aWindowsNetworkFunctionsWrapper);
|
||||
|
||||
switch (winAPIResponse){
|
||||
case NO_ERROR:
|
||||
{
|
||||
if (DhcpRequestedOptionParams.nBytesData == 0) {
|
||||
*aOptionSize = 0;
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*aOptionSize >= DhcpRequestedOptionParams.nBytesData) {
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
rv = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
|
||||
}
|
||||
|
||||
uint32_t actualSizeReturned =
|
||||
*aOptionSize > DhcpRequestedOptionParams.nBytesData?
|
||||
DhcpRequestedOptionParams.nBytesData: *aOptionSize;
|
||||
|
||||
memcpy(aOptionValueBuf.data(),
|
||||
DhcpRequestedOptionParams.Data, actualSizeReturned);
|
||||
*aOptionSize = DhcpRequestedOptionParams.nBytesData;
|
||||
break;
|
||||
}
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
MOZ_LOG(gDhcpUtilsLog, mozilla::LogLevel::Warning,
|
||||
("RetrieveOption returned %d (ERROR_INVALID_PARAMETER) when option %d requested",
|
||||
winAPIResponse, aOption));
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
break;
|
||||
default:
|
||||
MOZ_LOG(gDhcpUtilsLog, mozilla::LogLevel::Warning,
|
||||
("RetrieveOption returned %d when option %d requested", winAPIResponse, aOption));
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_toolkit_system_windowsDHCPClient_DHCPUtils_h
|
||||
#define mozilla_toolkit_system_windowsDHCPClient_DHCPUtils_h
|
||||
|
||||
#include "WindowsNetworkFunctionsWrapper.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
nsresult GetActiveDHCPNetworkAdapterName(
|
||||
nsACString& aNetworkAdapterName,
|
||||
WindowsNetworkFunctionsWrapper* aWindowsNetworkFunctionsWrapper);
|
||||
|
||||
nsresult RetrieveOption(
|
||||
const nsACString& aAdapterName,
|
||||
uint8_t aOption,
|
||||
std::vector<char>& aOptionValueBuf,
|
||||
uint32_t* aOptionSize,
|
||||
WindowsNetworkFunctionsWrapper* aWindowsNetworkFunctionsWrapper
|
||||
);
|
||||
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
||||
#endif // mozilla_toolkit_system_windowsDHCPClient_DHCPUtils_h
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WindowsNetworkFunctionsWrapper.h"
|
||||
|
||||
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
#pragma comment(lib, "dhcpcsvc.lib" )
|
||||
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
NS_IMPL_ISUPPORTS(WindowsNetworkFunctionsWrapper, nsISupports)
|
||||
|
||||
ULONG WindowsNetworkFunctionsWrapper::GetAdaptersAddressesWrapped(
|
||||
_In_ ULONG aFamily,
|
||||
_In_ ULONG aFlags,
|
||||
_In_ PVOID aReserved,
|
||||
_Inout_ PIP_ADAPTER_ADDRESSES aAdapterAddresses,
|
||||
_Inout_ PULONG aSizePointer)
|
||||
{
|
||||
return GetAdaptersAddresses(aFamily, aFlags, aReserved, aAdapterAddresses, aSizePointer);
|
||||
}
|
||||
|
||||
DWORD WindowsNetworkFunctionsWrapper::DhcpRequestParamsWrapped(
|
||||
_In_ DWORD aFlags,
|
||||
_In_ LPVOID aReserved,
|
||||
_In_ LPWSTR aAdapterName,
|
||||
_In_ LPDHCPCAPI_CLASSID aClassId,
|
||||
_In_ DHCPCAPI_PARAMS_ARRAY aSendParams,
|
||||
_Inout_ DHCPCAPI_PARAMS_ARRAY aRecdParams,
|
||||
_In_ LPBYTE aBuffer,
|
||||
_Inout_ LPDWORD apSize,
|
||||
_In_ LPWSTR aRequestIdStr)
|
||||
{
|
||||
return DhcpRequestParams(aFlags, aReserved, aAdapterName, aClassId, aSendParams, aRecdParams, aBuffer, apSize, aRequestIdStr);
|
||||
}
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_toolkit_system_windowsDHCPClient_windowsNetworkFunctionsWrapper_h
|
||||
#define mozilla_toolkit_system_windowsDHCPClient_windowsNetworkFunctionsWrapper_h
|
||||
|
||||
#include <Winsock2.h> // there is a compilation error if Winsock.h is not
|
||||
// declared before dhcpcsdk.h
|
||||
#include <dhcpcsdk.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
// Thin wrapper around low-level network functions needed for DHCP querying for web proxy
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
class WindowsNetworkFunctionsWrapper : nsISupports
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
WindowsNetworkFunctionsWrapper(){};
|
||||
|
||||
virtual ULONG GetAdaptersAddressesWrapped(
|
||||
_In_ ULONG aFamily,
|
||||
_In_ ULONG aFlags,
|
||||
_In_ PVOID aReserved,
|
||||
_Inout_ PIP_ADAPTER_ADDRESSES aAdapterAddresses,
|
||||
_Inout_ PULONG aSizePointer
|
||||
);
|
||||
|
||||
virtual DWORD DhcpRequestParamsWrapped(
|
||||
_In_ DWORD aFlags,
|
||||
_In_ LPVOID aReserved,
|
||||
_In_ LPWSTR aAdapterName,
|
||||
_In_ LPDHCPCAPI_CLASSID aClassId,
|
||||
_In_ DHCPCAPI_PARAMS_ARRAY aSendParams,
|
||||
_Inout_ DHCPCAPI_PARAMS_ARRAY aRecdParams,
|
||||
_In_ LPBYTE aBuffer,
|
||||
_Inout_ LPDWORD apSize,
|
||||
_In_ LPWSTR aRequestIdStr
|
||||
);
|
||||
|
||||
protected:
|
||||
~WindowsNetworkFunctionsWrapper(){};
|
||||
|
||||
};
|
||||
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
||||
#endif //mozilla_toolkit_system_windowsDHCPClient_windowsNetworkFunctionsWrapper_h
|
|
@ -0,0 +1,15 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['tests/gtest']
|
||||
|
||||
SOURCES += [
|
||||
'DHCPUtils.cpp',
|
||||
'nsWindowsDHCPClient.cpp',
|
||||
'WindowsNetworkFunctionsWrapper.cpp'
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsWindowsDHCPClient.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "DHCPUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
LazyLogModule gDhcpLog("windowsDHCPClient");
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gDhcpLog, LogLevel::Debug, args)
|
||||
|
||||
#define MOZ_MAX_DHCP_OPTION_LENGTH 255 // this is the maximum option length in DHCP V4 and 6
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsWindowsDHCPClient, nsIDHCPClient)
|
||||
|
||||
nsresult
|
||||
nsWindowsDHCPClient::Init()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsDHCPClient::GetOption(uint8_t aOption, nsACString& aRetVal)
|
||||
{
|
||||
nsCString networkAdapterName;
|
||||
nsresult rv;
|
||||
rv = GetActiveDHCPNetworkAdapterName(networkAdapterName, mNetworkFunctions);
|
||||
if (rv != NS_OK) {
|
||||
LOG(("Failed to get network adapter name in nsWindowsDHCPClient::GetOption due to error %d", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t sizeOptionValue = MOZ_MAX_DHCP_OPTION_LENGTH;
|
||||
std::vector<char> optionValue;
|
||||
|
||||
bool retryingAfterLossOfSignificantData = false;
|
||||
do {
|
||||
optionValue.resize(sizeOptionValue);
|
||||
rv = RetrieveOption(networkAdapterName,
|
||||
aOption,
|
||||
optionValue,
|
||||
&sizeOptionValue,
|
||||
mNetworkFunctions);
|
||||
if (rv == NS_ERROR_LOSS_OF_SIGNIFICANT_DATA) {
|
||||
LOG(("In nsWindowsDHCPClient::GetOption, DHCP Option %d required %d bytes", aOption, sizeOptionValue));
|
||||
if (retryingAfterLossOfSignificantData) {
|
||||
break;
|
||||
}
|
||||
retryingAfterLossOfSignificantData = true;
|
||||
}
|
||||
} while (rv == NS_ERROR_LOSS_OF_SIGNIFICANT_DATA);
|
||||
if (rv != NS_OK) {
|
||||
LOG(("Failed to get DHCP Option %d nsWindowsDHCPClient::GetOption due to error %d", aOption, rv));
|
||||
return rv;
|
||||
}
|
||||
aRetVal.Assign(optionValue.data(), sizeOptionValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define NS_WINDOWSDHCPCLIENTSERVICE_CID /* {FEBF1D69-4D7D-4891-9524-045AD18B5592} */\
|
||||
{ 0xFEBF1D69, 0x4D7D, 0x4891, \
|
||||
{0x95, 0x24, 0x04, 0x5a, 0xd1, 0x8b, 0x55, 0x92 } }
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsDHCPClient, Init)
|
||||
NS_DEFINE_NAMED_CID(NS_WINDOWSDHCPCLIENTSERVICE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kSysDHCPClientCIDs[] = {
|
||||
{ &kNS_WINDOWSDHCPCLIENTSERVICE_CID, false, nullptr, nsWindowsDHCPClientConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kSysDHCPClientContracts[] = {
|
||||
{ NS_DHCPCLIENT_CONTRACTID, &kNS_WINDOWSDHCPCLIENTSERVICE_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kSysDHCPClientModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kSysDHCPClientCIDs,
|
||||
kSysDHCPClientContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsDHCPClientModule) = &kSysDHCPClientModule;
|
||||
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIDHCPClient.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "WindowsNetworkFunctionsWrapper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace toolkit {
|
||||
namespace system {
|
||||
namespace windowsDHCPClient {
|
||||
|
||||
class nsWindowsDHCPClient final : public nsIDHCPClient
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDHCPCLIENT
|
||||
|
||||
explicit nsWindowsDHCPClient(WindowsNetworkFunctionsWrapper *aNetworkFunctions = new WindowsNetworkFunctionsWrapper())
|
||||
: mNetworkFunctions(aNetworkFunctions) {};
|
||||
nsresult Init();
|
||||
|
||||
private:
|
||||
|
||||
~nsWindowsDHCPClient() {};
|
||||
WindowsNetworkFunctionsWrapper* mNetworkFunctions;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace windowsDHCPClient
|
||||
} // namespace system
|
||||
} // namespace toolkit
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,323 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "DHCPUtils.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWindowsDHCPClient.h"
|
||||
|
||||
using namespace mozilla::toolkit::system::windowsDHCPClient;
|
||||
|
||||
|
||||
|
||||
class WindowsNetworkFunctionsMock : public WindowsNetworkFunctionsWrapper {
|
||||
|
||||
public:
|
||||
WindowsNetworkFunctionsMock():mAddressesToReturn(nullptr) {
|
||||
memset(mOptions, 0, sizeof(char*) * 256);
|
||||
}
|
||||
|
||||
|
||||
ULONG GetAdaptersAddressesWrapped(
|
||||
_In_ ULONG Family,
|
||||
_In_ ULONG Flags,
|
||||
_In_ PVOID Reserved,
|
||||
_Inout_ PIP_ADAPTER_ADDRESSES AdapterAddresses,
|
||||
_Inout_ PULONG SizePointer
|
||||
){
|
||||
if (*SizePointer < sizeof(*mAddressesToReturn)){
|
||||
*SizePointer = sizeof(*mAddressesToReturn);
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
*SizePointer = sizeof(*mAddressesToReturn);
|
||||
memcpy(AdapterAddresses, mAddressesToReturn,
|
||||
*SizePointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD DhcpRequestParamsWrapped(
|
||||
_In_ DWORD Flags,
|
||||
_In_ LPVOID Reserved,
|
||||
_In_ LPWSTR AdapterName,
|
||||
_In_ LPDHCPCAPI_CLASSID ClassId,
|
||||
_In_ DHCPCAPI_PARAMS_ARRAY SendParams,
|
||||
_Inout_ DHCPCAPI_PARAMS_ARRAY RecdParams,
|
||||
_In_ LPBYTE Buffer,
|
||||
_Inout_ LPDWORD pSize,
|
||||
_In_ LPWSTR RequestIdStr
|
||||
)
|
||||
{
|
||||
mLastRequestedNetworkAdapterName.Assign(AdapterName);
|
||||
|
||||
if (mOptions[RecdParams.Params[0].OptionId] == nullptr) {
|
||||
RecdParams.Params[0].nBytesData = 0;
|
||||
}
|
||||
else {
|
||||
RecdParams.Params[0].Data = Buffer;
|
||||
size_t lengthOfValue = strlen(mOptions[RecdParams.Params[0].OptionId]);
|
||||
if (*pSize > lengthOfValue) {
|
||||
memcpy(Buffer, mOptions[RecdParams.Params[0].OptionId], lengthOfValue);
|
||||
RecdParams.Params[0].nBytesData = lengthOfValue;
|
||||
} else {
|
||||
*pSize = lengthOfValue;
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
AddAdapterAddresses(IP_ADAPTER_ADDRESSES& aAddressesToAdd)
|
||||
{
|
||||
if (mAddressesToReturn == nullptr) {
|
||||
mAddressesToReturn = &aAddressesToAdd;
|
||||
return;
|
||||
}
|
||||
IP_ADAPTER_ADDRESSES* tail = mAddressesToReturn;
|
||||
|
||||
while (tail->Next != nullptr) {
|
||||
tail = tail->Next;
|
||||
}
|
||||
tail->Next = &aAddressesToAdd;
|
||||
}
|
||||
|
||||
void
|
||||
SetDHCPOption(uint8_t option, char* value)
|
||||
{
|
||||
mOptions[option] = value;
|
||||
}
|
||||
|
||||
nsString
|
||||
GetLastRequestedNetworkAdapterName()
|
||||
{
|
||||
return mLastRequestedNetworkAdapterName;
|
||||
}
|
||||
|
||||
private:
|
||||
IP_ADAPTER_ADDRESSES* mAddressesToReturn = nullptr;
|
||||
char* mOptions[256];
|
||||
nsString mLastRequestedNetworkAdapterName;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class TestDHCPUtils : public ::testing::Test {
|
||||
protected:
|
||||
RefPtr<WindowsNetworkFunctionsMock> mMockWindowsFunctions;
|
||||
nsCString mDefaultAdapterName;
|
||||
|
||||
virtual void
|
||||
SetUp()
|
||||
{
|
||||
mMockWindowsFunctions = new WindowsNetworkFunctionsMock();
|
||||
mDefaultAdapterName.AssignLiteral("my favourite network adapter");
|
||||
}
|
||||
|
||||
void
|
||||
Given_DHCP_Option_Is(uint8_t option, char* value)
|
||||
{
|
||||
mMockWindowsFunctions.get()->SetDHCPOption(option, value);
|
||||
}
|
||||
|
||||
void
|
||||
Given_Network_Adapter_Called(
|
||||
IP_ADAPTER_ADDRESSES& adapterAddresses,
|
||||
char* adapterName)
|
||||
{
|
||||
adapterAddresses.AdapterName = adapterName;
|
||||
adapterAddresses.Next = nullptr;
|
||||
adapterAddresses.Dhcpv4Server.iSockaddrLength = 0;
|
||||
adapterAddresses.Dhcpv6Server.iSockaddrLength = 0;
|
||||
AddAdapterAddresses(adapterAddresses);
|
||||
}
|
||||
|
||||
void
|
||||
Given_Network_Adapter_Supports_DHCP_V4(IP_ADAPTER_ADDRESSES& adapterAddresses)
|
||||
{
|
||||
adapterAddresses.Dhcpv4Server.iSockaddrLength = 4;
|
||||
}
|
||||
|
||||
void
|
||||
Given_Network_Adapter_Supports_DHCP_V6(IP_ADAPTER_ADDRESSES& adapterAddresses)
|
||||
{
|
||||
adapterAddresses.Dhcpv6Server.iSockaddrLength = 12;
|
||||
}
|
||||
|
||||
void
|
||||
Given_Network_Adapter_Has_Operational_Status(
|
||||
IP_ADAPTER_ADDRESSES& adapterAddresses,
|
||||
IF_OPER_STATUS operStatus)
|
||||
{
|
||||
adapterAddresses.OperStatus = operStatus;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
AddAdapterAddresses(IP_ADAPTER_ADDRESSES& aAddressToAdd)
|
||||
{
|
||||
mMockWindowsFunctions.get()->AddAdapterAddresses(aAddressToAdd);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// following class currently just distinguishes tests of nsWindowsDHCPClient from
|
||||
// tests of DHCPUtils.
|
||||
class TestNsWindowsDHCPClient : public TestDHCPUtils { };
|
||||
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetAdaptersAddresses)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V4(adapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusUp);
|
||||
|
||||
nsCString networkAdapterName;
|
||||
|
||||
ASSERT_EQ(NS_OK, GetActiveDHCPNetworkAdapterName(networkAdapterName, mMockWindowsFunctions));
|
||||
|
||||
ASSERT_STREQ(networkAdapterName.Data(), "my favourite network adapter");
|
||||
}
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetAdaptersAddressesNoAvailableNetworks)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V4(adapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusDown);
|
||||
|
||||
nsCString networkAdapterName;
|
||||
ASSERT_EQ(NS_ERROR_NOT_AVAILABLE, GetActiveDHCPNetworkAdapterName(networkAdapterName, mMockWindowsFunctions));
|
||||
|
||||
ASSERT_STREQ(networkAdapterName.Data(), "");
|
||||
}
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetAdaptersAddressesNoNetworksWithDHCP)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusUp);
|
||||
|
||||
nsCString networkAdapterName;
|
||||
ASSERT_EQ(NS_ERROR_NOT_AVAILABLE, GetActiveDHCPNetworkAdapterName(networkAdapterName, mMockWindowsFunctions));
|
||||
|
||||
ASSERT_STREQ(networkAdapterName.Data(), "");
|
||||
}
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetAdaptersAddressesSecondNetworkIsAvailable)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V4(adapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusDown);
|
||||
|
||||
|
||||
IP_ADAPTER_ADDRESSES secondAdapterAddresses = {};
|
||||
Given_Network_Adapter_Called(secondAdapterAddresses, "my second favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V6(secondAdapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(secondAdapterAddresses, IfOperStatusUp);
|
||||
|
||||
nsCString networkAdapterName;
|
||||
ASSERT_EQ(NS_OK, GetActiveDHCPNetworkAdapterName(networkAdapterName, mMockWindowsFunctions));
|
||||
|
||||
ASSERT_STREQ(networkAdapterName.Data(), "my second favourite network adapter");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetOption)
|
||||
{
|
||||
|
||||
char* pacURL = "http://pac.com";
|
||||
Given_DHCP_Option_Is(1, "My network option");
|
||||
Given_DHCP_Option_Is(252, pacURL);
|
||||
|
||||
std::vector<char> optionValue(255, *"originalValue originalValue");
|
||||
memcpy(optionValue.data(), "originalValue originalValue", strlen("originalValue originalValue") + 1);
|
||||
|
||||
uint32_t size = 255;
|
||||
|
||||
nsresult retVal = RetrieveOption(mDefaultAdapterName, 252, optionValue, &size, mMockWindowsFunctions);
|
||||
|
||||
ASSERT_EQ(strlen(pacURL), size);
|
||||
ASSERT_STREQ("http://pac.comoriginalValue", optionValue.data());
|
||||
ASSERT_EQ(NS_OK, retVal);
|
||||
}
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetAbsentOption)
|
||||
{
|
||||
std::vector<char> optionValue(255);
|
||||
uint32_t size = 256;
|
||||
memcpy(optionValue.data(), "originalValue", strlen("originalValue") + 1);
|
||||
|
||||
nsresult retVal = RetrieveOption(mDefaultAdapterName, 252, optionValue, &size, mMockWindowsFunctions);
|
||||
|
||||
ASSERT_EQ(0, size);
|
||||
ASSERT_EQ(NS_ERROR_NOT_AVAILABLE, retVal);
|
||||
}
|
||||
|
||||
TEST_F(TestDHCPUtils, TestGetTooLongOption)
|
||||
{
|
||||
Given_DHCP_Option_Is(252, "http://pac.com");
|
||||
|
||||
std::vector<char> optionValue(255);
|
||||
memcpy(optionValue.data(), "originalValue", strlen("originalValue") + 1);
|
||||
uint32_t size = 4;
|
||||
nsresult retVal = RetrieveOption(mDefaultAdapterName, 252, optionValue, &size, mMockWindowsFunctions);
|
||||
|
||||
ASSERT_STREQ("httpinalValue", optionValue.data());
|
||||
ASSERT_EQ(NS_ERROR_LOSS_OF_SIGNIFICANT_DATA, retVal);
|
||||
ASSERT_EQ(strlen("http://pac.com"), size);
|
||||
}
|
||||
|
||||
TEST_F(TestNsWindowsDHCPClient, TestGettingOptionThroughNSWindowsDHCPClient)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V4(adapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusUp);
|
||||
Given_DHCP_Option_Is(252, "http://pac.com");
|
||||
|
||||
nsCString optionValue;
|
||||
nsCOMPtr<nsIDHCPClient> dhcpClient = new nsWindowsDHCPClient(mMockWindowsFunctions);
|
||||
nsresult retVal = dhcpClient->GetOption(252, optionValue);
|
||||
|
||||
ASSERT_STREQ("http://pac.com", optionValue.Data());
|
||||
ASSERT_STREQ(L"my favourite network adapter", mMockWindowsFunctions->GetLastRequestedNetworkAdapterName().Data());
|
||||
ASSERT_EQ(NS_OK, retVal);
|
||||
}
|
||||
|
||||
TEST_F(TestNsWindowsDHCPClient, TestGettingOptionThroughNSWindowsDHCPClientWhenNoAvailableNetworkAdapter)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusDown);
|
||||
Given_DHCP_Option_Is(252, "http://pac.com");
|
||||
|
||||
nsCString optionValue;
|
||||
nsCOMPtr<nsIDHCPClient> dhcpClient = new nsWindowsDHCPClient(mMockWindowsFunctions);
|
||||
nsresult retVal = dhcpClient->GetOption(252, optionValue);
|
||||
|
||||
ASSERT_STREQ("", optionValue.Data());
|
||||
ASSERT_EQ(NS_ERROR_NOT_AVAILABLE, retVal);
|
||||
}
|
||||
|
||||
TEST_F(TestNsWindowsDHCPClient, TestGettingAbsentOptionThroughNSWindowsDHCPClient)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses = {};
|
||||
Given_Network_Adapter_Called(adapterAddresses, "my favourite network adapter");
|
||||
Given_Network_Adapter_Supports_DHCP_V6(adapterAddresses);
|
||||
Given_Network_Adapter_Has_Operational_Status(adapterAddresses, IfOperStatusUp);
|
||||
|
||||
nsCString optionValue;
|
||||
nsCOMPtr<nsIDHCPClient> dhcpClient = new nsWindowsDHCPClient(mMockWindowsFunctions);
|
||||
nsresult retVal = dhcpClient->GetOption(252, optionValue);
|
||||
|
||||
ASSERT_STREQ("", optionValue.Data());
|
||||
ASSERT_EQ(NS_ERROR_NOT_AVAILABLE, retVal);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestDHCPUtils.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/toolkit/system/windowsDHCPClient',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wshadow']
|
Загрузка…
Ссылка в новой задаче