home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / iis4_07.cab / cte_enc.c < prev    next >
C/C++ Source or Header  |  1997-10-25  |  7KB  |  336 lines

  1. /*++
  2.  
  3. Copyright (c) 1997 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     cte_enc.c
  8.  
  9. Abstract:
  10.  
  11.     This module contains routines implementing Chunked Transfer 
  12.     Encoding (CTE) for ISAPI Extension DLLs. See Section 3.6 
  13.     "Transfer Codings" of RFC 2068 for details.
  14.  
  15. Functions:
  16.     CteBeginWrite
  17.     CteWrite
  18.     CteEndWrite
  19.  
  20. --*/
  21.  
  22.  
  23. #include "ctetest.h"
  24.  
  25.  
  26. //
  27. // Encoder context structure 
  28. //
  29.  
  30. typedef struct CTE_ENCODER_STRUCT {
  31.     EXTENSION_CONTROL_BLOCK * pECB;         // a copy of current ECB pointer
  32.     DWORD                     dwChunkSize;  // user-specified chunk size
  33.     DWORD                     cbData;       // number of bytes in the buffer
  34.     BYTE *                    pData;        // pointer to chunk data bytes
  35. } CTE_ENCODER;
  36.  
  37. //
  38. // Chunk header consists of HEX string for the chunk size in bytes
  39. // (DWORD needs up to 8 bytes in HEX), followed by CRLF,
  40. // therefore the maximum chunk header size is 10 bytes.
  41. //
  42.  
  43. #define CTE_MAX_CHUNK_HEADER_SIZE 10
  44.  
  45. //
  46. // Chunk data is always followed by CRLF
  47. //
  48.  
  49. #define CTE_MAX_ENCODING_OVERHEAD (CTE_MAX_CHUNK_HEADER_SIZE + 2)
  50.  
  51. //
  52. // Total encoder size includes:
  53. //   the size of the encoder context structure itself,
  54. //   the chunk data size,
  55. //   the maximum encoding overhead (header and terminating CRLF)
  56. //
  57.  
  58. #define CTE_ENCODER_SIZE(dwChunkSize) \
  59.     (sizeof(CTE_ENCODER) + dwChunkSize + CTE_MAX_ENCODING_OVERHEAD)
  60.  
  61.  
  62.  
  63. HCTE_ENCODER
  64. CteBeginWrite(
  65.     IN EXTENSION_CONTROL_BLOCK * pECB,
  66.     IN DWORD dwChunkSize
  67.     )   
  68. /*++
  69.  
  70. Purpose:
  71.  
  72.     Allocate and initialize chunked transfer encoder context
  73.     
  74. Arguments:    
  75.  
  76.     pECB - pointer to extension control as passed to HttpExtensionProc()
  77.     dwChunkSize - the maximum size of the chunk to transmit
  78.  
  79. Returns:
  80.     encoder context handle, or 
  81.     NULL if memory allocation failed or chunk size was zero
  82.     
  83. --*/
  84. {
  85.     HCTE_ENCODER h;
  86.  
  87.  
  88.     //
  89.     // reject zero-length chunk size
  90.     //
  91.  
  92.     if( dwChunkSize == 0 ) {
  93.         SetLastError( ERROR_INVALID_PARAMETER );
  94.         return NULL;
  95.     }
  96.  
  97.     //
  98.     // allocate context structure
  99.     // 
  100.     
  101.     h = LocalAlloc( LMEM_FIXED, CTE_ENCODER_SIZE(dwChunkSize) );
  102.  
  103.     if( h != NULL ) {
  104.  
  105.         //
  106.         // initialize context structure
  107.         //
  108.  
  109.         h->pECB         = pECB;
  110.         h->dwChunkSize  = dwChunkSize;
  111.         h->cbData       = 0;
  112.  
  113.         //
  114.         // chunk data bytes follow the context structure itself 
  115.         // and chunk header 
  116.         //
  117.  
  118.         h->pData = (BYTE *) h + sizeof( *h ) + CTE_MAX_CHUNK_HEADER_SIZE;
  119.  
  120.         //
  121.         // this is the CRLF which follows chunk size 
  122.         // (and immediately precedes data)
  123.         //
  124.  
  125.         h->pData[-2] = '\r';
  126.         h->pData[-1] = '\n';
  127.  
  128.     } else {
  129.  
  130.         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  131.     }
  132.  
  133.     return h;
  134. }
  135.  
  136.  
  137. static BOOL
  138. CteSendChunk(
  139.     IN HCTE_ENCODER h
  140. )
  141. /*++
  142.  
  143. Purpose: 
  144.  
  145.     Send one chunk of data using ClientWrite() 
  146.     <hex encoded chunk size>, CRLF, data bytes, if any, CRLF
  147.  
  148. Arguments:
  149.  
  150.     h - CTE Encoder handle    
  151.       
  152. Returns:
  153.  
  154.     TRUE if WriteClient succeeded
  155.     FALSE if WriteClient failed
  156.     
  157. --*/
  158. {
  159.     char szChunkLength[9];
  160.     DWORD cbChunkLength;
  161.     BYTE *buf;
  162.     DWORD cbToSend;
  163.     BOOL success;
  164.  
  165.     //
  166.     // produce hex string of the number of bytes
  167.     // and compute the length of this string
  168.     //
  169.     _itoa( h->cbData, szChunkLength, 16 ); 
  170.     cbChunkLength = strlen( szChunkLength );
  171.  
  172.     //
  173.     // step back to make place for hex number and CRLF,
  174.     // copy hex string to its location
  175.     //
  176.  
  177.     buf = h->pData - 2 - cbChunkLength;
  178.     memmove( buf, szChunkLength, cbChunkLength );
  179.  
  180.     //
  181.     // compute the number of bytes to send
  182.     // (this includes chunk data size, hex string and CRLF)
  183.     // 
  184.  
  185.     cbToSend = h->cbData + cbChunkLength + 2;
  186.  
  187.     //
  188.     // append trailing CRLF right after the data bytes
  189.     //
  190.     
  191.     buf[cbToSend++] = '\r';
  192.     buf[cbToSend++] = '\n';
  193.  
  194.     //
  195.     // issue synchronous WriteClient and return result to the caller 
  196.     //
  197.     
  198.     success = h->pECB->WriteClient(
  199.                     h->pECB->ConnID, 
  200.                     buf, 
  201.                     &cbToSend, 
  202.                     HSE_IO_SYNC 
  203.                     );
  204.  
  205.     //
  206.     // reset buffer pointer
  207.     //
  208.     
  209.     h->cbData = 0;
  210.  
  211.     return success;
  212. }
  213.  
  214.  
  215. BOOL
  216. CteWrite(
  217.     IN HCTE_ENCODER h,
  218.     IN PVOID pData,
  219.     IN DWORD cbData
  220. )
  221. /*++
  222.  
  223. Purpose:
  224.  
  225.     Write specified number of data bytes to the chunk buffer.
  226.     When the chunk buffer becomes full, call CteSendChunk() 
  227.     to send it out.
  228.  
  229. Arguments:
  230.  
  231.     h - CTE Encoder handle 
  232.     pData - pointer to data bytes 
  233.     cbData - number of data bytes to send
  234.     
  235. Returns:    
  236.  
  237.     TRUE if bytes were successfully written
  238.     FALSE if WriteClient() failed
  239.     
  240. --*/
  241. {
  242.     DWORD cbToConsume;
  243.     PBYTE pBytesToSend = (PBYTE) pData;
  244.  
  245.     for( ;; ) {
  246.  
  247.         //
  248.         // compute the number of bytes to consume,
  249.         // break out of the loop, if nothing is left
  250.         //
  251.  
  252.         cbToConsume = min( cbData, h->dwChunkSize - h->cbData );
  253.  
  254.         if( cbToConsume == 0 ) {
  255.             break;
  256.         }
  257.  
  258.         //
  259.         // move bytes to the buffer, advance pointers and counters
  260.         //
  261.         
  262.         memmove( h->pData + h->cbData, pBytesToSend, cbToConsume );
  263.  
  264.         h->cbData += cbToConsume;
  265.         pBytesToSend += cbToConsume;
  266.         cbData -= cbToConsume;
  267.  
  268.         //
  269.         // if the chunk buffer is full, send it
  270.         //
  271.         
  272.         if( h->cbData == h->dwChunkSize ) {
  273.             if( !CteSendChunk( h ) ) {
  274.                 return FALSE;
  275.             }
  276.         }
  277.  
  278.     }
  279.  
  280.     return TRUE;
  281. }
  282.  
  283.  
  284. BOOL 
  285. CteEndWrite(
  286.     IN HCTE_ENCODER h
  287. )
  288. /*++
  289.  
  290. Purpose:
  291.  
  292.     Complete the transfer and release the encoder context
  293.  
  294. Arguments:
  295.  
  296.     h - CTE Encoder handle
  297.     
  298. Returns:
  299.  
  300.     TRUE if transfer was successfully completed
  301.     FALSE if WriteClient() failed
  302.     
  303. --*/ 
  304. {
  305.     BOOL success;
  306.  
  307.     //
  308.     // if there are some bytes in the chunk, send them
  309.     //
  310.     
  311.     if( h->cbData ) {
  312.         if( !CteSendChunk( h ) ) {
  313.             return FALSE;
  314.         }
  315.     }
  316.     
  317.     //
  318.     // send empty chunk (which means EOF)
  319.     //
  320.     
  321.     success = CteSendChunk( h );
  322.     
  323.     //
  324.     // release chunk transfer context
  325.     //
  326.  
  327.     LocalFree( h );
  328.     
  329.     return success;
  330. }
  331.  
  332.  
  333.  
  334.  
  335.  
  336.