mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1081 lines
25 KiB
1081 lines
25 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
|
|
Module Name:
|
|
|
|
httptran.cxx
|
|
|
|
Abstract:
|
|
|
|
HTTP transport-specific functions.
|
|
|
|
Author:
|
|
|
|
GopalP 06-25-97 Cloned from EdwardR's NT 4.0 RPC version.
|
|
|
|
Revision History:
|
|
|
|
EdwardR 01-26-98 Rewrite NetworkOptions parsing.
|
|
|
|
|
|
--*/
|
|
|
|
#define FD_SETSIZE 1
|
|
|
|
#include <precomp.hxx>
|
|
|
|
#include <CharConv.hxx>
|
|
|
|
#define SPACE ' '
|
|
#define TAB '\t'
|
|
#define EQUALS '='
|
|
#define COMMA ','
|
|
#define COLON ':'
|
|
#define ZERO '0'
|
|
#define NINE '9'
|
|
|
|
#define KEYWORD_HTTPPROXY "httpproxy"
|
|
#define KEYWORD_RPCPROXY "rpcproxy"
|
|
|
|
#define KID_NONE 0
|
|
#define KID_HTTPPROXY 1
|
|
#define KID_RPCPROXY 2
|
|
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// SkipWhiteSpace()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Skip over spaces and tabs, return new string position.
|
|
// Return NULL on end-of-string.
|
|
//-------------------------------------------------------------
|
|
inline static CHAR *SkipWhiteSpace( IN CHAR *psz )
|
|
{
|
|
if (psz)
|
|
{
|
|
while ((*psz)&&((*psz==SPACE)||(*psz==TAB))) psz++;
|
|
|
|
if (!*psz)
|
|
{
|
|
psz = NULL; // Return NULL on end-of-string.
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
|
|
inline static char *
|
|
NextToken(
|
|
IN char *psz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine skips whitespace characters to the start of the
|
|
next token in the string.
|
|
|
|
Arguments:
|
|
|
|
psz - The string in question.
|
|
|
|
Return Value:
|
|
|
|
NULL, if there is no next token.
|
|
|
|
Pointer to the next token, otherwise.
|
|
|
|
--*/
|
|
{
|
|
while ((*psz != CHAR_SPACE) &&
|
|
(*psz != CHAR_TAB) &&
|
|
(*psz != CHAR_NL) &&
|
|
(*psz != CHAR_NUL))
|
|
{
|
|
psz++;
|
|
}
|
|
|
|
if ((*psz == CHAR_NL) || (*psz == CHAR_NUL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
psz = SkipWhiteSpace(psz);
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
|
|
|
|
inline unsigned int
|
|
HttpMessageLength(
|
|
IN char *pBuffer
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
unsigned int len = 0;
|
|
char *p = pBuffer;
|
|
|
|
ASSERT(p);
|
|
if (p == NULL)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Look for a <CR><LF> sequence.
|
|
//
|
|
while ((*p != CHAR_CR) &&
|
|
(*(p+1) != CHAR_LF) &&
|
|
(len <= MAX_HTTP_MESSAGE_LENGTH))
|
|
{
|
|
p++;
|
|
len++;
|
|
}
|
|
|
|
return (len);
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
HttpParseResponse(
|
|
IN char *pBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for a string of the form:
|
|
HTTP/1.0 nnnn message_string
|
|
Ex: "HTTP/1.0 200 Connection established"
|
|
|
|
Arguments:
|
|
|
|
pBuffer - The response buffer.
|
|
|
|
Return Value:
|
|
|
|
HTTP status code (nnnn), if successful.
|
|
|
|
-1, if there is no next token yet.
|
|
|
|
0, otherwise.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = 0;
|
|
char *psz = pBuffer;
|
|
|
|
psz = NextToken(psz);
|
|
|
|
if (psz)
|
|
{
|
|
dwStatus = atoi(psz);
|
|
}
|
|
else
|
|
{
|
|
return (-1);
|
|
}
|
|
|
|
// Make sure a connection is established:
|
|
if ( (dwStatus < 200) || (dwStatus > 299) )
|
|
{
|
|
#ifdef DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"HttpParseResponse(): Connection Failed: %d\n",
|
|
dwStatus));
|
|
#endif // DBG
|
|
dwStatus = 0;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseLiteral()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Check the next non-whitespace literal character to see if
|
|
// its equal to cLiteral. If yes, the advance the string pointer
|
|
// past it to the next character in the string. If no, then
|
|
// return status set to RPC_S_INVALID_NETWORK_OPTIONS and return
|
|
// the string pointer pointing to the invalid character.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CHAR *ParseLiteral( IN CHAR *psz,
|
|
IN CHAR cLiteral,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
psz = SkipWhiteSpace(psz);
|
|
|
|
if (psz)
|
|
{
|
|
if (*psz == cLiteral)
|
|
{
|
|
psz++;
|
|
}
|
|
else
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParsePort()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Parse the next token as a "port-number", return its value
|
|
// in the out parameter ppszPort.
|
|
//
|
|
// Note: Use I_RpcFree() to release the memory for ppszPort
|
|
// when you are finished with it.
|
|
//-------------------------------------------------------------
|
|
CHAR *ParsePort( IN CHAR *psz,
|
|
OUT CHAR **ppszPort,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
psz = SkipWhiteSpace(psz);
|
|
if (psz)
|
|
{
|
|
CHAR *p = psz;
|
|
while ((*p >= ZERO) && (*p <= NINE))
|
|
{
|
|
p++;
|
|
}
|
|
|
|
if (p == psz)
|
|
{
|
|
// The next token isn't a number...
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
return psz;
|
|
}
|
|
|
|
CHAR cSave = *p;
|
|
*p = 0;
|
|
*ppszPort = (CHAR*)RpcpFarAllocate(1+strlen(psz));
|
|
if (!*ppszPort)
|
|
{
|
|
*p = cSave;
|
|
*pdwStatus = RPC_S_OUT_OF_MEMORY;
|
|
return psz;
|
|
}
|
|
strcpy(*ppszPort,psz);
|
|
*p = cSave;
|
|
psz = p;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseMachine()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Parse the next token as a machine name. The machine name
|
|
// is returned in ppszMachine, and psz is advance to point to
|
|
// the next character after the machine name.
|
|
//
|
|
// Note: That the machine name cannot contain any of ':' (colon),
|
|
// ',' (comma), or ' ' (space). These are used in finding
|
|
// the end of the machine name sub-string.
|
|
//
|
|
// Note: Use I_RpcFree() to release the memory for ppszMachine
|
|
// when you are finished with it.
|
|
//-------------------------------------------------------------
|
|
CHAR *ParseMachine( IN CHAR *psz,
|
|
OUT CHAR **ppszMachine,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
psz = SkipWhiteSpace(psz);
|
|
if (psz)
|
|
{
|
|
CHAR *p = psz;
|
|
while ((*p) && (*p != COLON) && (*p != COMMA) && (*p != SPACE))
|
|
{
|
|
p++;
|
|
}
|
|
|
|
if (p == psz)
|
|
{
|
|
// zero length machine name...
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
return psz;
|
|
}
|
|
|
|
CHAR cSave = *p;
|
|
*p = 0;
|
|
*ppszMachine = (CHAR*)RpcpFarAllocate(1+strlen(psz));
|
|
if (!*ppszMachine)
|
|
{
|
|
*p = cSave;
|
|
*pdwStatus = RPC_S_OUT_OF_MEMORY;
|
|
return psz;
|
|
}
|
|
|
|
strcpy(*ppszMachine,psz);
|
|
*p = cSave;
|
|
psz = p;
|
|
}
|
|
else
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// KeywordMatch()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Compare the starting characters of the string (psz) with
|
|
// the specified keyword (pszKeyword). If they match independent
|
|
// of case, then return TRUE. If they don't match, return FALSE.
|
|
//-------------------------------------------------------------
|
|
BOOL KeywordMatch( CHAR *psz,
|
|
CHAR *pszKeyword )
|
|
{
|
|
DWORD dwLen1 = strlen( (char*)psz);
|
|
DWORD dwLen2 = strlen( (char*)pszKeyword);
|
|
BOOL fMatch;
|
|
|
|
if (dwLen1 < dwLen2)
|
|
{
|
|
return FALSE; // String is not long enough to hold
|
|
} // the keyword.
|
|
|
|
CHAR cSave = psz[dwLen2];
|
|
psz[dwLen2] = 0;
|
|
|
|
if (!RpcpStringCompareA((char*)psz,(char*)pszKeyword))
|
|
{
|
|
// Keyword matches the start of the string.
|
|
fMatch = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Not a match.
|
|
fMatch = FALSE;
|
|
}
|
|
|
|
psz[dwLen2] = cSave;
|
|
return fMatch;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseKeyword()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Parse the next token as a keyword, return its keyword ID
|
|
// in pdwKid. There are currently two keywords to look for
|
|
// "HttpProxy" (ID is KID_HTTPPROXY) and "RpcProxy" (ID is
|
|
// KID_RPCPROXY). If the next text token doesn't match either
|
|
// of these, then return KID_NONE (no match) and status is
|
|
// returned as RPC_S_INVALID_NETWORK_OPTIONS.
|
|
//
|
|
// If there is a match return the string pointer (psz) updated
|
|
// to point to the next character after the end of the keyword.
|
|
//-------------------------------------------------------------
|
|
CHAR *ParseKeyword( IN CHAR *psz,
|
|
OUT DWORD *pdwKid,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
psz = SkipWhiteSpace(psz);
|
|
if (psz)
|
|
{
|
|
if (KeywordMatch(psz,(CHAR*)KEYWORD_HTTPPROXY))
|
|
{
|
|
// Keyword is "HttpProxy".
|
|
*pdwKid = KID_HTTPPROXY;
|
|
psz += strlen(KEYWORD_HTTPPROXY);
|
|
}
|
|
else if (KeywordMatch(psz,(CHAR*)KEYWORD_RPCPROXY))
|
|
{
|
|
// Keyword is "RpcProxy".
|
|
*pdwKid = KID_RPCPROXY;
|
|
psz += strlen(KEYWORD_RPCPROXY);
|
|
}
|
|
else
|
|
{
|
|
*pdwKid = KID_NONE;
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseOptValue()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Parse strings of the following form:
|
|
//
|
|
// OptValue <- machine ':' port
|
|
// <- machine
|
|
//
|
|
// If the parse is successful, then return the machine name
|
|
// in ppszProxy, and the port in ppszPort. These are both new
|
|
// strings allocated via RpcpFarAllocate().
|
|
//
|
|
// The production ends with either the end of the string (null
|
|
// terminated), the end of the port number (non-digit), or a
|
|
// comma (which will start the begining of a new OptValue string.
|
|
//
|
|
// On successful parse, return updated string position to the
|
|
// next character after the end of the OptValue sub-string.
|
|
//-------------------------------------------------------------
|
|
CHAR *ParseOptValue( IN CHAR *psz,
|
|
OUT CHAR **ppszProxy,
|
|
OUT CHAR **ppszPort,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
//
|
|
// Get the machine name:
|
|
//
|
|
psz = ParseMachine(psz,ppszProxy,pdwStatus);
|
|
if (*pdwStatus != NO_ERROR)
|
|
{
|
|
return psz;
|
|
}
|
|
|
|
//
|
|
// If we're at the end of the string, or we've run into a
|
|
// comma (start of another option) then we are done.
|
|
//
|
|
if ((!psz) || (*psz == 0) || (*psz == COMMA))
|
|
{
|
|
return psz;
|
|
}
|
|
|
|
psz = ParseLiteral(psz,COLON,pdwStatus);
|
|
if (*pdwStatus != NO_ERROR)
|
|
{
|
|
return psz;
|
|
}
|
|
|
|
if (!psz)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
return psz;
|
|
}
|
|
|
|
psz = ParsePort(psz,ppszPort,pdwStatus);
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseOpt()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Opt <- Keyword '=' OptValue
|
|
//
|
|
// Parse an option, which is a keywork equals value pair.
|
|
//
|
|
// If the parse is successful, then return the machine name
|
|
// in ppszProxy, and the port in ppszPort. These are both new
|
|
// strings allocated via RpcpFarAllocate(), and are represented
|
|
// in the OptValue non-terminal.
|
|
//
|
|
// The production ends with either the end of the string (null
|
|
// terminated), the end of the port number (non-digit), or a
|
|
// comma (which will start the begining of a new Opt string.
|
|
//
|
|
// On successful parse, return updated string position to the
|
|
// next character after the end of the Opt (option) sub-string.
|
|
//-------------------------------------------------------------
|
|
CHAR *ParseOpt( IN CHAR *psz,
|
|
OUT DWORD *pdwKid,
|
|
OUT CHAR **ppszProxy,
|
|
OUT CHAR **ppszPort,
|
|
OUT DWORD *pdwStatus )
|
|
{
|
|
if (psz)
|
|
{
|
|
psz = ParseKeyword(psz,pdwKid,pdwStatus);
|
|
if (*pdwStatus != NO_ERROR)
|
|
{
|
|
return psz;
|
|
}
|
|
}
|
|
|
|
if (!psz)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
return psz;
|
|
}
|
|
|
|
psz = ParseLiteral(psz,EQUALS,pdwStatus);
|
|
if (*pdwStatus != NO_ERROR)
|
|
{
|
|
return psz;
|
|
}
|
|
|
|
if (!psz)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
return psz;
|
|
}
|
|
|
|
psz = ParseOptValue(psz,ppszProxy,ppszPort,pdwStatus);
|
|
|
|
if ((psz) && (*psz == 0))
|
|
{
|
|
psz = NULL;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// ParseOptList()
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Parse ncacn_http network options strings. These are of the
|
|
// following form:
|
|
//
|
|
// OptList <- Opt
|
|
// <- Opt ',' Opt
|
|
//
|
|
// Opt <- Keyword '=' OptValue
|
|
//
|
|
// OptValue <- Machine ':' PortNumber
|
|
// <- Machine ':'
|
|
// <- Machine
|
|
//
|
|
// Keyword <- 'HttpProxy'
|
|
// <- 'RpcProxy'
|
|
//
|
|
// Machine and PortNumber are terminal strings.
|
|
//-------------------------------------------------------------
|
|
DWORD ParseOptList( IN CHAR *pszOptList,
|
|
OUT CHAR **ppszRpcProxy,
|
|
OUT CHAR **ppszRpcProxyPort,
|
|
OUT CHAR **ppszHttpProxy,
|
|
OUT CHAR **ppszHttpProxyPort )
|
|
{
|
|
DWORD dwStatus = NO_ERROR;
|
|
DWORD dwKid = KID_NONE;
|
|
CHAR *psz = pszOptList;
|
|
CHAR *pszProxy = NULL;
|
|
CHAR *pszPort = NULL;
|
|
|
|
psz = ParseOpt(psz,&dwKid,&pszProxy,&pszPort,&dwStatus);
|
|
if (dwStatus != NO_ERROR)
|
|
{
|
|
return dwStatus;
|
|
}
|
|
|
|
if (dwKid == KID_RPCPROXY)
|
|
{
|
|
*ppszRpcProxy = pszProxy;
|
|
*ppszRpcProxyPort = pszPort;
|
|
}
|
|
else if (dwKid == KID_HTTPPROXY)
|
|
{
|
|
*ppszHttpProxy = pszProxy;
|
|
*ppszHttpProxyPort = pszPort;
|
|
}
|
|
|
|
if (psz)
|
|
{
|
|
psz = ParseLiteral(psz,COMMA,&dwStatus);
|
|
if (dwStatus != NO_ERROR)
|
|
{
|
|
return dwStatus;
|
|
}
|
|
}
|
|
|
|
if (psz)
|
|
{
|
|
pszProxy = pszPort = NULL;
|
|
psz = ParseOpt(psz,&dwKid,&pszProxy,&pszPort,&dwStatus);
|
|
if (dwStatus != NO_ERROR)
|
|
{
|
|
return dwStatus;
|
|
}
|
|
|
|
if (dwKid == KID_RPCPROXY)
|
|
{
|
|
*ppszRpcProxy = pszProxy;
|
|
*ppszRpcProxyPort = pszPort;
|
|
}
|
|
else if (dwKid == KID_HTTPPROXY)
|
|
{
|
|
*ppszHttpProxy = pszProxy;
|
|
*ppszHttpProxyPort = pszPort;
|
|
}
|
|
}
|
|
|
|
psz = SkipWhiteSpace(psz);
|
|
|
|
if (psz)
|
|
{
|
|
dwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
HttpParseNetworkOptions(
|
|
IN RPC_CHAR *pNetworkOptions,
|
|
IN char *pszDefaultServer,
|
|
OUT char **ppszRpcProxy,
|
|
OUT char **ppszRpcProxyPort,
|
|
IN BOOL UseSSLProxyPortAsDefault,
|
|
OUT char **ppszHttpProxy,
|
|
OUT char **ppszHttpProxyPort,
|
|
OUT RPCProxyAccessType *AccessType,
|
|
OUT DWORD *pdwStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse the Http network options specified in the string binding. The
|
|
options would look like:
|
|
|
|
HttpProxy=<Server_Name>:<Port>,RpcProxy=<Server_Name>:<Port>
|
|
|
|
That is, two separate proxy servers, each with an optional port.
|
|
|
|
The HttpProxy=<> specification is optional, if not specified then use
|
|
the specified default server name. Its default Port is 80.
|
|
|
|
If RpcProxy is optional as well, if not specified then use the
|
|
default server name and Port 80.
|
|
|
|
Arguments:
|
|
|
|
pNetworkOptions - Network options string
|
|
|
|
pszDefaultServer - Default Server.
|
|
|
|
ppszRpcProxy - RpcProxy, if specified in the options string.
|
|
|
|
ppszRpcProxyPort - RpcProxyPort, if specified in the options string.
|
|
|
|
UseSSLProxyPortAsDefault - if non-zero, the SSL port will be used as
|
|
default if a port is not specified in the network options.
|
|
|
|
ppszHttpProxy - HttpProxy, if specified in the options string.
|
|
|
|
ppszHttpProxyPort- HttpProxyPort, if specified in the options string.
|
|
|
|
AccessType - if we should try direct access, proxy access, or unknown yet.
|
|
|
|
pdwStatus - Pointer to a DWORD where the return status will be put.
|
|
|
|
Notes:
|
|
|
|
Returned strings should be free'd with I_RpcFree().
|
|
|
|
Return Value:
|
|
|
|
TRUE, if successful.
|
|
|
|
FALSE, otherwise. *pdwStatus will have the exact cause.
|
|
|
|
--*/
|
|
{
|
|
char szNetworkOptions[MAX_NETWORK_OPTIONS_SIZE];
|
|
char *pszNetworkOptions;
|
|
char *DefaultRpcProxyPortToUse;
|
|
|
|
// OUT variable initialization.
|
|
*ppszRpcProxy = *ppszRpcProxyPort = NULL;
|
|
*ppszHttpProxy = *ppszHttpProxyPort = NULL;
|
|
*AccessType = rpcpatUnknown;
|
|
*pdwStatus = 0;
|
|
|
|
// Make sure we have and options string to parse:
|
|
if ( (pNetworkOptions) && (*pNetworkOptions) )
|
|
{
|
|
// Make sure the Network Options is not too long.
|
|
if (RpcpStringLength(pNetworkOptions) > MAX_NETWORK_OPTIONS_SIZE)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Convert it to ANSI, since HTTP is ANSI (actually ASCII I think...):
|
|
SimplePlatformToAnsi(pNetworkOptions, szNetworkOptions);
|
|
|
|
//
|
|
// Parse out the options:
|
|
//
|
|
pszNetworkOptions = szNetworkOptions;
|
|
|
|
*pdwStatus = ParseOptList(pszNetworkOptions,
|
|
ppszRpcProxy,
|
|
ppszRpcProxyPort,
|
|
ppszHttpProxy,
|
|
ppszHttpProxyPort );
|
|
if (*pdwStatus != RPC_S_OK)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
#if FALSE
|
|
psz = RpcStrTok(pszNetworkOptions, ",", &pszNetworkOptions);
|
|
if (!ParseKeywordEqValue(
|
|
psz,
|
|
HTTP_PROXY_OPTION_STR,
|
|
ppszHttpProxy,
|
|
ppszHttpProxyPort,
|
|
pdwStatus
|
|
))
|
|
{
|
|
if (*pdwStatus != RPC_S_OK)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if (*ppszHttpProxy)
|
|
{
|
|
psz = RpcStrTok(NULL, ",", &pszNetworkOptions);
|
|
}
|
|
|
|
if (!ParseKeywordEqValue(
|
|
psz,
|
|
RPC_PROXY_OPTION_STR,
|
|
ppszRpcProxy,
|
|
ppszRpcProxyPort,
|
|
pdwStatus
|
|
))
|
|
{
|
|
if (*pdwStatus != RPC_S_OK)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Make sure that we have an RPC Proxy (IIS machine):
|
|
if (!*ppszRpcProxy)
|
|
{
|
|
*ppszRpcProxy = (char*)RpcpFarAllocate(1+strlen(pszDefaultServer));
|
|
if (!*ppszRpcProxy)
|
|
{
|
|
*pdwStatus = RPC_S_OUT_OF_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
strcpy(*ppszRpcProxy, pszDefaultServer);
|
|
}
|
|
else
|
|
{
|
|
// Length validation for RpcProxy name.
|
|
if (strlen(*ppszRpcProxy) > MAX_HTTP_COMPUTERNAME_SIZE)
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// Make sure we have a port for the RPC Proxy.
|
|
if (!*ppszRpcProxyPort)
|
|
{
|
|
if (UseSSLProxyPortAsDefault)
|
|
DefaultRpcProxyPortToUse = DEF_HTTP_SSL_PORT;
|
|
else
|
|
DefaultRpcProxyPortToUse = DEF_HTTP_PORT;
|
|
*ppszRpcProxyPort = (char*)RpcpFarAllocate(1+strlen(DefaultRpcProxyPortToUse));
|
|
if (!*ppszRpcProxyPort)
|
|
{
|
|
*pdwStatus = RPC_S_OUT_OF_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
strcpy(*ppszRpcProxyPort, DefaultRpcProxyPortToUse);
|
|
}
|
|
|
|
// If no HTTP proxy was specified in the options string, check the
|
|
// registry to see if IE has configured one:
|
|
if (!*ppszHttpProxy)
|
|
{
|
|
if (!HttpCheckRegistry(
|
|
*ppszRpcProxy,
|
|
ppszHttpProxy,
|
|
ppszHttpProxyPort,
|
|
AccessType
|
|
) )
|
|
{
|
|
*pdwStatus = RPC_S_OUT_OF_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// Length validation for HttpProxy name.
|
|
if ((*ppszHttpProxy) &&
|
|
(strlen(*ppszHttpProxy) > MAX_HTTP_COMPUTERNAME_SIZE))
|
|
{
|
|
*pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifdef MAJOR_DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"ParseNetworkOptions(): RpcProxy: %s RpcProxyPort: %s\n",
|
|
*ppszRpcProxy,
|
|
*ppszRpcProxyPort));
|
|
#endif // MAJOR_DBG
|
|
|
|
if (*AccessType != rpcpatDirect)
|
|
{
|
|
ASSERT(*ppszHttpProxy);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (*ppszRpcProxy)
|
|
{
|
|
I_RpcFree(*ppszRpcProxy);
|
|
*ppszRpcProxy = NULL;
|
|
}
|
|
|
|
if (*ppszRpcProxyPort)
|
|
{
|
|
I_RpcFree(*ppszRpcProxyPort);
|
|
*ppszRpcProxyPort = NULL;
|
|
}
|
|
|
|
if (*ppszHttpProxy)
|
|
{
|
|
I_RpcFree(*ppszHttpProxy);
|
|
*ppszHttpProxy = NULL;
|
|
}
|
|
|
|
if (*ppszHttpProxyPort)
|
|
{
|
|
I_RpcFree(*ppszHttpProxyPort);
|
|
*ppszHttpProxyPort = NULL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL
|
|
HttpSetupTunnel(
|
|
IN SOCKET Socket,
|
|
IN char *pszConnect
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Try to setup a connection to the IIS RPC Proxy.
|
|
|
|
Arguments:
|
|
|
|
Socket - Socket on which to contact the IIS RPC Proxy.
|
|
|
|
pszConnect - The message to send.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if successful
|
|
|
|
FALSE, otherwise
|
|
|
|
--*/
|
|
{
|
|
int retval;
|
|
DWORD dwStatus;
|
|
DWORD dwSize;
|
|
char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
|
|
|
|
// Ok, try to connect to the IIS RPC proxy process:
|
|
retval = send( Socket, pszConnect, 1+strlen(pszConnect), 0 );
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
#ifdef DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"HttpSetupTunnel(): send() failed: %d\n",
|
|
WSAGetLastError()));
|
|
#endif // DBG
|
|
return FALSE;
|
|
}
|
|
|
|
dwSize = sizeof(szBuffer) - 1;
|
|
retval = recv( Socket, szBuffer, dwSize, 0 );
|
|
if ((retval == SOCKET_ERROR)||(retval == 0))
|
|
{
|
|
#ifdef DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"HttpSetupTunnel(): recv() failed: %d\n",
|
|
WSAGetLastError()));
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
szBuffer[dwSize] = 0; // Note: dwSize is already sizeof()-1.
|
|
|
|
dwStatus = HttpParseResponse(szBuffer);
|
|
#ifdef MAJOR_DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"HttpSetupTunnel(): response: %s",
|
|
szBuffer));
|
|
#endif
|
|
|
|
// Make sure a connection is established:
|
|
if ( (dwStatus < 200) || (dwStatus > 299) )
|
|
{
|
|
#ifdef DBG
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"HttpSetupTunnel(): Connection Failed: %d\n",
|
|
dwStatus));
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
inline BOOL
|
|
HttpTunnelToRpcProxy(
|
|
IN SOCKET Socket,
|
|
IN char *pszRpcProxy,
|
|
IN char *pszRpcProxyPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to setup the HTTP chat to do a CONNECT
|
|
through a proxy (like MSProxy). This will get you a tunnel to
|
|
the IIS Server that you really want to get to. The call at the
|
|
end, HttpSetupTunnel() does the connection.
|
|
|
|
Arguments:
|
|
|
|
Socket - Socket on which to contact the IIS RPC Proxy.
|
|
|
|
pszRpcProxy - The RPC Proxy to connect to.
|
|
|
|
pszRpcProxyPort - RPC Proxy's port.
|
|
|
|
Return Value:
|
|
|
|
Status from HttpSetupTunnel()
|
|
|
|
--*/
|
|
{
|
|
char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
|
|
|
|
// make sure strings use \r\n instead of \n only. \n goes on the wire
|
|
// as LF only, and some firewalls drop packets that use LF only
|
|
strcpy(szBuffer, "CONNECT ");
|
|
lstrcatA(szBuffer, pszRpcProxy);
|
|
lstrcatA(szBuffer, ":");
|
|
lstrcatA(szBuffer, pszRpcProxyPort);
|
|
lstrcatA(szBuffer, " HTTP/1.0\r\nUser-Agent: RPC\r\nConnection: Keep-Alive\r\n\r\n");
|
|
// Was:
|
|
//
|
|
// lstrcatA(szBuffer, " HTTP/1.1\nUser-Agent: RPC\nPragma: No-Cache\n\n");
|
|
//
|
|
// Some proxy servers (like MSProxy2.0 don't seem to like the version
|
|
// number to be greater that 1.0.
|
|
|
|
ASSERT(strlen(szBuffer) < MAX_HTTP_CHAT_BUFFER_SIZE);
|
|
|
|
return HttpSetupTunnel(Socket, szBuffer);
|
|
}
|
|
|
|
|
|
|
|
|
|
inline BOOL
|
|
HttpTunnelToRpcServer(
|
|
IN SOCKET Socket,
|
|
IN char *pszRpcServer,
|
|
IN char *pszRpcServerPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open the socket to the IIS on which the RpcProxy resides.
|
|
|
|
Arguments:
|
|
|
|
Socket - Socket on which to contact the IIS RPC Proxy.
|
|
|
|
pszRpcServer - The RPC Server to connect to.
|
|
|
|
pszRpcServerPort - RPC Server's port.
|
|
|
|
Return Value:
|
|
|
|
Status from HttpSetupTunnel()
|
|
|
|
--*/
|
|
{
|
|
int retval;
|
|
DWORD dwStatus;
|
|
char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
|
|
|
|
strcpy(szBuffer, "RPC_CONNECT ");
|
|
lstrcatA(szBuffer, pszRpcServer);
|
|
lstrcatA(szBuffer, ":");
|
|
lstrcatA(szBuffer, pszRpcServerPort);
|
|
lstrcatA(szBuffer, " HTTP/1.1\nUser-Agent: RPC\nPragma: No-Cache\n\n");
|
|
|
|
ASSERT(strlen(szBuffer) < MAX_HTTP_CHAT_BUFFER_SIZE);
|
|
|
|
// Ok, try to connect to the RPC server process:
|
|
return HttpSetupTunnel(Socket, szBuffer);
|
|
}
|
|
|