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.
1839 lines
50 KiB
1839 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1995-1997 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
w3meta.cxx
|
|
|
|
Abstract:
|
|
Defines the functions for W3_METADATA
|
|
|
|
Author:
|
|
|
|
IIS Core Team 1997
|
|
|
|
Environment:
|
|
Win32 - User Mode
|
|
|
|
Project:
|
|
|
|
W3 Service DLL
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
#include "w3p.hxx"
|
|
#include <inetinfo.h>
|
|
#include "basereq.hxx"
|
|
#include <lonsi.hxx>
|
|
|
|
#define SET_WIN32_ERR(p,x) { (p)->IsValid = TRUE; \
|
|
(p)->ErrorReason = METADATA_ERROR_WIN32;\
|
|
(p)->Win32Error = (x); \
|
|
}
|
|
|
|
#define SET_VALUE_ERR(x) { (x)->IsValid = TRUE; \
|
|
(x)->ErrorReason = METADATA_ERROR_VALUE;\
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
BOOL
|
|
W3_METADATA::BuildCustomErrorTable(
|
|
CHAR *pszErrorList,
|
|
PMETADATA_ERROR_INFO pMDErrorInfo
|
|
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Take an input string and build a custom error table out of it. The
|
|
input string is a multi-sz, where each string is of the form error,
|
|
suberror, {FILE | URL}, path.
|
|
|
|
Arguments:
|
|
pszErrorList - Pointer to the error list.
|
|
|
|
Returns:
|
|
TRUE if we built the table successfully, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
CHAR *pszType;
|
|
CHAR *pszSubError;
|
|
CHAR *pszPath;
|
|
CHAR *pszNewPath;
|
|
CHAR cTemp;
|
|
DWORD dwError;
|
|
DWORD dwSubError;
|
|
BOOL bWildcardSubError;
|
|
BOOL bIsFile;
|
|
PCUSTOM_ERROR_ENTRY pNewEntry;
|
|
DWORD dwPathLength;
|
|
|
|
for (;;)
|
|
{
|
|
|
|
// Convert the first parameter to a number.
|
|
dwError = atoi(pszErrorList);
|
|
|
|
if (dwError < 300)
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
// Now convert the second parameter (the suberror) to a number.
|
|
|
|
pszSubError = strchr(pszErrorList, ',');
|
|
|
|
if (pszSubError == NULL)
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
pszSubError++;
|
|
while (isspace((UCHAR)(*pszSubError)))
|
|
{
|
|
pszSubError++;
|
|
}
|
|
|
|
if (*pszSubError == '*')
|
|
{
|
|
bWildcardSubError = TRUE;
|
|
dwSubError = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!isdigit((UCHAR)(*pszSubError)))
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
dwSubError = atoi(pszSubError);
|
|
bWildcardSubError = FALSE;
|
|
}
|
|
|
|
|
|
// Now find the comma that seperates the number and the type.
|
|
pszType = strchr(pszSubError, ',');
|
|
|
|
if (pszType == NULL)
|
|
{
|
|
// Didn't find it.
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
pszType++;
|
|
|
|
// Skip any preceding ws.
|
|
|
|
while (isspace((UCHAR)(*pszType)))
|
|
{
|
|
pszType++;
|
|
}
|
|
|
|
// We found the end of ws. If this isn't an alphabetic character, it's
|
|
// an error. If it is, find the end of the alpha. chars.
|
|
|
|
if (!isalpha((UCHAR)(*pszType)))
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
pszPath = pszType;
|
|
|
|
while (isalpha((UCHAR)(*pszPath)))
|
|
{
|
|
pszPath++;
|
|
}
|
|
|
|
cTemp = *pszPath;
|
|
*pszPath = '\0';
|
|
|
|
// Now see what the parameter is.
|
|
|
|
if (!_stricmp(pszType, "FILE"))
|
|
{
|
|
bIsFile = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (!_stricmp(pszType, "URL"))
|
|
{
|
|
bIsFile = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pszPath = cTemp;
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*pszPath = cTemp;
|
|
|
|
// Now find the comma that seperates the type from the URL/path.
|
|
|
|
pszPath = strchr(pszPath, ',');
|
|
|
|
if (pszPath == NULL)
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
// Found the comma. Go one past and find the path or URL.
|
|
|
|
pszPath++;
|
|
|
|
while (isspace((UCHAR)(*pszPath)))
|
|
{
|
|
pszPath++;
|
|
}
|
|
|
|
if (*pszPath == '\0')
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
dwPathLength = strlen(pszPath) + 1;
|
|
|
|
pszNewPath = (CHAR *)TCP_ALLOC(dwPathLength);
|
|
|
|
if (pszNewPath == NULL)
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(pszNewPath, pszPath, dwPathLength);
|
|
|
|
pNewEntry = new CUSTOM_ERROR_ENTRY(dwError, dwSubError,
|
|
bWildcardSubError, pszNewPath, bIsFile);
|
|
|
|
if (pNewEntry == NULL)
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
TCP_FREE(pszNewPath);
|
|
return FALSE;
|
|
}
|
|
|
|
// Insert wildcard errors at the end, and specific errors at the
|
|
// begining, so that specific errors have priority.
|
|
|
|
if (bWildcardSubError)
|
|
{
|
|
InsertTailList(&m_CustomErrorHead, &pNewEntry->_ListEntry );
|
|
}
|
|
else
|
|
{
|
|
InsertHeadList(&m_CustomErrorHead, &pNewEntry->_ListEntry );
|
|
}
|
|
|
|
pszErrorList = pszPath + dwPathLength;
|
|
|
|
if (*pszErrorList == '\0')
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
W3_METADATA::DestroyCustomErrorTable(
|
|
VOID
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
Destroy the custom error table for this metadata.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
LIST_ENTRY *pEntry;
|
|
PCUSTOM_ERROR_ENTRY pErrorEntry;
|
|
|
|
while ( !IsListEmpty( &m_CustomErrorHead ))
|
|
{
|
|
pErrorEntry = CONTAINING_RECORD( m_CustomErrorHead.Flink,
|
|
CUSTOM_ERROR_ENTRY,
|
|
_ListEntry );
|
|
|
|
RemoveEntryList( &pErrorEntry->_ListEntry );
|
|
|
|
delete pErrorEntry;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CompactParameters
|
|
|
|
SYNOPSIS: Reads a metadata multisz set of comma seperated
|
|
strings, and copies this into a BUFFER while stripping
|
|
whitespace. There can be multiple lines.
|
|
|
|
ENTRY: bufDest - Pointer to BUFFER to copy into.
|
|
pszSrc - Source string.
|
|
dwNumParam - Number of paramters to retrieve.
|
|
fFlags - Bit field, indicating which parameters
|
|
are to have white space stripped.
|
|
|
|
RETURNS: TRUE if successful, FALSE if an error occurred.
|
|
|
|
NOTES:
|
|
|
|
|
|
********************************************************************/
|
|
BOOL
|
|
CompactParameters(
|
|
BUFFER *bufDest,
|
|
CHAR *pszSrc,
|
|
DWORD dwNumParam,
|
|
DWORD fFlags,
|
|
PMETADATA_ERROR_INFO pMDErrorInfo
|
|
)
|
|
{
|
|
DWORD dwParamFound;
|
|
CHAR *pszCurrent;
|
|
BOOL bFirst;
|
|
DWORD dwBytesCopied;
|
|
DWORD dwBufferSize;
|
|
CHAR *pszBuffer;
|
|
DWORD fWSFlags;
|
|
|
|
DBG_ASSERT(pszSrc != NULL);
|
|
|
|
|
|
// Go through each line, looking for dwNumParam parameters. When we find
|
|
// that many, go to end of line, and start again. If we don't find
|
|
// enough parameters in a line, fail.
|
|
|
|
dwParamFound = 0;
|
|
dwBytesCopied = 0;
|
|
bFirst = TRUE;
|
|
fWSFlags = fFlags;
|
|
|
|
dwBufferSize = bufDest->QuerySize();
|
|
pszBuffer = (CHAR *)bufDest->QueryPtr();
|
|
|
|
for (;;)
|
|
{
|
|
DWORD dwBytesNeeded;
|
|
|
|
while (isspace((UCHAR)(*pszSrc)))
|
|
{
|
|
pszSrc++;
|
|
}
|
|
|
|
if (*pszSrc == '\0')
|
|
{
|
|
// Didn't find enough.
|
|
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
// Now scan this parameter, looking for either WS or a comma,
|
|
// depending on fWSFlags.
|
|
|
|
pszCurrent = pszSrc;
|
|
|
|
while (*pszSrc != ',' && ( (fWSFlags & 1) ? TRUE : !isspace((UCHAR)(*pszSrc))) &&
|
|
*pszSrc != '\0')
|
|
{
|
|
pszSrc++;
|
|
}
|
|
|
|
dwParamFound++;
|
|
|
|
// Now pszSrc points at the character that terminated our parameter.
|
|
// Make sure we have enough room to copy this.
|
|
|
|
dwBytesNeeded = DIFF(pszSrc - pszCurrent) + (bFirst ? 0 : sizeof(CHAR)) +
|
|
((dwParamFound != dwNumParam) ? 0 : sizeof(CHAR));
|
|
|
|
if ((dwBufferSize - dwBytesCopied) < dwBytesNeeded)
|
|
{
|
|
if (!bufDest->Resize(dwBytesCopied + dwBytesNeeded + 32))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
dwBufferSize = bufDest->QuerySize();
|
|
pszBuffer = (CHAR *)bufDest->QueryPtr();
|
|
}
|
|
|
|
if (!bFirst)
|
|
{
|
|
*(pszBuffer + dwBytesCopied) = ',';
|
|
dwBytesCopied++;
|
|
}
|
|
|
|
memcpy(pszBuffer + dwBytesCopied, pszCurrent, DIFF(pszSrc - pszCurrent));
|
|
dwBytesCopied += DIFF(pszSrc - pszCurrent);
|
|
|
|
bFirst = FALSE;
|
|
fWSFlags >>= 1;
|
|
|
|
if (dwParamFound == dwNumParam)
|
|
{
|
|
// Found all we need on this line, look for the next.
|
|
*(pszBuffer + dwBytesCopied) = '\0';
|
|
dwBytesCopied++;
|
|
|
|
bFirst = TRUE;
|
|
fWSFlags = fFlags;
|
|
dwParamFound = 0;
|
|
|
|
while (*pszSrc != '\0')
|
|
{
|
|
pszSrc++;
|
|
}
|
|
|
|
// Move to start of next line.
|
|
pszSrc++;
|
|
|
|
if (*pszSrc == '\0')
|
|
{
|
|
// Found end of multisz. Terminate buffer and return.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, still have more parameters to find on this line.
|
|
|
|
while (*pszSrc != ',')
|
|
{
|
|
if (*pszSrc == '\0')
|
|
{
|
|
if (dwNumParam != 0xffffffff)
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
// Copying an unknown number, so terminate the line now.
|
|
|
|
if ((dwBufferSize - dwBytesCopied) == 0)
|
|
{
|
|
if (!bufDest->Resize(dwBytesCopied + 32))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
dwBufferSize = bufDest->QuerySize();
|
|
pszBuffer = (CHAR *)bufDest->QueryPtr();
|
|
}
|
|
|
|
*(pszBuffer + dwBytesCopied) = '\0';
|
|
dwBytesCopied++;
|
|
bFirst = TRUE;
|
|
fWSFlags = fFlags;
|
|
dwParamFound = 0;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
else
|
|
{
|
|
pszSrc++;
|
|
}
|
|
|
|
}
|
|
|
|
if (*pszSrc == '\0')
|
|
{
|
|
// We broke out of the loop because we hit the end of the
|
|
// line on a 'read all' string.
|
|
|
|
if (*(pszSrc + 1) == '\0')
|
|
{
|
|
// Hit the end of a multisz.
|
|
break;
|
|
}
|
|
}
|
|
|
|
pszSrc++;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// We get here when we've copied all of the buffer. Terminate the multisz
|
|
// and we're done.
|
|
|
|
if ((dwBufferSize - dwBytesCopied) == 0)
|
|
{
|
|
if (!bufDest->Resize(dwBytesCopied + 1))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
pszBuffer = (CHAR *)bufDest->QueryPtr();
|
|
}
|
|
|
|
*(pszBuffer + dwBytesCopied) = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
W3_METADATA::ReadCustomFooter(
|
|
CHAR *pszFooter,
|
|
TSVC_CACHE &Cache,
|
|
HANDLE User,
|
|
PMETADATA_ERROR_INFO pMDErrorInfo
|
|
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a footer string, either reading the file or copying the string
|
|
to the buffer.
|
|
|
|
Arguments:
|
|
|
|
pszFooter - The footer string, which may be a string or a file name.
|
|
Cache - Cache info for opening file
|
|
User - Token for opening user
|
|
|
|
Returns:
|
|
|
|
TRUE if we succeed, FALSE if we don't.
|
|
|
|
--*/
|
|
{
|
|
BOOL bIsString;
|
|
DWORD dwLength;
|
|
STACK_STR(strError, 128);
|
|
|
|
if (!FooterEnabled())
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// First thing to do is to determine if this is a string or a file name.
|
|
// Skip preceding whitespace and then strcmp.
|
|
|
|
while (isspace((UCHAR)(*pszFooter)))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
|
|
if (!_strnicmp(pszFooter, "STRING", sizeof("STRING") - 1))
|
|
{
|
|
bIsString = TRUE;
|
|
pszFooter += sizeof("STRING") - 1;
|
|
}
|
|
else
|
|
{
|
|
if (!_strnicmp(pszFooter, "FILE", sizeof("FILE") - 1))
|
|
{
|
|
bIsString = FALSE;
|
|
pszFooter += sizeof("FILE") - 1;
|
|
}
|
|
else
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Now we look for 0 or more white space, followed by a colon, followed by
|
|
// more white space.
|
|
|
|
while (isspace((UCHAR)(*pszFooter)))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
if (*pszFooter != ':')
|
|
{
|
|
// No colon seperator, error.
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
pszFooter++;
|
|
|
|
//
|
|
// OK, now if this is a string we take everything after the colon to the
|
|
// end for the string. If this is a file name then we'll open and read the
|
|
// file.
|
|
//
|
|
|
|
if (bIsString)
|
|
{
|
|
|
|
dwLength = strlen(pszFooter);
|
|
|
|
if (!m_bufFooter.Resize(dwLength))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(m_bufFooter.QueryPtr(), pszFooter, dwLength);
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For files, we'll skip any more white space before the name.
|
|
//
|
|
|
|
while (isspace((UCHAR)(*pszFooter)))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
|
|
if (!ReadEntireFile(pszFooter, Cache, User ,&m_bufFooter, &dwLength))
|
|
{
|
|
// Couldn't read the file, so instead we'll read the error
|
|
// string and use that.
|
|
if ( g_pInetSvc->LoadStr( strError, IDS_ERROR_FOOTER ))
|
|
{
|
|
dwLength = strError.QueryCB();
|
|
|
|
if (!m_bufFooter.Resize(dwLength))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(m_bufFooter.QueryPtr(), strError.QueryStr(), dwLength);
|
|
}
|
|
else
|
|
{
|
|
// Couldn't read the error string, so fail.
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetFooter(dwLength, (CHAR *)m_bufFooter.QueryPtr());
|
|
return TRUE;
|
|
}
|
|
|
|
#define SIZEOF_EXPIRE_HEADER sizeof("Expires: \r\n")
|
|
#define SIZEOF_GMT_DATETIME 64
|
|
#define SIZEOF_CACHE_CONTROL (sizeof("Cache-Control: max-age=4294967295\r\n") - 1)
|
|
|
|
|
|
BOOL
|
|
W3_METADATA::SetExpire(
|
|
CHAR* pszExpire,
|
|
PMETADATA_ERROR_INFO pMDErrorInfo
|
|
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set metadata based on MD_HTTP_EXPIRES entry
|
|
|
|
Arguments:
|
|
|
|
pszExpire - expire configuration
|
|
|
|
Return value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
DWORD dwExpires;
|
|
LPSTR pszParam;
|
|
CHAR *EndPtr;
|
|
|
|
while (isspace((UCHAR)(*pszExpire)))
|
|
{
|
|
pszExpire++;
|
|
}
|
|
|
|
if ( !(pszParam = strchr( pszExpire, ',' )) )
|
|
{
|
|
if (*pszExpire == '\0' || toupper(*pszExpire) == 'N')
|
|
{
|
|
m_dwExpireMode = EXPIRE_MODE_OFF;
|
|
return TRUE;
|
|
}
|
|
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
++pszParam;
|
|
|
|
while (isspace((UCHAR)(*pszParam)))
|
|
{
|
|
pszParam++;
|
|
}
|
|
|
|
switch ( *(CHAR*)pszExpire )
|
|
{
|
|
case 's': case 'S':
|
|
if ( !m_strExpireHeader.Copy( "Expires: " ) ||
|
|
!m_strExpireHeader.Append( pszParam ) ||
|
|
!m_strExpireHeader.Append( "\r\n" ) )
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
m_dwExpireMaxLength = m_strExpireHeader.QueryCCH() +
|
|
SIZEOF_CACHE_CONTROL;
|
|
m_dwExpireMode = EXPIRE_MODE_STATIC;
|
|
|
|
if ( !StringTimeToFileTime( pszParam,
|
|
&m_liExpireTime ))
|
|
{
|
|
m_liExpireTime.QuadPart = 0;
|
|
}
|
|
break;
|
|
|
|
case 'd': case 'D':
|
|
dwExpires = strtoul(pszParam,&EndPtr,0);
|
|
|
|
if (!isspace((UCHAR)(*EndPtr)) && *EndPtr != '\0')
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( dwExpires != NO_GLOBAL_EXPIRE )
|
|
{
|
|
if (dwExpires > MAX_GLOBAL_EXPIRE )
|
|
{
|
|
dwExpires = MAX_GLOBAL_EXPIRE;
|
|
}
|
|
|
|
m_dwExpireMode = EXPIRE_MODE_DYNAMIC;
|
|
m_dwExpireDelta = dwExpires;
|
|
m_dwExpireMaxLength = SIZEOF_EXPIRE_HEADER + SIZEOF_GMT_DATETIME;
|
|
}
|
|
break;
|
|
|
|
case 'n': case 'N':
|
|
m_dwExpireMode = EXPIRE_MODE_OFF;
|
|
break;
|
|
|
|
default:
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
SetLastError( ERROR_INVALID_DATA );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define RMD_ASSERT(x) if (!(x)) { pMDErrorInfo->IsValid = TRUE; \
|
|
pMDErrorInfo->ErrorParameter = pMDRecord->dwMDIdentifier; \
|
|
pMDErrorInfo->ErrorReason = METADATA_ERROR_TYPE;\
|
|
SetLastError(ERROR_INVALID_PARAMETER);\
|
|
return FALSE; \
|
|
}
|
|
|
|
BOOL
|
|
W3_METADATA::HandlePrivateProperty(
|
|
LPSTR pszURL,
|
|
PIIS_SERVER_INSTANCE pInstance,
|
|
METADATA_GETALL_INTERNAL_RECORD *pMDRecord,
|
|
PVOID pDataPointer,
|
|
BUFFER *pBuffer,
|
|
DWORD *pdwBytesUsed,
|
|
PMETADATA_ERROR_INFO pMDErrorInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle metadata properties specific to W3
|
|
|
|
Arguments:
|
|
|
|
pszURL - URL for which we are reading metadata
|
|
pInstance - current w3 instance
|
|
pMDRecord - metadata record to process
|
|
pDataPointer - data associated with pMDRecord
|
|
|
|
Return value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BUFFER bufTemp1;
|
|
PW3_METADATA_INFO pMDInfo;
|
|
CHAR *pszStart;
|
|
|
|
pMDErrorInfo->ErrorParameter = pMDRecord->dwMDIdentifier;
|
|
|
|
if (*pdwBytesUsed == 0)
|
|
{
|
|
if (!pBuffer->Resize(sizeof(W3_METADATA_INFO)))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
*pdwBytesUsed = sizeof(W3_METADATA_INFO);
|
|
|
|
}
|
|
|
|
|
|
switch( pMDRecord->dwMDIdentifier )
|
|
{
|
|
CHAR *pszTemp;
|
|
DWORD dwTemp;
|
|
|
|
case MD_ANONYMOUS_USER_NAME:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if ( *(CHAR*)pDataPointer == '\0' )
|
|
{
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !SetAnonUserName( (CHAR *) pDataPointer ) ||
|
|
!BuildAnonymousAcctDesc( QueryAuthentInfo() ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(CAL_ENABLED)
|
|
CalExemptAddRef( (CHAR *) pDataPointer, &m_dwCalHnd );
|
|
#endif
|
|
break;
|
|
|
|
case MD_ANONYMOUS_PWD:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if ( !SetAnonUserPassword( (CHAR *) pDataPointer ) ||
|
|
!BuildAnonymousAcctDesc( QueryAuthentInfo() ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_ANONYMOUS_USE_SUBAUTH:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetUseAnonSubAuth( *((UNALIGNED DWORD *) pDataPointer ));
|
|
break;
|
|
|
|
case MD_DEFAULT_LOGON_DOMAIN:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if ( !SetDefaultLogonDomain( (CHAR *) pDataPointer ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_LOGON_METHOD:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
|
|
//
|
|
// The MD_LOGON_METHOD values in the metabase don't match the NT logon
|
|
// values, so we'll convert them
|
|
//
|
|
// Win64 UNALIGNED pointer fix
|
|
switch ( *((UNALIGNED DWORD *) pDataPointer ) )
|
|
{
|
|
case MD_LOGON_BATCH:
|
|
SetLogonMethod( LOGON32_LOGON_BATCH );
|
|
break;
|
|
|
|
case MD_LOGON_INTERACTIVE:
|
|
SetLogonMethod( LOGON32_LOGON_INTERACTIVE );
|
|
break;
|
|
|
|
case MD_LOGON_NETWORK:
|
|
SetLogonMethod( LOGON32_LOGON_NETWORK );
|
|
break;
|
|
|
|
case MD_LOGON_NETWORK_CLEARTEXT:
|
|
SetLogonMethod( LOGON32_LOGON_NETWORK_CLEARTEXT );
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_AUTHORIZATION:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
if ( QuerySingleAccessToken() )
|
|
{
|
|
// Win64 UNALIGNED pointer fix
|
|
SetAuthentication( (*((UNALIGNED DWORD *) pDataPointer)&~MD_AUTH_BASIC ));
|
|
}
|
|
else
|
|
{
|
|
// Win64 UNALIGNED pointer fix
|
|
SetAuthentication( *((UNALIGNED DWORD *) pDataPointer ));
|
|
}
|
|
break;
|
|
|
|
case MD_AUTHORIZATION_PERSISTENCE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetAuthenticationPersistence( *((UNALIGNED DWORD *) pDataPointer ));
|
|
break;
|
|
|
|
case MD_REALM:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if ( !SetRealm( (CHAR *)pDataPointer ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_DEFAULT_LOAD_FILE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
if (!QueryDefaultDocs()->Copy((const CHAR *)pDataPointer))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_DIRECTORY_BROWSING:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetDirBrowseFlags( *((UNALIGNED DWORD *) pDataPointer ));
|
|
break;
|
|
|
|
case MD_MIME_MAP:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
|
|
|
|
if ( *((CHAR *)pDataPointer) )
|
|
{
|
|
if (!CompactParameters(QueryMimeMap(), (CHAR *)pDataPointer,
|
|
2, 0x2, pMDErrorInfo))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MD_SCRIPT_MAPS:
|
|
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
|
|
|
|
if ( *((CHAR *)pDataPointer) )
|
|
{
|
|
if (!CompactParameters(&bufTemp1, (CHAR *)pDataPointer, 0xffffffff,
|
|
0x02, pMDErrorInfo))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!BuildExtMap((CHAR *)bufTemp1.QueryPtr()))
|
|
{
|
|
|
|
if (GetLastError() == ERROR_INVALID_DATA)
|
|
{
|
|
// Return the specific error that the script map is bad
|
|
SET_VALUE_ERR(pMDErrorInfo);
|
|
}
|
|
else
|
|
{
|
|
// Handle other errors
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MD_HTTP_EXPIRES:
|
|
|
|
// An Expires value. Range check it, and then format it and
|
|
// save it in the metadata.
|
|
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
return SetExpire( (CHAR*)pDataPointer, pMDErrorInfo );
|
|
|
|
case MD_HTTP_PICS:
|
|
case MD_HTTP_CUSTOM:
|
|
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
|
|
|
|
// Copies these headers into our header structure. If it fails,
|
|
// free our metadata and give up.
|
|
|
|
|
|
pszStart = (CHAR *)pDataPointer;
|
|
|
|
while ( *pszStart != '\0' )
|
|
{
|
|
DWORD dwLength;
|
|
|
|
dwLength = strlen(pszStart);
|
|
|
|
if ( !QueryHeaders()->Append( pszStart,
|
|
dwLength ) ||
|
|
!QueryHeaders()->Append( "\r\n",
|
|
sizeof("\r\n") - 1) )
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
pszStart += (dwLength + 1);
|
|
|
|
}
|
|
break;
|
|
|
|
case MD_CREATE_PROCESS_AS_USER:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetCreateProcessAsUser( *((UNALIGNED DWORD *) pDataPointer ));
|
|
break;
|
|
|
|
case MD_CREATE_PROC_NEW_CONSOLE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetCreateProcessNewConsole( *((UNALIGNED DWORD *) pDataPointer ));
|
|
break;
|
|
|
|
case MD_HTTP_REDIRECT:
|
|
{
|
|
STACK_STR( strRealSource, MAX_PATH );
|
|
STACK_STR( strDestination, MAX_PATH );
|
|
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( (pMDRecord->dwMDDataType == STRING_METADATA) ||
|
|
(pMDRecord->dwMDDataType == MULTISZ_METADATA) );
|
|
|
|
if ( !strDestination.Copy( (CHAR*) pDataPointer ) ||
|
|
!GetTrueRedirectionSource( pszURL,
|
|
pInstance,
|
|
(CHAR*) pDataPointer,
|
|
pMDRecord->dwMDDataType == STRING_METADATA,
|
|
&strRealSource ) ||
|
|
!SetRedirectionBlob( strRealSource,
|
|
strDestination ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pMDRecord->dwMDDataType == MULTISZ_METADATA)
|
|
{
|
|
// Have some conditional headers, add them now.
|
|
//
|
|
DBG_ASSERT(QueryRedirectionBlob() != NULL);
|
|
|
|
if (!QueryRedirectionBlob()->SetConditionalHeaders(
|
|
(CHAR *)pDataPointer + strlen((CHAR *)pDataPointer) + 1)
|
|
)
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MD_CUSTOM_ERROR:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
|
|
|
|
// Treat a NULL custom error string as not being present.
|
|
|
|
if (*(CHAR *)pDataPointer == '\0')
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!BuildCustomErrorTable( (CHAR *) pDataPointer,pMDErrorInfo ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_FOOTER_DOCUMENT:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if (!ReadCustomFooter((CHAR *)pDataPointer,
|
|
pInstance->GetTsvcCache(),
|
|
g_hSysAccToken,
|
|
pMDErrorInfo
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_FOOTER_ENABLED:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
if (*(UNALIGNED DWORD *)pDataPointer == 0)
|
|
{
|
|
SetFooterEnabled(FALSE);
|
|
SetFooter(0, NULL);
|
|
}
|
|
break;
|
|
|
|
case MD_SSI_EXEC_DISABLED:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetSSIExecDisabled( !!*((UNALIGNED DWORD *) pDataPointer) );
|
|
break;
|
|
|
|
case MD_SCRIPT_TIMEOUT:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetCGIScriptTimeout( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_POOL_IDC_TIMEOUT:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetPoolIDCTimeout( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_NTAUTHENTICATION_PROVIDERS:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
if ( !BuildProviderList( (CHAR *) pDataPointer ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_ALLOW_KEEPALIVES:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetAllowKeepAlives( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_CACHE_EXTENSIONS:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetCacheISAPIApps( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_DO_REVERSE_DNS:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
m_fDoReverseDns = !!*((UNALIGNED DWORD *) pDataPointer);
|
|
break;
|
|
|
|
case MD_NOTIFY_EXAUTH:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
m_dwNotifyExAuth = *((UNALIGNED DWORD *) pDataPointer);
|
|
break;
|
|
|
|
case MD_CC_NO_CACHE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
if (*(UNALIGNED DWORD *)pDataPointer != 0)
|
|
{
|
|
SetConfigNoCache();
|
|
|
|
if (QueryExpireMode() == EXPIRE_MODE_NONE)
|
|
{
|
|
return SetExpire("d, 0", pMDErrorInfo);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MD_CC_MAX_AGE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
|
|
pMDInfo = (PW3_METADATA_INFO)pBuffer->QueryPtr();
|
|
// Win64 UNALIGNED pointer fix
|
|
pMDInfo->dwMaxAge = *(UNALIGNED DWORD *)pDataPointer;
|
|
|
|
SetHaveMaxAge();
|
|
break;
|
|
|
|
case MD_CC_OTHER:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
|
|
|
|
if (*(CHAR *)pDataPointer != '\0')
|
|
{
|
|
if (!m_strCacheControlHeader.Copy("Cache-Control: ",
|
|
sizeof("Cache-Control: ") - 1) ||
|
|
!m_strCacheControlHeader.Append((CHAR *)pDataPointer))
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MD_REDIRECT_HEADERS:
|
|
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
|
|
|
|
// Copies these headers into our redirect header structure.
|
|
pszStart = (CHAR *)pDataPointer;
|
|
|
|
while ( *pszStart != '\0' )
|
|
{
|
|
DWORD dwLength;
|
|
|
|
dwLength = strlen(pszStart);
|
|
|
|
if ( !QueryRedirectHeaders()->Append( pszStart,
|
|
dwLength ) ||
|
|
!QueryRedirectHeaders()->Append( "\r\n",
|
|
sizeof("\r\n") - 1) )
|
|
{
|
|
SET_WIN32_ERR(pMDErrorInfo, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
pszStart += (dwLength + 1);
|
|
|
|
}
|
|
break;
|
|
|
|
case MD_UPLOAD_READAHEAD_SIZE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetUploadReadAhead( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_PUT_READ_SIZE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetPutReadSize( *((UNALIGNED DWORD *) pDataPointer ) );
|
|
break;
|
|
|
|
case MD_CPU_CGI_ENABLED:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
#ifdef _WIN64
|
|
// SetJobCGIEnabled( *((CHAR *) pDataPointer ));
|
|
// Win64 UNALIGNED pointer fix
|
|
SetJobCGIEnabled( *((UNALIGNED DWORD *) pDataPointer ));
|
|
#else
|
|
SetJobCGIEnabled( *((DWORD *) pDataPointer ));
|
|
#endif
|
|
break;
|
|
|
|
case MD_VR_IGNORE_TRANSLATE:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
// Win64 UNALIGNED pointer fix
|
|
SetIgnoreTranslate( *((UNALIGNED DWORD *) pDataPointer) );
|
|
break;
|
|
|
|
case MD_USE_DIGEST_SSP:
|
|
DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
|
|
RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
|
|
SetUseDigestSSP( *((UNALIGNED DWORD *) pDataPointer) );
|
|
break;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
W3_METADATA::SetCCHeader(
|
|
BOOL bNoCache,
|
|
BOOL bMaxAge,
|
|
DWORD dwMaxAge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a Cache-Control header with no-cache or max-age=.
|
|
|
|
Arguments:
|
|
|
|
bNoCache - True if we're to build a no-cache header.
|
|
bMaxAge - True if we're to build a max-age= header.
|
|
dwMaxAge - Max-Age to use.
|
|
|
|
|
|
Return value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
CHAR cMaxAgeBuffer[34];
|
|
BOOL bHaveCCHeader;
|
|
METADATA_ERROR_INFO DummyError;
|
|
|
|
bHaveCCHeader = !m_strCacheControlHeader.IsEmpty();
|
|
|
|
//
|
|
// If we don't already have the basic Cache-Control: header, add it.
|
|
//
|
|
|
|
if (!bHaveCCHeader)
|
|
{
|
|
if (!m_strCacheControlHeader.Copy("Cache-Control: ",
|
|
sizeof("Cache-Control: ") - 1) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Now see if we're to add a no-cache or max-age= header.
|
|
//
|
|
if (bNoCache)
|
|
{
|
|
// It's a no-cache, this is straightforward.
|
|
//
|
|
if (!m_strCacheControlHeader.Append(bHaveCCHeader ?
|
|
",no-cache" : "no-cache",
|
|
sizeof("no-cache") - (bHaveCCHeader ? 0 : 1) ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bMaxAge)
|
|
{
|
|
// Add a max-age header. First convert it to a string.
|
|
// We build the string at an offset into the MaxAge buffer
|
|
// so later we can convert the MaxAge buffer into a string
|
|
// suitable for SetExpire if we need to.
|
|
|
|
_itoa(dwMaxAge, &cMaxAgeBuffer[2], 10);
|
|
|
|
if (!m_strCacheControlHeader.Append(bHaveCCHeader ?
|
|
",max-age=" : "max-age=",
|
|
sizeof("max-age=") - (bHaveCCHeader ? 0 : 1) ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!m_strCacheControlHeader.Append(&cMaxAgeBuffer[2]))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Now, if we don't already have an expiration time, set one.
|
|
if (QueryExpireMode() == EXPIRE_MODE_NONE)
|
|
{
|
|
cMaxAgeBuffer[0] = 'd';
|
|
cMaxAgeBuffer[1] = ',';
|
|
|
|
if (!SetExpire(cMaxAgeBuffer, &DummyError))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
W3_METADATA::FinishPrivateProperties(
|
|
BUFFER *pBuffer,
|
|
DWORD dwBytesUsed,
|
|
BOOL bSucceeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finish processing of private W3 metadata properties.
|
|
|
|
Arguments:
|
|
|
|
pBuffer - Pointer to BUFFER containing info gathered during
|
|
calls to HandlePrivateProperty.
|
|
dwBytesUsed - Size in bytes of buffer pointed to by pBuffer
|
|
bSucceede - TRUE iff we read all private properties successfully.
|
|
|
|
Return value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
PW3_METADATA_INFO pMDInfo;
|
|
BOOL bHaveCCHeader;
|
|
|
|
if (dwBytesUsed != 0 && dwBytesUsed != sizeof(W3_METADATA_INFO))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pMDInfo = (PW3_METADATA_INFO)pBuffer->QueryPtr();
|
|
|
|
if (bSucceeded)
|
|
{
|
|
|
|
bHaveCCHeader = !m_strCacheControlHeader.IsEmpty();
|
|
|
|
if (QueryExpireMode() == EXPIRE_MODE_OFF)
|
|
{
|
|
ClearConfigNoCache();
|
|
ClearHaveMaxAge();
|
|
}
|
|
else
|
|
{
|
|
if (QueryConfigNoCache() || QueryHaveMaxAge())
|
|
{
|
|
// We have some sort of cache-control header to add here.
|
|
|
|
if (!SetCCHeader(QueryConfigNoCache(), QueryHaveMaxAge(),
|
|
QueryHaveMaxAge() ? pMDInfo->dwMaxAge : 0))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
bHaveCCHeader = TRUE;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't have either a max-age or no-cache header. If we have
|
|
// a dynamic Expires header, create a max-age header now.
|
|
//
|
|
if (QueryExpireMode() == EXPIRE_MODE_DYNAMIC)
|
|
{
|
|
DWORD dwDelta = QueryExpireDelta();
|
|
BOOL SetCCRetVal;
|
|
|
|
if (dwDelta != 0)
|
|
{
|
|
SetCCRetVal = SetCCHeader(FALSE, TRUE, dwDelta);
|
|
}
|
|
else
|
|
{
|
|
SetCCRetVal = SetCCHeader(TRUE, FALSE, 0);
|
|
}
|
|
|
|
if (!SetCCRetVal)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
bHaveCCHeader = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (QueryExpireMode() == EXPIRE_MODE_STATIC)
|
|
{
|
|
// We have a static expiration data and no configured
|
|
// max-age or no-cache controls. If we don't have a
|
|
// cache-control header built, build one, and leave off
|
|
// the trailing CRLF, that'll be added later when we build
|
|
// the whole header.
|
|
|
|
if (!bHaveCCHeader)
|
|
{
|
|
if (!m_strCacheControlHeader.Copy("Cache-Control: ",
|
|
sizeof("Cache-Control: ") - 1) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Already have a header, append a comma.
|
|
if (!m_strCacheControlHeader.Append(",",
|
|
sizeof(",") - 1) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bHaveCCHeader = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (bHaveCCHeader)
|
|
{
|
|
if ( !m_strCacheControlHeader.Append("\r\n", sizeof("\r\n") - 1))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define DEFINE_MD_MAP(x) {x, #x }
|
|
|
|
struct MDIDMap
|
|
{
|
|
DWORD MDID;
|
|
CHAR *IDName;
|
|
|
|
} MDIDMappingTable[] =
|
|
{
|
|
DEFINE_MD_MAP(MD_AUTHORIZATION),
|
|
DEFINE_MD_MAP(MD_REALM),
|
|
DEFINE_MD_MAP(MD_HTTP_EXPIRES),
|
|
DEFINE_MD_MAP(MD_HTTP_PICS),
|
|
DEFINE_MD_MAP(MD_HTTP_CUSTOM),
|
|
DEFINE_MD_MAP(MD_DIRECTORY_BROWSING),
|
|
DEFINE_MD_MAP(MD_DEFAULT_LOAD_FILE),
|
|
DEFINE_MD_MAP(MD_CONTENT_NEGOTIATION),
|
|
DEFINE_MD_MAP(MD_CUSTOM_ERROR),
|
|
DEFINE_MD_MAP(MD_FOOTER_DOCUMENT),
|
|
DEFINE_MD_MAP(MD_FOOTER_ENABLED),
|
|
DEFINE_MD_MAP(MD_HTTP_REDIRECT),
|
|
DEFINE_MD_MAP(MD_DEFAULT_LOGON_DOMAIN),
|
|
DEFINE_MD_MAP(MD_LOGON_METHOD),
|
|
DEFINE_MD_MAP(MD_SCRIPT_MAPS),
|
|
DEFINE_MD_MAP(MD_MIME_MAP),
|
|
DEFINE_MD_MAP(MD_ACCESS_PERM),
|
|
#if 0
|
|
DEFINE_MD_MAP(MD_HEADER_DOCUMENT),
|
|
DEFINE_MD_MAP(MD_HEADER_ENABLED),
|
|
#endif
|
|
DEFINE_MD_MAP(MD_IP_SEC),
|
|
DEFINE_MD_MAP(MD_ANONYMOUS_USER_NAME),
|
|
DEFINE_MD_MAP(MD_ANONYMOUS_PWD),
|
|
DEFINE_MD_MAP(MD_ANONYMOUS_USE_SUBAUTH),
|
|
DEFINE_MD_MAP(MD_DONT_LOG),
|
|
DEFINE_MD_MAP(MD_ADMIN_ACL),
|
|
DEFINE_MD_MAP(MD_SSI_EXEC_DISABLED),
|
|
DEFINE_MD_MAP(MD_DO_REVERSE_DNS),
|
|
DEFINE_MD_MAP(MD_SSL_ACCESS_PERM),
|
|
DEFINE_MD_MAP(MD_AUTHORIZATION_PERSISTENCE),
|
|
DEFINE_MD_MAP(MD_NTAUTHENTICATION_PROVIDERS),
|
|
DEFINE_MD_MAP(MD_SCRIPT_TIMEOUT),
|
|
DEFINE_MD_MAP(MD_CACHE_EXTENSIONS),
|
|
DEFINE_MD_MAP(MD_CREATE_PROCESS_AS_USER),
|
|
DEFINE_MD_MAP(MD_CREATE_PROC_NEW_CONSOLE),
|
|
DEFINE_MD_MAP(MD_POOL_IDC_TIMEOUT),
|
|
DEFINE_MD_MAP(MD_ALLOW_KEEPALIVES),
|
|
DEFINE_MD_MAP(MD_IS_CONTENT_INDEXED),
|
|
DEFINE_MD_MAP(MD_NOTIFY_EXAUTH),
|
|
DEFINE_MD_MAP(MD_CC_NO_CACHE),
|
|
DEFINE_MD_MAP(MD_CC_MAX_AGE),
|
|
DEFINE_MD_MAP(MD_CC_OTHER),
|
|
DEFINE_MD_MAP(MD_REDIRECT_HEADERS),
|
|
DEFINE_MD_MAP(MD_UPLOAD_READAHEAD_SIZE),
|
|
DEFINE_MD_MAP(MD_PUT_READ_SIZE)
|
|
};
|
|
|
|
CHAR *
|
|
MapMetaDataID(
|
|
DWORD dwMDID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a DWORD metadata identifier to it's name as an ASCII string.
|
|
Arguments:
|
|
|
|
dwMDID - Identifier to be mapped.
|
|
|
|
Return value:
|
|
|
|
String describing identifier
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < (sizeof(MDIDMappingTable)/sizeof(struct MDIDMap)); i++)
|
|
{
|
|
if (MDIDMappingTable[i].MDID == dwMDID)
|
|
{
|
|
return MDIDMappingTable[i].IDName;
|
|
}
|
|
}
|
|
|
|
return "an unknown metabase property";
|
|
}
|
|
|
|
BOOL
|
|
HTTP_REQUEST::SendMetaDataError(
|
|
PMETADATA_ERROR_INFO pErrorInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look at the error information returned from a previous call to
|
|
ReadMetaData(), and format and send an appropriate error message.
|
|
|
|
Arguments:
|
|
|
|
pErrorInfo - Pointer to the returned error information.
|
|
|
|
Return value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
STACK_STR(strBody, 80);
|
|
STACK_STR(strResp, 80);
|
|
STACK_STR(strWin32Error, 80);
|
|
DWORD dwContentLength;
|
|
BOOL fDone;
|
|
BOOL bHaveCustomError = FALSE;
|
|
BOOL fRet;
|
|
CHAR *IDName;
|
|
CHAR szMDID[17];
|
|
CHAR szCL[17];
|
|
CHAR szWin32Error[17];
|
|
DWORD dwCurrentSize;
|
|
DWORD dwBytesNeeded;
|
|
DWORD dwCLLength;
|
|
CHAR *pszTail;
|
|
|
|
if (!pErrorInfo->IsValid)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// First check to see if we've got a custom error handler set up for this.
|
|
//
|
|
|
|
if (CheckCustomError(&strBody, HT_SERVER_ERROR, 0, &fDone, &dwContentLength))
|
|
{
|
|
// Had at least some custom error processing. If we're done, we can
|
|
// return, but set a flag telling our callers not to disconnect, since
|
|
// we're still processing.
|
|
|
|
if (fDone)
|
|
{
|
|
_fNoDisconnectOnError = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
bHaveCustomError = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Build the error string and header fields. If we didn't have a custom
|
|
// error, load an error body string from.
|
|
|
|
if (!bHaveCustomError)
|
|
{
|
|
fRet = BuildStatusLine( &strResp, HT_SERVER_ERROR,
|
|
IDS_METADATA_CONFIG_ERROR + pErrorInfo->ErrorReason,
|
|
QueryURL(),
|
|
&strBody);
|
|
|
|
dwContentLength = strBody.QueryCB();
|
|
}
|
|
else
|
|
{
|
|
fRet = BuildStatusLine( &strResp, HT_SERVER_ERROR, 0, QueryURL(), NULL );
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
// Trouble building the status line.
|
|
return FALSE;
|
|
}
|
|
|
|
// Now build the various header fields.
|
|
strResp.SetLen(strlen((CHAR *)strResp.QueryPtr()));
|
|
SetKeepConn(FALSE);
|
|
SetAuthenticationRequested(FALSE);
|
|
|
|
fDone = FALSE;
|
|
|
|
if ( !BuildBaseResponseHeader( QueryRespBuf(), &fDone, &strResp,
|
|
HTTPH_NO_CUSTOM)
|
|
)
|
|
{
|
|
// Couldn't build the headers, so return.
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If it failed because of a Win32 error, load a descriptive string.
|
|
//
|
|
|
|
if (pErrorInfo->ErrorReason == METADATA_ERROR_WIN32)
|
|
{
|
|
if ( !g_pInetSvc->LoadStr( strWin32Error, pErrorInfo->Win32Error ))
|
|
{
|
|
// Couldn't load the string, convert the error number and
|
|
// use that.
|
|
_itoa(pErrorInfo->Win32Error, szWin32Error, 10);
|
|
|
|
if (!strWin32Error.Copy(szWin32Error))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Adjust content length for extra %s.
|
|
dwContentLength -= sizeof("%s") - 1;
|
|
}
|
|
|
|
// OK, we've built everything. Map the metabase ID to a string, and
|
|
// format the message.
|
|
|
|
|
|
IDName = MapMetaDataID(pErrorInfo->ErrorParameter);
|
|
_itoa( pErrorInfo->ErrorParameter, szMDID, 10 );
|
|
|
|
// Adjust content length for size of strings we're adding in, and for
|
|
// the formatting characters.
|
|
|
|
dwContentLength += strlen(szMDID) + strlen(IDName) + strWin32Error.QueryCB();
|
|
|
|
dwContentLength -= (sizeof("%s") - 1) * 2;
|
|
|
|
_itoa( dwContentLength, szCL, 10 );
|
|
|
|
dwCLLength = strlen(szCL);
|
|
|
|
// Make sure we have enough room in the response buffer.
|
|
|
|
dwCurrentSize = strlen(QueryRespBufPtr());
|
|
|
|
dwBytesNeeded = dwCurrentSize + dwContentLength + dwCLLength +
|
|
sizeof("Content-Length: \r\n") - 1 +
|
|
sizeof("Content-Type: text/html\r\n") - 1;
|
|
|
|
if (!QueryRespBuf()->Resize(dwBytesNeeded))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Everything's set up, go ahead and copy it into the buffer.
|
|
|
|
pszTail = QueryRespBufPtr() + dwCurrentSize;
|
|
|
|
APPEND_STRING(pszTail, "Content-Length: ");
|
|
memcpy(pszTail, szCL, dwCLLength + 1);
|
|
pszTail += dwCLLength;
|
|
APPEND_STRING(pszTail, "\r\n");
|
|
|
|
if (!bHaveCustomError)
|
|
{
|
|
APPEND_STRING(pszTail, "Content-Type: text/html\r\n\r\n");
|
|
}
|
|
|
|
|
|
pszTail += wsprintf(pszTail, strBody.QueryStr(), IDName, szMDID,
|
|
strWin32Error.QueryStr());
|
|
|
|
// Now send the header.
|
|
if ( !SendHeader( QueryRespBufPtr(), (DWORD) (pszTail - QueryRespBufPtr()),
|
|
IO_FLAG_SYNC, &fDone ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
_fDiscNoError = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************ End of File ***********************/
|