/*++ Copyright (c) 2000 Microsoft Corporation Module Name: compression.h Abstract: Do Http compression Author: Anil Ruia (AnilR) 10-Apr-2000 --*/ #ifndef _COMPRESSION_H_ #define _COMPRESSION_H_ #define COMPRESSION_MIN_IO_BUFFER_SIZE 256 #define COMPRESSION_MAX_IO_BUFFER_SIZE 100000 #define COMPRESSION_MIN_COMP_BUFFER_SIZE 1024 #define COMPRESSION_MAX_COMP_BUFFER_SIZE 100000 #define COMPRESSION_MAX_QUEUE_LENGTH 10000 #define COMPRESSION_MIN_FILES_DELETED_PER_DISK_FREE 1 #define COMPRESSION_MAX_FILES_DELETED_PER_DISK_FREE 1024 #define COMPRESSION_MAX_COMPRESSION_LEVEL 10 #define COMPRESSION_DEFAULT_DISK_SPACE_USAGE 100000000 #define COMPRESSION_DEFAULT_BUFFER_SIZE 8192 #define COMPRESSION_DEFAULT_QUEUE_LENGTH 1000 #define COMPRESSION_DEFAULT_FILES_DELETED_PER_DISK_FREE 256 #define COMPRESSION_DEFAULT_FILE_SIZE_FOR_COMPRESSION 1 enum COMP_INIT_STATUS { COMP_INIT_NONE, COMP_INIT_SCHEMES, COMP_INIT_DIRLOCK, COMP_INIT_CONTEXT, COMP_INIT_DONE }; class COMPRESSION_SCHEME { public: COMPRESSION_SCHEME() : m_hCompressionDll (NULL), m_pCompressionContext (NULL), m_dwPriority (1), m_dwDynamicCompressionLevel (0), m_dwOnDemandCompressionLevel (COMPRESSION_MAX_COMPRESSION_LEVEL), m_dwCreateFlags (0), m_fDoStaticCompression (TRUE), m_fDoOnDemandCompression (TRUE), m_fDoDynamicCompression (TRUE), m_pfnInitCompression (NULL), m_pfnDeInitCompression (NULL), m_pfnCreateCompression (NULL), m_pfnCompress (NULL), m_pfnDestroyCompression (NULL), m_pfnResetCompression (NULL) {} HRESULT Initialize(MB *pmb, LPWSTR schemeName); ~COMPRESSION_SCHEME() { if (m_pfnDestroyCompression && m_pCompressionContext) { m_pfnDestroyCompression(m_pCompressionContext); m_pCompressionContext = NULL; } if (m_pfnDeInitCompression) { m_pfnDeInitCompression(); } if (m_hCompressionDll) { FreeLibrary(m_hCompressionDll); m_hCompressionDll = NULL; } } STRU m_strCompressionSchemeName; STRA m_straCompressionSchemeName; STRU m_strFilePrefix; MULTISZ m_mszFileExtensions; MULTISZ m_mszScriptFileExtensions; DWORD m_dwPriority; HMODULE m_hCompressionDll; PFNCODEC_INIT_COMPRESSION m_pfnInitCompression; PFNCODEC_DEINIT_COMPRESSION m_pfnDeInitCompression; PFNCODEC_CREATE_COMPRESSION m_pfnCreateCompression; PFNCODEC_COMPRESS m_pfnCompress; PFNCODEC_DESTROY_COMPRESSION m_pfnDestroyCompression; PFNCODEC_RESET_COMPRESSION m_pfnResetCompression; // The compression context used for static compression PVOID m_pCompressionContext; DWORD m_dwDynamicCompressionLevel; DWORD m_dwOnDemandCompressionLevel; DWORD m_dwCreateFlags; BOOL m_fDoDynamicCompression; BOOL m_fDoStaticCompression; BOOL m_fDoOnDemandCompression; }; typedef enum { COMPRESSION_WORK_ITEM_COMPRESS, COMPRESSION_WORK_ITEM_DELETE, COMPRESSION_WORK_ITEM_TERMINATE, COMPRESSION_WORK_ITEM_INVALID } COMPRESSION_WORK_ITEM_TYPE; class COMPRESSION_WORK_ITEM { public: COMPRESSION_WORK_ITEM() : WorkItemType (COMPRESSION_WORK_ITEM_INVALID), scheme (NULL), pFileInfo (NULL) { InitializeListHead(&ListEntry); } virtual ~COMPRESSION_WORK_ITEM() { InitializeListHead(&ListEntry); if (pFileInfo != NULL) { pFileInfo->DereferenceCacheEntry(); pFileInfo = NULL; } } LIST_ENTRY ListEntry; COMPRESSION_WORK_ITEM_TYPE WorkItemType; COMPRESSION_SCHEME *scheme; STRU strPhysicalPath; W3_FILE_INFO *pFileInfo; }; #define MAX_SERVER_SCHEMES 100 typedef enum { DO_STATIC_COMPRESSION, DO_DYNAMIC_COMPRESSION } COMPRESSION_TO_PERFORM; #define DYNAMIC_COMPRESSION_BUFFER_SIZE 2000 typedef enum { IN_CHUNK_LENGTH, IN_CHUNK_EXTENSION, IN_CHUNK_HEADER_NEW_LINE, AT_CHUNK_DATA_NEW_LINE, IN_CHUNK_DATA_NEW_LINE, IN_CHUNK_DATA } COMPRESS_CHUNK_STATE; class COMPRESSION_CONTEXT { public: static HRESULT Initialize() { ALLOC_CACHE_CONFIGURATION acConfig; acConfig.nConcurrency = 1; acConfig.nThreshold = 100; acConfig.cbSize = sizeof COMPRESSION_CONTEXT; allocHandler = new ALLOC_CACHE_HANDLER("COMPRESSION_CONTEXT", &acConfig); if (allocHandler == NULL) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } return S_OK; } static void Terminate() { if (allocHandler != NULL) { delete allocHandler; } } void *operator new( #if DBG size_t size #else size_t #endif ) { DBG_ASSERT(size == sizeof COMPRESSION_CONTEXT); DBG_ASSERT(allocHandler != NULL); return allocHandler->Alloc(); } void operator delete(void *pCompressionContext) { DBG_ASSERT(pCompressionContext != NULL); DBG_ASSERT(allocHandler != NULL); DBG_REQUIRE(allocHandler->Free(pCompressionContext)); } COMPRESSION_CONTEXT() : m_pScheme (NULL), m_fTransferChunkEncoded (FALSE), m_pCompressionContext (NULL), m_dwBytesInCurrentEncodedChunk (0), m_encodedChunkState (IN_CHUNK_LENGTH), m_fHeadersSent (FALSE), m_fRequestIsHead (FALSE), m_fOriginalBodyEmpty (TRUE) {} ~COMPRESSION_CONTEXT() { if (m_pCompressionContext) { m_pScheme->m_pfnDestroyCompression(m_pCompressionContext); m_pCompressionContext = NULL; } } HRESULT ProcessEncodedChunkHeader(); HRESULT CalculateEncodedChunkByteCount(); VOID DeleteEncodedChunkExtension(); VOID IncrementPointerInULChunk(IN DWORD dwIncr = 1) { m_pbOrigData += dwIncr; m_cbOrigData -= dwIncr; } COMPRESSION_SCHEME *m_pScheme; // // Is the original response chunk encoded? // BOOL m_fTransferChunkEncoded; // // If the original response is Chunk encoded, information about the // current chunk in the response // DWORD m_dwBytesInCurrentEncodedChunk; COMPRESS_CHUNK_STATE m_encodedChunkState; // // The context used by the compression routines // PVOID m_pCompressionContext; // // position in the original response // PBYTE m_pbOrigData; DWORD m_cbOrigData; static ALLOC_CACHE_HANDLER *allocHandler; // // Some members to keep track of HEAD request body suppression // BOOL m_fRequestIsHead; BOOL m_fOriginalBodyEmpty; // // Has the end of response headers been seen? // BOOL m_fHeadersSent; // // A chunk's worth of data // BUFFER m_bufChunk; }; class HTTP_COMPRESSION { public: static HRESULT Initialize(); static VOID Terminate(); static HRESULT DoStaticFileCompression(IN W3_CONTEXT *pW3Context, IN OUT W3_FILE_INFO **ppFileInfo, OUT BOOL *pfDoCache); static HRESULT OnSendResponse( IN W3_CONTEXT *pW3Context); static HRESULT DoDynamicCompression( IN W3_CONTEXT *pW3Context, IN BOOL fMoreData, IN HTTP_FILTER_RAW_DATA * pRawData ); static BOOL QueryDoStaticCompression() { return sm_fDoStaticCompression; } static BOOL QueryDoDynamicCompression() { return sm_fDoDynamicCompression; } private: static COMPRESSION_SCHEME *sm_pCompressionSchemes[MAX_SERVER_SCHEMES]; static DWORD sm_dwNumberOfSchemes; static STRU *sm_pstrCompressionDirectory; static STRA *sm_pstrCacheControlHeader; static STRA *sm_pstrExpiresHeader; static BOOL sm_fDoStaticCompression; static BOOL sm_fDoDynamicCompression; static BOOL sm_fDoOnDemandCompression; static BOOL sm_fDoDiskSpaceLimiting; static BOOL sm_fNoCompressionForHttp10; static BOOL sm_fNoCompressionForProxies; static BOOL sm_fNoCompressionForRange; static BOOL sm_fSendCacheHeaders; static DWORD sm_dwMaxDiskSpaceUsage; static DWORD sm_dwIoBufferSize; static DWORD sm_dwCompressionBufferSize; static DWORD sm_dwMaxQueueLength; static DWORD sm_dwFilesDeletedPerDiskFree; static DWORD sm_dwMinFileSizeForCompression; static PBYTE sm_pIoBuffer; static PBYTE sm_pCompressionBuffer; static CRITICAL_SECTION sm_CompressionDirectoryLock; static DWORD sm_dwCurrentDiskSpaceUsage; static BOOL sm_fCompressionVolumeIsFat; static LIST_ENTRY sm_CompressionThreadWorkQueue; static CRITICAL_SECTION sm_CompressionThreadLock; static HANDLE sm_hThreadEvent; static HANDLE sm_hCompressionThreadHandle; static DWORD sm_dwCurrentQueueLength; static COMP_INIT_STATUS sm_InitStatus; static BOOL sm_fIsTerminating; static HRESULT ReadMetadata(MB *pmb); static HRESULT InitializeCompressionSchemes(MB *pmb); static HRESULT InitializeCompressionDirectory(); static HRESULT InitializeCompressionThread(); static DWORD WINAPI CompressionThread(LPVOID); static BOOL QueueWorkItem( IN COMPRESSION_WORK_ITEM *WorkItem, IN BOOL fOverrideMaxQueueLength, IN BOOL fQueueAtHead); static VOID FindMatchingSchemes( IN CHAR * pszAcceptEncoding, IN LPWSTR pszExtension, IN COMPRESSION_TO_PERFORM performCompr, OUT DWORD matchingSchemes[], OUT DWORD *pdwClientCompressionCount); static HRESULT ConvertPhysicalPathToCompressedPath( IN COMPRESSION_SCHEME *scheme, IN STRU *pstrPhysicalPath, OUT STRU *pstrCompressedFileName); static BOOL CheckForExistenceOfCompressedFile( IN W3_FILE_INFO *pOrigFile, IN STRU *pstrCompressedFileName, OUT W3_FILE_INFO **ppCompFile, IN BOOL fDeleteAllowed = TRUE); static BOOL QueueCompressFile( IN COMPRESSION_SCHEME *scheme, IN W3_FILE_INFO *pFileInfo); static VOID CompressFile(IN COMPRESSION_SCHEME *scheme, IN W3_FILE_INFO *pFileInfo); static VOID FreeDiskSpace(); static BOOL CompressAndWriteData( IN COMPRESSION_SCHEME *scheme, IN PBYTE InputBuffer, IN DWORD BytesToCompress, OUT PDWORD BytesWritten, IN HANDLE hCompressedFile); }; #endif _COMPRESSION_H_