|
|
/*++
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
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_TYPE;
typedef struct { LIST_ENTRY ListEntry; COMPRESSION_WORK_ITEM_TYPE WorkItemType; COMPRESSION_SCHEME *scheme; STRU strPhysicalPath; } COMPRESSION_WORK_ITEM;
#define MAX_SERVER_SCHEMES 100
typedef enum { DO_STATIC_COMPRESSION, DO_DYNAMIC_COMPRESSION } COMPRESSION_TO_PERFORM;
#define DYNAMIC_COMPRESSION_BUFFER_SIZE 4096
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_BUFFER { public: static HRESULT Initialize() { ALLOC_CACHE_CONFIGURATION acConfig; acConfig.nConcurrency = 1; acConfig.nThreshold = 100; acConfig.cbSize = sizeof COMPRESSION_BUFFER;
allocHandler = new ALLOC_CACHE_HANDLER("COMPRESSION_BUFFER", &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(size_t size) { DBG_ASSERT(size == sizeof COMPRESSION_BUFFER); DBG_ASSERT(allocHandler != NULL); return allocHandler->Alloc(); }
void operator delete(void *pCompressionBuffer) { DBG_ASSERT(pCompressionBuffer != NULL); DBG_ASSERT(allocHandler != NULL); DBG_REQUIRE(allocHandler->Free(pCompressionBuffer)); }
BYTE buffer[6 + DYNAMIC_COMPRESSION_BUFFER_SIZE + 7]; LIST_ENTRY listEntry;
static ALLOC_CACHE_HANDLER *allocHandler; };
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(size_t size) { 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_pIoBuffer (NULL), m_fRequestIsHead (FALSE), m_fOriginalBodyEmpty (TRUE) { InitializeListHead(&m_BufferListHead); }
~COMPRESSION_CONTEXT() { FreeBuffers();
if (m_pIoBuffer != NULL) { delete m_pIoBuffer; }
if (m_pCompressionContext) { m_pScheme->m_pfnDestroyCompression(m_pCompressionContext); m_pCompressionContext = NULL; } }
void FreeBuffers() { while (!IsListEmpty(&m_BufferListHead)) { LIST_ENTRY *pEntry = RemoveHeadList(&m_BufferListHead); COMPRESSION_BUFFER *pBuffer = CONTAINING_RECORD(pEntry, COMPRESSION_BUFFER, listEntry); delete pBuffer; } }
BYTE *GetNewBuffer() { COMPRESSION_BUFFER *pBuffer = new COMPRESSION_BUFFER; if (pBuffer == NULL) { return NULL; }
InitializeListHead(&pBuffer->listEntry); InsertHeadList(&m_BufferListHead, &pBuffer->listEntry);
return pBuffer->buffer; }
HRESULT SetupCurrentULChunk();
DWORD QueryBytesAvailable() { if (m_fCurrentULChunkFromMemory) { return m_pCurrentULChunk->FromMemory.BufferLength; }
// We don't handle (nor do we plan to) FileName chunks
DBG_ASSERT(m_pCurrentULChunk->DataChunkType == HttpDataChunkFromFileHandle); return m_bytesInIoBuffer - m_currentLocationInIoBuffer; }
BYTE *QueryBytePtr() { if (m_fCurrentULChunkFromMemory) { return (PBYTE)m_pCurrentULChunk->FromMemory.pBuffer; }
// We don't handle (nor do we plan to) FileName chunks
DBG_ASSERT(m_pCurrentULChunk->DataChunkType == HttpDataChunkFromFileHandle); return m_pIoBuffer + m_currentLocationInIoBuffer; }
HRESULT ProcessEncodedChunkHeader();
HRESULT CalculateEncodedChunkByteCount();
HRESULT DeleteEncodedChunkExtension();
HRESULT IncrementPointerInULChunk(IN DWORD dwIncr = 1);
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;
//
// Storage for the original response
//
BUFFER m_ULChunkBuffer; DWORD m_cULChunks;
//
// position in the original response
//
DWORD m_cCurrentULChunk; HTTP_DATA_CHUNK *m_pCurrentULChunk; BOOL m_fCurrentULChunkFromMemory;
//
// buffer for reading data for FileHandle chunks
//
BYTE *m_pIoBuffer; DWORD m_currentLocationInIoBuffer; DWORD m_bytesInIoBuffer;
static ALLOC_CACHE_HANDLER *allocHandler;
LIST_ENTRY m_BufferListHead;
//
// Some members to keep track of HEAD request body suppression
//
BOOL m_fRequestIsHead; BOOL m_fOriginalBodyEmpty; };
class HTTP_COMPRESSION { public:
static HRESULT Initialize();
static VOID Terminate();
static HRESULT DoStaticFileCompression(IN W3_CONTEXT *pW3Context, IN OUT W3_FILE_INFO **ppFileInfo);
static HRESULT OnSendResponse( IN W3_CONTEXT *pW3Context, IN BOOL fMoreData);
static HRESULT DoDynamicCompression( IN W3_CONTEXT *pW3Context, IN BOOL fMoreData);
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 BOOL sm_fHttpCompressionInitialized; 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 STRU &strPhysicalPath);
static VOID CompressFile(IN COMPRESSION_SCHEME *scheme, IN STRU &strPhysicalPath);
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_
|