2740 lines
63 KiB
Plaintext
2740 lines
63 KiB
Plaintext
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
proxysup.cxx
|
||
|
||
Abstract:
|
||
|
||
Contains class implementation for proxy server and proxy bypass list
|
||
|
||
Contents:
|
||
IsLocalMacro
|
||
LoadExternalAutoConfigDll
|
||
|
||
PROXY_SERVER_LIST_ENTRY::WriteEntry
|
||
|
||
PROXY_SERVER_LIST::AddList
|
||
PROXY_SERVER_LIST::Find
|
||
PROXY_SERVER_LIST::Add
|
||
PROXY_SERVER_LIST::ProxyScheme
|
||
PROXY_SERVER_LIST::GetProxyInfo
|
||
PROXY_SERVER_LIST::AddToBypassList
|
||
PROXY_SERVER_LIST::GetList
|
||
|
||
PROXY_BYPASS_LIST_ENTRY::WriteEntry
|
||
|
||
PROXY_BYPASS_LIST::AddList
|
||
PROXY_BYPASS_LIST::Find
|
||
PROXY_BYPASS_LIST::Add
|
||
PROXY_BYPASS_LIST::IsBypassed
|
||
PROXY_BYPASS_LIST::GetList
|
||
|
||
PROXY_INFO::SetProxyInfo
|
||
PROXY_INFO::GetProxyInfo
|
||
PROXY_INFO::IsBypassed
|
||
PROXY_INFO::ProxyScheme
|
||
|
||
(GetRegistryProxyParameter)
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 03-Feb-1996
|
||
|
||
Revision History:
|
||
|
||
03-Feb-1996 rfirth
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
|
||
//
|
||
// private manifests
|
||
//
|
||
|
||
#define DEFAULT_PROXY_BUFFER_LENGTH (4 K)
|
||
#define MAX_IP_ADDRESS_STRING_LENGTH (4 * 4 - 1) // ###.###.###.###
|
||
#define PROXY_REGISTRY_STRING_LENGTH (4 K)
|
||
|
||
//
|
||
// private types
|
||
//
|
||
|
||
typedef enum {
|
||
STATE_START,
|
||
STATE_PROTOCOL,
|
||
STATE_SCHEME,
|
||
STATE_SERVER,
|
||
STATE_PORT,
|
||
STATE_END,
|
||
STATE_ERROR
|
||
} PARSER_STATE;
|
||
|
||
|
||
#define EXT_PROXY_FUNC *
|
||
|
||
typedef BOOL
|
||
(EXT_PROXY_FUNC IS_BYPASSED_FN) (
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
);
|
||
|
||
typedef BOOL
|
||
(EXT_PROXY_FUNC PROXY_SCHEME_FN) (
|
||
IN INTERNET_SCHEME tProtocol,
|
||
OUT LPINTERNET_SCHEME lptScheme
|
||
) ;
|
||
|
||
typedef BOOL
|
||
(EXT_PROXY_FUNC GET_PROXY_INFO_FN) (
|
||
IN INTERNET_SCHEME tProtocol,
|
||
IN OUT LPINTERNET_SCHEME lptScheme,
|
||
OUT LPSTR * lplpszHostName,
|
||
OUT LPDWORD lpdwHostNameLength,
|
||
OUT LPINTERNET_PORT lpHostPort
|
||
) ;
|
||
|
||
typedef BOOL
|
||
(EXT_PROXY_FUNC PROXY_DLL_INIT_FN) (
|
||
IN DWORD dwReserved
|
||
);
|
||
|
||
#define IS_BYPASSED_FN_NAME "InternetIsBypassed"
|
||
#define PROXY_SCHEME_FN_NAME "InternetProxyScheme"
|
||
#define GET_PROXY_INFO_FN_NAME "InternetGetProxyInfo"
|
||
#define PROXY_DLL_INIT_FN_NAME "InternetInitalizeAutoProxyDll"
|
||
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
LPSTR
|
||
GetRegistryProxyParameter(
|
||
IN LPSTR lpszParameterName
|
||
);
|
||
|
||
|
||
|
||
//
|
||
// private vars
|
||
//
|
||
|
||
//
|
||
// hExternalAutoConfigDLL - NULL when DLL is not Loaded, a specialized
|
||
// DLL that WININET can load, and use to determine what proxies to use.
|
||
//
|
||
|
||
HINSTANCE hExternalAutoConfigDLL = NULL;
|
||
|
||
GET_PROXY_INFO_FN pGetProxyInfo;
|
||
|
||
PROXY_SCHEME_FN pProxyScheme;
|
||
|
||
IS_BYPASSED_FN pIsBypassed;
|
||
|
||
PROXY_DLL_INIT_FN pProxyDllInit;
|
||
|
||
|
||
|
||
BOOL fExternalAutoConfigDllInited = FALSE;
|
||
BOOL fExternalAutoConfigDllInitFuncCalled = FALSE;
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
BOOL
|
||
IsLocalMacro(
|
||
IN LPSTR lpszMetaName,
|
||
IN DWORD dwMetaNameLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks for local macro name
|
||
|
||
Arguments:
|
||
|
||
lpszMetaName - name to check
|
||
|
||
dwMetaNameLength - length
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - it is <local>
|
||
|
||
FALSE - not
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(lpszMetaName != NULL);
|
||
|
||
static const char s_local[] = "<local>";
|
||
|
||
return (strnicmp(s_local, lpszMetaName, dwMetaNameLength) == 0);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
LoadExternalAutoConfigDll(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads an external DLL which decides which proxy to use on a per connection basis.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - DLL loaded successfully, and should be used.
|
||
|
||
FALSE - Could not load DLL.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL fReturn = FALSE;
|
||
|
||
if (lpszAutoProxyDll == NULL)
|
||
return FALSE;
|
||
|
||
EnterCriticalSection(&AutoProxyDllCritSec);
|
||
|
||
if ( fExternalAutoConfigDllInited )
|
||
{
|
||
fReturn = TRUE;
|
||
goto quit;
|
||
}
|
||
|
||
hExternalAutoConfigDLL = LoadLibrary(lpszAutoProxyDll);
|
||
|
||
if ( !hExternalAutoConfigDLL )
|
||
{
|
||
goto quit;
|
||
}
|
||
|
||
|
||
pGetProxyInfo = (GET_PROXY_INFO_FN)
|
||
GetProcAddress(hExternalAutoConfigDLL, GET_PROXY_INFO_FN_NAME);
|
||
|
||
|
||
pProxyScheme = (PROXY_SCHEME_FN)
|
||
GetProcAddress(hExternalAutoConfigDLL, PROXY_SCHEME_FN_NAME);
|
||
|
||
|
||
pIsBypassed = (IS_BYPASSED_FN)
|
||
GetProcAddress(hExternalAutoConfigDLL, IS_BYPASSED_FN_NAME);
|
||
|
||
|
||
pProxyDllInit = (PROXY_DLL_INIT_FN)
|
||
GetProcAddress(hExternalAutoConfigDLL, PROXY_DLL_INIT_FN_NAME );
|
||
|
||
//
|
||
// Don't error out unless we don't succeed on anything
|
||
//
|
||
|
||
if ( !pGetProxyInfo && !pProxyScheme && !pIsBypassed && !pProxyDllInit)
|
||
{
|
||
goto quit;
|
||
}
|
||
|
||
|
||
fExternalAutoConfigDllInited = TRUE;
|
||
fReturn = TRUE;
|
||
|
||
quit:
|
||
|
||
if ( !fReturn && hExternalAutoConfigDLL )
|
||
{
|
||
FreeLibrary(hExternalAutoConfigDLL);
|
||
}
|
||
|
||
LeaveCriticalSection(&AutoProxyDllCritSec);
|
||
|
||
return fReturn;
|
||
}
|
||
|
||
|
||
BOOL
|
||
InitalizeAutoConfigDllIfNeeded(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Executes an initalization callback function exported by an autoproxy DLL.
|
||
This function insures the callback is only executed once.
|
||
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - success
|
||
|
||
FALSE - failure
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL fReturn;
|
||
|
||
EnterCriticalSection(&AutoProxyDllCritSec);
|
||
|
||
if ( ! fExternalAutoConfigDllInited )
|
||
{
|
||
fReturn = TRUE;
|
||
goto quit;
|
||
}
|
||
|
||
if ( fExternalAutoConfigDllInitFuncCalled )
|
||
{
|
||
fReturn = TRUE;
|
||
goto quit;
|
||
}
|
||
|
||
if ( pProxyDllInit )
|
||
{
|
||
fReturn = (pProxyDllInit) ( 0 );
|
||
fExternalAutoConfigDllInitFuncCalled = TRUE;
|
||
}
|
||
else
|
||
{
|
||
fReturn = TRUE;
|
||
}
|
||
|
||
quit:
|
||
|
||
LeaveCriticalSection(&AutoProxyDllCritSec);
|
||
|
||
return fReturn;
|
||
}
|
||
|
||
|
||
//
|
||
// member functions
|
||
//
|
||
|
||
|
||
BOOL
|
||
PROXY_SERVER_LIST_ENTRY::WriteEntry(
|
||
OUT LPSTR lpszBuffer,
|
||
IN OUT LPDWORD lpdwBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes this proxy server list entry as a string in the supplied buffer
|
||
|
||
Arguments:
|
||
|
||
lpszBuffer - pointer to buffer where string is written
|
||
|
||
lpdwBufferLength - IN: amount of space in buffer
|
||
OUT: number of bytes copied, or required size
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - entry written to buffer
|
||
|
||
FALSE - entry not written to buffer - *lpdwBufferLength contains
|
||
required size
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD requiredLength;
|
||
LPSTR protocolName;
|
||
DWORD protocolNameLength;
|
||
LPSTR schemeName;
|
||
DWORD schemeNameLength;
|
||
INTERNET_PORT magnitude;
|
||
|
||
protocolName = MapUrlScheme(_Protocol, &protocolNameLength);
|
||
if (protocolName != NULL) {
|
||
requiredLength = protocolNameLength + 1; // for '='
|
||
} else {
|
||
requiredLength = 0;
|
||
}
|
||
schemeName = MapUrlScheme(_Scheme, &schemeNameLength);
|
||
if (schemeName != NULL) {
|
||
requiredLength += schemeNameLength + sizeof("://") - 1;
|
||
}
|
||
requiredLength += _ProxyName.StringLength();
|
||
if (_ProxyPort != INTERNET_INVALID_PORT_NUMBER) {
|
||
for (INTERNET_PORT n = 10000, i = 5; n > 0; n /= 10, --i) {
|
||
if (_ProxyPort / n) {
|
||
requiredLength += i + 1; // for ':'
|
||
magnitude = n;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOL success;
|
||
|
||
if (*lpdwBufferLength > requiredLength) {
|
||
if (protocolName != NULL) {
|
||
memcpy(lpszBuffer, protocolName, protocolNameLength);
|
||
lpszBuffer += protocolNameLength;
|
||
*lpszBuffer++ = '=';
|
||
}
|
||
if (schemeName != NULL) {
|
||
memcpy(lpszBuffer, schemeName, schemeNameLength);
|
||
lpszBuffer += schemeNameLength;
|
||
memcpy(lpszBuffer, "://", sizeof("://") - 1);
|
||
lpszBuffer += sizeof("://") - 1;
|
||
}
|
||
_ProxyName.CopyTo(lpszBuffer);
|
||
lpszBuffer += _ProxyName.StringLength();
|
||
if (_ProxyPort != INTERNET_INVALID_PORT_NUMBER) {
|
||
*lpszBuffer++ = ':';
|
||
for (INTERNET_PORT n = _ProxyPort, i = magnitude; i; i /= 10) {
|
||
*lpszBuffer++ = (char)(n / i) + '0';
|
||
n %= i;
|
||
}
|
||
}
|
||
success = TRUE;
|
||
} else {
|
||
success = FALSE;
|
||
}
|
||
*lpdwBufferLength = requiredLength;
|
||
return success;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_SERVER_LIST::AddList(
|
||
IN LPSTR lpszList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses a list of proxy servers and creates a PROXY_SERVER_LIST_ENTRY for
|
||
each one
|
||
|
||
Arguments:
|
||
|
||
lpszList - pointer to list of proxies of the form:
|
||
|
||
[<scheme>=][<scheme>"://"]<server>[":"<port>][";"*]
|
||
|
||
The list can be NULL, in which case we read it from the
|
||
registry
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_INVALID_PARAMETER
|
||
At least one entry in lpszList is bogus
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_SERVER_LIST::AddList",
|
||
"%.80q",
|
||
lpszList
|
||
));
|
||
|
||
DWORD entryLength;
|
||
LPSTR protocolName;
|
||
DWORD protocolLength;
|
||
LPSTR schemeName;
|
||
DWORD schemeLength;
|
||
LPSTR serverName;
|
||
DWORD serverLength;
|
||
PARSER_STATE state;
|
||
DWORD nSlashes;
|
||
INTERNET_PORT port;
|
||
BOOL done;
|
||
|
||
entryLength = 0;
|
||
protocolName = lpszList;
|
||
protocolLength = 0;
|
||
schemeName = NULL;
|
||
schemeLength = 0;
|
||
serverName = NULL;
|
||
serverLength = 0;
|
||
state = STATE_PROTOCOL;
|
||
nSlashes = 0;
|
||
port = 0;
|
||
done = FALSE;
|
||
|
||
//
|
||
// walk the list, pulling out the various scheme parts
|
||
//
|
||
|
||
do {
|
||
|
||
char ch = *lpszList++;
|
||
|
||
if ((nSlashes == 1) && (ch != '/')) {
|
||
state = STATE_ERROR;
|
||
break;
|
||
}
|
||
|
||
switch (ch) {
|
||
case '=':
|
||
if ((state == STATE_PROTOCOL) && (entryLength != 0)) {
|
||
protocolLength = entryLength;
|
||
entryLength = 0;
|
||
state = STATE_SCHEME;
|
||
schemeName = lpszList;
|
||
} else {
|
||
|
||
//
|
||
// '=' can't legally appear anywhere else
|
||
//
|
||
|
||
state = STATE_ERROR;
|
||
}
|
||
break;
|
||
|
||
case ':':
|
||
switch (state) {
|
||
case STATE_PROTOCOL:
|
||
if (*lpszList == '/') {
|
||
schemeName = protocolName;
|
||
protocolName = NULL;
|
||
schemeLength = entryLength;
|
||
protocolLength = 0;
|
||
state = STATE_SCHEME;
|
||
} else if (*lpszList != '\0') {
|
||
serverName = protocolName;
|
||
serverLength = entryLength;
|
||
state = STATE_PORT;
|
||
} else {
|
||
state = STATE_ERROR;
|
||
}
|
||
entryLength = 0;
|
||
break;
|
||
|
||
case STATE_SCHEME:
|
||
if (*lpszList == '/') {
|
||
schemeLength = entryLength;
|
||
} else if (*lpszList != '\0') {
|
||
serverName = schemeName;
|
||
serverLength = entryLength;
|
||
state = STATE_PORT;
|
||
} else {
|
||
state = STATE_ERROR;
|
||
}
|
||
entryLength = 0;
|
||
break;
|
||
|
||
case STATE_SERVER:
|
||
serverLength = entryLength;
|
||
state = STATE_PORT;
|
||
entryLength = 0;
|
||
break;
|
||
|
||
default:
|
||
state = STATE_ERROR;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case '/':
|
||
if ((state == STATE_SCHEME) && (nSlashes < 2) && (entryLength == 0)) {
|
||
if (++nSlashes == 2) {
|
||
state = STATE_SERVER;
|
||
serverName = lpszList;
|
||
}
|
||
} else {
|
||
state = STATE_ERROR;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
if (state != STATE_PORT) {
|
||
++entryLength;
|
||
} else if (isdigit(ch)) {
|
||
|
||
//
|
||
// BUGBUG - we will overflow if >65535
|
||
//
|
||
|
||
port = port * 10 + (ch - '0');
|
||
} else {
|
||
|
||
//
|
||
// STATE_PORT && non-digit character - error
|
||
//
|
||
|
||
state = STATE_ERROR;
|
||
}
|
||
break;
|
||
|
||
case '\0':
|
||
done = TRUE;
|
||
|
||
//
|
||
// fall through
|
||
//
|
||
|
||
case '\t':
|
||
case '\n':
|
||
case '\v': // vertical tab, 0x0b
|
||
case '\f': // form feed, 0x0c
|
||
case '\r':
|
||
case ' ':
|
||
case ';':
|
||
case ',':
|
||
if (serverLength == 0) {
|
||
serverLength = entryLength;
|
||
}
|
||
if (serverLength != 0) {
|
||
if (serverName == NULL) {
|
||
serverName = (schemeName != NULL)
|
||
? schemeName
|
||
: protocolName;
|
||
}
|
||
|
||
INET_ASSERT(serverName != NULL);
|
||
|
||
INTERNET_SCHEME protocol;
|
||
|
||
if (protocolLength != 0) {
|
||
protocol = MapUrlSchemeName(protocolName, protocolLength);
|
||
} else {
|
||
protocol = INTERNET_SCHEME_DEFAULT;
|
||
}
|
||
|
||
INTERNET_SCHEME scheme;
|
||
|
||
if (schemeLength != 0) {
|
||
scheme = MapUrlSchemeName(schemeName, schemeLength);
|
||
} else {
|
||
scheme = INTERNET_SCHEME_DEFAULT;
|
||
}
|
||
|
||
//
|
||
// add an entry if this is a protocol we handle and we don't
|
||
// already have an entry for it
|
||
//
|
||
|
||
if ((protocol != INTERNET_SCHEME_UNKNOWN)
|
||
&& (scheme != INTERNET_SCHEME_UNKNOWN)
|
||
|
||
//
|
||
// we can only currently handle CERN (secure or unsecure) and
|
||
// FTP proxies, so kick out anything that wants to go via any
|
||
// other proxy scheme
|
||
//
|
||
|
||
&& ((scheme == INTERNET_SCHEME_DEFAULT)
|
||
|| (scheme == INTERNET_SCHEME_FTP)
|
||
|| (scheme == INTERNET_SCHEME_HTTP)
|
||
|| (scheme == INTERNET_SCHEME_HTTPS))) {
|
||
if (!Find(protocol)) {
|
||
|
||
//
|
||
// don't worry if Add() fails - we just continue
|
||
//
|
||
|
||
Add(protocol, scheme, serverName, serverLength, port);
|
||
}
|
||
}
|
||
}
|
||
entryLength = 0;
|
||
protocolName = lpszList;
|
||
protocolLength = 0;
|
||
schemeName = NULL;
|
||
schemeLength = 0;
|
||
serverName = NULL;
|
||
serverLength = 0;
|
||
nSlashes = 0;
|
||
port = 0;
|
||
state = STATE_PROTOCOL;
|
||
break;
|
||
}
|
||
if (state == STATE_ERROR) {
|
||
break;
|
||
}
|
||
} while (!done);
|
||
|
||
DWORD error;
|
||
|
||
if (state == STATE_ERROR) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
} else {
|
||
error = ERROR_SUCCESS;
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_SERVER_LIST::Find(
|
||
IN INTERNET_SCHEME tScheme
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find a PROXY_SERVER_LIST_ENTRY based on the scheme
|
||
|
||
Arguments:
|
||
|
||
tScheme - protocol scheme to find
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Bool,
|
||
"PROXY_SERVER_LIST::Find",
|
||
"%s",
|
||
InternetMapScheme(tScheme)
|
||
));
|
||
|
||
BOOL found = FALSE;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_SERVER_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
|
||
|
||
if (info->_Protocol == tScheme) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
UnlockSerializedList(&_List);
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_SERVER_LIST::Add(
|
||
IN INTERNET_SCHEME tProtocol,
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create an add a PROXY_SERVER_LIST_ENTRY to the PROXY_SERVER_LIST
|
||
|
||
Arguments:
|
||
|
||
tProtocol - protocol which uses the proxy
|
||
|
||
tScheme - scheme used to talk to the proxy
|
||
|
||
lpszHostName - proxy host name
|
||
|
||
dwHostNameLength - length of proxy host name
|
||
|
||
nPort - port at proxy host
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_NOT_ENOUGH_MEMORY
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_SERVER_LIST::Add",
|
||
"%s, %s, %.*q, %d, %d",
|
||
InternetMapScheme(tProtocol),
|
||
InternetMapScheme(tScheme),
|
||
dwHostNameLength,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
));
|
||
|
||
PROXY_SERVER_LIST_ENTRY * entry;
|
||
|
||
entry = new PROXY_SERVER_LIST_ENTRY(tProtocol,
|
||
tScheme,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
);
|
||
|
||
DWORD error;
|
||
|
||
if (entry != NULL) {
|
||
//error = entry->ResolveAddress();
|
||
//if (error == ERROR_SUCCESS) {
|
||
// InsertAtTailOfSerializedList(&_List, &entry->_List);
|
||
//}
|
||
if (entry->_Protocol == INTERNET_SCHEME_DEFAULT) {
|
||
InsertAtTailOfSerializedList(&_List, &entry->_List);
|
||
} else {
|
||
InsertAtHeadOfSerializedList(&_List, &entry->_List);
|
||
}
|
||
error = ERROR_SUCCESS;
|
||
} else {
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
INTERNET_SCHEME
|
||
PROXY_SERVER_LIST::ProxyScheme(
|
||
IN INTERNET_SCHEME tProtocol
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines protocol over which tScheme goes through proxy
|
||
|
||
Arguments:
|
||
|
||
tProtocol - protocol scheme used to retrieve data (e.g. FTP)
|
||
|
||
Return Value:
|
||
|
||
INTERNET_SCHEME
|
||
Success - scheme by which protocol goes via proxy
|
||
|
||
Failure - INTERNET_SCHEME_UNKNOWN
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Int,
|
||
"PROXY_SERVER_LIST::ProxyScheme",
|
||
"%s",
|
||
InternetMapScheme(tProtocol)
|
||
));
|
||
|
||
INTERNET_SCHEME tScheme = INTERNET_SCHEME_UNKNOWN;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
//
|
||
// the list really shouldn't be empty if we're here
|
||
//
|
||
|
||
INET_ASSERT(!IsSerializedListEmpty(&_List));
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_SERVER_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
|
||
|
||
//
|
||
// if we find a match for the protocol, or this protocol is handled by
|
||
// the default proxy entry then we are done
|
||
//
|
||
|
||
if ((info->_Protocol == tProtocol)
|
||
|| (info->_Protocol == INTERNET_SCHEME_DEFAULT)) {
|
||
tScheme = info->_Scheme;
|
||
|
||
//
|
||
// the default scheme is HTTP (CERN proxy)
|
||
//
|
||
|
||
if (tScheme == INTERNET_SCHEME_DEFAULT) {
|
||
tScheme = INTERNET_SCHEME_HTTP;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
UnlockSerializedList(&_List);
|
||
|
||
DEBUG_LEAVE(tScheme);
|
||
|
||
return tScheme;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_SERVER_LIST::GetProxyInfo(
|
||
IN INTERNET_SCHEME tProtocol,
|
||
IN OUT LPINTERNET_SCHEME lptScheme,
|
||
OUT LPSTR * lplpszHostName,
|
||
OUT LPDWORD lpdwHostNameLength,
|
||
OUT LPINTERNET_PORT lpHostPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a protocol, map it to the proxy we use to retrieve the data
|
||
|
||
Arguments:
|
||
|
||
tProtocol - protocol to map (e.g. find the proxy for FTP)
|
||
|
||
lptScheme - IN: preferred scheme if INTERNET_SCHEME_DEFAULT
|
||
OUT: returned scheme
|
||
|
||
lplpszHostName - pointer to returned pointer to host name
|
||
|
||
lpdwHostNameLength - pointer to returned host name length
|
||
|
||
lpHostPort - pointer to returned host port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - requested info has been returned
|
||
|
||
FALSE - requested info was not found
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Bool,
|
||
"PROXY_SERVER_LIST::GetProxyInfo",
|
||
"%s, %#x, %#x, %#x, %#x",
|
||
InternetMapScheme(tProtocol),
|
||
lptScheme,
|
||
lplpszHostName,
|
||
lpdwHostNameLength,
|
||
lpHostPort
|
||
));
|
||
|
||
INET_ASSERT(tProtocol != INTERNET_SCHEME_UNKNOWN);
|
||
|
||
//
|
||
// *lptScheme must now be one of the recognized schemes, or the default
|
||
//
|
||
|
||
INET_ASSERT((*lptScheme == INTERNET_SCHEME_DEFAULT)
|
||
|| (*lptScheme == INTERNET_SCHEME_FTP)
|
||
|| (*lptScheme == INTERNET_SCHEME_GOPHER)
|
||
|| (*lptScheme == INTERNET_SCHEME_HTTP)
|
||
|| (*lptScheme == INTERNET_SCHEME_HTTPS)
|
||
|| (*lptScheme == INTERNET_SCHEME_SOCKS)
|
||
);
|
||
|
||
BOOL found = FALSE;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
//
|
||
// the list really shouldn't be empty if we're here
|
||
//
|
||
|
||
INET_ASSERT(!IsSerializedListEmpty(&_List));
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_SERVER_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
|
||
|
||
//
|
||
// if we find a match for the protocol, or this protocol is handled by
|
||
// the default proxy entry then we are done
|
||
//
|
||
// Hack: But make sure its NOT socks since, socks must be
|
||
// an exact match !!! No defaults.
|
||
//
|
||
|
||
if ((info->_Protocol == tProtocol)
|
||
|| ((info->_Protocol == INTERNET_SCHEME_DEFAULT)
|
||
&& (tProtocol != INTERNET_SCHEME_SOCKS) )) {
|
||
|
||
INTERNET_SCHEME scheme = info->_Scheme;
|
||
|
||
//
|
||
// the returned scheme is the input preferred scheme unless it was
|
||
// the default scheme in which case we return HTTP (CERN proxy)
|
||
//
|
||
|
||
if (scheme == INTERNET_SCHEME_DEFAULT) {
|
||
scheme = (*lptScheme == INTERNET_SCHEME_DEFAULT)
|
||
? INTERNET_SCHEME_HTTP
|
||
: *lptScheme;
|
||
}
|
||
*lptScheme = scheme;
|
||
|
||
//
|
||
// BUGBUG
|
||
//
|
||
// N.B. We are returning a pointer to the ICSTRING's string buffer.
|
||
// While we don't expect this string to be reallocated or the proxy
|
||
// info to change, it may do if we ever reset the proxy list on the
|
||
// fly. Something we may have to enable for Nashville
|
||
//
|
||
|
||
*lplpszHostName = info->_ProxyName.StringAddress();
|
||
*lpdwHostNameLength = info->_ProxyName.StringLength();
|
||
|
||
INTERNET_PORT port = info->_ProxyPort;
|
||
|
||
//
|
||
// map the default port value
|
||
//
|
||
|
||
if (port == INTERNET_INVALID_PORT_NUMBER) {
|
||
switch (scheme) {
|
||
case INTERNET_SCHEME_FTP:
|
||
port = INTERNET_DEFAULT_FTP_PORT;
|
||
break;
|
||
|
||
case INTERNET_SCHEME_GOPHER:
|
||
port = INTERNET_DEFAULT_GOPHER_PORT;
|
||
break;
|
||
|
||
case INTERNET_SCHEME_HTTP:
|
||
port = INTERNET_DEFAULT_HTTP_PORT;
|
||
break;
|
||
|
||
case INTERNET_SCHEME_HTTPS:
|
||
port = INTERNET_DEFAULT_HTTPS_PORT;
|
||
break;
|
||
case INTERNET_SCHEME_SOCKS:
|
||
port = INTERNET_DEFAULT_SOCKS_PORT;
|
||
break;
|
||
}
|
||
}
|
||
*lpHostPort = port;
|
||
found = TRUE;
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
INFO,
|
||
("proxy = %s://%s:%d\n",
|
||
MapUrlSchemeToName(scheme),
|
||
info->_ProxyName.StringAddress(),
|
||
port
|
||
));
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
UnlockSerializedList(&_List);
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_SERVER_LIST::AddToBypassList(
|
||
IN PROXY_BYPASS_LIST * lpBypassList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For all proxy servers in the server list, we add the details to the bypass
|
||
list. By default, an app mustn't send a request to the proxy via the proxy!
|
||
Additionally, the app should not have to specifically nominate the proxy
|
||
server(s) as bypassing the proxy
|
||
|
||
Arguments:
|
||
|
||
lpBypassList - pointer to bypass proxy list where proxy servers will be
|
||
added
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_NOT_ENOUGH_MEMORY
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD error = ERROR_SUCCESS;
|
||
PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
|
||
while ((entry != (PLIST_ENTRY)SlSelf(&_List)) && (error == ERROR_SUCCESS)) {
|
||
|
||
PROXY_SERVER_LIST_ENTRY * info = (PROXY_SERVER_LIST_ENTRY *)entry;
|
||
|
||
if (!lpBypassList->Find(info->_Scheme,
|
||
info->_ProxyName.StringAddress(),
|
||
info->_ProxyName.StringLength(),
|
||
info->_ProxyPort)) {
|
||
error = lpBypassList->Add(info->_Scheme,
|
||
info->_ProxyName.StringAddress(),
|
||
info->_ProxyName.StringLength(),
|
||
info->_ProxyPort
|
||
);
|
||
}
|
||
entry = entry->Flink;
|
||
}
|
||
return error;
|
||
}
|
||
|
||
|
||
VOID
|
||
PROXY_SERVER_LIST::GetList(
|
||
OUT LPSTR * lplpszList,
|
||
IN DWORD dwBufferLength,
|
||
IN OUT LPDWORD lpdwRequiredLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes the list of proxy servers to a buffer, and/or returns the required
|
||
buffer length
|
||
|
||
Arguments:
|
||
|
||
lplpszList - pointer to pointer to buffer where list is written, if
|
||
sufficient space
|
||
|
||
dwBufferLength - amount of space in *lplpszList
|
||
|
||
lpdwRequiredLength - OUT: cumulative size of data
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPSTR lpszList = *lplpszList;
|
||
BOOL firstTime = TRUE;
|
||
BOOL outOfBuffer = FALSE;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_SERVER_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
|
||
if (!firstTime) {
|
||
|
||
//
|
||
// write delimiter if enough space
|
||
//
|
||
|
||
if (dwBufferLength >= 1) {
|
||
*lpszList++ = ' ';
|
||
--dwBufferLength;
|
||
}
|
||
++*lpdwRequiredLength;
|
||
} else {
|
||
firstTime = FALSE;
|
||
}
|
||
|
||
//
|
||
// find the length of the current entry & write it to the buffer if
|
||
// enough space
|
||
//
|
||
|
||
DWORD length = dwBufferLength;
|
||
|
||
info->WriteEntry(lpszList, &length);
|
||
if (dwBufferLength >= length) {
|
||
|
||
//
|
||
// we wrote it
|
||
//
|
||
|
||
dwBufferLength -= length;
|
||
} else {
|
||
|
||
//
|
||
// no buffer left
|
||
//
|
||
|
||
dwBufferLength = 0;
|
||
outOfBuffer = TRUE;
|
||
}
|
||
*lpdwRequiredLength += length;
|
||
lpszList += length;
|
||
}
|
||
|
||
if (!outOfBuffer) {
|
||
if (dwBufferLength > 0) {
|
||
*lpszList++ = '\0';
|
||
*lplpszList = lpszList;
|
||
}
|
||
}
|
||
|
||
//
|
||
// add 1 for the terminating NUL
|
||
//
|
||
|
||
++*lpdwRequiredLength;
|
||
|
||
UnlockSerializedList(&_List);
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_BYPASS_LIST_ENTRY::WriteEntry(
|
||
OUT LPSTR lpszBuffer,
|
||
IN OUT LPDWORD lpdwBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes this proxy bypass list entry as a string in the supplied buffer
|
||
|
||
Arguments:
|
||
|
||
lpszBuffer - pointer to buffer where string is written
|
||
|
||
lpdwBufferLength - IN: amount of space in buffer
|
||
OUT: number of bytes copied, or required size
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - entry written to buffer
|
||
|
||
FALSE - entry not written to buffer - *lpdwBufferLength contains
|
||
required size
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD requiredLength;
|
||
LPSTR schemeName;
|
||
DWORD schemeNameLength;
|
||
INTERNET_PORT magnitude;
|
||
|
||
if (_Scheme != INTERNET_SCHEME_DEFAULT) {
|
||
schemeName = MapUrlScheme(_Scheme, &schemeNameLength);
|
||
requiredLength = schemeNameLength + sizeof("://") - 1;
|
||
} else {
|
||
schemeName = NULL;
|
||
requiredLength = 0;
|
||
}
|
||
if (IsLocal()) {
|
||
requiredLength += sizeof("<local>") - 1;
|
||
} else {
|
||
requiredLength += _Name.StringLength();
|
||
}
|
||
if (_Port != INTERNET_INVALID_PORT_NUMBER) {
|
||
for (INTERNET_PORT n = 10000, i = 5; n > 0; n /= 10, --i) {
|
||
if (_Port / n) {
|
||
requiredLength += i + 1;
|
||
magnitude = n;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOL success;
|
||
|
||
if (*lpdwBufferLength > requiredLength) {
|
||
if (schemeName != NULL) {
|
||
memcpy(lpszBuffer, schemeName, schemeNameLength);
|
||
lpszBuffer += schemeNameLength;
|
||
memcpy(lpszBuffer, "://", sizeof("://") - 1);
|
||
lpszBuffer += sizeof("://") - 1;
|
||
}
|
||
if (IsLocal()) {
|
||
memcpy(lpszBuffer, "<local>", sizeof("<local>") - 1);
|
||
lpszBuffer += sizeof("<local>") - 1;
|
||
} else {
|
||
_Name.CopyTo(lpszBuffer);
|
||
lpszBuffer += _Name.StringLength();
|
||
}
|
||
if (_Port != INTERNET_INVALID_PORT_NUMBER) {
|
||
*lpszBuffer++ = ':';
|
||
for (INTERNET_PORT n = _Port, i = magnitude; i; i /= 10) {
|
||
*lpszBuffer++ = (char)(n / i) + '0';
|
||
n %= i;
|
||
}
|
||
}
|
||
success = TRUE;
|
||
} else {
|
||
success = FALSE;
|
||
}
|
||
*lpdwBufferLength = requiredLength;
|
||
return success;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_BYPASS_LIST::AddList(
|
||
IN LPSTR lpszList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses a list of proxy bypass specifiers and adds them to the list
|
||
|
||
Arguments:
|
||
|
||
lpszList - pointer to string containing list of proxy bypass specifiers.
|
||
The format is:
|
||
|
||
[<scheme>"://"][<server>][":"<port>"]
|
||
|
||
The list can be NULL, in which case we read it from the
|
||
registry
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_INVALID_PARAMETER
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_BYPASS_LIST::AddList",
|
||
"%.80q",
|
||
lpszList
|
||
));
|
||
|
||
DWORD entryLength;
|
||
LPSTR schemeName;
|
||
DWORD schemeLength;
|
||
LPSTR serverName;
|
||
DWORD serverLength;
|
||
PARSER_STATE state;
|
||
DWORD nSlashes;
|
||
INTERNET_PORT port;
|
||
BOOL done;
|
||
|
||
entryLength = 0;
|
||
schemeName = lpszList;
|
||
schemeLength = 0;
|
||
serverName = NULL;
|
||
serverLength = 0;
|
||
state = STATE_SCHEME;
|
||
nSlashes = 0;
|
||
port = 0;
|
||
done = FALSE;
|
||
|
||
//
|
||
// walk the list, pulling out the various scheme parts
|
||
//
|
||
|
||
do {
|
||
|
||
char ch = *lpszList++;
|
||
|
||
if ((nSlashes == 1) && (ch != '/')) {
|
||
state = STATE_ERROR;
|
||
break;
|
||
}
|
||
|
||
switch (ch) {
|
||
case ':':
|
||
switch (state) {
|
||
case STATE_SCHEME:
|
||
if (*lpszList == '/') {
|
||
schemeLength = entryLength;
|
||
} else if (*lpszList != '\0') {
|
||
serverName = schemeName;
|
||
serverLength = entryLength;
|
||
if (serverLength == 0) {
|
||
serverLength = 1;
|
||
serverName = "*";
|
||
}
|
||
state = STATE_PORT;
|
||
} else {
|
||
state = STATE_ERROR;
|
||
}
|
||
entryLength = 0;
|
||
break;
|
||
|
||
case STATE_SERVER:
|
||
serverLength = entryLength;
|
||
state = STATE_PORT;
|
||
entryLength = 0;
|
||
break;
|
||
|
||
default:
|
||
state = STATE_ERROR;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case '/':
|
||
if ((state == STATE_SCHEME) && (nSlashes < 2) && (entryLength == 0)) {
|
||
if (++nSlashes == 2) {
|
||
state = STATE_SERVER;
|
||
serverName = lpszList;
|
||
}
|
||
} else {
|
||
state = STATE_ERROR;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
if (state != STATE_PORT) {
|
||
++entryLength;
|
||
} else if (isdigit(ch)) {
|
||
|
||
//
|
||
// BUGBUG - we will overflow if >65535
|
||
//
|
||
|
||
port = port * 10 + (ch - '0');
|
||
} else {
|
||
|
||
//
|
||
// STATE_PORT && non-digit character - error
|
||
//
|
||
|
||
state = STATE_ERROR;
|
||
}
|
||
break;
|
||
|
||
case '\0':
|
||
done = TRUE;
|
||
|
||
//
|
||
// fall through
|
||
//
|
||
|
||
case '\t':
|
||
case '\n':
|
||
case '\v': // vertical tab, 0x0b
|
||
case '\f': // form feed, 0x0c
|
||
case '\r':
|
||
case ' ':
|
||
case ';':
|
||
case ',':
|
||
if (serverLength == 0) {
|
||
serverLength = entryLength;
|
||
if ((serverLength == 0)
|
||
&& ((state == STATE_SERVER) || (state == STATE_PORT))) {
|
||
|
||
//
|
||
// we found e.g. "http://" or "http://:80". We allow this as
|
||
// "http://*" or "http://*:80"
|
||
//
|
||
|
||
serverLength = 1;
|
||
serverName = "*";
|
||
}
|
||
}
|
||
if (serverLength != 0) {
|
||
if (serverName == NULL) {
|
||
serverName = schemeName;
|
||
}
|
||
|
||
INTERNET_SCHEME scheme;
|
||
|
||
if (schemeLength != 0) {
|
||
scheme = MapUrlSchemeName(schemeName, schemeLength);
|
||
} else {
|
||
scheme = INTERNET_SCHEME_DEFAULT;
|
||
}
|
||
|
||
//
|
||
// add an entry if this is a protocol we handle and we don't
|
||
// already have an entry for it
|
||
//
|
||
|
||
if ((scheme != INTERNET_SCHEME_UNKNOWN)
|
||
&& !Find(scheme, serverName, serverLength, port)) {
|
||
|
||
//
|
||
// don't worry if Add() fails - we just continue
|
||
//
|
||
|
||
Add(scheme, serverName, serverLength, port);
|
||
}
|
||
}
|
||
entryLength = 0;
|
||
schemeName = lpszList;
|
||
schemeLength = 0;
|
||
serverName = NULL;
|
||
serverLength = 0;
|
||
nSlashes = 0;
|
||
port = 0;
|
||
state = STATE_SCHEME;
|
||
break;
|
||
}
|
||
if (state == STATE_ERROR) {
|
||
break;
|
||
}
|
||
} while (!done);
|
||
|
||
DWORD error;
|
||
|
||
if (state == STATE_ERROR) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
} else {
|
||
error = ERROR_SUCCESS;
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_BYPASS_LIST::Find(
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName OPTIONAL,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if a proxy bypass entry matches the criteria.
|
||
|
||
Currently, name matching is simplistic: e.g. "*.com" and "**.com" are
|
||
treated as 2 separate strings, where we should collapse multiple wildcard
|
||
specifiers, etc. Also: "w*" should replace "ww*", etc.
|
||
|
||
Arguments:
|
||
|
||
tScheme - scheme for this entry
|
||
|
||
lpszHostName - host name or address. May contain wildcards (*)
|
||
|
||
dwHostNameLength - length of host name or address
|
||
|
||
nPort - port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - an entry corresponding to the arguments was found
|
||
|
||
FALSE - didn't find entry
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Bool,
|
||
"PROXY_BYPASS_LIST::Find",
|
||
"%s, %.*q, %d, %d",
|
||
InternetMapScheme(tScheme),
|
||
dwHostNameLength,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
));
|
||
|
||
BOOL isLocal = IsLocalMacro(lpszHostName, dwHostNameLength);
|
||
BOOL found = FALSE;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_BYPASS_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
|
||
|
||
//
|
||
// do the easy bits first
|
||
//
|
||
|
||
if (!((info->_Scheme == tScheme)
|
||
|| (info->_Scheme == INTERNET_SCHEME_DEFAULT))) {
|
||
continue;
|
||
}
|
||
if (!((info->_Port == nPort)
|
||
|| (info->_Port == INTERNET_INVALID_PORT_NUMBER))) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// check for name match
|
||
//
|
||
|
||
if (info->_LocalSemantics) {
|
||
if (isLocal) {
|
||
found = TRUE;
|
||
break;
|
||
} else {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// not local semantics, have to match target
|
||
//
|
||
|
||
//
|
||
// BUGBUG - we only do simplistic matching. If the strings don't match
|
||
// exactly, except for case, they are deemed to be different
|
||
//
|
||
|
||
if (info->_Name.Strnicmp(lpszHostName, (int)dwHostNameLength) != 0) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// any path that didn't continue, or has not already broken out has
|
||
// succeeded in finding a match
|
||
//
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
INFO,
|
||
("Matched: %q, %q\n",
|
||
lpszHostName,
|
||
info->_Name.StringAddress()
|
||
));
|
||
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
|
||
UnlockSerializedList(&_List);
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_BYPASS_LIST::Add(
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create and add a PROXY_BYPASS_LIST_ENTRY to the PROXY_BYPASS_LIST
|
||
|
||
Arguments:
|
||
|
||
tScheme - scheme to bypass. May be 0 meaning any protocol
|
||
|
||
lpszHostName - name of host to bypass. May be name or IP address and
|
||
may contain wildcard characters
|
||
|
||
dwHostNameLength - length of bypass name string
|
||
|
||
nPort - port to bypass. May be 0, meaning any port
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_NOT_ENOUGH_MEMORY
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_BYPASS_LIST::Add",
|
||
"%s, %.*q, %d, %d",
|
||
InternetMapScheme(tScheme),
|
||
dwHostNameLength,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
));
|
||
|
||
PROXY_BYPASS_LIST_ENTRY * entry;
|
||
|
||
entry = new PROXY_BYPASS_LIST_ENTRY(tScheme,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
);
|
||
|
||
DWORD error;
|
||
|
||
if (entry != NULL) {
|
||
|
||
//
|
||
// if the bypass entry uses local name matching semantics, then we add
|
||
// it to the end of the list, else the head. The reason we do this is
|
||
// to allow <local> to be a default after all other (possibly also
|
||
// local) entries are checked
|
||
//
|
||
|
||
if (entry->IsLocal()) {
|
||
InsertAtTailOfSerializedList(&_List, &entry->_List);
|
||
} else {
|
||
InsertAtHeadOfSerializedList(&_List, &entry->_List);
|
||
}
|
||
error = ERROR_SUCCESS;
|
||
} else {
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_BYPASS_LIST::IsBypassed(
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if a scheme/name/port is bypassed
|
||
|
||
Arguments:
|
||
|
||
tScheme - can be 0, meaning match any scheme
|
||
|
||
lpszHostName - can contain wildcards. May be name or IP address
|
||
|
||
dwHostNameLength - length of name/address part. May be 0, meaning match
|
||
any name/address
|
||
|
||
nPort - can be 0, meaning match any port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - an entry on the bypass list matched the criteria
|
||
|
||
FALSE - the host identified by the parameters is not on this bypass
|
||
list
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Bool,
|
||
"PROXY_BYPASS_LIST::IsBypassed",
|
||
"%s, %.*q, %d, %d",
|
||
InternetMapScheme(tScheme),
|
||
dwHostNameLength,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
));
|
||
|
||
INET_ASSERT(lpszHostName != NULL);
|
||
INET_ASSERT(dwHostNameLength != 0);
|
||
|
||
BOOL found = FALSE;
|
||
|
||
//
|
||
// determine if what we were given is an address, in which case we don't
|
||
// perform <local> semantics matching
|
||
//
|
||
|
||
BOOL isAddress = FALSE;
|
||
LPSTR mappedName;
|
||
|
||
if (dwHostNameLength <= MAX_IP_ADDRESS_STRING_LENGTH) {
|
||
|
||
char addressBuffer[MAX_IP_ADDRESS_STRING_LENGTH + 1];
|
||
|
||
//
|
||
// make the host name/address an ASCIIZ string
|
||
//
|
||
|
||
memcpy((LPVOID)addressBuffer, (LPVOID)lpszHostName, dwHostNameLength);
|
||
addressBuffer[dwHostNameLength] = '\0';
|
||
if (_I_inet_addr(addressBuffer) != INADDR_NONE) {
|
||
|
||
//
|
||
// looks like we were given an IP address
|
||
//
|
||
|
||
//
|
||
// maybe this is the IP address of a known server (in cache)
|
||
//
|
||
|
||
mappedName = MapNetAddressToName(addressBuffer);
|
||
if (mappedName == addressBuffer) {
|
||
|
||
//
|
||
// BUGBUG - transport independence?
|
||
//
|
||
|
||
isAddress = TRUE;
|
||
} else {
|
||
lpszHostName = mappedName;
|
||
dwHostNameLength = lstrlen(lpszHostName);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// if not an address, determine if the name contains at least one dot
|
||
//
|
||
|
||
BOOL isDot;
|
||
|
||
if (!isAddress) {
|
||
isDot = FALSE;
|
||
for (DWORD i = 0; i < dwHostNameLength; ++i) {
|
||
if (lpszHostName[i] == '.') {
|
||
isDot = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// addresses have dots
|
||
//
|
||
|
||
isDot = TRUE;
|
||
}
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_BYPASS_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
|
||
|
||
//
|
||
// do the easy bits first
|
||
//
|
||
|
||
if (!((info->_Scheme == tScheme)
|
||
|| (info->_Scheme == INTERNET_SCHEME_DEFAULT))) {
|
||
continue;
|
||
}
|
||
if (!((info->_Port == nPort)
|
||
|| (info->_Port == INTERNET_INVALID_PORT_NUMBER))) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// check local semantics
|
||
//
|
||
|
||
if (info->_LocalSemantics) {
|
||
if (!isDot) {
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
INFO,
|
||
("%q matched by <local>\n",
|
||
lpszHostName
|
||
));
|
||
|
||
found = TRUE;
|
||
|
||
//
|
||
// <local> is in the bypass list and the name does not contain a
|
||
// dot. It bypasses the proxy
|
||
//
|
||
|
||
break;
|
||
} else {
|
||
|
||
//
|
||
// the name contains a dot, but it may be matched by another
|
||
// proxy bypass entry
|
||
//
|
||
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// check for name match. Note that we take no special action if the host
|
||
// name contains wildcard characters
|
||
//
|
||
|
||
LPSTR target = info->_Name.StringAddress();
|
||
|
||
//
|
||
// NULL target name matches any server name/address
|
||
//
|
||
|
||
if (target != NULL) {
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
INFO,
|
||
("trying to match %q with %q\n",
|
||
lpszHostName,
|
||
target
|
||
));
|
||
|
||
DWORD i = 0;
|
||
DWORD j = 0;
|
||
DWORD i_back = (DWORD)-1;
|
||
|
||
while ((target[i] != '\0') && (j < dwHostNameLength)) {
|
||
if (target[i] == tolower(lpszHostName[j])) {
|
||
++i;
|
||
++j;
|
||
} else if (target[i] == '*') {
|
||
while (target[i + 1] == '*') {
|
||
++i;
|
||
}
|
||
i_back = i;
|
||
++i;
|
||
while ((tolower(lpszHostName[j]) != target[i])
|
||
&& (j < dwHostNameLength)) {
|
||
++j;
|
||
}
|
||
} else if (i_back != (DWORD)-1) {
|
||
|
||
//
|
||
// '*' is greedy closure. We already saw a '*' but later we
|
||
// discovered a mismatch. We will go back and try to eat as
|
||
// many characters as we can till the next match, or we hit
|
||
// the end of the string
|
||
//
|
||
|
||
i = i_back;
|
||
} else {
|
||
|
||
//
|
||
// no match; quit
|
||
//
|
||
|
||
j = 0;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// if we reached the end of the target, but not the host name
|
||
// AND we already met a '*' then back up
|
||
//
|
||
|
||
if ((target[i] == '\0')
|
||
&& (lpszHostName[j] != '\0')
|
||
&& (i_back != (DWORD)-1)) {
|
||
i = i_back;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if we hit the end of the host name while matching any character,
|
||
// bump the target to the next non-star character
|
||
//
|
||
|
||
while (target[i] == '*') {
|
||
++i;
|
||
}
|
||
|
||
//
|
||
// the host name matched if we reached the end of the target and end
|
||
// of the host name
|
||
//
|
||
|
||
if (!((target[i] == '\0') && (j == dwHostNameLength))) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// any path that didn't continue, or has not already broken out has
|
||
// succeeded in finding a match
|
||
//
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
INFO,
|
||
("Matched: %q, %q\n",
|
||
lpszHostName,
|
||
target
|
||
));
|
||
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
|
||
UnlockSerializedList(&_List);
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
VOID
|
||
PROXY_BYPASS_LIST::GetList(
|
||
OUT LPSTR * lplpszList,
|
||
IN DWORD dwBufferLength,
|
||
IN OUT LPDWORD lpdwRequiredLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes the list of proxy bypass servers to a buffer, and/or returns the
|
||
required buffer length
|
||
|
||
Arguments:
|
||
|
||
lplpszList - pointer to pointer to buffer where list is written, if
|
||
sufficient space
|
||
|
||
dwBufferLength - amount of space in *lplpszList
|
||
|
||
lpdwRequiredLength - OUT: cumulative size of data
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
--*/
|
||
|
||
{
|
||
LPSTR lpszList = *lplpszList;
|
||
BOOL firstTime = TRUE;
|
||
BOOL outOfBuffer = FALSE;
|
||
|
||
LockSerializedList(&_List);
|
||
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
|
||
entry != (PLIST_ENTRY)SlSelf(&_List);
|
||
entry = entry->Flink) {
|
||
|
||
PROXY_BYPASS_LIST_ENTRY * info;
|
||
|
||
info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
|
||
if (!firstTime) {
|
||
|
||
//
|
||
// write delimiter if enough space
|
||
//
|
||
|
||
if (dwBufferLength >= 1) {
|
||
*lpszList++ = ' ';
|
||
--dwBufferLength;
|
||
}
|
||
++*lpdwRequiredLength;
|
||
} else {
|
||
firstTime = FALSE;
|
||
}
|
||
|
||
//
|
||
// find the length of the current entry & write it to the buffer if
|
||
// enough space
|
||
//
|
||
|
||
DWORD length = dwBufferLength;
|
||
|
||
info->WriteEntry(lpszList, &length);
|
||
if (dwBufferLength >= length) {
|
||
|
||
//
|
||
// we wrote it
|
||
//
|
||
|
||
dwBufferLength -= length;
|
||
} else {
|
||
|
||
//
|
||
// no buffer left
|
||
//
|
||
|
||
dwBufferLength = 0;
|
||
outOfBuffer = TRUE;
|
||
}
|
||
*lpdwRequiredLength += length;
|
||
lpszList += length;
|
||
}
|
||
|
||
if (!outOfBuffer) {
|
||
if (dwBufferLength > 0) {
|
||
*lpszList++ = '\0';
|
||
*lplpszList = lpszList;
|
||
}
|
||
}
|
||
|
||
//
|
||
// add 1 for the terminating NUL
|
||
//
|
||
|
||
++*lpdwRequiredLength;
|
||
UnlockSerializedList(&_List);
|
||
}
|
||
|
||
|
||
INTERNET_SCHEME
|
||
PROXY_INFO::ProxyScheme(
|
||
IN INTERNET_SCHEME tProtocol
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines protocol over which tScheme goes through proxy
|
||
If there is an external proxy DLL, we call down to it for the
|
||
correct scheme to use. In other words, we defer to the DLL.
|
||
|
||
Arguments:
|
||
|
||
tProtocol - protocol scheme used to retrieve data (e.g. FTP)
|
||
|
||
Return Value:
|
||
|
||
INTERNET_SCHEME
|
||
Success - scheme by which protocol goes via proxy
|
||
|
||
Failure - INTERNET_SCHEME_UNKNOWN
|
||
--*/
|
||
|
||
{
|
||
|
||
INTERNET_SCHEME scheme;
|
||
|
||
Lock(FALSE);
|
||
|
||
if ( _UseExternalAutoConfigDLL && pProxyScheme) {
|
||
|
||
INET_ASSERT(!IsBadCodePtr((FARPROC)pProxyScheme));
|
||
|
||
(pProxyScheme)(tProtocol, &scheme);
|
||
}
|
||
else if (_ProxyServerList != NULL)
|
||
{
|
||
scheme = _ProxyServerList->ProxyScheme(tProtocol);
|
||
}
|
||
else
|
||
{
|
||
scheme = INTERNET_SCHEME_UNKNOWN;
|
||
}
|
||
|
||
Unlock();
|
||
|
||
return scheme;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_INFO::SetProxyInfo(
|
||
IN DWORD dwAccessType,
|
||
IN LPCSTR lpszProxy OPTIONAL,
|
||
IN LPCSTR lpszProxyBypass OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the proxy info. Either creates new proxy server and bypass lists, or
|
||
removes them (proxy to direct)
|
||
|
||
Assumes: 1. The parameters have already been validated in the API that calls
|
||
this method (i.e. InternetOpen(), InternetSetOption())
|
||
|
||
Arguments:
|
||
|
||
dwAccessType - type of proxy access required
|
||
|
||
lpszProxy - pointer to proxy server list
|
||
|
||
lpszProxyBypass - pointer to proxy bypass list
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_INVALID_PARAMETER
|
||
The lpszProxy or lpszProxyBypass list was bad
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY
|
||
Failed to create an object or allocate space for a list,
|
||
etc.
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_INFO::SetProxyInfo",
|
||
"%s (%d), %#x (%q), %#x (%q)",
|
||
InternetMapOpenType(dwAccessType),
|
||
dwAccessType,
|
||
lpszProxy,
|
||
lpszProxy,
|
||
lpszProxyBypass,
|
||
lpszProxyBypass
|
||
));
|
||
|
||
//
|
||
// parameters should already be validated by caller
|
||
//
|
||
|
||
INET_ASSERT((dwAccessType == INTERNET_OPEN_TYPE_DIRECT)
|
||
|| (dwAccessType == INTERNET_OPEN_TYPE_PROXY)
|
||
|| (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
|
||
);
|
||
|
||
BOOL isProxy;
|
||
BOOL newList;
|
||
LPSTR serverList;
|
||
LPSTR bypassList;
|
||
|
||
if (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) {
|
||
InternetReadRegistryDword("ProxyEnable", (LPDWORD)&isProxy);
|
||
if (isProxy) {
|
||
serverList = GetRegistryProxyParameter("ProxyServer");
|
||
if (serverList != NULL) {
|
||
bypassList = GetRegistryProxyParameter("ProxyOverride");
|
||
newList = TRUE;
|
||
} else {
|
||
|
||
DEBUG_PRINT(PROXY,
|
||
ERROR,
|
||
("PRECONFIG: ProxyEnable TRUE, ProxyServer NULL\n"
|
||
));
|
||
|
||
bypassList = NULL;
|
||
newList = FALSE;
|
||
}
|
||
} else {
|
||
serverList = NULL;
|
||
bypassList = NULL;
|
||
newList = FALSE;
|
||
}
|
||
} else if (dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
|
||
serverList = (LPSTR)lpszProxy;
|
||
bypassList = (LPSTR)lpszProxyBypass;
|
||
newList = TRUE;
|
||
|
||
INET_ASSERT(serverList != NULL);
|
||
|
||
} else {
|
||
newList = FALSE;
|
||
}
|
||
|
||
//
|
||
// about to start changing contents - acquire lock
|
||
//
|
||
|
||
Lock(TRUE);
|
||
|
||
//
|
||
// clear out current contents
|
||
//
|
||
|
||
CleanOutLists();
|
||
|
||
DWORD error = ERROR_SUCCESS;
|
||
|
||
if (newList) {
|
||
|
||
INET_ASSERT((serverList != NULL) && (*serverList != 0));
|
||
|
||
_ProxyServerList = new PROXY_SERVER_LIST(serverList);
|
||
_ProxyBypassList = new PROXY_BYPASS_LIST(bypassList);
|
||
if ((_ProxyServerList != NULL) && (_ProxyBypassList != NULL)) {
|
||
_Error = _ProxyServerList->GetError();
|
||
if (_Error == ERROR_SUCCESS) {
|
||
_Error = _ProxyBypassList->GetError();
|
||
if (_Error == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// add all proxy servers to bypass list
|
||
//
|
||
|
||
_ProxyServerList->AddToBypassList(_ProxyBypassList);
|
||
}
|
||
}
|
||
} else {
|
||
_Error = ERROR_NOT_ENOUGH_MEMORY;
|
||
CleanOutLists();
|
||
}
|
||
error = _Error;
|
||
}
|
||
|
||
//
|
||
// if we're setting anything other than preconfig then this PROXY_INFO has
|
||
// been modified. The reason is the new SetInfo semantics. So long as the
|
||
// proxy info is coming from registry, it can be updated automatically when
|
||
// the registry changes, but if an app is using its own global proxy
|
||
// settings then we can no longer update global settings from the registry.
|
||
// We rely on the INTERNET_HANDLE_OBJECT methods to ensure that requests to
|
||
// change global proxy info back to registry settings never make it this far
|
||
//
|
||
|
||
_Modified = (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) ? FALSE : TRUE;
|
||
|
||
//
|
||
// other threads free to access this PROXY_INFO again
|
||
//
|
||
|
||
Unlock();
|
||
|
||
//
|
||
// free up the lists we allocated
|
||
//
|
||
|
||
if (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) {
|
||
if (serverList != NULL) {
|
||
ResizeBuffer(serverList, 0, FALSE);
|
||
}
|
||
if (bypassList != NULL) {
|
||
ResizeBuffer(bypassList, 0, FALSE);
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_INFO::GetProxyInfo(
|
||
IN INTERNET_SCHEME tProtocol,
|
||
IN OUT LPINTERNET_SCHEME lptScheme,
|
||
OUT LPSTR * lplpszHostName,
|
||
OUT LPDWORD lpdwHostNameLength,
|
||
OUT LPINTERNET_PORT lpHostPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a protocol, map it to the proxy we use to retrieve the data
|
||
If there is an external proxy DLL, we call down to it for the
|
||
correct proxy to use.
|
||
|
||
Arguments:
|
||
|
||
tProtocol - protocol to map (e.g. find the proxy for FTP)
|
||
|
||
lptScheme - IN: preferred scheme if INTERNET_SCHEME_DEFAULT
|
||
OUT: returned scheme
|
||
|
||
lplpszHostName - pointer to returned pointer to host name
|
||
|
||
lpdwHostNameLength - pointer to returned host name length
|
||
|
||
lpHostPort - pointer to returned host port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - requested info has been returned
|
||
|
||
FALSE - requested info was not found
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL success;
|
||
|
||
Lock(FALSE);
|
||
|
||
if ( _UseExternalAutoConfigDLL && pGetProxyInfo) {
|
||
|
||
INET_ASSERT(!IsBadCodePtr((FARPROC)pGetProxyInfo));
|
||
|
||
success = (pGetProxyInfo)(tProtocol,
|
||
lptScheme,
|
||
lplpszHostName,
|
||
lpdwHostNameLength,
|
||
lpHostPort
|
||
);
|
||
|
||
}
|
||
else if (_ProxyServerList != NULL)
|
||
{
|
||
success = _ProxyServerList->GetProxyInfo(tProtocol,
|
||
lptScheme,
|
||
lplpszHostName,
|
||
lpdwHostNameLength,
|
||
lpHostPort
|
||
);
|
||
}
|
||
else
|
||
{
|
||
success = FALSE;
|
||
}
|
||
|
||
Unlock();
|
||
|
||
return success;
|
||
}
|
||
|
||
|
||
DWORD
|
||
PROXY_INFO::GetProxyInfo(
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpdwBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the proxy server and bypass lists in an INTERNET_PROXY_INFO. Called
|
||
by InternetQueryOption(INTERNET_OPTION_PROXY)
|
||
|
||
Assumes: Access to this is serialized while we are getting this info
|
||
|
||
Arguments:
|
||
|
||
lpBuffer - pointer to buffer where information will be returned
|
||
|
||
lpdwBufferLength - IN: size of lpBuffer in BYTEs
|
||
OUT: number of BYTEs returned in lpBuffer
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_INSUFFICIENT_BUFFER
|
||
*lpdwBufferLength contains the required buffer length
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_PROXY,
|
||
Dword,
|
||
"PROXY_INFO::GetProxyInfo",
|
||
"%#x, %#x [%d]",
|
||
lpBuffer,
|
||
lpdwBufferLength,
|
||
*lpdwBufferLength
|
||
));
|
||
|
||
DWORD requiredSize = sizeof(INTERNET_PROXY_INFO);
|
||
LPSTR lpVariable = (LPSTR)(((LPINTERNET_PROXY_INFO)lpBuffer) + 1);
|
||
LPSTR lpszProxy;
|
||
|
||
if (_ProxyServerList != NULL) {
|
||
lpszProxy = lpVariable;
|
||
_ProxyServerList->GetList(&lpVariable,
|
||
(*lpdwBufferLength > requiredSize)
|
||
? (*lpdwBufferLength - requiredSize)
|
||
: 0,
|
||
&requiredSize
|
||
);
|
||
} else {
|
||
lpszProxy = NULL;
|
||
}
|
||
|
||
LPSTR lpszProxyBypass;
|
||
|
||
if (_ProxyBypassList != NULL) {
|
||
|
||
DWORD size = requiredSize;
|
||
|
||
lpszProxyBypass = lpVariable;
|
||
_ProxyBypassList->GetList(&lpVariable,
|
||
(*lpdwBufferLength > requiredSize)
|
||
? (*lpdwBufferLength - requiredSize)
|
||
: 0,
|
||
&requiredSize
|
||
);
|
||
if (requiredSize == size) {
|
||
lpszProxyBypass = NULL;
|
||
}
|
||
} else {
|
||
lpszProxyBypass = NULL;
|
||
}
|
||
|
||
DWORD error;
|
||
|
||
if (*lpdwBufferLength >= requiredSize) {
|
||
|
||
LPINTERNET_PROXY_INFO lpInfo = (LPINTERNET_PROXY_INFO)lpBuffer;
|
||
|
||
lpInfo->dwAccessType = (lpszProxy == NULL)
|
||
? INTERNET_OPEN_TYPE_DIRECT
|
||
: INTERNET_OPEN_TYPE_PROXY;
|
||
lpInfo->lpszProxy = lpszProxy;
|
||
lpInfo->lpszProxyBypass = lpszProxyBypass;
|
||
error = ERROR_SUCCESS;
|
||
} else {
|
||
error = ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
*lpdwBufferLength = requiredSize;
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_INFO::IsBypassed(
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN DWORD dwHostNameLength,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if a scheme/name/port is bypassed
|
||
If there is an external proxy DLL, we call down to determine whether
|
||
a host should bypass the proxy.
|
||
|
||
|
||
Arguments:
|
||
|
||
tScheme - can be 0, meaning match any scheme
|
||
|
||
lpszHostName - can contain wildcards. May be name or IP address
|
||
|
||
dwHostNameLength - length of name/address part. May be 0, meaning match
|
||
any name/address
|
||
|
||
nPort - can be 0, meaning match any port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - an entry on the bypass list matched the criteria
|
||
|
||
FALSE - the host identified by the parameters is not on this bypass
|
||
list
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL success;
|
||
|
||
Lock(FALSE);
|
||
|
||
if ( _UseExternalAutoConfigDLL && pIsBypassed) {
|
||
|
||
INET_ASSERT(!IsBadCodePtr((FARPROC)pIsBypassed));
|
||
|
||
success = (pIsBypassed) ( tScheme,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
);
|
||
|
||
}
|
||
else if (_ProxyBypassList != NULL)
|
||
{
|
||
success = _ProxyBypassList->IsBypassed(tScheme,
|
||
lpszHostName,
|
||
dwHostNameLength,
|
||
nPort
|
||
);
|
||
}
|
||
else
|
||
{
|
||
success = FALSE;
|
||
}
|
||
|
||
Unlock();
|
||
|
||
return success;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PROXY_INFO::IsBypassed(
|
||
IN INTERNET_SCHEME tScheme,
|
||
IN LPSTR lpszHostName,
|
||
IN INTERNET_PORT nPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if a scheme/name/port is bypassed
|
||
If there is an external proxy DLL, we call down to determine whether
|
||
a host should bypass the proxy.
|
||
|
||
|
||
Arguments:
|
||
|
||
tScheme - can be 0, meaning match any scheme
|
||
|
||
lpszHostName - can contain wildcards. May be name or IP address
|
||
|
||
nPort - can be 0, meaning match any port
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - an entry on the bypass list matched the criteria
|
||
|
||
FALSE - the host identified by the parameters is not on this bypass
|
||
list
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
|
||
BOOL success;
|
||
|
||
Lock(FALSE);
|
||
|
||
if ( _UseExternalAutoConfigDLL && pIsBypassed) {
|
||
|
||
INET_ASSERT(!IsBadCodePtr((FARPROC)pIsBypassed));
|
||
|
||
success = (pIsBypassed) ( tScheme,
|
||
lpszHostName,
|
||
lstrlen(lpszHostName),
|
||
nPort
|
||
);
|
||
|
||
}
|
||
else if (_ProxyBypassList != NULL)
|
||
{
|
||
success = _ProxyBypassList->IsBypassed(tScheme,
|
||
lpszHostName,
|
||
nPort
|
||
);
|
||
}
|
||
else
|
||
{
|
||
success = FALSE;
|
||
}
|
||
|
||
Unlock();
|
||
|
||
return success;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
LPSTR
|
||
GetRegistryProxyParameter(
|
||
IN LPSTR lpszParameterName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a string from the registry into a buffer, then shrinks the buffer
|
||
|
||
Arguments:
|
||
|
||
lpszParameterName - name of string to retrieve
|
||
|
||
Return Value:
|
||
|
||
LPSTR
|
||
Success - pointer to allocated buffer
|
||
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
LPSTR buffer = NULL;
|
||
DWORD length = PROXY_REGISTRY_STRING_LENGTH;
|
||
BOOL done = FALSE;
|
||
|
||
do {
|
||
buffer = (LPSTR)ResizeBuffer(buffer, length, FALSE);
|
||
if (done || (buffer == NULL)) {
|
||
break;
|
||
}
|
||
|
||
DWORD error;
|
||
|
||
error = InternetReadRegistryString(lpszParameterName, buffer, &length);
|
||
length = (error == ERROR_SUCCESS) ? ((length == 0) ? 0 : (length + 1)) : 0;
|
||
done = TRUE;
|
||
} while (TRUE);
|
||
|
||
return buffer;
|
||
}
|