Leaked source code of windows server 2003
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.
 
 
 
 
 
 

411 lines
9.6 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
ssi_vector_send.cxx
Abstract:
wrapper for VectorSend related buffer manipulation
Segments of final response of stm file processing
are buffered in the SSI_VECTOR_BUFFER to optimize the
"send response" path
Author:
Jaroslad Apr-2001
--*/
#include "precomp.hxx"
HRESULT
SSI_VECTOR_BUFFER::AddVectorHeaders(
IN CHAR * pszHeaders,
IN BOOL fIncludesContentLength,
IN CHAR * pszStatus
)
/*++
Routine Description:
add headers and status line to be sent in response
Note: caller is responsible to ensure that
pszHeaders and pszStatus will not be freed
If lifetime cannot be guaranteed or use AllocateSpace() to allocate memory
Arguments:
pszHeaders - pointer to headers (including \r\n)
fIncludesContentLength - flag that headers include "Content-Length" header
pszStatus - if "" then it will be filled in automatically to "200 OK"
Return Value:
HRESULT
--*/
{
//
// function is expected to be called not more than once per request
//
if ( !_fHeadersSent )
{
_RespVector.dwFlags |= HSE_IO_SEND_HEADERS;
DBG_ASSERT( _RespVector.pszHeaders == NULL );
_RespVector.pszHeaders = pszHeaders;
_fVectorHeadersIncludeContentLength = fIncludesContentLength;
//
// pszStatus is required not to be NULL with HSE_IO_SEND_HEADERS
// so set it to empty string
//
_RespVector.pszStatus = pszStatus;
}
else
{
DBG_ASSERT( FALSE );
return( E_FAIL );
}
return S_OK;
}
HRESULT
SSI_VECTOR_BUFFER::AddToVector(
IN PCHAR pbData,
IN DWORD cbData
)
/*++
Routine Description:
add another chunk to response Vector
Note: caller is responsible to ensure that
buffer will not be freed until VectorSend completed
If lifetime cannot be guaranteed use CopyToVector()
instead (or use AllocateSpace() to allocate memory
for pbData )
Arguments:
pbData - pointer to chunk
cbData - size of chunk
Return Value:
HRESULT
--*/
{
DWORD nElementCount = _RespVector.nElementCount;
if( cbData != 0 )
{
if (!_buffVectorElementArray.Resize( (nElementCount + 1)*sizeof(HSE_VECTOR_ELEMENT) , 256 ))
{
return HRESULT_FROM_WIN32(GetLastError());
}
_RespVector.lpElementArray = (HSE_VECTOR_ELEMENT *)_buffVectorElementArray.QueryPtr();
_RespVector.lpElementArray[ nElementCount ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
_RespVector.lpElementArray[ nElementCount ].pvContext = pbData;
_RespVector.lpElementArray[ nElementCount ].cbSize = cbData;
_cbTotalBytesInVector += cbData;
_RespVector.nElementCount++;
}
return S_OK;
}
HRESULT
SSI_VECTOR_BUFFER::AddFileChunkToVector(
IN DWORD cbOffset,
IN DWORD cbData,
IN HANDLE hFile
)
/*++
Routine Description:
add another chunk to response Vector
Note: caller is responsible to ensure that
buffer will nt be freed until VectorSend completed
If lifetime cannot be guaranteed use CopyToVector()
instead (or use AllocateSpace() to allocate memory
for pbData )
Arguments:
pbOffset - offset within the file
cbData - size of chunk
hFile - file where file chunk is located
Return Value:
HRESULT
--*/
{
DWORD nElementCount = _RespVector.nElementCount;
if( cbData != 0 )
{
if (!_buffVectorElementArray.Resize( (nElementCount + 1)*sizeof(HSE_VECTOR_ELEMENT) , 256 ))
{
return HRESULT_FROM_WIN32(GetLastError());
}
_RespVector.lpElementArray = (HSE_VECTOR_ELEMENT *)_buffVectorElementArray.QueryPtr();
_RespVector.lpElementArray[ nElementCount ].ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
_RespVector.lpElementArray[ nElementCount ].pvContext = hFile;
_RespVector.lpElementArray[ nElementCount ].cbOffset = cbOffset;
_RespVector.lpElementArray[ nElementCount ].cbSize = cbData;
_cbTotalBytesInVector += cbData;
_RespVector.nElementCount++;
}
return S_OK;
}
HRESULT
SSI_VECTOR_BUFFER::CopyToVector(
IN PCHAR pszData,
IN DWORD cchData
)
/*++
Routine Description:
Copy data to private buffer and then add it
to response Vector
Arguments:
pbData - pointer to chunk
cbData - size of chunk
Return Value:
HRESULT
--*/
{
PCHAR pszVectorBufferSpace = NULL;
HRESULT hr = E_FAIL;
//
// Allocate space in private buffer
//
if ( FAILED( hr = AllocateSpace(
cchData,
&pszVectorBufferSpace
) ) )
{
return hr;
}
else
{
memcpy( pszVectorBufferSpace,
pszData,
cchData );
hr = AddToVector( pszVectorBufferSpace,
cchData );
}
return hr;
}
HRESULT
SSI_VECTOR_BUFFER::CopyToVector(
IN STRA& straSource
)
/*++
Routine Description:
Copy data to private buffer and then add it
to response Vector
Arguments:
straSource -string to be copied
Return Value:
HRESULT
--*/
{
return CopyToVector( straSource.QueryStr(),
straSource.QueryCB() );
}
HRESULT
SSI_VECTOR_BUFFER::CopyToVector(
IN STRU& struSource
)
/*++
Routine Description:
Copy data to private buffer and then add it
to response Vector
Arguments:
struSource - string to be copied
Return Value:
HRESULT
--*/
{
HRESULT hr = E_FAIL;
STRA straSource;
if ( FAILED( hr = straSource.CopyW( struSource.QueryStr() ) ) )
{
return hr;
}
else
{
return CopyToVector( straSource );
}
}
HRESULT
SSI_VECTOR_BUFFER::VectorSend(
OUT BOOL * pfAsyncPending,
IN BOOL fFinalSend
)
/*++
Routine Description:
HSE_REQ_VECTOR_SEND wrapper.
Arguments:
pfAsyncPending - Set to TRUE if async is pending
fFinalSend - TRUE if this is the last send for the response
it can help to determine if Keep-alive can be used
Return Value:
HRESULT
--*/
{
HRESULT hr = E_FAIL;
DBG_ASSERT( pfAsyncPending != NULL );
*pfAsyncPending = FALSE;
//
// check if there is any data to be sent
//
if ( ( _RespVector.pszHeaders == NULL &&
_RespVector.nElementCount == 0 ) ||
( _fHeadersSent &&
_fHeadRequest ) )
{
//
// there is nothing to be sent
// Also handle HEAD requests. Never send body with them
// handling HEAD request by processing whole SSI and only not
// sending data is not ideal, but this way it is guaranteed
// that HEAD and GET will get same headers
//
*pfAsyncPending = FALSE;
return S_OK;
}
if ( _fVectorHeadersIncludeContentLength )
{
//
// remove the disconnect flag since we have content length
//
_RespVector.dwFlags &= ( ~HSE_IO_DISCONNECT_AFTER_SEND );
}
else if ( !_fHeadersSent
&& fFinalSend )
{
//
// Optimization:
// This is final send and headers were not yet sent
// That means we can do keep-alive and specify Content-length
//
STACK_STRA( straFinalHeaders, SSI_DEFAULT_RESPONSE_HEADERS_SIZE + 1 );
CHAR achNum[ SSI_MAX_NUMBER_STRING + 1 ];
_ultoa( _cbTotalBytesInVector,
achNum,
10 );
if ( FAILED( hr = _straFinalHeaders.Copy( "Content-Length: " ) ) )
{
return hr;
}
if ( FAILED( hr = _straFinalHeaders.Append( achNum ) ) )
{
return hr;
}
if ( FAILED( hr = _straFinalHeaders.Append( "\r\n" ) ) )
{
return hr;
}
if ( FAILED( hr = _straFinalHeaders.Append( _RespVector.pszHeaders ) ) )
{
return hr;
}
_RespVector.pszHeaders = _straFinalHeaders.QueryStr();
// remove the disconnect flag
_RespVector.dwFlags &= ( ~HSE_IO_DISCONNECT_AFTER_SEND );
}
//
// Send Response Vector
//
if( _RespVector.dwFlags & HSE_IO_SEND_HEADERS )
{
_fHeadersSent = TRUE;
}
if ( _fHeadRequest )
{
// Handle HEAD requests. Never send body with them
// Handling HEAD request by processing the whole SSI and only not
// sending data is not ideal, but this way it is guaranteed
// that HEAD and GET will get the same headers
//
_RespVector.nElementCount = 0;
}
if (! _pECB->ServerSupportFunction(
_pECB->ConnID,
HSE_REQ_VECTOR_SEND,
&_RespVector,
NULL,
NULL) )
{
//
// No use in trying to reset _fHeadersSent in case of failure
//
return HRESULT_FROM_WIN32( GetLastError() );
}
*pfAsyncPending = TRUE;
return S_OK;
}