windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/hgetinfo.cxx
2020-09-26 16:20:57 +08:00

1404 lines
37 KiB
C++
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) 1995-1996 Microsoft Corporation
Module Name :
hgetinfo.cxx
Abstract:
This file contains the code for getting information from HTTP_REQUEST
object. This is useful for ISAPI apps and filters.
Author:
Murali R. Krishnan ( MuraliK ) 20-Nov-1996
Environment:
Project:
W3Svc DLL
Functions Exported:
Revision History:
--*/
/************************************************************
* Include Headers
************************************************************/
#include "w3p.hxx"
extern "C"
{
#include "md5.h"
}
//
// IsStringMatch()
// Matches the given string variable to the constant string supplied.
// The two variables involved are strings :( which are null-terminated
// So, we cannot apply Memory Comparisons
//
// Returns:
// TRUE on a match
// FALSE if there is a failure to match up
//
# define IsStringMatch( pszConstant, pszVar, cchVar) \
((cchVar == (sizeof( pszConstant) - 1)) && \
!strcmp( pszConstant, pszVar) \
)
//
// IsStringPrefixMatch()
// Matches the given string variable for a prefix constant string.
//
// Returns:
// TRUE on a match
// FALSE if there is a failure to match up
//
# define IsStringPrefixMatch( pszConstantPrefix, pszVar, cchVar) \
((cchVar >= (sizeof( pszConstantPrefix) - 1)) && \
!memcmp( pszConstantPrefix, pszVar, (sizeof(pszConstantPrefix) - 1))\
)
static const CHAR g_szHexDigits[] = "0123456789abcdef";
/************************************************************
* Function Prototypes and inlines
************************************************************/
BOOL
BuildCGIHeaderList(
HTTP_HEADERS * pHeaderList,
CHAR * pchBuffer,
DWORD * lpcchBuffer
);
BOOL
GetInfoFromCertificate(
IN TCP_AUTHENT & tcpauth,
IN LPCSTR pszValName,
DWORD cchValName,
OUT CHAR * pchBuffer,
IN OUT DWORD * lpcchBuffer
);
BOOL
HseBuildRawHeaders(
IN HTTP_HEADERS * pHeaderList,
OUT LPSTR lpvBuffer,
IN OUT LPDWORD lpdwSize
);
BOOL
CopyStringToBuffer(
IN LPCSTR psz,
IN DWORD cch,
OUT CHAR * pchBuffer,
IN OUT DWORD * lpcchBuffer
)
{
if ( *lpcchBuffer >= cch ) {
if ( pchBuffer != NULL ) {
CopyMemory( pchBuffer, psz, cch);
*lpcchBuffer = cch;
return (TRUE);
}
}
*lpcchBuffer = cch;
SetLastError( ERROR_INSUFFICIENT_BUFFER);
return ( FALSE);
} // CopyStringToBuffer()
BOOL
VariableNotAvailable(
OUT CHAR* pchBuffer,
IN OUT DWORD* lpcchBuffer
)
/*++
Description:
handles server request for which content is not available,
i.e. variables which depends on instance or metadata
when such info is not available.
In this case we return an empty string.
Arguments:
pchBuffer - pointer to character buffer which will contain
the value if found
lpcchBuffer - pointer to DWORD containing
IN: the count of characters pchBuffer can store
OUT: the count of characters actually stored (on success)
the count of characters required (on failure)
Returns:
TRUE if success, otherwise FALSE
Win32 Error Code :
NO_ERROR for success
ERROR_INSUFFICIENT_BUFFER - if space is not enough
ERROR_INVALID_INDEX - if item is not found
--*/
{
if ( *lpcchBuffer >= 1 ) {
if ( pchBuffer != NULL ) {
*pchBuffer = '\0';
*lpcchBuffer = 1;
return TRUE;
} else {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
*lpcchBuffer = 1;
SetLastError( ERROR_INSUFFICIENT_BUFFER);
return ( FALSE);
}
inline BOOL
CopyStringToBuffer(
IN LPCSTR psz,
OUT CHAR * pchBuffer,
IN OUT DWORD * lpcchBuffer
)
{
DBG_ASSERT( psz != NULL );
return (CopyStringToBuffer( psz, strlen(psz) + 1, pchBuffer, lpcchBuffer));
} // CopyStringToBuffer()
inline BOOL
ReturnNullString(
OUT CHAR * pchBuffer,
IN OUT DWORD * lpcchBuffer
)
{
return (CopyStringToBuffer( "", 1, pchBuffer, lpcchBuffer));
}
/************************************************************
* Functions
************************************************************/
PW3_METADATA
HTTP_REQUEST::GetWAMMetaData(
)
/*++
Description:
This function gets the metadata pointer taking into account
running child ISAPI scenario. For some ISAPI related gets
this should be used intstead of QueryMetaData()
Arguments:
Returns:
PW3_METADATA pointer or NULL
--*/
{
if ( _pWamRequest && _pWamRequest->IsChild() ) {
return _pWamRequest->QueryExecMetaData();
}
else {
return QueryMetaData();
}
}
BOOL
HTTP_REQUEST::GetInfoForName(
const CHAR * pszValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
/*++
Description:
This function acts as the switch board for getting values
for requested ValueName. It is used by Filters/ISAPI applications
to obtain the required server and request values.
Arguments:
pszValName - pointer to string containing the name of the value
pchBuffer - pointer to character buffer which will contain
the value if found
lpcchBuffer - pointer to DWORD containing
IN: the count of characters pchBuffer can store
OUT: the count of characters actually stored (on success)
the count of characters required (on failure)
Returns:
Win32 Error Code
NO_ERROR for success
ERROR_INSUFFICIENT_BUFFER - if space is not enough
ERROR_INVALID_INDEX - if item is not found
--*/
{
if ( !pszValName)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if ( !( *pszValName ) || !isalpha( (UCHAR)(*pszValName) ) )
{
SetLastError( ERROR_INVALID_INDEX);
return (FALSE);
}
BOOL fRet;
PFN_GET_INFO pfnGI;
DWORD cchValName = strlen( pszValName);
pfnGI = HTTP_REQUEST::sm_GetInfoFuncs[IndexOfChar(*pszValName)];
DBG_ASSERT( NULL != pfnGI);
fRet = (this->*pfnGI)( pszValName, cchValName, pchBuffer, lpcchBuffer );
#if OLD_MODE_COMPATIBILITY
//
// Once upon a time, this function was not there. Then all the queries
// if they did not get resolved were passed onto GetEnvironmentString()
// to extract and environment parameter.
//
// These days the GetEnvironmentString() which is part of the GetInfoMisc()
// is not a fast function => it consumes more time
// So we will avoid this. Thanks for listening to the story.
//
if ( !fRet && ( GetLastError() == ERROR_INVALID_INDEX ) )
{
//
// Try again with the Misc() function if we do not find
// the item in the general location.
// This has performance costs :(
//
fRet = GetInfoMisc( pszValName, cchValName,
pchBuffer, lpcchBuffer );
}
# endif // OLD_MODE_COMPATIBILITY
return fRet;
} // HTTP_REQUEST::GetInfoForName()
BOOL
HTTP_REQUEST::GetInfoA(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'A');
//
// ALL_HTTP is a special server specific value used by the CGI code
// to retrieve all of the HTTP headers the client sent
//
if ( IsStringMatch( "ALL_RAW", pszValName, cchValName)) {
//
// Probably the proxy is making the request
// Get the raw list of headers
//
return ( HseBuildRawHeaders( QueryHeaderList(),
pchBuffer, lpcchBuffer)
);
} else if ( IsStringMatch( "APPL_MD_PATH", pszValName, cchValName )) {
PW3_METADATA pMetaData = GetWAMMetaData();
if ( pMetaData == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
DBG_ASSERT( pMetaData->QueryAppPath() != NULL);
return ( pMetaData->QueryAppPath()->
CopyToBuffer( pchBuffer, lpcchBuffer)
);
} else if ( IsStringMatch( "APPL_PHYSICAL_PATH", pszValName, cchValName )) {
PW3_METADATA pMetaData = GetWAMMetaData();
MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject());
if ( pMetaData == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
STACK_STR( strAppPhysicalPath, MAX_PATH);
//
// Create the Applicaiton Physical Path in a separate buffer
// and then copy it over to the incoming buffer
//
return ( ( pMetaData->BuildApplPhysicalPath(
&mb,
&strAppPhysicalPath))
&& strAppPhysicalPath.CopyToBuffer( pchBuffer, lpcchBuffer)
);
} else if ( IsStringMatch( "ALL_HTTP", pszValName, cchValName )) {
return BuildCGIHeaderList( QueryHeaderList(), pchBuffer, lpcchBuffer );
} else if ( IsStringMatch( "AUTH_TYPE", pszValName, cchValName )) {
return ( _strAuthType.CopyToBuffer( pchBuffer, lpcchBuffer));
} else if ( IsStringMatch( "AUTH_PASSWORD", pszValName, cchValName )) {
return ( _strUnmappedPassword.CopyToBuffer( pchBuffer, lpcchBuffer));
} else if ( IsStringMatch( "AUTH_USER", pszValName, cchValName )) {
return ( _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer));
} else {
SetLastError( ERROR_INVALID_INDEX);
}
return ( FALSE);
} // HTTP_REQUEST::GetInfoA()
BOOL
HTTP_REQUEST::GetInfoC(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'C');
if ( IsStringMatch( "CONTENT_LENGTH", pszValName, cchValName )) {
CHAR rgchCL[40];
_ultoa( _cbContentLength, rgchCL, 10);
fReturn = CopyStringToBuffer( rgchCL,
pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "CONTENT_TYPE", pszValName, cchValName )) {
fReturn = _strContentType.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringPrefixMatch( "CERT_", pszValName, cchValName)) {
//
// All the certificates related stuff has to go in here.
//
fReturn = GetInfoFromCertificate( _tcpauth, (pszValName + 5),
cchValName - 5,
pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoC()
BOOL
HTTP_REQUEST::GetInfoH(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn = TRUE;
LPCSTR pszSuffix;
DWORD cchSuffix;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'H');
if ( IsStringPrefixMatch( "HTTP_", pszValName, cchValName)) {
pszSuffix = pszValName + (sizeof("HTTP_") - 1);
cchSuffix = cchValName - (sizeof("HTTP_") - 1);
if ( IsStringMatch( "REQ_REALM", pszSuffix, cchSuffix)) {
LPCSTR psz;
//
// generate the real information
//
if ( QueryMetaData() == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
psz = ( QueryMetaData()->QueryRealm()
? QueryMetaData()->QueryRealm()
: QueryHostAddr() );
fReturn = CopyStringToBuffer( psz, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "REQ_PWD_EXPIRE", pszSuffix, cchSuffix )) {
CHAR rgExp[40];
_ultoa( _dwExpireInDay, rgExp, 10);
fReturn = CopyStringToBuffer( rgExp, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "CFG_ENC_CAPS", pszSuffix, cchSuffix )) {
if ( QueryW3Instance() == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
CHAR rgNum[40];
_ultoa( (UINT) QueryW3Instance()->QueryEncCaps(),
rgNum, 10);
fReturn = CopyStringToBuffer( rgNum, pchBuffer, lpcchBuffer);
} else {
//
// Since the value begins with "HTTP_"
// then it's probably in our headers list
//
CHAR achHeader[MAX_HEADER_LENGTH];
CHAR * pch;
LPCSTR pszValue;
DWORD cchValue;
HTTP_FAST_MAP_HEADERS iField;
// adjust "1" for the terminating ":" if needed
if ( cchSuffix >= sizeof( achHeader ) - 1 ) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
//
// Copy the client specified header name to a temp buffer
// so we can replace all "_" with "-"s so it will match the
// header names in our list.
// We also need to append a colon if needed
//
strcpy( achHeader, pszValName + 5 );
for ( pch = achHeader; pch = strchr( pch, '_' ); *pch++ = '-')
;
pszValue = NULL;
// Lookup the name in the fast map first.
if ( HTTP_HEADERS::FindOrdinalForHeader( achHeader, cchSuffix,
(LPDWORD ) &iField)
) {
// get the header value from fast map
pszValue = _HeaderList.FastMapQueryValue( iField);
cchValue = ((pszValue != NULL) ? strlen( pszValue) : 0);
}
// if the header is absent in the fast map, lookup the slow map
if ( NULL == pszValue ) {
// append a ':' if not already present
if ( (cchSuffix >= 1) && (achHeader[cchSuffix-1] != ':') &&
(cchSuffix < sizeof(achHeader))) {
achHeader[cchSuffix] = ':';
achHeader[cchSuffix+1] = '\0';
cchSuffix++;
}
pszValue = _HeaderList.FindValue( achHeader, &cchValue );
}
if ( pszValue != NULL) {
// Copy including the "null" character for the string.
fReturn = CopyStringToBuffer( pszValue, cchValue + 1,
pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
}
} else if ( IsStringPrefixMatch( "HTTPS", pszValName, cchValName)) {
pszSuffix = pszValName + (sizeof("HTTPS") - 1);
cchSuffix = cchValName - (sizeof("HTTPS") - 1);
if ( *pszSuffix == '\0') {
// pszValName == "HTTPS"
fReturn = CopyStringToBuffer( IsSecurePort() ? "on" : "off",
pchBuffer, lpcchBuffer);
} else if ( *pszSuffix == '_' ) {
fReturn = GetInfoFromCertificate( _tcpauth, pszSuffix+1,
cchSuffix - 1,
pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoH()
BOOL
HTTP_REQUEST::GetInfoI(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn = FALSE;
LPCSTR pszSuffix;
DWORD cchSuffix;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'I');
if ( IsStringPrefixMatch( "INSTANCE_", pszValName, cchValName))
{
pszSuffix = pszValName + (sizeof("INSTANCE_")-1);
cchSuffix = cchValName - (sizeof("INSTANCE_") - 1);
if ( IsStringMatch( "ID", pszSuffix, cchSuffix))
{
if ( QueryW3Instance() == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
CHAR rgch[40];
_ultoa( QueryW3Instance()->QueryInstanceId(),
rgch,
10);
fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
}
else if ( IsStringMatch( "META_PATH", pszSuffix, cchSuffix ))
{
if ( QueryW3Instance() == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
fReturn = CopyStringToBuffer( QueryW3Instance()->QueryMDPath(),
pchBuffer,
lpcchBuffer);
}
else
{
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
}
else
{
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return fReturn;
} // HTTP_REQUEST::GetInfoI()
BOOL
HTTP_REQUEST::GetInfoL(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'L');
if ( IsStringMatch( "LOCAL_ADDR", pszValName, cchValName)) {
//
// Note this returns the server IP address since we don't necessarily
// know the DNS name of this server
//
fReturn = CopyStringToBuffer( QueryClientConn()->QueryLocalAddr(),
pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "LOGON_USER", pszValName, cchValName )) {
fReturn = _strUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoL()
BOOL
HTTP_REQUEST::GetInfoP(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'P');
if ( IsStringMatch( "PATH_INFO", pszValName, cchValName )) {
fReturn = _strPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "PATH_TRANSLATED", pszValName, cchValName )) {
//
// Note that _strPathInfo has already been escaped
//
// If the path can't be found (no home root for example) then
// treat it as success and return the empty string.
//
// Easiest is to use a string object to obtain the xlation.
PW3_METADATA pMetaData = GetWAMMetaData();
if ( pMetaData == NULL )
{
return VariableNotAvailable( pchBuffer, lpcchBuffer);
}
STACK_STR( str, MAX_PATH);
if ( !LookupVirtualRoot( &str,
_strPathInfo.QueryStr() ,
_strPathInfo.QueryCCH() ) &&
GetLastError() != ERROR_PATH_NOT_FOUND ) {
fReturn = FALSE;
} else {
fReturn = str.CopyToBuffer( pchBuffer, lpcchBuffer);
}
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoP()
BOOL
HTTP_REQUEST::GetInfoR(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
char chBuff[8]; // plenty of room for _itoa(USHORT_MAX, ...)
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'R');
if ( IsStringMatch( "REQUEST_METHOD", pszValName, cchValName )) {
fReturn = _strMethod.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "REMOTE_HOST", pszValName, cchValName)) {
//
// Note that REMOTE_HOST returns DNS name if available
//
fReturn =
CopyStringToBuffer( (( QueryClientConn()->IsDnsResolved() )?
( QueryClientConn()->QueryResolvedDnsName()) :
( QueryClientConn()->QueryRemoteAddr() )
),
pchBuffer,
lpcchBuffer);
} else if ( IsStringMatch( "REMOTE_ADDR", pszValName, cchValName ) ) {
fReturn = CopyStringToBuffer( QueryClientConn()->QueryRemoteAddr(),
pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "REMOTE_USER", pszValName, cchValName)) {
fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "REMOTE_PORT", pszValName, cchValName ) ) {
_itoa( QueryClientConn()->QueryRemotePort(), chBuff, 10);
fReturn = CopyStringToBuffer( chBuff, pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoR()
BOOL
HTTP_REQUEST::GetInfoS(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'S');
if ( IsStringMatch( "SCRIPT_NAME", pszValName, cchValName ) ) {
fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer );
} else if ( IsStringPrefixMatch( "SERVER_", pszValName, cchValName)) {
LPCSTR pszSuffix = pszValName + (sizeof("SERVER_") - 1);
DWORD cchSuffix = cchValName - (sizeof("SERVER_") - 1);
if ( IsStringMatch( "NAME", pszSuffix, cchSuffix ) ) {
fReturn = CopyStringToBuffer( QueryHostAddr(),
pchBuffer, lpcchBuffer );
} else if ( IsStringMatch( "PROTOCOL", pszSuffix, cchSuffix)) {
CHAR rgch[40];
wsprintf( rgch,
"HTTP/%d.%d",
_VersionMajor,
_VersionMinor );
fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "PORT", pszSuffix, cchSuffix )) {
CHAR rgch[40];
_ultoa( QueryClientConn()->QueryPort(),
rgch, 10);
fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "PORT_SECURE", pszSuffix, cchSuffix)) {
fReturn = CopyStringToBuffer( ( IsSecurePort() ? "1" : "0"), 2,
pchBuffer, lpcchBuffer );
} else if ( IsStringMatch( "SOFTWARE", pszSuffix, cchSuffix)) {
DBG_ASSERT( g_szServerType[g_cbServerType] == '\0');
fReturn = CopyStringToBuffer( g_szServerType, g_cbServerType + 1,
pchBuffer, lpcchBuffer);
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
} else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoS()
BOOL
HTTP_REQUEST::GetInfoU(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( toupper(*pszValName) == 'U');
if ( IsStringMatch( "UNMAPPED_REMOTE_USER", pszValName, cchValName )) {
fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "URL", pszValName, cchValName ) ) {
fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "URL_PATH_INFO", pszValName, cchValName ) ) {
fReturn = _strURLPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "UNENCODED_URL", pszValName, cchValName ) ) {
fReturn = _strRawURL.CopyToBuffer( pchBuffer, lpcchBuffer);
}
else {
SetLastError( ERROR_INVALID_INDEX);
fReturn = FALSE;
}
return ( fReturn);
} // HTTP_REQUEST::GetInfoU()
BOOL
HTTP_REQUEST::GetInfoMisc(
const CHAR * pszValName,
DWORD cchValName,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
{
BOOL fReturn;
DBG_ASSERT( pszValName != NULL);
if ( IsStringMatch( "GATEWAY_INTERFACE", pszValName, cchValName )) {
fReturn = CopyStringToBuffer( "CGI/1.1", sizeof("CGI/1.1"),
pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "QUERY_STRING", pszValName, cchValName )) {
fReturn = _strURLParams.CopyToBuffer( pchBuffer, lpcchBuffer);
} else {
//
// Any other value we assume to be a real environment variable
//
DWORD cch;
//
// GetEnvironmentVariable()
// If the function succeeds, the return value is the number of
// characters stored into the buffer pointed to by lpcchBuffer,
// not including the terminating null character.
// If the specified environment variable name was not found
// in the environment block for the current process,
// the return value is zero.
// If the buffer pointed to by lpcchBuffer is not large enough,
// the return value is the buffer size, in characters,
// required to hold the value string and its terminating
// null character.
//
cch = GetEnvironmentVariable( pszValName,
pchBuffer,
*lpcchBuffer);
if ( cch == 0) {
SetLastError( ERROR_INVALID_INDEX );
fReturn = FALSE;
} else if ( cch < *lpcchBuffer ) {
// data is already copied. No problems. Return the length.
*lpcchBuffer = (cch + 1);
fReturn = TRUE;
} else {
*lpcchBuffer = cch;
SetLastError( ERROR_INSUFFICIENT_BUFFER);
fReturn = FALSE;
}
}
return (fReturn);
} // HTTP_REQUEST::GetInfoMisc()
/************************************************************
* Support Functions for GetInfoXXX
************************************************************/
BOOL
GetInfoFromCertificate(
IN TCP_AUTHENT & tcpauth,
IN LPCSTR pszValName,
DWORD cchValName,
OUT CHAR * pchBuffer,
IN OUT DWORD * lpcchBuffer
)
{
IISMD5_CTX md5;
BOOL fReturn = FALSE;
BOOL fNoCert;
DWORD i;
CHAR achCertName[MAX_CERT_FIELD_SIZE];
DWORD dwCertInfo;
DBG_ASSERT( pszValName != NULL);
DBG_ASSERT( !memcmp( pszValName - 5, "CERT_", 5) ||
!memcmp( pszValName - 6, "HTTPS_", 6)
);
//
// Find the value for the field in a certificate that is requested
//
if ( IsStringMatch( "SUBJECT", pszValName, cchValName )) {
LPSTR pV = NULL;
if ( !tcpauth.QueryCertificateSubject( achCertName, sizeof(achCertName), &fNoCert ) ) {
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer);
}
} else if ( IsStringMatch( "ISSUER", pszValName, cchValName )) {
LPSTR pV = NULL;
if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) {
// no certificate available
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer);
}
} else if ( IsStringMatch( "FLAGS", pszValName, cchValName )) {
DWORD dwF;
CHAR rgF[40];
if ( !tcpauth.QueryCertificateFlags( &dwF, &fNoCert ) ) {
rgF[0] = '\0';
} else {
_ultoa( dwF, rgF, 10);
}
fReturn = CopyStringToBuffer( rgF, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "SERIALNUMBER", pszValName, cchValName )) {
LPBYTE pV;
DWORD cch; // Buffer bytes
if ( !tcpauth.QueryCertificateSerialNumber( &pV, &dwCertInfo, &fNoCert ) ) {
// no certificate available
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
// Buffer size (cert bytes * 2 + # of '-' + NULL)
cch = dwCertInfo * 3;
if ( (pchBuffer == NULL) || (*lpcchBuffer < cch) )
{
SetLastError( ERROR_INSUFFICIENT_BUFFER);
fReturn = FALSE;
}
else
{
// Serial number is in reverse byte order
i = 0;
for( INT iSerialByte = dwCertInfo - 1; iSerialByte >= 0; --iSerialByte )
{
pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) >> 4 ];
pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) & 0xf ];
pchBuffer[i++] = '-';
}
DBG_ASSERT(i == cch);
pchBuffer[ cch - 1 ] = 0;
fReturn = TRUE;
}
*lpcchBuffer = cch;
}
} else if ( IsStringMatch( "COOKIE", pszValName, cchValName )) {
LPSTR pV;
DWORD cch; // Buffer bytes
if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) {
// no certificate available
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
IISMD5Init( &md5 );
IISMD5Update( &md5, (LPBYTE)achCertName, strlen(achCertName) );
if ( !tcpauth.QueryCertificateSerialNumber( (LPBYTE*)&pV, &dwCertInfo, &fNoCert )) {
// assumes that the above call set the error code
DBG_ASSERT( fReturn == FALSE);
} else {
// Buffer size
cch = (sizeof(md5.digest) * 2) + 1;
if ((pchBuffer == NULL) || (*lpcchBuffer < cch) )
{
SetLastError( ERROR_INSUFFICIENT_BUFFER);
fReturn = FALSE;
}
else
{
IISMD5Update( &md5, (LPBYTE)pV, dwCertInfo );
IISMD5Final( &md5 );
for ( i = 0 ; i < sizeof(md5.digest) ; ++i ) {
wsprintf( pchBuffer + i * 2, "%02x", md5.digest[i] );
}
fReturn = TRUE;
}
*lpcchBuffer = cch;
}
}
} else if ( IsStringMatch( "KEYSIZE", pszValName, cchValName)) {
DWORD dwVal;
CHAR rgVal[40];
if ( !tcpauth.QueryEncryptionKeySize( &dwVal, &fNoCert ) ) {
rgVal[0] = '\0';
} else {
_ultoa( dwVal, rgVal, 10);
}
fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "SECRETKEYSIZE", pszValName, cchValName )) {
DWORD dwVal;
CHAR rgVal[40];
if ( !tcpauth.QueryEncryptionServerPrivateKeySize( &dwVal, &fNoCert ) ) {
rgVal[0] = '\0';
} else {
_ultoa( dwVal, rgVal, 10);
}
fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer);
} else if ( IsStringMatch( "SERVER_SUBJECT", pszValName, cchValName )) {
LPSTR pV;
if ( !tcpauth.QueryServerCertificateSubject( &pV, &fNoCert ) ) {
// no certificate available
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer);
}
} else if ( IsStringMatch( "SERVER_ISSUER", pszValName, cchValName )) {
LPSTR pV;
if ( !tcpauth.QueryServerCertificateIssuer( &pV, &fNoCert ) ) {
// no certificate available
fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
} else {
fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer);
}
} else {
SetLastError( ERROR_INVALID_INDEX);
DBG_ASSERT( fReturn == FALSE);
}
return ( fReturn);
} // GetInfoFromCertificate()
# define PSZ_HTTP_PREFIX "HTTP_"
# define LEN_PSZ_HTTP_PREFIX (sizeof(PSZ_HTTP_PREFIX) - 1)
BOOL
BuildCGIHeaderList(
HTTP_HEADERS * pHeaderList,
CHAR * pchBuffer,
DWORD * lpcchBuffer
)
/*++
Routine Description:
Builds a list of all client passed headers in the form of
//
// Builds a list of all client HTTP headers in the form of:
//
// HTTP_<up-case header>: <field>\n
// HTTP_<up-case header>: <field>\n
// ...
//
Arguments:
pstr - Receives full list
pHeaderList - List of headers
--*/
{
CHAR * pchStart = pchBuffer;
DWORD cchReq = 0;
BOOL fReturn = TRUE;
HH_ITERATOR hhi;
NAME_VALUE_PAIR * pnp = NULL;
pHeaderList->InitIterator( &hhi);
while ( pHeaderList->NextPair( &hhi, &pnp)) {
//
// Ignore "method", "url" and "version"
//
if ( pnp->pchName[pnp->cchName - 1] != ':' ) {
continue;
}
//
// add HTTP_ as prefix to the headers
// convert all "-" to "_"
// convert header names to UpperCase
//
//+1 for terminating '\n'
cchReq += (pnp->cchName + pnp->cchValue + 1 + LEN_PSZ_HTTP_PREFIX);
if ( pchStart != NULL && cchReq < *lpcchBuffer) {
DWORD i;
CopyMemory( pchBuffer, PSZ_HTTP_PREFIX, LEN_PSZ_HTTP_PREFIX);
pchBuffer += LEN_PSZ_HTTP_PREFIX;
//
// Convert the destination to upper and replace all '-' with '_'
// Also convert lower-case header names to upper-case
//
for ( i = 0; i < pnp->cchName; i++) {
pchBuffer[i] = (( pnp->pchName[i] == '-') ? '_' :
toupper( pnp->pchName[i])
);
} // for
pchBuffer += i;
CopyMemory( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue);
pchBuffer += pnp->cchValue;
*pchBuffer++ = '\n'; // store a \n
} else {
fReturn = FALSE;
}
} // while
// Store the size depending upon if buffer was sufficient or not
if ( fReturn && (pchStart != NULL)) {
DBG_ASSERT( pchBuffer >= pchStart);
*pchBuffer++ = '\0'; // +1 for '\0'
*lpcchBuffer = DIFF(pchBuffer - pchStart);
} else {
fReturn = FALSE;
*lpcchBuffer = cchReq + sizeof(CHAR);
SetLastError( ERROR_INSUFFICIENT_BUFFER);
}
return ( fReturn);
} // BuildCGIHeaderList()
BOOL
HseBuildRawHeaders( IN HTTP_HEADERS * pHeaderList,
OUT LPSTR pchBuffer,
IN OUT LPDWORD lpcchBuffer
)
/*++
Routine Description:
Builds a list of all raw client passed headers in the form of
<header>:<blank><field>\n
<header>:<blank><field>\n
Arguments:
pHeaderList - List of headers
pchBuffer - pointer to buffer which will contain generated headers
lpcchBuffer - pointer to DWORD containing size of buffer
It will contain the size of written data on return.
Returns:
TRUE on success and FALSE if failure.
Error code is set to ERROR_INSUFFICIENT_BUFFER
if there is not enough buffer.
--*/
{
CHAR * pchStart = pchBuffer;
DWORD cchReq = 0;
BOOL fReturn = TRUE;
HH_ITERATOR hhi;
NAME_VALUE_PAIR * pnp = NULL;
pHeaderList->InitIterator( &hhi);
while ( pHeaderList->NextPair( &hhi, &pnp)) {
//
// Ignore "method", "url" and "version"
//
if ( pnp->pchName[pnp->cchName - 1] != ':' ) {
continue;
}
//
// leave the headers in native form i.e. no conversion of '-' to '_'
//
cchReq += (pnp->cchName + pnp->cchValue + 3); //+3 for blank & \r\n
if ( pchStart != NULL && cchReq < *lpcchBuffer) {
CopyMemory( (LPVOID) pchBuffer, pnp->pchName,
pnp->cchName * sizeof(CHAR));
pchBuffer += pnp->cchName;
*pchBuffer++ = ' '; // store a blank
memmove( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue);
pchBuffer += pnp->cchValue;
*pchBuffer++ = '\r'; // store a \r
*pchBuffer++ = '\n'; // store a \n
} else {
fReturn = FALSE;
}
} // while
// Store the size depending upon if buffer was sufficient or not
if ( fReturn && (pchStart != NULL)) {
DBG_ASSERT( pchBuffer >= pchStart);
*pchBuffer++ = '\0'; // +1 for '\0'
*lpcchBuffer = DIFF(pchBuffer - pchStart);
} else {
fReturn = FALSE;
*lpcchBuffer = cchReq + sizeof(CHAR);
SetLastError( ERROR_INSUFFICIENT_BUFFER);
}
return (fReturn);
} // HseBuildRawHeaders()
/************************ End of File ***********************/