Leaked source code of windows server 2003
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.

661 lines
22 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. chunkflt.cxx
  5. Abstract:
  6. Contains a filter for encoding and decoding chunked transfers.
  7. Contents:
  8. FILTER_LIST::Insert
  9. FILTER_LIST::RemoveAll
  10. FILTER_LIST::Decode
  11. ChunkFilter::Reset
  12. ChunkFilter::Decode
  13. ChunkFilter::Encode
  14. ChunkFilter::RegisterContext
  15. ChunkFilter::UnregisterContext
  16. Revision History:
  17. Created 13-Feb-2001
  18. --*/
  19. #include <wininetp.h>
  20. // Global lookup table to map 0x0 - 0x7f bytes for obtaining mapping to its
  21. // token value. All values above 0x7f are considered to be data.
  22. const BYTE g_bChunkTokenTable[] =
  23. {
  24. /* 0x00 */
  25. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  26. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  27. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_LF, CHUNK_TOKEN_DATA,
  28. CHUNK_TOKEN_DATA, CHUNK_TOKEN_CR, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  29. /* 0x10 */
  30. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  31. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  32. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  33. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  34. /* 0x20 */
  35. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  36. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  37. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  38. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  39. /* 0x30 */
  40. CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT,
  41. CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT,
  42. CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_COLON, CHUNK_TOKEN_DATA,
  43. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  44. /* 0x40 */
  45. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT,
  46. CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DATA,
  47. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  48. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  49. /* 0x50 */
  50. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  51. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  52. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  53. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  54. /* 0x60 */
  55. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT,
  56. CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DIGIT, CHUNK_TOKEN_DATA,
  57. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  58. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  59. /* 0x70 */
  60. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  61. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  62. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA,
  63. CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA, CHUNK_TOKEN_DATA
  64. };
  65. // Look-up table to map a token in a given state to the next state
  66. const CHUNK_DECODE_STATE g_eMapChunkTokenToNextState[CHUNK_DECODE_STATE_LAST+1][CHUNK_TOKEN_LAST+1] =
  67. {
  68. /*
  69. |---------DIGIT----------|-------------CR-------------|-------------LF------------|----------COLON----------|-----------DATA----------|
  70. */
  71. // CHUNK_DECODE_STATE_START
  72. CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE,
  73. // CHUNK_DECODE_STATE_SIZE
  74. CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE_CRLF,CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_EXT, CHUNK_DECODE_STATE_EXT,
  75. // CHUNK_DECODE_STATE_SIZE_CRLF
  76. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_SIZE_CRLF,CHUNK_DECODE_STATE_DATA, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR,
  77. // CHUNK_DECODE_STATE_EXT
  78. CHUNK_DECODE_STATE_EXT, CHUNK_DECODE_STATE_SIZE_CRLF,CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_EXT, CHUNK_DECODE_STATE_EXT,
  79. // CHUNK_DECODE_STATE_DATA
  80. CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_DATA_CRLF,CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_DATA, CHUNK_DECODE_STATE_ERROR,
  81. // CHUNK_DECODE_STATE_DATA_CRLF
  82. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_DATA_CRLF,CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR,
  83. // CHUNK_DECODE_STATE_FOOTER_NAME
  84. CHUNK_DECODE_STATE_FOOTER_NAME, CHUNK_DECODE_STATE_FINAL_CRLF, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_FOOTER_VALUE, CHUNK_DECODE_STATE_FOOTER_NAME,
  85. // CHUNK_DECODE_STATE_FOOTER_VALUE
  86. CHUNK_DECODE_STATE_FOOTER_VALUE, CHUNK_DECODE_STATE_FOOTER_CRLF, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_FOOTER_VALUE, CHUNK_DECODE_STATE_FOOTER_VALUE,
  87. // CHUNK_DECODE_STATE_FOOTER_CRLF
  88. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_FINAL_CRLF, CHUNK_DECODE_STATE_FOOTER_NAME, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR,
  89. // CHUNK_DECODE_STATE_FINAL_CRLF
  90. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_FINAL_CRLF, CHUNK_DECODE_STATE_FINISHED, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR,
  91. // CHUNK_DECODE_STATE_QUOTED_DATA -- go until next quote, then manually revert to m_eQuoteExitState
  92. CHUNK_DECODE_STATE_QUOTED_DATA, CHUNK_DECODE_STATE_QUOTED_DATA, CHUNK_DECODE_STATE_QUOTED_DATA, CHUNK_DECODE_STATE_QUOTED_DATA, CHUNK_DECODE_STATE_QUOTED_DATA,
  93. // CHUNK_DECODE_STATE_ERROR
  94. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR,
  95. // CHUNK_DECODE_STATE_FINISHED -- force client to reset before reuse
  96. CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_ERROR
  97. };
  98. // Helper macros
  99. // Where to next?
  100. #define MAP_CHUNK_TOKEN_TO_NEXT_STATE(eCurState, chToken) \
  101. (g_eMapChunkTokenToNextState[(eCurState)][(chToken)])
  102. // Given a byte, what does it represent w/regards to chunked responses
  103. #define GET_CHUNK_TOKEN(ch) ((ch) & 0x80 ? CHUNK_TOKEN_DATA : g_bChunkTokenTable[ch])
  104. // Should only be used with digit tokens.
  105. // Expects byte in range 0x30-0x39 (digits), 0x41-0x46 (uppercase hex),
  106. // or 0x61-0x66 (lowercase hex)
  107. #define GET_VALUE_FROM_ASCII_HEX(ch) ((ch) - ((ch) & 0xf0) + (((ch) & 0x40) ? 9 : 0))
  108. HRESULT ChunkFilter::Reset(DWORD_PTR dwContext)
  109. {
  110. DEBUG_ENTER((DBG_HTTP,
  111. Dword,
  112. "ChunkFilter::Reset",
  113. "%#x",
  114. dwContext
  115. ));
  116. if (dwContext)
  117. (reinterpret_cast<ChunkDecodeContext *>(dwContext))->Reset();
  118. DEBUG_LEAVE(TRUE);
  119. return S_OK;
  120. }
  121. HRESULT
  122. ChunkFilter::Decode(
  123. DWORD_PTR dwContext,
  124. IN OUT LPBYTE pInBuffer,
  125. IN DWORD dwInBufSize,
  126. IN OUT LPBYTE *ppOutBuffer,
  127. IN OUT LPDWORD pdwOutBufSize,
  128. OUT LPDWORD pdwBytesRead,
  129. OUT LPDWORD pdwBytesWritten
  130. )
  131. /*++
  132. Routine Description:
  133. Decode downloaded chunked data based on the inputted context and
  134. its current state
  135. Arguments:
  136. dwContext - registered encode/decode context for this filter
  137. pInBuffer - input data buffer to be processed
  138. dwInBufSize - byte count of pInBuffer
  139. ppOutBuffer - allocated buffer containing encoded/decoded data if
  140. not done in place with pInBuffer.
  141. pdwOutBufSize - size of allocated output buffer, or 0 if pInBuffer holds
  142. the processed data
  143. pdwBytesRead - Number of input buffer bytes used
  144. pdwBytesWritten - Number of output buffer bytes written
  145. Return Value:
  146. HRESULT
  147. Success - S_OK
  148. Failure - E_FAIL
  149. --*/
  150. {
  151. HRESULT hResult = S_OK;
  152. LPBYTE pCurrentLoc = pInBuffer;
  153. LPBYTE pStartOfChunk = pInBuffer;
  154. ChunkDecodeContext * pCtx = reinterpret_cast<ChunkDecodeContext *>(dwContext);
  155. CHUNK_DECODE_STATE ePreviousState;
  156. BYTE chToken;
  157. DEBUG_ENTER((DBG_HTTP,
  158. Dword,
  159. "ChunkFilter::Decode",
  160. "%x, [%x, %.10q], %u, %x, %u, %x, %x",
  161. dwContext,
  162. pInBuffer,
  163. pInBuffer,
  164. dwInBufSize,
  165. ppOutBuffer,
  166. pdwOutBufSize,
  167. pdwBytesRead,
  168. pdwBytesWritten
  169. ));
  170. if (!dwContext)
  171. {
  172. hResult = E_INVALIDARG;
  173. goto quit;
  174. }
  175. else if (!pdwBytesRead || !pdwBytesWritten || !pInBuffer ||
  176. (ppOutBuffer && !pdwOutBufSize))
  177. {
  178. hResult = E_POINTER;
  179. goto quit;
  180. }
  181. *pdwBytesRead = 0;
  182. *pdwBytesWritten = 0;
  183. while (*pdwBytesRead < dwInBufSize &&
  184. pCtx->GetState() != CHUNK_DECODE_STATE_ERROR)
  185. {
  186. bool fUseTransitionMatrix = false;
  187. chToken = (BYTE)GET_CHUNK_TOKEN(*pCurrentLoc);
  188. ePreviousState = pCtx->GetState();
  189. pCtx->CheckStateSize();
  190. pCtx->IncrementStateSize();
  191. DEBUG_PRINT(HTTP,
  192. INFO,
  193. ("ChunkFilter::Decode: %q, %q, %u/%u\n",
  194. InternetMapChunkState(ePreviousState),
  195. InternetMapChunkToken((CHUNK_TOKEN_VALUE)chToken),
  196. *pdwBytesRead,
  197. dwInBufSize
  198. ));
  199. INET_ASSERT(pCurrentLoc < pInBuffer + dwInBufSize);
  200. switch (pCtx->GetState())
  201. {
  202. case CHUNK_DECODE_STATE_START:
  203. pCtx->Reset();
  204. pCtx->SetState(CHUNK_DECODE_STATE_SIZE);
  205. // fall through
  206. case CHUNK_DECODE_STATE_SIZE:
  207. {
  208. if (chToken == CHUNK_TOKEN_DIGIT)
  209. {
  210. if (pCtx->m_dwParsedSize & 0xF0000000)
  211. {
  212. // Don't allow overflow if by some chance
  213. // the server is trying to send a chunk over
  214. // 0x0FFFFFFF bytes worth in size.
  215. pCtx->SetState(CHUNK_DECODE_STATE_ERROR);
  216. break;
  217. }
  218. pCtx->m_dwParsedSize <<= 4;
  219. pCtx->m_dwParsedSize += GET_VALUE_FROM_ASCII_HEX(*pCurrentLoc);
  220. }
  221. else
  222. {
  223. fUseTransitionMatrix = true;
  224. }
  225. break;
  226. }
  227. case CHUNK_DECODE_STATE_SIZE_CRLF:
  228. // Handle the zero case which can take us to the footer or final CRLF
  229. // If it's the final CRLF, then this should be the end of the data.
  230. if (pCtx->m_dwParsedSize == 0 && chToken == CHUNK_TOKEN_LF)
  231. {
  232. pCtx->SetState(CHUNK_DECODE_STATE_FOOTER_NAME);
  233. }
  234. else
  235. {
  236. fUseTransitionMatrix = true;
  237. }
  238. break;
  239. case CHUNK_DECODE_STATE_DATA:
  240. {
  241. INET_ASSERT(pCtx->m_dwParsedSize);
  242. // account for EOB
  243. if (pCurrentLoc + pCtx->m_dwParsedSize <= pInBuffer + dwInBufSize)
  244. {
  245. const DWORD dwParsedSize = pCtx->m_dwParsedSize;
  246. // Move or skip the parsed size and crlf, if needed.
  247. // The start of the chunk could be equal this time if
  248. // spread across multiple decode calls.
  249. if (pStartOfChunk != pCurrentLoc)
  250. {
  251. MoveMemory(pStartOfChunk,
  252. pCurrentLoc,
  253. dwParsedSize);
  254. }
  255. // -1 so we can look at the first byte after the data
  256. // in the next pass.
  257. pCurrentLoc += dwParsedSize - 1;
  258. *pdwBytesRead += dwParsedSize - 1;
  259. *pdwBytesWritten += dwParsedSize;
  260. pStartOfChunk += dwParsedSize;
  261. pCtx->m_dwParsedSize = 0;
  262. pCtx->IncrementStateSize(dwParsedSize-1);
  263. // Should be CRLF terminated
  264. pCtx->SetState(CHUNK_DECODE_STATE_DATA_CRLF);
  265. }
  266. else
  267. {
  268. const DWORD dwSlice = dwInBufSize - (DWORD)(pCurrentLoc - pInBuffer);
  269. // We're reaching the end of the buffer before
  270. // the end of the chunk. Update the parsed
  271. // size remaining, so it will be carried over
  272. // to the next call.
  273. if (pStartOfChunk != pCurrentLoc)
  274. {
  275. // Skip over preceding size info.
  276. MoveMemory(pStartOfChunk,
  277. pCurrentLoc,
  278. dwSlice);
  279. }
  280. // -1 so we can look at the first byte after the data
  281. // in the next pass. Offset should never be bigger than DWORD since
  282. // since that's the biggest chunk we can handle.
  283. *pdwBytesWritten += dwSlice;
  284. pCtx->m_dwParsedSize -= dwSlice;
  285. *pdwBytesRead += dwSlice - 1;
  286. pCurrentLoc = pInBuffer + dwInBufSize - 1;
  287. pCtx->IncrementStateSize(dwSlice-1);
  288. }
  289. break;
  290. }
  291. case CHUNK_DECODE_STATE_EXT:
  292. case CHUNK_DECODE_STATE_FOOTER_VALUE:
  293. if( (char)*pCurrentLoc == '"')
  294. pCtx->SetStateEnterQuotedData();
  295. else
  296. fUseTransitionMatrix = true;
  297. break;
  298. case CHUNK_DECODE_STATE_QUOTED_DATA:
  299. if( (char)*pCurrentLoc == '"')
  300. pCtx->SetStateLeaveQuotedData();
  301. else
  302. fUseTransitionMatrix = true;
  303. break;
  304. // All remaining states simply parse over the value and
  305. // change state, depending on the token.
  306. default:
  307. {
  308. fUseTransitionMatrix = true;
  309. break;
  310. }
  311. }
  312. if( fUseTransitionMatrix)
  313. {
  314. pCtx->SetState(MAP_CHUNK_TOKEN_TO_NEXT_STATE(
  315. ePreviousState,
  316. chToken));
  317. }
  318. (*pdwBytesRead)++;
  319. pCurrentLoc++;
  320. }
  321. if (pCtx->GetState() == CHUNK_DECODE_STATE_ERROR)
  322. {
  323. DEBUG_PRINT(HTTP,
  324. INFO,
  325. ("ChunkFilter::Decode entered error state\n"
  326. ));
  327. hResult = HRESULT_FROM_WIN32(pCtx->m_dwError);
  328. }
  329. quit:
  330. DEBUG_LEAVE(hResult == S_OK ? TRUE : FALSE);
  331. return hResult;
  332. }
  333. HRESULT
  334. ChunkFilter::Encode(
  335. DWORD_PTR dwContext,
  336. IN OUT LPBYTE pInBuffer,
  337. IN DWORD dwInBufSize,
  338. IN OUT LPBYTE *ppOutBuffer,
  339. IN OUT LPDWORD pdwOutBufSize,
  340. OUT LPDWORD pdwBytesRead,
  341. OUT LPDWORD pdwBytesWritten
  342. )
  343. /*++
  344. Routine Description:
  345. Chunk data for uploading based on the inputted context and current state
  346. Arguments:
  347. dwContext - registered encode/decode context for this filter
  348. pInBuffer - input data buffer to be processed
  349. dwInBufSize - byte count of pInBuffer
  350. ppOutBuffer - allocated buffer containing encoded/decoded data if
  351. not done in place with pInBuffer.
  352. pdwOutBufSize - size of allocated output buffer, or 0 if pInBuffer holds
  353. the processed data
  354. pdwBytesRead - Number of input buffer bytes used
  355. pdwBytesWritten - Number of output buffer bytes written
  356. Return Value:
  357. HRESULT
  358. E_NOTIMPL - currently no chunked upload support
  359. --*/
  360. {
  361. // We don't support chunked uploads...yet
  362. UNREFERENCED_PARAMETER(dwContext);
  363. UNREFERENCED_PARAMETER(pInBuffer);
  364. UNREFERENCED_PARAMETER(dwInBufSize);
  365. UNREFERENCED_PARAMETER(ppOutBuffer);
  366. UNREFERENCED_PARAMETER(pdwOutBufSize);
  367. UNREFERENCED_PARAMETER(pdwBytesRead);
  368. UNREFERENCED_PARAMETER(pdwBytesWritten);
  369. return E_NOTIMPL;
  370. }
  371. HRESULT
  372. ChunkFilter::RegisterContext(OUT DWORD_PTR *pdwContext)
  373. {
  374. INET_ASSERT(0); //
  375. return RegisterContextEx(pdwContext, (DWORD)-1);
  376. }
  377. HRESULT
  378. ChunkFilter::RegisterContextEx(OUT DWORD_PTR *pdwContext, DWORD dwMaxHeaderSize)
  379. {
  380. DEBUG_ENTER((DBG_HTTP,
  381. Dword,
  382. "ChunkFilter::RegisterContext",
  383. "%#x",
  384. pdwContext
  385. ));
  386. HRESULT hr = S_OK;
  387. if (!pdwContext || IsBadWritePtr(pdwContext, sizeof(DWORD_PTR)))
  388. {
  389. hr = E_POINTER;
  390. goto quit;
  391. }
  392. *pdwContext = (DWORD_PTR) New ChunkDecodeContext(dwMaxHeaderSize);
  393. if (!*pdwContext)
  394. {
  395. hr = E_OUTOFMEMORY;
  396. }
  397. quit:
  398. DEBUG_LEAVE(hr == S_OK ? TRUE : FALSE);
  399. return hr;
  400. }
  401. HRESULT
  402. ChunkFilter::UnregisterContext(IN DWORD_PTR dwContext)
  403. {
  404. DEBUG_ENTER((DBG_HTTP,
  405. Dword,
  406. "ChunkFilter::UnregisterContext",
  407. "%#x",
  408. dwContext
  409. ));
  410. HRESULT hr = S_OK;
  411. if (!dwContext)
  412. {
  413. hr = E_INVALIDARG;
  414. goto quit;
  415. }
  416. delete reinterpret_cast<ChunkDecodeContext *>(dwContext);
  417. quit:
  418. DEBUG_LEAVE(hr == S_OK ? TRUE : FALSE);
  419. return hr;
  420. }
  421. // Always inserts as the beginning of the list
  422. BOOL
  423. FILTER_LIST::Insert(IN BaseFilter *pFilter, IN DWORD_PTR dwContext)
  424. {
  425. LPFILTER_LIST_ENTRY pNewEntry;
  426. pNewEntry = New FILTER_LIST_ENTRY;
  427. if (pNewEntry != NULL)
  428. {
  429. pNewEntry->pFilter = pFilter;
  430. pNewEntry->dwContext = dwContext;
  431. pNewEntry->pNext = _pFilterEntry;
  432. _pFilterEntry = pNewEntry;
  433. _uFilterCount++;
  434. return TRUE;
  435. }
  436. else
  437. {
  438. return FALSE;
  439. }
  440. }
  441. VOID
  442. FILTER_LIST::ClearList()
  443. {
  444. LPFILTER_LIST_ENTRY pEntry = _pFilterEntry;
  445. while (pEntry)
  446. {
  447. pEntry->pFilter->UnregisterContext(pEntry->dwContext);
  448. pEntry = pEntry->pNext;
  449. delete _pFilterEntry;
  450. _pFilterEntry = pEntry;
  451. }
  452. _uFilterCount = 0;
  453. }
  454. DWORD
  455. FILTER_LIST::Decode(
  456. IN OUT LPBYTE pInBuffer,
  457. IN DWORD dwInBufSize,
  458. IN OUT LPBYTE *ppOutBuffer,
  459. IN OUT LPDWORD pdwOutBufSize,
  460. OUT LPDWORD pdwBytesRead,
  461. OUT LPDWORD pdwBytesWritten
  462. )
  463. {
  464. LPFILTER_LIST_ENTRY pEntry = _pFilterEntry;
  465. HRESULT hr = S_OK;
  466. DWORD dwBytesRead = 0;
  467. DWORD dwBytesWritten = 0;
  468. LPBYTE pLocalInBuffer = pInBuffer;
  469. DWORD dwLocalInBufSize = dwInBufSize;
  470. *pdwBytesRead = 0;
  471. *pdwBytesWritten = 0;
  472. // Loop through filters which should be in the proper order
  473. while (pEntry)
  474. {
  475. dwBytesRead = 0;
  476. dwBytesWritten = 0;
  477. // At a minimum, we're guaranteed the decode method parses
  478. // the input buffer until one of the following is met:
  479. //
  480. // - Input buffer is fully parsed and processed
  481. // - Output buffer is filled up
  482. // - Decoder reaches a finished state
  483. // - Error occurs while processing input data
  484. //
  485. // Currently, only 1, 3, and 4 are possible since chunked
  486. // transfers are decoded in place. We also don't need
  487. // to loop since chunked decoding is always fully done
  488. // in the first pass.
  489. do
  490. {
  491. pLocalInBuffer = pLocalInBuffer + dwBytesRead;
  492. dwLocalInBufSize = dwLocalInBufSize - dwBytesRead;
  493. dwBytesWritten = 0;
  494. dwBytesRead = 0;
  495. hr = pEntry->pFilter->Decode(pEntry->dwContext,
  496. pLocalInBuffer,
  497. dwLocalInBufSize,
  498. ppOutBuffer,
  499. pdwOutBufSize,
  500. &dwBytesRead,
  501. &dwBytesWritten
  502. );
  503. *pdwBytesWritten += dwBytesWritten;
  504. *pdwBytesRead += dwBytesRead;
  505. if (hr == S_OK && dwBytesRead < dwLocalInBufSize)
  506. {
  507. // Given the current requirements we shouldn't be here
  508. // if there's still input buffer data to process.
  509. RIP(FALSE);
  510. hr = E_FAIL;
  511. goto quit;
  512. }
  513. } while (hr == S_OK &&
  514. dwLocalInBufSize > 0 &&
  515. dwBytesRead < dwLocalInBufSize);
  516. pEntry = pEntry->pNext;
  517. }
  518. INET_ASSERT(hr != S_OK || dwBytesRead == dwLocalInBufSize);
  519. quit:
  520. switch (hr)
  521. {
  522. case S_OK:
  523. return ERROR_SUCCESS;
  524. case E_OUTOFMEMORY:
  525. return ERROR_NOT_ENOUGH_MEMORY;
  526. case HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE):
  527. return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
  528. case HRESULT_FROM_WIN32(ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW):
  529. return ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW;
  530. default:
  531. return ERROR_WINHTTP_INTERNAL_ERROR;
  532. }
  533. }