Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
14 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. compression.h
  5. Abstract:
  6. Do Http compression
  7. Author:
  8. Anil Ruia (AnilR) 10-Apr-2000
  9. --*/
  10. #ifndef _COMPRESSION_H_
  11. #define _COMPRESSION_H_
  12. #define COMPRESSION_MIN_IO_BUFFER_SIZE 256
  13. #define COMPRESSION_MAX_IO_BUFFER_SIZE 100000
  14. #define COMPRESSION_MIN_COMP_BUFFER_SIZE 1024
  15. #define COMPRESSION_MAX_COMP_BUFFER_SIZE 100000
  16. #define COMPRESSION_MAX_QUEUE_LENGTH 10000
  17. #define COMPRESSION_MIN_FILES_DELETED_PER_DISK_FREE 1
  18. #define COMPRESSION_MAX_FILES_DELETED_PER_DISK_FREE 1024
  19. #define COMPRESSION_MAX_COMPRESSION_LEVEL 10
  20. #define COMPRESSION_DEFAULT_DISK_SPACE_USAGE 100000000
  21. #define COMPRESSION_DEFAULT_BUFFER_SIZE 8192
  22. #define COMPRESSION_DEFAULT_QUEUE_LENGTH 1000
  23. #define COMPRESSION_DEFAULT_FILES_DELETED_PER_DISK_FREE 256
  24. #define COMPRESSION_DEFAULT_FILE_SIZE_FOR_COMPRESSION 1
  25. class COMPRESSION_SCHEME
  26. {
  27. public:
  28. COMPRESSION_SCHEME()
  29. : m_hCompressionDll (NULL),
  30. m_pCompressionContext (NULL),
  31. m_dwPriority (1),
  32. m_dwDynamicCompressionLevel (0),
  33. m_dwOnDemandCompressionLevel (COMPRESSION_MAX_COMPRESSION_LEVEL),
  34. m_dwCreateFlags (0),
  35. m_fDoStaticCompression (TRUE),
  36. m_fDoOnDemandCompression (TRUE),
  37. m_fDoDynamicCompression (TRUE),
  38. m_pfnInitCompression (NULL),
  39. m_pfnDeInitCompression (NULL),
  40. m_pfnCreateCompression (NULL),
  41. m_pfnCompress (NULL),
  42. m_pfnDestroyCompression (NULL),
  43. m_pfnResetCompression (NULL)
  44. {}
  45. HRESULT Initialize(MB *pmb, LPWSTR schemeName);
  46. ~COMPRESSION_SCHEME()
  47. {
  48. if (m_pfnDestroyCompression && m_pCompressionContext)
  49. {
  50. m_pfnDestroyCompression(m_pCompressionContext);
  51. m_pCompressionContext = NULL;
  52. }
  53. if (m_pfnDeInitCompression)
  54. {
  55. m_pfnDeInitCompression();
  56. }
  57. if (m_hCompressionDll)
  58. {
  59. FreeLibrary(m_hCompressionDll);
  60. m_hCompressionDll = NULL;
  61. }
  62. }
  63. STRU m_strCompressionSchemeName;
  64. STRA m_straCompressionSchemeName;
  65. STRU m_strFilePrefix;
  66. MULTISZ m_mszFileExtensions;
  67. MULTISZ m_mszScriptFileExtensions;
  68. DWORD m_dwPriority;
  69. HMODULE m_hCompressionDll;
  70. PFNCODEC_INIT_COMPRESSION m_pfnInitCompression;
  71. PFNCODEC_DEINIT_COMPRESSION m_pfnDeInitCompression;
  72. PFNCODEC_CREATE_COMPRESSION m_pfnCreateCompression;
  73. PFNCODEC_COMPRESS m_pfnCompress;
  74. PFNCODEC_DESTROY_COMPRESSION m_pfnDestroyCompression;
  75. PFNCODEC_RESET_COMPRESSION m_pfnResetCompression;
  76. // The compression context used for static compression
  77. PVOID m_pCompressionContext;
  78. DWORD m_dwDynamicCompressionLevel;
  79. DWORD m_dwOnDemandCompressionLevel;
  80. DWORD m_dwCreateFlags;
  81. BOOL m_fDoDynamicCompression;
  82. BOOL m_fDoStaticCompression;
  83. BOOL m_fDoOnDemandCompression;
  84. };
  85. typedef enum
  86. {
  87. COMPRESSION_WORK_ITEM_COMPRESS,
  88. COMPRESSION_WORK_ITEM_DELETE,
  89. COMPRESSION_WORK_ITEM_TERMINATE
  90. } COMPRESSION_WORK_ITEM_TYPE;
  91. typedef struct
  92. {
  93. LIST_ENTRY ListEntry;
  94. COMPRESSION_WORK_ITEM_TYPE WorkItemType;
  95. COMPRESSION_SCHEME *scheme;
  96. STRU strPhysicalPath;
  97. } COMPRESSION_WORK_ITEM;
  98. #define MAX_SERVER_SCHEMES 100
  99. typedef enum
  100. {
  101. DO_STATIC_COMPRESSION,
  102. DO_DYNAMIC_COMPRESSION
  103. } COMPRESSION_TO_PERFORM;
  104. #define DYNAMIC_COMPRESSION_BUFFER_SIZE 4096
  105. typedef enum
  106. {
  107. IN_CHUNK_LENGTH,
  108. IN_CHUNK_EXTENSION,
  109. IN_CHUNK_HEADER_NEW_LINE,
  110. AT_CHUNK_DATA_NEW_LINE,
  111. IN_CHUNK_DATA_NEW_LINE,
  112. IN_CHUNK_DATA
  113. } COMPRESS_CHUNK_STATE;
  114. class COMPRESSION_BUFFER
  115. {
  116. public:
  117. static HRESULT Initialize()
  118. {
  119. ALLOC_CACHE_CONFIGURATION acConfig;
  120. acConfig.nConcurrency = 1;
  121. acConfig.nThreshold = 100;
  122. acConfig.cbSize = sizeof COMPRESSION_BUFFER;
  123. allocHandler = new ALLOC_CACHE_HANDLER("COMPRESSION_BUFFER",
  124. &acConfig);
  125. if (allocHandler == NULL)
  126. {
  127. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  128. }
  129. return S_OK;
  130. }
  131. static void Terminate()
  132. {
  133. if (allocHandler != NULL)
  134. {
  135. delete allocHandler;
  136. }
  137. }
  138. void *operator new(size_t size)
  139. {
  140. DBG_ASSERT(size == sizeof COMPRESSION_BUFFER);
  141. DBG_ASSERT(allocHandler != NULL);
  142. return allocHandler->Alloc();
  143. }
  144. void operator delete(void *pCompressionBuffer)
  145. {
  146. DBG_ASSERT(pCompressionBuffer != NULL);
  147. DBG_ASSERT(allocHandler != NULL);
  148. DBG_REQUIRE(allocHandler->Free(pCompressionBuffer));
  149. }
  150. BYTE buffer[6 + DYNAMIC_COMPRESSION_BUFFER_SIZE + 7];
  151. LIST_ENTRY listEntry;
  152. static ALLOC_CACHE_HANDLER *allocHandler;
  153. };
  154. class COMPRESSION_CONTEXT
  155. {
  156. public:
  157. static HRESULT Initialize()
  158. {
  159. ALLOC_CACHE_CONFIGURATION acConfig;
  160. acConfig.nConcurrency = 1;
  161. acConfig.nThreshold = 100;
  162. acConfig.cbSize = sizeof COMPRESSION_CONTEXT;
  163. allocHandler = new ALLOC_CACHE_HANDLER("COMPRESSION_CONTEXT",
  164. &acConfig);
  165. if (allocHandler == NULL)
  166. {
  167. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  168. }
  169. return S_OK;
  170. }
  171. static void Terminate()
  172. {
  173. if (allocHandler != NULL)
  174. {
  175. delete allocHandler;
  176. }
  177. }
  178. void *operator new(size_t size)
  179. {
  180. DBG_ASSERT(size == sizeof COMPRESSION_CONTEXT);
  181. DBG_ASSERT(allocHandler != NULL);
  182. return allocHandler->Alloc();
  183. }
  184. void operator delete(void *pCompressionContext)
  185. {
  186. DBG_ASSERT(pCompressionContext != NULL);
  187. DBG_ASSERT(allocHandler != NULL);
  188. DBG_REQUIRE(allocHandler->Free(pCompressionContext));
  189. }
  190. COMPRESSION_CONTEXT()
  191. : m_pScheme (NULL),
  192. m_fTransferChunkEncoded (FALSE),
  193. m_pCompressionContext (NULL),
  194. m_dwBytesInCurrentEncodedChunk (0),
  195. m_encodedChunkState (IN_CHUNK_LENGTH),
  196. m_pIoBuffer (NULL),
  197. m_fRequestIsHead (FALSE),
  198. m_fOriginalBodyEmpty (TRUE)
  199. {
  200. InitializeListHead(&m_BufferListHead);
  201. }
  202. ~COMPRESSION_CONTEXT()
  203. {
  204. FreeBuffers();
  205. if (m_pIoBuffer != NULL)
  206. {
  207. delete m_pIoBuffer;
  208. }
  209. if (m_pCompressionContext)
  210. {
  211. m_pScheme->m_pfnDestroyCompression(m_pCompressionContext);
  212. m_pCompressionContext = NULL;
  213. }
  214. }
  215. void FreeBuffers()
  216. {
  217. while (!IsListEmpty(&m_BufferListHead))
  218. {
  219. LIST_ENTRY *pEntry = RemoveHeadList(&m_BufferListHead);
  220. COMPRESSION_BUFFER *pBuffer = CONTAINING_RECORD(pEntry,
  221. COMPRESSION_BUFFER,
  222. listEntry);
  223. delete pBuffer;
  224. }
  225. }
  226. BYTE *GetNewBuffer()
  227. {
  228. COMPRESSION_BUFFER *pBuffer = new COMPRESSION_BUFFER;
  229. if (pBuffer == NULL)
  230. {
  231. return NULL;
  232. }
  233. InitializeListHead(&pBuffer->listEntry);
  234. InsertHeadList(&m_BufferListHead, &pBuffer->listEntry);
  235. return pBuffer->buffer;
  236. }
  237. HRESULT SetupCurrentULChunk();
  238. DWORD QueryBytesAvailable()
  239. {
  240. if (m_fCurrentULChunkFromMemory)
  241. {
  242. return m_pCurrentULChunk->FromMemory.BufferLength;
  243. }
  244. // We don't handle (nor do we plan to) FileName chunks
  245. DBG_ASSERT(m_pCurrentULChunk->DataChunkType == HttpDataChunkFromFileHandle);
  246. return m_bytesInIoBuffer - m_currentLocationInIoBuffer;
  247. }
  248. BYTE *QueryBytePtr()
  249. {
  250. if (m_fCurrentULChunkFromMemory)
  251. {
  252. return (PBYTE)m_pCurrentULChunk->FromMemory.pBuffer;
  253. }
  254. // We don't handle (nor do we plan to) FileName chunks
  255. DBG_ASSERT(m_pCurrentULChunk->DataChunkType == HttpDataChunkFromFileHandle);
  256. return m_pIoBuffer + m_currentLocationInIoBuffer;
  257. }
  258. HRESULT ProcessEncodedChunkHeader();
  259. HRESULT CalculateEncodedChunkByteCount();
  260. HRESULT DeleteEncodedChunkExtension();
  261. HRESULT IncrementPointerInULChunk(IN DWORD dwIncr = 1);
  262. COMPRESSION_SCHEME *m_pScheme;
  263. //
  264. // Is the original response chunk encoded?
  265. //
  266. BOOL m_fTransferChunkEncoded;
  267. //
  268. // If the original response is Chunk encoded, information about the
  269. // current chunk in the response
  270. //
  271. DWORD m_dwBytesInCurrentEncodedChunk;
  272. COMPRESS_CHUNK_STATE m_encodedChunkState;
  273. //
  274. // The context used by the compression routines
  275. //
  276. PVOID m_pCompressionContext;
  277. //
  278. // Storage for the original response
  279. //
  280. BUFFER m_ULChunkBuffer;
  281. DWORD m_cULChunks;
  282. //
  283. // position in the original response
  284. //
  285. DWORD m_cCurrentULChunk;
  286. HTTP_DATA_CHUNK *m_pCurrentULChunk;
  287. BOOL m_fCurrentULChunkFromMemory;
  288. //
  289. // buffer for reading data for FileHandle chunks
  290. //
  291. BYTE *m_pIoBuffer;
  292. DWORD m_currentLocationInIoBuffer;
  293. DWORD m_bytesInIoBuffer;
  294. static ALLOC_CACHE_HANDLER *allocHandler;
  295. LIST_ENTRY m_BufferListHead;
  296. //
  297. // Some members to keep track of HEAD request body suppression
  298. //
  299. BOOL m_fRequestIsHead;
  300. BOOL m_fOriginalBodyEmpty;
  301. };
  302. class HTTP_COMPRESSION
  303. {
  304. public:
  305. static HRESULT Initialize();
  306. static VOID Terminate();
  307. static HRESULT DoStaticFileCompression(IN W3_CONTEXT *pW3Context,
  308. IN OUT W3_FILE_INFO **ppFileInfo);
  309. static HRESULT OnSendResponse(
  310. IN W3_CONTEXT *pW3Context,
  311. IN BOOL fMoreData);
  312. static HRESULT DoDynamicCompression(
  313. IN W3_CONTEXT *pW3Context,
  314. IN BOOL fMoreData);
  315. static BOOL QueryDoStaticCompression()
  316. {
  317. return sm_fDoStaticCompression;
  318. }
  319. static BOOL QueryDoDynamicCompression()
  320. {
  321. return sm_fDoDynamicCompression;
  322. }
  323. private:
  324. static COMPRESSION_SCHEME *sm_pCompressionSchemes[MAX_SERVER_SCHEMES];
  325. static DWORD sm_dwNumberOfSchemes;
  326. static STRU *sm_pstrCompressionDirectory;
  327. static STRA *sm_pstrCacheControlHeader;
  328. static STRA *sm_pstrExpiresHeader;
  329. static BOOL sm_fDoStaticCompression;
  330. static BOOL sm_fDoDynamicCompression;
  331. static BOOL sm_fDoOnDemandCompression;
  332. static BOOL sm_fDoDiskSpaceLimiting;
  333. static BOOL sm_fNoCompressionForHttp10;
  334. static BOOL sm_fNoCompressionForProxies;
  335. static BOOL sm_fNoCompressionForRange;
  336. static BOOL sm_fSendCacheHeaders;
  337. static DWORD sm_dwMaxDiskSpaceUsage;
  338. static DWORD sm_dwIoBufferSize;
  339. static DWORD sm_dwCompressionBufferSize;
  340. static DWORD sm_dwMaxQueueLength;
  341. static DWORD sm_dwFilesDeletedPerDiskFree;
  342. static DWORD sm_dwMinFileSizeForCompression;
  343. static PBYTE sm_pIoBuffer;
  344. static PBYTE sm_pCompressionBuffer;
  345. static CRITICAL_SECTION sm_CompressionDirectoryLock;
  346. static DWORD sm_dwCurrentDiskSpaceUsage;
  347. static BOOL sm_fCompressionVolumeIsFat;
  348. static LIST_ENTRY sm_CompressionThreadWorkQueue;
  349. static CRITICAL_SECTION sm_CompressionThreadLock;
  350. static HANDLE sm_hThreadEvent;
  351. static HANDLE sm_hCompressionThreadHandle;
  352. static DWORD sm_dwCurrentQueueLength;
  353. static BOOL sm_fHttpCompressionInitialized;
  354. static BOOL sm_fIsTerminating;
  355. static HRESULT ReadMetadata(MB *pmb);
  356. static HRESULT InitializeCompressionSchemes(MB *pmb);
  357. static HRESULT InitializeCompressionDirectory();
  358. static HRESULT InitializeCompressionThread();
  359. static DWORD WINAPI CompressionThread(LPVOID);
  360. static BOOL QueueWorkItem(
  361. IN COMPRESSION_WORK_ITEM *WorkItem,
  362. IN BOOL fOverrideMaxQueueLength,
  363. IN BOOL fQueueAtHead);
  364. static VOID FindMatchingSchemes(
  365. IN CHAR * pszAcceptEncoding,
  366. IN LPWSTR pszExtension,
  367. IN COMPRESSION_TO_PERFORM performCompr,
  368. OUT DWORD matchingSchemes[],
  369. OUT DWORD *pdwClientCompressionCount);
  370. static HRESULT ConvertPhysicalPathToCompressedPath(
  371. IN COMPRESSION_SCHEME *scheme,
  372. IN STRU *pstrPhysicalPath,
  373. OUT STRU *pstrCompressedFileName);
  374. static BOOL CheckForExistenceOfCompressedFile(
  375. IN W3_FILE_INFO *pOrigFile,
  376. IN STRU *pstrCompressedFileName,
  377. OUT W3_FILE_INFO **ppCompFile,
  378. IN BOOL fDeleteAllowed = TRUE);
  379. static BOOL QueueCompressFile(
  380. IN COMPRESSION_SCHEME *scheme,
  381. IN STRU &strPhysicalPath);
  382. static VOID CompressFile(IN COMPRESSION_SCHEME *scheme,
  383. IN STRU &strPhysicalPath);
  384. static VOID FreeDiskSpace();
  385. static BOOL CompressAndWriteData(
  386. IN COMPRESSION_SCHEME *scheme,
  387. IN PBYTE InputBuffer,
  388. IN DWORD BytesToCompress,
  389. OUT PDWORD BytesWritten,
  390. IN HANDLE hCompressedFile);
  391. };
  392. #endif _COMPRESSION_H_