home *** CD-ROM | disk | FTP | other *** search
- /*++
-
- Copyright (c) 1997 Microsoft Corporation
-
- Module Name:
-
- cte_enc.c
-
- Abstract:
-
- This module contains routines implementing Chunked Transfer
- Encoding (CTE) for ISAPI Extension DLLs. See Section 3.6
- "Transfer Codings" of RFC 2068 for details.
-
- Functions:
- CteBeginWrite
- CteWrite
- CteEndWrite
-
- --*/
-
-
- #include "ctetest.h"
-
-
- //
- // Encoder context structure
- //
-
- typedef struct CTE_ENCODER_STRUCT {
- EXTENSION_CONTROL_BLOCK * pECB; // a copy of current ECB pointer
- DWORD dwChunkSize; // user-specified chunk size
- DWORD cbData; // number of bytes in the buffer
- BYTE * pData; // pointer to chunk data bytes
- } CTE_ENCODER;
-
- //
- // Chunk header consists of HEX string for the chunk size in bytes
- // (DWORD needs up to 8 bytes in HEX), followed by CRLF,
- // therefore the maximum chunk header size is 10 bytes.
- //
-
- #define CTE_MAX_CHUNK_HEADER_SIZE 10
-
- //
- // Chunk data is always followed by CRLF
- //
-
- #define CTE_MAX_ENCODING_OVERHEAD (CTE_MAX_CHUNK_HEADER_SIZE + 2)
-
- //
- // Total encoder size includes:
- // the size of the encoder context structure itself,
- // the chunk data size,
- // the maximum encoding overhead (header and terminating CRLF)
- //
-
- #define CTE_ENCODER_SIZE(dwChunkSize) \
- (sizeof(CTE_ENCODER) + dwChunkSize + CTE_MAX_ENCODING_OVERHEAD)
-
-
-
- HCTE_ENCODER
- CteBeginWrite(
- IN EXTENSION_CONTROL_BLOCK * pECB,
- IN DWORD dwChunkSize
- )
- /*++
-
- Purpose:
-
- Allocate and initialize chunked transfer encoder context
-
- Arguments:
-
- pECB - pointer to extension control as passed to HttpExtensionProc()
- dwChunkSize - the maximum size of the chunk to transmit
-
- Returns:
- encoder context handle, or
- NULL if memory allocation failed or chunk size was zero
-
- --*/
- {
- HCTE_ENCODER h;
-
-
- //
- // reject zero-length chunk size
- //
-
- if( dwChunkSize == 0 ) {
- SetLastError( ERROR_INVALID_PARAMETER );
- return NULL;
- }
-
- //
- // allocate context structure
- //
-
- h = LocalAlloc( LMEM_FIXED, CTE_ENCODER_SIZE(dwChunkSize) );
-
- if( h != NULL ) {
-
- //
- // initialize context structure
- //
-
- h->pECB = pECB;
- h->dwChunkSize = dwChunkSize;
- h->cbData = 0;
-
- //
- // chunk data bytes follow the context structure itself
- // and chunk header
- //
-
- h->pData = (BYTE *) h + sizeof( *h ) + CTE_MAX_CHUNK_HEADER_SIZE;
-
- //
- // this is the CRLF which follows chunk size
- // (and immediately precedes data)
- //
-
- h->pData[-2] = '\r';
- h->pData[-1] = '\n';
-
- } else {
-
- SetLastError( ERROR_NOT_ENOUGH_MEMORY );
- }
-
- return h;
- }
-
-
- static BOOL
- CteSendChunk(
- IN HCTE_ENCODER h
- )
- /*++
-
- Purpose:
-
- Send one chunk of data using ClientWrite()
- <hex encoded chunk size>, CRLF, data bytes, if any, CRLF
-
- Arguments:
-
- h - CTE Encoder handle
-
- Returns:
-
- TRUE if WriteClient succeeded
- FALSE if WriteClient failed
-
- --*/
- {
- char szChunkLength[9];
- DWORD cbChunkLength;
- BYTE *buf;
- DWORD cbToSend;
- BOOL success;
-
- //
- // produce hex string of the number of bytes
- // and compute the length of this string
- //
- _itoa( h->cbData, szChunkLength, 16 );
- cbChunkLength = strlen( szChunkLength );
-
- //
- // step back to make place for hex number and CRLF,
- // copy hex string to its location
- //
-
- buf = h->pData - 2 - cbChunkLength;
- memmove( buf, szChunkLength, cbChunkLength );
-
- //
- // compute the number of bytes to send
- // (this includes chunk data size, hex string and CRLF)
- //
-
- cbToSend = h->cbData + cbChunkLength + 2;
-
- //
- // append trailing CRLF right after the data bytes
- //
-
- buf[cbToSend++] = '\r';
- buf[cbToSend++] = '\n';
-
- //
- // issue synchronous WriteClient and return result to the caller
- //
-
- success = h->pECB->WriteClient(
- h->pECB->ConnID,
- buf,
- &cbToSend,
- HSE_IO_SYNC
- );
-
- //
- // reset buffer pointer
- //
-
- h->cbData = 0;
-
- return success;
- }
-
-
- BOOL
- CteWrite(
- IN HCTE_ENCODER h,
- IN PVOID pData,
- IN DWORD cbData
- )
- /*++
-
- Purpose:
-
- Write specified number of data bytes to the chunk buffer.
- When the chunk buffer becomes full, call CteSendChunk()
- to send it out.
-
- Arguments:
-
- h - CTE Encoder handle
- pData - pointer to data bytes
- cbData - number of data bytes to send
-
- Returns:
-
- TRUE if bytes were successfully written
- FALSE if WriteClient() failed
-
- --*/
- {
- DWORD cbToConsume;
- PBYTE pBytesToSend = (PBYTE) pData;
-
- for( ;; ) {
-
- //
- // compute the number of bytes to consume,
- // break out of the loop, if nothing is left
- //
-
- cbToConsume = min( cbData, h->dwChunkSize - h->cbData );
-
- if( cbToConsume == 0 ) {
- break;
- }
-
- //
- // move bytes to the buffer, advance pointers and counters
- //
-
- memmove( h->pData + h->cbData, pBytesToSend, cbToConsume );
-
- h->cbData += cbToConsume;
- pBytesToSend += cbToConsume;
- cbData -= cbToConsume;
-
- //
- // if the chunk buffer is full, send it
- //
-
- if( h->cbData == h->dwChunkSize ) {
- if( !CteSendChunk( h ) ) {
- return FALSE;
- }
- }
-
- }
-
- return TRUE;
- }
-
-
- BOOL
- CteEndWrite(
- IN HCTE_ENCODER h
- )
- /*++
-
- Purpose:
-
- Complete the transfer and release the encoder context
-
- Arguments:
-
- h - CTE Encoder handle
-
- Returns:
-
- TRUE if transfer was successfully completed
- FALSE if WriteClient() failed
-
- --*/
- {
- BOOL success;
-
- //
- // if there are some bytes in the chunk, send them
- //
-
- if( h->cbData ) {
- if( !CteSendChunk( h ) ) {
- return FALSE;
- }
- }
-
- //
- // send empty chunk (which means EOF)
- //
-
- success = CteSendChunk( h );
-
- //
- // release chunk transfer context
- //
-
- LocalFree( h );
-
- return success;
- }
-
-
-
-
-
-