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
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;
|
|
}
|
|
|