Windows2000/private/inet/wininet/handles/proxysup.cxx.1475
2020-09-30 17:12:32 +02:00

2740 lines
63 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}