windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/iisplus/ulw3/compress.h
2020-09-26 16:20:57 +08:00

488 lines
14 KiB
C++

/*++
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_