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.

4128 lines
103 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. httpfilt.cxx
  5. Abstract:
  6. This module contains the Microsoft HTTP server filter module
  7. Author:
  8. John Ludeman (johnl) 31-Jan-1995
  9. Revision History:
  10. --*/
  11. #include "w3p.hxx"
  12. //
  13. // Maximum allowable cached buffer
  14. //
  15. #define MAX_CACHED_FILTER_BUFFER (8 * 1024)
  16. //
  17. // Maximum number of filters we allow (per-instance - includes global filters)
  18. //
  19. #define MAX_FILTERS 50
  20. //
  21. // Private globals.
  22. //
  23. BOOL
  24. WINAPI
  25. ServerFilterCallback(
  26. struct _HTTP_FILTER_CONTEXT * pfc,
  27. enum SF_REQ_TYPE se,
  28. void * pData,
  29. ULONG_PTR ul,
  30. ULONG_PTR ul2
  31. );
  32. BOOL
  33. WINAPI
  34. GetServerVariable(
  35. struct _HTTP_FILTER_CONTEXT * pfc,
  36. LPSTR lpszVariableName,
  37. LPVOID lpvBuffer,
  38. LPDWORD lpdwSize
  39. );
  40. BOOL
  41. WINAPI
  42. WriteFilterClient(
  43. struct _HTTP_FILTER_CONTEXT * pfc,
  44. LPVOID Buffer,
  45. LPDWORD lpdwBytes,
  46. DWORD dwReserved
  47. );
  48. VOID *
  49. WINAPI
  50. AllocFilterMem(
  51. struct _HTTP_FILTER_CONTEXT * pfc,
  52. DWORD cbSize,
  53. DWORD dwReserved
  54. );
  55. BOOL
  56. WINAPI
  57. ServerSupportFunction(
  58. struct _HTTP_FILTER_CONTEXT * pfc,
  59. enum SF_REQ_TYPE sfReq,
  60. PVOID pData,
  61. ULONG_PTR ul1,
  62. ULONG_PTR ul2
  63. );
  64. BOOL
  65. WINAPI
  66. AddFilterResponseHeaders(
  67. HTTP_FILTER_CONTEXT * pfc,
  68. LPSTR lpszHeaders,
  69. DWORD dwReserved
  70. );
  71. VOID
  72. FilterAtqCompletion(
  73. PVOID Context,
  74. DWORD BytesWritten,
  75. DWORD CompletionStatus,
  76. OVERLAPPED * lpo
  77. );
  78. VOID
  79. ContinueRawRead(
  80. PVOID Context,
  81. DWORD BytesWritten,
  82. DWORD CompletionStatus,
  83. OVERLAPPED * lpo
  84. );
  85. BOOL
  86. WINAPI
  87. CompressionFilterCheck(
  88. HTTP_FILTER_CONTEXT *pfc,
  89. LPVOID lpszEncodingString,
  90. ULONG_PTR lpszVerbString,
  91. ULONG_PTR sizesForBuffers
  92. );
  93. /*****************************************************************/
  94. BOOL
  95. HTTP_FILTER::NotifyRequestSecurityContextClose(
  96. HTTP_FILTER_DLL * pFilterDLL,
  97. CtxtHandle * pCtxt
  98. )
  99. {
  100. HTTP_FILTER_REQUEST_CLOSE_SECURITY_CONTEXT hfcc;
  101. HTTP_FILTER_CONTEXT * phfc;
  102. HTTP_FILTER_DLL * pFilt;
  103. FILTER_LIST * pFilterList;
  104. SF_STATUS_TYPE sfStatus = SF_STATUS_REQ_HANDLED_NOTIFICATION;
  105. DWORD i;
  106. hfcc.pCtxt = (PVOID)pCtxt;
  107. phfc = QueryContext();
  108. phfc->fIsSecurePort = QueryReq()->IsSecurePort();
  109. pFilterList = QueryFilterList();
  110. //
  111. // If this filter doesn't support this type of notification
  112. // then ignore it
  113. //
  114. if ( !pFilterDLL->IsNotificationNeeded(
  115. SF_NOTIFY_REQUEST_SECURITY_CONTEXT_CLOSE,
  116. phfc->fIsSecurePort ))
  117. {
  118. //
  119. // This filter doesn't support this type of notification.
  120. //
  121. return FALSE;
  122. }
  123. //
  124. // This request is targetted at a particular DLL so find the filter
  125. // context in the filter list
  126. //
  127. for ( i = 0; i < pFilterList->QueryFilterCount(); i++ )
  128. {
  129. if ( pFilterDLL == pFilterList->QueryDll( i ) )
  130. {
  131. phfc->pFilterContext = QueryClientContext( i );
  132. sfStatus = (SF_STATUS_TYPE)
  133. pFilterDLL->QueryEntryPoint()( phfc,
  134. SF_NOTIFY_REQUEST_SECURITY_CONTEXT_CLOSE,
  135. &hfcc );
  136. SetClientContext( i, phfc->pFilterContext );
  137. }
  138. break;
  139. }
  140. return sfStatus == SF_STATUS_REQ_HANDLED_NOTIFICATION;
  141. }
  142. BOOL
  143. HTTP_FILTER::NotifyRawReadDataFilters(
  144. VOID * pvInData,
  145. DWORD cbInData,
  146. DWORD cbInBuffer,
  147. VOID * * ppvOutData,
  148. DWORD * pcbOutData,
  149. BOOL * pfRequestFinished,
  150. BOOL * pfReadAgain
  151. )
  152. /*++
  153. Routine Description:
  154. This method handles notification of all filters that handle the
  155. raw data notifications.
  156. Note this is the only routine that needs to save phfc->pFilterContext
  157. because this is the only notification that can get occur while we're
  158. in another notification.
  159. Arguments:
  160. pvInData - Raw data
  161. cbInData - count of bytes of raw data
  162. cbInBuffer - Size of input buffer
  163. ppvOutData - Receives pointer to buffer of translated data
  164. pcbOutData - Number of bytes of translated data
  165. pfRequestFinished - Set to TRUE if the filter completed request processing
  166. pfReadAgain - Set to TRUE if the caller should issue another read and
  167. call this routine again
  168. Return Value:
  169. TRUE if successful, FALSE on error
  170. --*/
  171. {
  172. HTTP_FILTER_RAW_DATA hfrd;
  173. HTTP_FILTER_CONTEXT * phfc;
  174. HTTP_FILTER_DLL * pFilterDLL;
  175. FILTER_LIST * pFilterList;
  176. SF_STATUS_TYPE sfStatus;
  177. VOID * pvClientContext;
  178. DWORD CurrentDll;
  179. DWORD i;
  180. PVOID pvtmp;
  181. //
  182. // Don't notify on zero length writes
  183. //
  184. if ( !cbInData )
  185. {
  186. *ppvOutData = pvInData;
  187. *pcbOutData = cbInData;
  188. return TRUE;
  189. }
  190. //
  191. // Fill out the raw read structure
  192. //
  193. hfrd.pvInData = pvInData;
  194. hfrd.cbInData = cbInData;
  195. hfrd.cbInBuffer = cbInBuffer;
  196. //
  197. // Increment the nested notification level
  198. //
  199. _cRawNotificationLevel++;
  200. //
  201. // Initialize items specific to this request
  202. //
  203. phfc = QueryContext();
  204. phfc->fIsSecurePort = QueryReq()->IsSecurePort();
  205. //
  206. // Save the current client context in the filter structure and the
  207. // current dll because we may be in the middle of another filter
  208. // notification
  209. //
  210. pvClientContext = phfc->pFilterContext;
  211. CurrentDll = QueryCurrentDll();
  212. pFilterList = QueryFilterList();
  213. //
  214. // If a filter needs to do a WriteClient in the middle of a raw data
  215. // notification, we only notify the filters down (or up) the chain
  216. //
  217. i = (CurrentDll == INVALID_DLL ? 0 : CurrentDll);
  218. //
  219. // For recv operations, walk the list in order so encryption filters
  220. // are at the front of the list
  221. //
  222. for ( ; i < pFilterList->QueryFilterCount(); i++ )
  223. {
  224. pFilterDLL = pFilterList->QueryDll( i );
  225. //
  226. // Notification flags are cached in the HTTP_FILTER object, but they're
  227. // only copied from the actual HTTP_FILTER_DLL object if a filter dll
  228. // disables a particular notification [sort of a copy-on-write scheme].
  229. // If a filter dll disables/changes a notification, we need to check the flags
  230. // in the HTTP_FILTER object, not those in the HTTP_FILTER_DLL object
  231. //
  232. // NOTE : This code is also executed in the functions
  233. // HTTP_FILTER::NotifyRawSendDataFilters and HTTP_FILTER::NotifyFilters, so
  234. // any changes/corrections need to be made there as well. The reason it wasn't
  235. // broken out into a function is that this code is on the main-line code path
  236. // for each request and making a function call for each filter loaded would
  237. // be an efficiency hit.
  238. //
  239. if ( !QueryNotificationChanged() )
  240. {
  241. if (! pFilterDLL->IsNotificationNeeded(SF_NOTIFY_READ_RAW_DATA,
  242. phfc->fIsSecurePort ))
  243. {
  244. //
  245. // This filter doesn't support this type of notification.
  246. //
  247. continue;
  248. }
  249. }
  250. else
  251. {
  252. if ( !IsDisableNotificationNeeded( i,
  253. SF_NOTIFY_READ_RAW_DATA,
  254. phfc->fIsSecurePort ))
  255. {
  256. //
  257. // This filter doesn't support this type of notification.
  258. //
  259. continue;
  260. }
  261. }
  262. SetCurrentDll( i );
  263. pvtmp = phfc->pFilterContext = QueryClientContext( i );
  264. sfStatus = (SF_STATUS_TYPE)
  265. pFilterDLL->QueryEntryPoint()( phfc,
  266. SF_NOTIFY_READ_RAW_DATA,
  267. &hfrd );
  268. if ( pvtmp != phfc->pFilterContext )
  269. SetClientContext( i, phfc->pFilterContext );
  270. switch ( sfStatus )
  271. {
  272. default:
  273. DBGPRINTF((DBG_CONTEXT,
  274. "[NotifyRawReadDataFilters] Unknown status code from filter %d\n",
  275. sfStatus ));
  276. //
  277. // Fall through
  278. //
  279. case SF_STATUS_REQ_NEXT_NOTIFICATION:
  280. continue;
  281. case SF_STATUS_REQ_ERROR:
  282. SetCurrentDll( CurrentDll );
  283. _cRawNotificationLevel--;
  284. phfc->pFilterContext = pvClientContext;
  285. return FALSE;
  286. case SF_STATUS_REQ_FINISHED:
  287. case SF_STATUS_REQ_FINISHED_KEEP_CONN: // Not supported for raw data
  288. QueryReq()->Disconnect();
  289. *pfRequestFinished = TRUE;
  290. goto Exit;
  291. case SF_STATUS_REQ_HANDLED_NOTIFICATION:
  292. //
  293. // Don't notify any other filters
  294. //
  295. goto Exit;
  296. case SF_STATUS_REQ_READ_NEXT:
  297. *pfReadAgain = TRUE;
  298. goto Exit;
  299. }
  300. }
  301. Exit:
  302. *ppvOutData = hfrd.pvInData;
  303. *pcbOutData = hfrd.cbInData;
  304. phfc->pFilterContext = pvClientContext;
  305. _cRawNotificationLevel--;
  306. SetCurrentDll( CurrentDll );
  307. return TRUE;
  308. }
  309. BOOL
  310. HTTP_FILTER::NotifyRawSendDataFilters(
  311. VOID * pvInData,
  312. DWORD cbInData,
  313. DWORD cbInBuffer,
  314. VOID * * ppvOutData,
  315. DWORD * pcbOutData,
  316. BOOL * pfRequestFinished
  317. )
  318. /*++
  319. Routine Description:
  320. This method handles notification of all filters that handle the
  321. raw data notifications.
  322. Note this is the only routine that needs to save phfc->pFilterContext
  323. because this is the only notification that can get occur while we're
  324. in another notification.
  325. Arguments:
  326. pvInData - Raw data
  327. cbInData - count of bytes of raw data
  328. cbInBuffer - Size of input buffer
  329. ppvOutData - Receives pointer to buffer of translated data
  330. pcbOutData - Number of bytes of translated data
  331. pfRequestFinished - Set to TRUE if the filter completed request processing
  332. Return Value:
  333. TRUE if successful, FALSE on error
  334. --*/
  335. {
  336. HTTP_FILTER_RAW_DATA hfrd;
  337. HTTP_FILTER_CONTEXT * phfc;
  338. HTTP_FILTER_DLL * pFilterDLL;
  339. FILTER_LIST * pFilterList;
  340. DWORD err;
  341. SF_STATUS_TYPE sfStatus;
  342. VOID * pvClientContext;
  343. DWORD CurrentDll;
  344. DWORD i;
  345. PVOID pvtmp;
  346. //
  347. // Don't notify on zero length writes
  348. //
  349. if ( !cbInData )
  350. {
  351. *ppvOutData = pvInData;
  352. *pcbOutData = cbInData;
  353. return TRUE;
  354. }
  355. pFilterList = QueryFilterList();
  356. //
  357. // Fill out the raw send structure
  358. //
  359. hfrd.pvInData = pvInData;
  360. hfrd.cbInData = cbInData;
  361. hfrd.cbInBuffer = cbInBuffer;
  362. //
  363. // Increment the nested notification level
  364. //
  365. _cRawNotificationLevel++;
  366. //
  367. // Initialize items specific to this request
  368. //
  369. phfc = QueryContext();
  370. phfc->fIsSecurePort = QueryReq()->IsSecurePort();
  371. //
  372. // Save the current client context in the filter structure and the
  373. // current dll in the because we may be in the middle of another filter
  374. // notification
  375. //
  376. pvClientContext = phfc->pFilterContext;
  377. CurrentDll = QueryCurrentDll();
  378. pFilterList = QueryFilterList();
  379. //
  380. // If a filter needs to do a WriteClient in the middle of a raw data
  381. // notification, we only notify the filters up the chain
  382. //
  383. i = (CurrentDll == INVALID_DLL ? pFilterList->QueryFilterCount() - 1
  384. : CurrentDll) ;
  385. //
  386. // For send operations, walk the list in reverse so encryption filters
  387. // are at the end of the list
  388. //
  389. do {
  390. pFilterDLL = pFilterList->QueryDll( i );
  391. //
  392. // Notification flags are cached in the HTTP_FILTER object, but they're
  393. // only copied from the actual HTTP_FILTER_DLL object if a filter dll
  394. // disables a particular notification [sort of a copy-on-write scheme].
  395. // If a filter dll disables/changes a notification, we need to check the flags
  396. // in the HTTP_FILTER object, not those in the HTTP_FILTER_DLL object
  397. //
  398. // NOTE : This code is also executed in the functions
  399. // HTTP_FILTER::NotifyRawReadDataFilters and HTTP_FILTER::NotifyFilters, so
  400. // any changes/corrections need to be made there as well. The reason it wasn't
  401. // broken out into a function is that this code is on the main-line code path
  402. // for each request and making a function call for each filter loaded would
  403. // be an efficiency hit.
  404. //
  405. if ( !QueryNotificationChanged() )
  406. {
  407. if (! pFilterDLL->IsNotificationNeeded(SF_NOTIFY_SEND_RAW_DATA,
  408. phfc->fIsSecurePort ))
  409. {
  410. //
  411. // This filter doesn't support this type of notification.
  412. //
  413. continue;
  414. }
  415. }
  416. else
  417. {
  418. if ( !IsDisableNotificationNeeded( i,
  419. SF_NOTIFY_SEND_RAW_DATA,
  420. phfc->fIsSecurePort ))
  421. {
  422. //
  423. // This filter doesn't support this type of notification.
  424. //
  425. continue;
  426. }
  427. }
  428. SetCurrentDll( i );
  429. pvtmp = phfc->pFilterContext = QueryClientContext( i );
  430. sfStatus = (SF_STATUS_TYPE)
  431. pFilterDLL->QueryEntryPoint()( phfc,
  432. SF_NOTIFY_SEND_RAW_DATA,
  433. &hfrd );
  434. if ( pvtmp != phfc->pFilterContext )
  435. SetClientContext( i, phfc->pFilterContext );
  436. switch ( sfStatus )
  437. {
  438. default:
  439. DBGPRINTF((DBG_CONTEXT,
  440. "[NotifyRawSendDataFilters] Unknown status code from filter %d\n",
  441. sfStatus ));
  442. //
  443. // Fall through
  444. //
  445. case SF_STATUS_REQ_NEXT_NOTIFICATION:
  446. continue;
  447. case SF_STATUS_REQ_ERROR:
  448. SetCurrentDll( CurrentDll );
  449. _cRawNotificationLevel--;
  450. phfc->pFilterContext = pvClientContext;
  451. return FALSE;
  452. case SF_STATUS_REQ_FINISHED:
  453. case SF_STATUS_REQ_FINISHED_KEEP_CONN: // Not supported for raw data
  454. QueryReq()->Disconnect();
  455. *pfRequestFinished = TRUE;
  456. goto Exit;
  457. case SF_STATUS_REQ_HANDLED_NOTIFICATION:
  458. //
  459. // Don't notify any other filters
  460. //
  461. goto Exit;
  462. }
  463. } while ( i-- > 0 );
  464. Exit:
  465. *ppvOutData = hfrd.pvInData;
  466. *pcbOutData = hfrd.cbInData;
  467. phfc->pFilterContext = pvClientContext;
  468. _cRawNotificationLevel--;
  469. SetCurrentDll( CurrentDll );
  470. return TRUE;
  471. }
  472. BOOL
  473. HTTP_FILTER::NotifyRequestRenegotiate(
  474. HTTP_FILTER * pFilter,
  475. LPBOOL pfAccepted,
  476. BOOL fMapCert
  477. )
  478. /*++
  479. Routine Description:
  480. Arguments:
  481. pFilter - Pointer to filter object
  482. pAccepted - updated with TRUE if request accepted
  483. Return Value:
  484. TRUE if successful, FALSE on error
  485. --*/
  486. {
  487. HTTP_FILTER_CONTEXT * phfc;
  488. HTTP_FILTER_DLL * pFilterDLL;
  489. SF_STATUS_TYPE sfStatus;
  490. HTTP_FILTER_REQUEST_CERT hfrc;
  491. DWORD i;
  492. FILTER_LIST * pFilterList;
  493. PVOID pvtmp;
  494. //
  495. // Increment the nested notification level
  496. //
  497. pFilter->_cRawNotificationLevel++;
  498. //
  499. // Initialize items specific to this request
  500. //
  501. phfc = pFilter->QueryContext();
  502. phfc->fIsSecurePort = pFilter->QueryReq()->IsSecurePort();
  503. phfc->ulReserved = 0;
  504. pFilterList = QueryFilterList();
  505. hfrc.fMapCert = fMapCert;
  506. hfrc.dwReserved = 0;
  507. for ( i = 0; i < pFilterList->QueryFilterCount(); i++ )
  508. {
  509. pFilterDLL = pFilterList->QueryDll( i );
  510. //
  511. // Skip this DLL if it doesn't want this notification
  512. //
  513. if ( !pFilterDLL->IsNotificationNeeded( SF_NOTIFY_RENEGOTIATE_CERT,
  514. phfc->fIsSecurePort ))
  515. {
  516. continue;
  517. }
  518. pFilter->SetCurrentDll( i );
  519. pvtmp = phfc->pFilterContext = pFilter->QueryClientContext( i );
  520. sfStatus = (SF_STATUS_TYPE)
  521. pFilterDLL->QueryEntryPoint()( phfc,
  522. SF_NOTIFY_RENEGOTIATE_CERT,
  523. &hfrc );
  524. if ( pvtmp != phfc->pFilterContext )
  525. pFilter->SetClientContext( i, phfc->pFilterContext );
  526. switch ( sfStatus )
  527. {
  528. default:
  529. DBGPRINTF((DBG_CONTEXT,
  530. "[NotifyRenegoCert] Unknown status code from filter %d\n",
  531. sfStatus ));
  532. //
  533. // Fall through
  534. //
  535. case SF_STATUS_REQ_NEXT_NOTIFICATION:
  536. continue;
  537. case SF_STATUS_REQ_ERROR:
  538. pFilter->SetCurrentDll( INVALID_DLL );
  539. pFilter->_cRawNotificationLevel--;
  540. return FALSE;
  541. case SF_STATUS_REQ_FINISHED: // not supported
  542. case SF_STATUS_REQ_FINISHED_KEEP_CONN: // Not supported at this point
  543. pFilter->QueryReq()->SetKeepConn( FALSE );
  544. goto Exit;
  545. case SF_STATUS_REQ_HANDLED_NOTIFICATION:
  546. //
  547. // Don't notify any other filters
  548. //
  549. *pfAccepted = hfrc.fAccepted;
  550. goto Exit;
  551. }
  552. }
  553. Exit:
  554. pFilter->SetCurrentDll( INVALID_DLL );
  555. pFilter->_cRawNotificationLevel--;
  556. return TRUE;
  557. }
  558. BOOL
  559. HTTP_FILTER::NotifyAccessDenied(
  560. const CHAR * pszURL,
  561. const CHAR * pszPhysicalPath,
  562. BOOL * pfFinished
  563. )
  564. /*++
  565. Routine Description:
  566. This method handles notification of all filters that handle the
  567. access denied notification
  568. Arguments:
  569. pszURL - URL that was target of request
  570. pszPath - Physical path the URL mapped to
  571. pfFinished - Set to TRUE if no further processing is required
  572. Return Value:
  573. TRUE if successful, FALSE on error
  574. --*/
  575. {
  576. HTTP_FILTER_ACCESS_DENIED hfad;
  577. HTTP_FILTER_CONTEXT * phfc;
  578. BOOL fRet;
  579. //
  580. // If these flags are not set, then somebody hasn't indicated the reason
  581. // for denying the user access
  582. //
  583. DBG_ASSERT( QueryDeniedFlags() != 0 );
  584. //
  585. // Ignore the notification of a send "401 ..." if this notification
  586. // generated it
  587. //
  588. if ( _fInAccessDeniedNotification )
  589. {
  590. return TRUE;
  591. }
  592. _fInAccessDeniedNotification = TRUE;
  593. //
  594. // Fill out the url map structure
  595. //
  596. hfad.pszURL = pszURL;
  597. hfad.pszPhysicalPath = pszPhysicalPath;
  598. hfad.dwReason = QueryDeniedFlags();
  599. //
  600. // Initialize items specific to this request
  601. //
  602. phfc = QueryContext();
  603. phfc->fIsSecurePort = QueryReq()->IsSecurePort();
  604. fRet = NotifyFilters(
  605. SF_NOTIFY_ACCESS_DENIED,
  606. phfc,
  607. &hfad,
  608. pfFinished,
  609. FALSE );
  610. _fInAccessDeniedNotification = FALSE;
  611. return fRet;
  612. }
  613. BOOL
  614. HTTP_FILTER::NotifySendHeaders( const CHAR * pszHeaderList,
  615. BOOL * pfFinished,
  616. BOOL * pfAnyChanges,
  617. BUFFER * pChangeBuff )
  618. {
  619. HTTP_FILTER_SEND_RESPONSE hfph;
  620. BOOL fRet;
  621. DWORD cbJump;
  622. hfph.GetHeader = GetSendHeader;
  623. hfph.SetHeader = SetSendHeader;
  624. hfph.AddHeader = AddSendHeader;
  625. _pchSendHeaders = pszHeaderList;
  626. // When parsing out the status code, beware of bad response buffers:
  627. // - empty buffers (in case of HTTP 0.x requests)
  628. // - buffers not starting with HTTP/X.X
  629. //
  630. // first line is the status
  631. cbJump = sizeof( "HTTP/X.X" );
  632. if ( strlen( pszHeaderList ) > ( cbJump - 1 ) )
  633. {
  634. pszHeaderList += cbJump;
  635. }
  636. while ( *pszHeaderList != '\0' &&
  637. *pszHeaderList != '\r' &&
  638. *pszHeaderList != '\n' &&
  639. !isdigit( (UCHAR)(*pszHeaderList) ))
  640. {
  641. pszHeaderList++;
  642. }
  643. // If for some reason, there was no version in string,
  644. // atoi() returns 0 on the empty string, which I guess is OK.
  645. hfph.HttpStatus = atoi( pszHeaderList );
  646. fRet = NotifyFilters( SF_NOTIFY_SEND_RESPONSE,
  647. QueryContext(),
  648. &hfph,
  649. pfFinished,
  650. FALSE );
  651. if ( pfAnyChanges )
  652. {
  653. *pfAnyChanges = _fSendHeadersChanged;
  654. }
  655. if ( fRet && _fSendHeadersChanged )
  656. {
  657. fRet = BuildNewSendHeaders( pChangeBuff );
  658. }
  659. //
  660. // Make sure we reparse the headers
  661. //
  662. SetSendHeadersParsed(FALSE);
  663. _SendHeaders.Reset();
  664. return fRet;
  665. }
  666. BOOL
  667. FILTER_LIST::NotifyFilters(
  668. HTTP_FILTER * pFilter,
  669. DWORD NotificationType,
  670. HTTP_FILTER_CONTEXT * phfc,
  671. PVOID NotificationData,
  672. BOOL * pfFinished,
  673. BOOL fNotifyAll
  674. )
  675. /*++
  676. Routine Description:
  677. Notifies all registered filters on this filter list for the specified
  678. notification type
  679. Arguments:
  680. pFilter - Pointer to filter making this request
  681. NotificationType - SF_NOTIFY_ flag indicating the notification type
  682. pfc - Pointer to filter context
  683. NotificationData - Pointer to notification specific structure
  684. fNotifyAll - If TRUE, always notify all filters regardless of return code
  685. from filter
  686. Return Value:
  687. TRUE on success, FALSE on failure (call GetLastError)
  688. --*/
  689. {
  690. HTTP_FILTER_DLL * pFilterDLL;
  691. DWORD err;
  692. SF_STATUS_TYPE sfStatus;
  693. DWORD i;
  694. PVOID pvtmp;
  695. PVOID pvCurrentClientContext;
  696. //
  697. // In certain cases, we can send a notification to a filter while we're still
  698. // processing another filter's notification. In that case, we need to make sure
  699. // we restore the current filter's context when we're done with the notifications
  700. //
  701. pvCurrentClientContext = phfc->pFilterContext;
  702. phfc->fIsSecurePort = pFilter->QueryReq()->IsSecurePort();
  703. for ( i = 0; i < m_cFilters; i++ )
  704. {
  705. pFilterDLL = QueryDll( i );
  706. //
  707. // Notification flags are cached in the HTTP_FILTER object, but they're
  708. // only copied from the actual HTTP_FILTER_DLL object if a filter dll
  709. // disables a particular notification [sort of a copy-on-write scheme].
  710. // If a filter dll disables/changes a notification, we need to check the flags
  711. // in the HTTP_FILTER object, not those in the HTTP_FILTER_DLL object
  712. //
  713. // NOTE : This code is also executed in the functions
  714. // HTTP_FILTER::NotifyRawSendDataFilters and HTTP_FILTER::NotifyRawReadDataFilters, so
  715. // any changes/corrections need to be made there as well. The reason it wasn't
  716. // broken out into a function is that this code is on the main-line code path
  717. // for each request and making a function call for each filter loaded would
  718. // be an efficiency hit.
  719. //
  720. if ( !pFilter->QueryNotificationChanged() )
  721. {
  722. if ( !pFilterDLL->IsNotificationNeeded( NotificationType,
  723. phfc->fIsSecurePort ))
  724. {
  725. //
  726. // This filter doesn't support this type of notification.
  727. //
  728. continue;
  729. }
  730. }
  731. else
  732. {
  733. if ( !pFilter->IsDisableNotificationNeeded( i,
  734. NotificationType,
  735. phfc->fIsSecurePort ) )
  736. {
  737. continue;
  738. }
  739. }
  740. pFilter->SetCurrentDll( i );
  741. pvtmp = phfc->pFilterContext = pFilter->QueryClientContext( i );
  742. sfStatus = (SF_STATUS_TYPE)
  743. pFilterDLL->QueryEntryPoint()( phfc,
  744. NotificationType,
  745. NotificationData );
  746. if ( pvtmp != phfc->pFilterContext )
  747. pFilter->SetClientContext( i, phfc->pFilterContext );
  748. switch ( sfStatus )
  749. {
  750. default:
  751. DBGPRINTF((DBG_CONTEXT,
  752. "[NotifyFilters] Unknown status code from filter %d\n",
  753. sfStatus ));
  754. //
  755. // Fall through
  756. //
  757. case SF_STATUS_REQ_NEXT_NOTIFICATION:
  758. continue;
  759. case SF_STATUS_REQ_ERROR:
  760. phfc->pFilterContext = pvCurrentClientContext;
  761. pFilter->SetCurrentDll( INVALID_DLL );
  762. return FALSE;
  763. case SF_STATUS_REQ_FINISHED:
  764. case SF_STATUS_REQ_FINISHED_KEEP_CONN: // Not supported at this point
  765. pFilter->QueryReq()->SetKeepConn( FALSE );
  766. *pfFinished = TRUE;
  767. goto Exit;
  768. case SF_STATUS_REQ_HANDLED_NOTIFICATION:
  769. //
  770. // Don't notify any other filters
  771. //
  772. goto Exit;
  773. }
  774. }
  775. Exit:
  776. //
  777. // Reset the filter context we came in with
  778. //
  779. phfc->pFilterContext = pvCurrentClientContext;
  780. pFilter->SetCurrentDll( INVALID_DLL );
  781. return TRUE;
  782. }
  783. VOID FILTER_LIST::SetNotificationFlags(
  784. DWORD i,
  785. HTTP_FILTER_DLL * pFilterDll
  786. )
  787. /*++
  788. Routine Description:
  789. Adjusts the filter flags in the filter list. Note this is only safe on
  790. global filters, not per website filters.
  791. Arguments:
  792. i - index of filter dll that is being adjusted
  793. pFilterDll - Pointer to filter dll that contains the updated list
  794. Return Value:
  795. --*/
  796. {
  797. DWORD dwSec = 0;
  798. DWORD dwNonSec = 0;
  799. //
  800. // Reset the flags in the array then rebuild the set of flags for
  801. // the filter list. Build the set in a temporary so the filter list
  802. // gets updated in a single action so other filters won't be impacted
  803. //
  804. ((DWORD*) m_buffSecureArray.QueryPtr())[i] = pFilterDll->QuerySecureFlags();
  805. ((DWORD*) m_buffNonSecureArray.QueryPtr())[i] = pFilterDll->QueryNonsecureFlags();
  806. for (DWORD j = 0; j < m_cFilters; j++)
  807. {
  808. dwSec |= QueryDll(j)->QuerySecureFlags();
  809. dwNonSec |= QueryDll(j)->QueryNonsecureFlags();
  810. }
  811. m_SecureNotifications = dwSec;
  812. m_NonSecureNotifications = dwNonSec;
  813. }
  814. HTTP_FILTER_DLL* FILTER_LIST::HasFilterDll(
  815. HTTP_FILTER_DLL *pFilterDll
  816. )
  817. /*++
  818. Routine Description:
  819. Checks whether this filter list contains a specific filter dll
  820. Arguments:
  821. pFilterDll - filter dll to look for
  822. Return Value:
  823. Pointer to matching HTTP_FILTER_DLL object if found, NULL otherwise.
  824. [This is probably redundant, since HTTP_FILTER_DLL objects are unique ...]
  825. --*/
  826. {
  827. HTTP_FILTER_DLL **apFilterDll = (HTTP_FILTER_DLL **)(m_buffFilterArray.QueryPtr());
  828. for ( DWORD i = 0; i < m_cFilters; i++ )
  829. {
  830. if ( apFilterDll[i] == pFilterDll )
  831. {
  832. return pFilterDll;
  833. }
  834. }
  835. return NULL;
  836. }
  837. HTTP_FILTER::HTTP_FILTER(
  838. HTTP_REQ_BASE * pRequest
  839. )
  840. /*++
  841. Routine Description:
  842. Copies the filter context
  843. Arguments:
  844. pRequest - Pointer to HTTP request this filter should be applied to
  845. Return Value:
  846. --*/
  847. : _fIsValid ( FALSE ),
  848. _pRequest ( pRequest ),
  849. _apvContexts ( NULL ),
  850. _pFilterList ( NULL ),
  851. _pGlobalFilterList( NULL ),
  852. _fSendHeadersChanged( FALSE ),
  853. _fSendHeadersParsed( FALSE ),
  854. _dwSecureNotifications( 0 ),
  855. _dwNonSecureNotifications( 0 ),
  856. _fNotificationsDisabled( FALSE )
  857. {
  858. InitializeListHead( &_PoolHead );
  859. _hfc.cbSize = sizeof( _hfc );
  860. _hfc.Revision = HTTP_FILTER_REVISION;
  861. _hfc.ServerContext = (void *) this;
  862. _hfc.ulReserved = 0;
  863. _hfc.ServerSupportFunction = ServerFilterCallback;
  864. _hfc.GetServerVariable = GetServerVariable;
  865. _hfc.AddResponseHeaders = AddFilterResponseHeaders;
  866. _hfc.WriteClient = WriteFilterClient;
  867. _hfc.AllocMem = AllocFilterMem;
  868. _Overlapped.hEvent = NULL;
  869. _CurrentFilter = INVALID_DLL;
  870. //
  871. // Allocate the array of contexts for this request
  872. //
  873. _apvContexts = new PVOID[MAX_FILTERS];
  874. if ( !_apvContexts )
  875. {
  876. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  877. return;
  878. }
  879. //
  880. // Initialize the array of filter contexts
  881. //
  882. memset( _apvContexts, 0, MAX_FILTERS * sizeof(PVOID) );
  883. //Reset(); We Assume Reset will be called when initializing the session
  884. SetGlobalFilterList( GLOBAL_FILTER_LIST() );
  885. _fIsValid = TRUE;
  886. }
  887. VOID
  888. HTTP_FILTER::Reset(
  889. VOID
  890. )
  891. /*++
  892. Routine Description:
  893. Resets the state of this filter. Called between net sessions.
  894. --*/
  895. {
  896. FILTER_POOL_ITEM * pfpi;
  897. _cbRecvRaw = 0;
  898. _cbRecvTrans = 0;
  899. _hFile = NULL;
  900. _pFilterGetFile = NULL;
  901. _cbFileReadSize = 4096;
  902. _cRawNotificationLevel = 0;
  903. _dwDeniedFlags = 0;
  904. _fInAccessDeniedNotification = FALSE;
  905. _pchSendHeaders = NULL;
  906. _fNotificationsDisabled = FALSE;
  907. if ( _fSendHeadersParsed )
  908. {
  909. _SendHeaders.Reset();
  910. }
  911. _fSendHeadersChanged = FALSE;
  912. _fSendHeadersParsed = FALSE;
  913. }
  914. VOID
  915. HTTP_FILTER::Cleanup(
  916. VOID
  917. )
  918. /*++
  919. Routine Description:
  920. Cleans up this filter. Called after a session terminates.
  921. --*/
  922. {
  923. FILTER_POOL_ITEM * pfpi;
  924. //
  925. // Reset the array of filter contexts
  926. //
  927. memset( _apvContexts, 0, MAX_FILTERS * sizeof(PVOID) );
  928. //
  929. // Clean up the allocated buffers
  930. //
  931. if ( _bufRecvRaw.QuerySize( ) > MAX_CACHED_FILTER_BUFFER ) {
  932. _bufRecvRaw.FreeMemory();
  933. }
  934. _bufRecvTrans.Resize( 0 );
  935. //
  936. // Free pool items
  937. //
  938. while ( !IsListEmpty( &_PoolHead )) {
  939. pfpi = CONTAINING_RECORD( _PoolHead.Flink,
  940. FILTER_POOL_ITEM,
  941. _ListEntry );
  942. RemoveEntryList( &pfpi->_ListEntry );
  943. delete pfpi;
  944. }
  945. if ( _pFilterList )
  946. {
  947. FILTER_LIST::Dereference( _pFilterList );
  948. _pFilterList = NULL;
  949. }
  950. _fNotificationsDisabled = FALSE;
  951. } // Cleanup
  952. HTTP_FILTER::~HTTP_FILTER(
  953. VOID
  954. )
  955. /*++
  956. Routine Description:
  957. Destructor for HTTP filter class
  958. Arguments:
  959. Return Value:
  960. --*/
  961. {
  962. if ( _Overlapped.hEvent )
  963. CloseHandle( _Overlapped.hEvent );
  964. if ( _pFilterList )
  965. {
  966. DBGPRINTF(( DBG_CONTEXT,
  967. "[~HTTP_FILTER] Dereferencing _pFilterList at %lx\n",
  968. _pFilterList ));
  969. FILTER_LIST::Dereference( _pFilterList );
  970. _pFilterList = NULL;
  971. }
  972. #if 0 // Global filter lists are not dynamic so they're not counted
  973. if ( _pGlobalFilterList )
  974. {
  975. DBGPRINTF(( DBG_CONTEXT,
  976. "[~HTTP_FILTER] Dereferencing _pGlobalFilterList at %lx\n",
  977. _pGlobalFilterList ));
  978. FILTER_LIST::Dereference( _pGlobalFilterList );
  979. _pGlobalFilterList = NULL;
  980. }
  981. #endif
  982. delete [] _apvContexts;
  983. }
  984. BOOL
  985. HTTP_FILTER::ReadData(
  986. LPVOID lpBuffer,
  987. DWORD nBytesToRead,
  988. DWORD *pcbBytesRead,
  989. DWORD dwFlags
  990. )
  991. /*++
  992. Routine Description:
  993. This method reads data from the network and calls the
  994. filter dlls. It also handles data tracking on data overflow
  995. or underflow. The number of bytes read are translated
  996. bytes, which may be more or less then actual bytes transferred
  997. on the network.
  998. The user's buffer is used for the initial receive. If a filter comes
  999. back indicating it needs more data (got the first 8k of a 32k SSL message
  1000. for example) then we switch to using the _bufRecvRaw buffers.
  1001. Arguments:
  1002. lpBuffer - Destination buffer
  1003. nBytesToRead - Number of bytes to read
  1004. *pcbBytesRead - Number of bytes read
  1005. dwFlags - IO_FLAG values
  1006. Return Value:
  1007. TRUE on success, FALSE on failure (call GetLastError)
  1008. --*/
  1009. {
  1010. DWORD cbBytesRead = 0;
  1011. DWORD cbToCopy;
  1012. if ( pcbBytesRead )
  1013. {
  1014. *pcbBytesRead = 0;
  1015. }
  1016. _pbReadBuff = _pbClientBuff = (BYTE *) lpBuffer;
  1017. _cbReadBuff = _cbClientBuff = nBytesToRead;
  1018. _cbReadBuffUsed = 0;
  1019. //
  1020. // If there is old translated data that we need to give
  1021. // to the client, copy that now
  1022. //
  1023. if ( _cbRecvTrans )
  1024. {
  1025. cbToCopy = min( _cbRecvTrans, nBytesToRead );
  1026. memcpy( lpBuffer,
  1027. _bufRecvTrans.QueryPtr(),
  1028. cbToCopy );
  1029. if ( pcbBytesRead )
  1030. {
  1031. *pcbBytesRead = cbToCopy;
  1032. }
  1033. if ( _cbRecvTrans > cbToCopy )
  1034. {
  1035. _cbRecvTrans -= cbToCopy;
  1036. //
  1037. // This should be very rare this happens, so flag it and if
  1038. // it does happen often then add an offset counter
  1039. //
  1040. DBGPRINTF(( DBG_CONTEXT,
  1041. "[HTTP_FILTER::ReadData] PERF WARNING! In place buffer copy (%d bytes)!\n",
  1042. _cbRecvTrans ));
  1043. memmove( (BYTE *) _bufRecvTrans.QueryPtr(),
  1044. (BYTE *) _bufRecvTrans.QueryPtr() + cbToCopy,
  1045. _cbRecvTrans );
  1046. }
  1047. else
  1048. {
  1049. _cbRecvTrans = 0;
  1050. }
  1051. nBytesToRead -= cbToCopy;
  1052. _cbReadBuffUsed += cbToCopy;
  1053. //
  1054. // If there were any bytes from the previous request, just complete
  1055. // the request now. This prevents potentially blocking on a recv()
  1056. // with no data.
  1057. //
  1058. if ( dwFlags & IO_FLAG_ASYNC )
  1059. {
  1060. DBGPRINTF(( DBG_CONTEXT,
  1061. "[ReadData] Posting dummy completion\n" ));
  1062. if ( !_pRequest->PostCompletionStatus( cbToCopy ))
  1063. {
  1064. return FALSE;
  1065. }
  1066. }
  1067. return TRUE;
  1068. }
  1069. if ( dwFlags & IO_FLAG_SYNC )
  1070. {
  1071. BOOL fRet;
  1072. //
  1073. // Get the raw data, put it after any old raw data. We temporarily
  1074. // bump up the thread pool count so we don't eat all of the threads.
  1075. //
  1076. AtqSetInfo( AtqIncMaxPoolThreads, 0 );
  1077. fRet = TcpSockRecv(_pRequest->QueryClientConn()->QuerySocket(),
  1078. (char *) _pbReadBuff + _cbReadBuffUsed,
  1079. nBytesToRead,
  1080. &cbBytesRead,
  1081. 60 // 60s timeout
  1082. );
  1083. AtqSetInfo( AtqDecMaxPoolThreads, 0 );
  1084. if ( !fRet || (cbBytesRead == 0) )
  1085. {
  1086. return FALSE;
  1087. }
  1088. if ( !ContinueRawRead( cbBytesRead,
  1089. NO_ERROR,
  1090. NULL,
  1091. pcbBytesRead ))
  1092. {
  1093. return FALSE;
  1094. }
  1095. }
  1096. else
  1097. {
  1098. DBG_ASSERT( dwFlags & IO_FLAG_ASYNC );
  1099. //
  1100. // Hook the Atq IO completion routine so reads complete through
  1101. // ContinueRawRead
  1102. //
  1103. _OldAtqCompletion = (ATQ_COMPLETION) AtqContextSetInfo( QueryAtqContext(),
  1104. ATQ_INFO_COMPLETION,
  1105. (ULONG_PTR) ::ContinueRawRead );
  1106. _OldAtqContext = (PVOID) AtqContextSetInfo( QueryAtqContext(),
  1107. ATQ_INFO_COMPLETION_CONTEXT,
  1108. (ULONG_PTR) this );
  1109. if ( !_pRequest->ReadFile( _pbReadBuff + _cbReadBuffUsed,
  1110. nBytesToRead,
  1111. NULL,
  1112. IO_FLAG_ASYNC | IO_FLAG_NO_FILTER ))
  1113. {
  1114. AtqContextSetInfo( QueryAtqContext(),
  1115. ATQ_INFO_COMPLETION,
  1116. (ULONG_PTR) _OldAtqCompletion );
  1117. AtqContextSetInfo( QueryAtqContext(),
  1118. ATQ_INFO_COMPLETION_CONTEXT,
  1119. (ULONG_PTR) _OldAtqContext );
  1120. return FALSE;
  1121. }
  1122. }
  1123. return TRUE;
  1124. } // HTTP_FILTER::ReadData
  1125. VOID
  1126. ContinueRawRead(
  1127. PVOID Context,
  1128. DWORD BytesWritten,
  1129. DWORD CompletionStatus,
  1130. OVERLAPPED * lpo
  1131. )
  1132. {
  1133. HTTP_FILTER * pFilter;
  1134. pFilter = (HTTP_FILTER *) Context;
  1135. ((HTTP_FILTER *)Context)->ContinueRawRead( BytesWritten,
  1136. CompletionStatus,
  1137. lpo );
  1138. }
  1139. BOOL
  1140. HTTP_FILTER::ContinueRawRead(
  1141. DWORD cbBytesRead,
  1142. DWORD CompletionStatus,
  1143. OVERLAPPED * lpo,
  1144. DWORD * pcbRead
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. This method is the completion routine for an async (or sync) read.
  1149. Note : It's a sync read if the overlapped structure [lpo] is null and
  1150. a completion status [CompletionStatus] of NO_ERROR
  1151. Arguments:
  1152. cbBytesRead - Number of bytes read
  1153. CompletionStatus - status code of read operation
  1154. lpo - Pointer to overlapped structure
  1155. Return Value:
  1156. TRUE on success, FALSE on failure (call GetLastError)
  1157. --*/
  1158. {
  1159. PVOID pvOutData;
  1160. DWORD cbOutData;
  1161. BOOL fReadAgain;
  1162. BOOL fRequestFinished = FALSE;
  1163. DWORD cbToCopy;
  1164. BOOL fSyncRead = (lpo == NULL && CompletionStatus == NO_ERROR);
  1165. //
  1166. // Don't update _cbReadBuffUsed until we get the data translated
  1167. //
  1168. if ( lpo )
  1169. {
  1170. _pRequest->Dereference();
  1171. //
  1172. // If the socket has been closed get out. It's the responsibility of the
  1173. // caller to detect this
  1174. //
  1175. if ( cbBytesRead == 0 )
  1176. {
  1177. goto CompleteRequest;
  1178. }
  1179. }
  1180. if ( CompletionStatus )
  1181. {
  1182. goto CompleteRequest;
  1183. }
  1184. ReadAgain:
  1185. //
  1186. // Keeps track of the number of bytes the filter has *not* seen
  1187. //
  1188. _cbRecvRaw += cbBytesRead;
  1189. //
  1190. // Call the filters to translate the raw data. No need to check for
  1191. // any filters that need this notification as we wouldn't be here otherwise
  1192. //
  1193. // _cbReadBuffUsed is translated bytes, _cbRecvRaw is untranslated bytes
  1194. //
  1195. fReadAgain = FALSE;
  1196. if ( !NotifyRawReadDataFilters( _pbReadBuff + _cbReadBuffUsed,
  1197. _cbRecvRaw,
  1198. _cbReadBuff - _cbReadBuffUsed,
  1199. &pvOutData,
  1200. &cbOutData,
  1201. &fRequestFinished,
  1202. &fReadAgain ))
  1203. {
  1204. CompletionStatus = GetLastError();
  1205. goto CompleteRequest;
  1206. }
  1207. //
  1208. // If the filter indicated this connection should be finished, force
  1209. // a tear down of our connection state
  1210. //
  1211. if ( fRequestFinished )
  1212. {
  1213. CompletionStatus = WSAECONNRESET;
  1214. goto CompleteRequest;
  1215. }
  1216. if ( fReadAgain )
  1217. {
  1218. //
  1219. // If we need to read the next chunk, make sure it will fit in
  1220. // our read buffer. If it won't, then switch to our own buffer
  1221. // and issue the read from there
  1222. //
  1223. if ( QueryNextReadSize() > (_cbReadBuff - _cbRecvRaw ) )
  1224. {
  1225. if ( !_bufRecvRaw.Resize( _cbRecvRaw + QueryNextReadSize() ))
  1226. {
  1227. CompletionStatus = GetLastError();
  1228. goto CompleteRequest;
  1229. }
  1230. memcpy( _bufRecvRaw.QueryPtr(),
  1231. _pbReadBuff,
  1232. _cbRecvRaw );
  1233. _pbReadBuff = (BYTE *) _bufRecvRaw.QueryPtr();
  1234. _cbReadBuff = _bufRecvRaw.QuerySize();
  1235. }
  1236. if ( !_pRequest->ReadFile( _pbReadBuff + _cbRecvRaw,
  1237. QueryNextReadSize(),
  1238. pcbRead,
  1239. (lpo ? (IO_FLAG_ASYNC | IO_FLAG_NO_FILTER) :
  1240. (IO_FLAG_SYNC | IO_FLAG_NO_FILTER)) ))
  1241. {
  1242. CompletionStatus = GetLastError();
  1243. goto CompleteRequest;
  1244. }
  1245. //
  1246. // Operation aborted, set error and return
  1247. //
  1248. if ( pcbRead && *pcbRead == 0 )
  1249. {
  1250. SetLastError( ERROR_OPERATION_ABORTED );
  1251. return FALSE;
  1252. }
  1253. //
  1254. // If this is a sync request process the additional bytes now
  1255. //
  1256. if ( !lpo )
  1257. {
  1258. cbBytesRead = *pcbRead;
  1259. goto ReadAgain;
  1260. }
  1261. return TRUE;
  1262. }
  1263. //
  1264. // Adjust the byte counts for the bytes just translated.
  1265. //
  1266. _pRequest->IncrementBytesSeenByRawReadFilter( cbOutData );
  1267. _cbReadBuffUsed += cbOutData;
  1268. _cbRecvRaw = 0;
  1269. //
  1270. // If we weren't able to use the original client buffer, copy as many
  1271. // bytes as possible to the client's buffer now. We only hit this case
  1272. // if a filter indicated we need to read again.
  1273. //
  1274. if ( _pbReadBuff != _pbClientBuff )
  1275. {
  1276. cbToCopy = min( cbOutData, _cbClientBuff );
  1277. memcpy( _pbClientBuff,
  1278. pvOutData,
  1279. cbToCopy );
  1280. _cbReadBuffUsed = cbToCopy;
  1281. //
  1282. // If more bytes were translated then what the client
  1283. // requested us to read, save those away for the next
  1284. // read request
  1285. //
  1286. if ( cbOutData > _cbClientBuff )
  1287. {
  1288. _cbRecvTrans = cbOutData - _cbClientBuff;
  1289. if ( !_bufRecvTrans.Resize( _cbRecvTrans ))
  1290. {
  1291. CompletionStatus = GetLastError();
  1292. goto CompleteRequest;
  1293. }
  1294. memcpy( _bufRecvTrans.QueryPtr(),
  1295. (BYTE *) pvOutData + cbToCopy,
  1296. _cbRecvTrans );
  1297. }
  1298. }
  1299. if ( pcbRead )
  1300. {
  1301. *pcbRead = _cbReadBuffUsed;
  1302. }
  1303. //
  1304. // If this was an async request, reset the Atq information and complete
  1305. // the receive with _cbReadBuffUsed
  1306. //
  1307. CompleteRequest:
  1308. if (!fSyncRead)
  1309. {
  1310. //
  1311. // This is an async completion, the return is not used
  1312. //
  1313. AtqContextSetInfo( QueryAtqContext(),
  1314. ATQ_INFO_COMPLETION,
  1315. (ULONG_PTR) _OldAtqCompletion );
  1316. AtqContextSetInfo( QueryAtqContext(),
  1317. ATQ_INFO_COMPLETION_CONTEXT,
  1318. (ULONG_PTR) _OldAtqContext );
  1319. _OldAtqCompletion( _OldAtqContext,
  1320. _cbReadBuffUsed,
  1321. CompletionStatus,
  1322. NULL );
  1323. return TRUE;
  1324. }
  1325. return (CompletionStatus == NO_ERROR);
  1326. }
  1327. BOOL
  1328. HTTP_FILTER::SendData(
  1329. LPVOID lpBuffer,
  1330. DWORD nBytesToSend,
  1331. DWORD * pnBytesSent,
  1332. DWORD dwFlags
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This method calls the interested filters to do the appropriate data
  1337. transformation then sends the data.
  1338. Arguments:
  1339. lpBuffer - Destination buffer
  1340. nBytesToRead - Number of bytes to read
  1341. *pcbBytesRead - Number of bytes read
  1342. dwFlags - IO_FLAG values
  1343. Return Value:
  1344. TRUE on success, FALSE on failure (call GetLastError)
  1345. --*/
  1346. {
  1347. PVOID pvOutData;
  1348. DWORD cbOutData;
  1349. DWORD cbToCopy;
  1350. BOOL fRequestFinished = FALSE;
  1351. //
  1352. // We buffer any unsent data so indicate all the data was sent
  1353. //
  1354. if ( pnBytesSent )
  1355. *pnBytesSent = nBytesToSend;
  1356. pvOutData = lpBuffer;
  1357. cbOutData = nBytesToSend;
  1358. if ( IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA,
  1359. QueryReq()->IsSecurePort() ) &&
  1360. !NotifyRawSendDataFilters( lpBuffer,
  1361. nBytesToSend,
  1362. nBytesToSend,
  1363. &pvOutData,
  1364. &cbOutData,
  1365. &fRequestFinished ))
  1366. {
  1367. DBGPRINTF(( DBG_CONTEXT,
  1368. "[SendData] NotifyRawDataFilters failed with %d\n",
  1369. GetLastError()));
  1370. return FALSE;
  1371. }
  1372. if ( fRequestFinished )
  1373. {
  1374. //
  1375. // We have to return an error so the client doesn't think
  1376. // they will receive an IO completion. This may have odd
  1377. // manifestations
  1378. //
  1379. SetLastError( ERROR_OPERATION_ABORTED );
  1380. return FALSE;
  1381. }
  1382. if ( !_pRequest->WriteFile( pvOutData,
  1383. cbOutData,
  1384. &nBytesToSend,
  1385. dwFlags | IO_FLAG_NO_FILTER ))
  1386. {
  1387. DBGPRINTF(( DBG_CONTEXT,
  1388. "[SendData] Send failed with %d\n",
  1389. GetLastError()));
  1390. if ( pnBytesSent )
  1391. {
  1392. *pnBytesSent = (DWORD)SOCKET_ERROR;
  1393. }
  1394. return FALSE;
  1395. }
  1396. return TRUE;
  1397. }
  1398. BOOL
  1399. HTTP_FILTER::SendFile(
  1400. TS_OPEN_FILE_INFO * pGetFile,
  1401. HANDLE hFile,
  1402. DWORD dwOffset,
  1403. DWORD nBytesToWrite,
  1404. DWORD dwFlags,
  1405. PVOID pHead,
  1406. DWORD HeadLength,
  1407. PVOID pTail,
  1408. DWORD TailLength
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. This method simulates Winsock's TransmitFile with the addition
  1413. of running the data through the interested filters. This only
  1414. supports async IO.
  1415. Arguments:
  1416. pGetFile - Cached TS_OPEN_FILE_INFO to send
  1417. hFile - Overlapped IO file to send (if NULL, pGetFile used to get handle)
  1418. dwOffset - Offset from start of file
  1419. nBytesToWrite - Bytes of file to send, note zero (meaning send the whole
  1420. file) is not supported
  1421. dwFlags - IO_FLAGs
  1422. pHead - Optional pre-data to send
  1423. HeadLength - Number of bytes of pHead
  1424. pTail - Optional post data to send
  1425. TailLength - Number of bytes of pTail
  1426. Return Value:
  1427. TRUE on success, FALSE on failure (call GetLastError)
  1428. --*/
  1429. {
  1430. HANDLE hEvent;
  1431. DBG_ASSERT( (dwFlags & IO_FLAG_ASYNC) );
  1432. //
  1433. // We assume pHead points to header data. Send it synchronously, then
  1434. // we'll do chunk async sends for the file
  1435. //
  1436. if ( HeadLength )
  1437. {
  1438. DWORD cbSent;
  1439. if ( !SendData( pHead,
  1440. HeadLength,
  1441. &cbSent,
  1442. (dwFlags & ~IO_FLAG_ASYNC) | IO_FLAG_SYNC ))
  1443. {
  1444. DBGPRINTF(( DBG_CONTEXT,
  1445. "[SendFile] SendData failed with %d\n",
  1446. GetLastError()));
  1447. return FALSE;
  1448. }
  1449. }
  1450. if ( !nBytesToWrite )
  1451. {
  1452. if ( hFile )
  1453. {
  1454. BY_HANDLE_FILE_INFORMATION hfi;
  1455. if ( !GetFileInformationByHandle( hFile, &hfi ))
  1456. {
  1457. return FALSE;
  1458. }
  1459. if ( hfi.nFileSizeHigh )
  1460. {
  1461. SetLastError( ERROR_NOT_SUPPORTED );
  1462. return FALSE;
  1463. }
  1464. nBytesToWrite = hfi.nFileSizeLow;
  1465. }
  1466. else if ( pGetFile )
  1467. {
  1468. LARGE_INTEGER liSize;
  1469. if ( !pGetFile->QuerySize( liSize ) )
  1470. {
  1471. return FALSE;
  1472. }
  1473. nBytesToWrite = liSize.LowPart;
  1474. }
  1475. // else -- We are doing a file-less transmit
  1476. }
  1477. //
  1478. // Set up variables for doing the file transmit
  1479. //
  1480. _hFile = hFile;
  1481. _pFilterGetFile = pGetFile;
  1482. _cbFileBytesToWrite = nBytesToWrite;
  1483. _cbFileBytesSent = 0;
  1484. _cbFileData = 0;
  1485. _dwCompletionStatus = NO_ERROR;
  1486. _pTail = pTail;
  1487. _cbTailLength = TailLength;
  1488. _dwFlags = dwFlags;
  1489. //
  1490. // Save the event handle if we previously created one
  1491. //
  1492. if ( _Overlapped.hEvent )
  1493. {
  1494. hEvent = _Overlapped.hEvent;
  1495. }
  1496. else
  1497. {
  1498. if ( !_Overlapped.hEvent )
  1499. {
  1500. hEvent = IIS_CREATE_EVENT(
  1501. "HTTP_FILTER::_Overlapped::hEvent",
  1502. this,
  1503. TRUE,
  1504. FALSE
  1505. );
  1506. if ( !hEvent )
  1507. {
  1508. return FALSE;
  1509. }
  1510. }
  1511. }
  1512. memset( &_Overlapped, 0, sizeof( _Overlapped ));
  1513. _Overlapped.hEvent = hEvent;
  1514. _Overlapped.Offset = dwOffset;
  1515. if ( !_bufFileData.Resize( 8192 ))
  1516. {
  1517. return FALSE;
  1518. }
  1519. //
  1520. // Hook the ATQ completion routine so the caller only sees a single
  1521. // completion since we have to chunk the sends for the filters
  1522. //
  1523. // NOTE: If multiple requests over the same TCP session are being
  1524. // handled at once (not currently supported by protocol, but may
  1525. // eventually be) then there is a potential race condition between
  1526. // setting the context and setting the completion on the ATQ context
  1527. //
  1528. _OldAtqCompletion = (ATQ_COMPLETION) AtqContextSetInfo( QueryAtqContext(),
  1529. ATQ_INFO_COMPLETION,
  1530. (ULONG_PTR) FilterAtqCompletion );
  1531. _OldAtqContext = (PVOID) AtqContextSetInfo( QueryAtqContext(),
  1532. ATQ_INFO_COMPLETION_CONTEXT,
  1533. (ULONG_PTR) this );
  1534. //
  1535. // Kick off the first send
  1536. //
  1537. OnAtqCompletion( 0, NO_ERROR, NULL );
  1538. return TRUE;
  1539. }
  1540. VOID
  1541. FilterAtqCompletion(
  1542. PVOID Context,
  1543. DWORD BytesWritten,
  1544. DWORD CompletionStatus,
  1545. OVERLAPPED * lpo
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This function substitutes for the normal request's ATQ completion. It
  1550. is used to simulate an Async transmit file that passes all data through
  1551. the interested filters.
  1552. Arguments:
  1553. Context - Pointer to filter object
  1554. BytesWritten - Number of bytes written on last completion
  1555. CompletionStatus - Status of last send
  1556. lpo - Overlapped structure. NULL if error completion, non-null if IO comp.
  1557. --*/
  1558. {
  1559. HTTP_FILTER * pFilter;
  1560. pFilter = (HTTP_FILTER *) Context;
  1561. ((HTTP_FILTER *)Context)->OnAtqCompletion( BytesWritten,
  1562. CompletionStatus,
  1563. lpo );
  1564. }
  1565. VOID
  1566. HTTP_FILTER::OnAtqCompletion(
  1567. DWORD BytesWritten,
  1568. DWORD CompletionStatus,
  1569. OVERLAPPED * lpo
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. This method handles ATQ completions. It is used to simulate an Async
  1574. transmit file that passes all data through the interested filters.
  1575. Arguments:
  1576. BytesWritten - Number of bytes written on last completion
  1577. CompletionStatus - Status of last send
  1578. lpo - !NULL if this is a completion from an async IO
  1579. --*/
  1580. {
  1581. DWORD dwIoFlag;
  1582. DWORD BytesRead;
  1583. DWORD dwToRead;
  1584. IF_DEBUG( CONNECTION )
  1585. {
  1586. DBGPRINTF(( DBG_CONTEXT,
  1587. "HTTP_FILTER::OnAtqCompletion: Last IO error %lu Bytes = %d IsIO = %s\n",
  1588. CompletionStatus,
  1589. BytesWritten,
  1590. lpo != NULL ? "TRUE" : "FALSE" ));
  1591. }
  1592. //
  1593. // Decrement the outstanding IO count
  1594. //
  1595. if ( lpo )
  1596. _pRequest->Dereference();
  1597. //
  1598. // If an error occurred on the completion and we haven't previous recorded
  1599. // an error, then record this one. This prevents overwriting the real
  1600. // status code from a cancelled IO error.
  1601. //
  1602. if ( CompletionStatus && !_dwCompletionStatus )
  1603. {
  1604. _dwCompletionStatus = CompletionStatus;
  1605. }
  1606. //
  1607. // If an error occurred, restore the old ATQ information and forward
  1608. // the error
  1609. //
  1610. if ( _dwCompletionStatus ||
  1611. _cbFileBytesSent >= _cbFileBytesToWrite )
  1612. {
  1613. // In the file-less case _cbFileBytesSent ==
  1614. // _cbFileBytesToWrite == 0, so we will send the tail
  1615. // if there is no error.
  1616. if ( !_dwCompletionStatus && _cbTailLength )
  1617. {
  1618. DWORD cbSent;
  1619. if ( !SendData( _pTail,
  1620. _cbTailLength,
  1621. &cbSent,
  1622. (_dwFlags & ~IO_FLAG_ASYNC) | IO_FLAG_SYNC ))
  1623. {
  1624. DBGPRINTF(( DBG_CONTEXT,
  1625. "[SendFile] SendData failed with %d\n",
  1626. GetLastError()));
  1627. CompletionStatus = GetLastError();
  1628. if ( CompletionStatus && !_dwCompletionStatus )
  1629. _dwCompletionStatus = CompletionStatus;
  1630. }
  1631. }
  1632. goto ErrorExit;
  1633. }
  1634. //
  1635. // Read the next chunk of data from the file
  1636. //
  1637. dwToRead = _bufFileData.QuerySize();
  1638. if ( dwToRead > _cbFileBytesToWrite - _cbFileBytesSent ) {
  1639. dwToRead = _cbFileBytesToWrite - _cbFileBytesSent;
  1640. }
  1641. DBG_ASSERT(_dwCompletionStatus == NO_ERROR);
  1642. if ( _pFilterGetFile && _pFilterGetFile->QueryFileBuffer() )
  1643. {
  1644. // Fast path. We already have a buffer with the file contents, so
  1645. // read from the buffer directly.
  1646. memcpy( (PCHAR) _bufFileData.QueryPtr(),
  1647. _pFilterGetFile->QueryFileBuffer() + _Overlapped.Offset,
  1648. dwToRead );
  1649. BytesRead = dwToRead;
  1650. }
  1651. else
  1652. {
  1653. if ( !DoSynchronousReadFile(
  1654. _pFilterGetFile ?
  1655. _pFilterGetFile->QueryFileHandle() : _hFile,
  1656. (PCHAR)_bufFileData.QueryPtr(),
  1657. dwToRead,
  1658. &BytesRead,
  1659. &_Overlapped ))
  1660. {
  1661. _dwCompletionStatus = GetLastError();
  1662. DBGPRINTF(( DBG_CONTEXT,
  1663. "[Filter AtqCompletion] ReadFile failed with %d\n",
  1664. _dwCompletionStatus ));
  1665. goto ErrorExit;
  1666. }
  1667. }
  1668. //
  1669. // Now send the data through the filters
  1670. //
  1671. dwIoFlag = IO_FLAG_ASYNC;
  1672. _cbFileBytesSent += BytesRead;
  1673. _Overlapped.Offset += BytesRead;
  1674. if ( !SendData( _bufFileData.QueryPtr(),
  1675. BytesRead,
  1676. NULL,
  1677. dwIoFlag ))
  1678. {
  1679. _dwCompletionStatus = GetLastError();
  1680. DBGPRINTF(( DBG_CONTEXT,
  1681. "[Filter AtqCompletion] SendData failed with %d\n",
  1682. CompletionStatus ));
  1683. goto ErrorExit;
  1684. }
  1685. return;
  1686. ErrorExit:
  1687. IF_DEBUG( CONNECTION )
  1688. {
  1689. DBGPRINTF(( DBG_CONTEXT,
  1690. "HTTP_FILTER::OnAtqCompletion: Restoring AtqContext, "
  1691. "Bytes Sent = %d, Status = %d, IsIO = %s\n",
  1692. _cbFileBytesSent,
  1693. _dwCompletionStatus,
  1694. (lpo == NULL ? "FALSE" : "TRUE")));
  1695. }
  1696. AtqContextSetInfo( QueryAtqContext(),
  1697. ATQ_INFO_COMPLETION,
  1698. (ULONG_PTR) _OldAtqCompletion );
  1699. AtqContextSetInfo( QueryAtqContext(),
  1700. ATQ_INFO_COMPLETION_CONTEXT,
  1701. (ULONG_PTR) _OldAtqContext );
  1702. //
  1703. // Forward the error onto the old ATQ completion handler. We always
  1704. // pass an lpo of NULL because we've already decremented the IO
  1705. // ref count.
  1706. //
  1707. // NOTE: 'this' may be deleted in this callback!
  1708. //
  1709. _OldAtqCompletion( _OldAtqContext,
  1710. _cbFileBytesSent,
  1711. CompletionStatus,
  1712. NULL );
  1713. return;
  1714. }
  1715. BOOL
  1716. HTTP_FILTER::DisableNotification(
  1717. IN DWORD dwNotification
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. Called when a filter wants to disable one/more of its own notifications
  1722. for the given request.
  1723. Arguments:
  1724. dwNotification - Mask of notifications to disable for this request
  1725. --*/
  1726. {
  1727. DBG_ASSERT( _pFilterList || _pGlobalFilterList );
  1728. if ( !_fNotificationsDisabled )
  1729. {
  1730. //
  1731. // All subsequent calls to IsNotificationNeeded() and NotifyFilter() must
  1732. // use local copy of flags to determine action.
  1733. //
  1734. _fNotificationsDisabled = TRUE;
  1735. //
  1736. // Copy notification tables created in the FILTER_LIST objects
  1737. //
  1738. if ( !_BuffSecureArray.Resize( QueryFilterList()->QuerySecureArray()->QuerySize() ) ||
  1739. !_BuffNonSecureArray.Resize( QueryFilterList()->QueryNonSecureArray()->QuerySize() ) )
  1740. {
  1741. return FALSE;
  1742. }
  1743. memcpy( _BuffSecureArray.QueryPtr(),
  1744. QueryFilterList()->QuerySecureArray()->QueryPtr(),
  1745. QueryFilterList()->QuerySecureArray()->QuerySize() );
  1746. memcpy( _BuffNonSecureArray.QueryPtr(),
  1747. QueryFilterList()->QueryNonSecureArray()->QueryPtr(),
  1748. QueryFilterList()->QueryNonSecureArray()->QuerySize() );
  1749. }
  1750. //
  1751. // Disable the appropriate filter in our local table
  1752. //
  1753. ((DWORD*)_BuffSecureArray.QueryPtr())[ QueryCurrentDll() ] &=
  1754. ~dwNotification;
  1755. ((DWORD*)_BuffNonSecureArray.QueryPtr())[ QueryCurrentDll() ] &=
  1756. ~dwNotification;
  1757. //
  1758. // Calculate the aggregate notification status for our local scenario
  1759. // NYI: Might want to defer this operation?
  1760. //
  1761. _dwSecureNotifications = 0;
  1762. _dwNonSecureNotifications = 0;
  1763. for( DWORD i = 0; i < QueryFilterList()->QueryFilterCount(); i++ )
  1764. {
  1765. _dwSecureNotifications |= ((DWORD*)_BuffSecureArray.QueryPtr())[i];
  1766. _dwNonSecureNotifications |= ((DWORD*)_BuffNonSecureArray.QueryPtr())[i];
  1767. }
  1768. return TRUE;
  1769. }
  1770. BOOL
  1771. HTTP_FILTER::SetFilterList(
  1772. IN FILTER_LIST *pFilterList
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Sets the filter list associated with this object
  1777. Arguments :
  1778. pFilterList - new filter list
  1779. Returns:
  1780. Nothing
  1781. --*/
  1782. {
  1783. DBG_ASSERT( !_pFilterList );
  1784. FILTER_LIST *pOldList = _pFilterList;
  1785. if ( pFilterList )
  1786. {
  1787. //
  1788. // This function is called during HTTP_REQUEST::Parse, when a -global- filter
  1789. // may already have disabled some notifications during READ_RAW processing
  1790. // and thus set the _fNotificationsDisabled flag, so we'll leave the flag
  1791. // as-is [it's reset at the end of each request and connection, so we're
  1792. // not going to be using a stale value].
  1793. //
  1794. // The first time a notification is disabled, we make a local copy
  1795. // of the notification flag arrays from the filter list and make the modifications
  1796. // to our local copy. Hence, when the filter list is (re)set, the notification
  1797. // arrays of the new filter list and the local copies have to be merged, since we
  1798. // want to keep our old flags as well as picking up the flags for the new filters
  1799. // that might be in the list.
  1800. //
  1801. //_fNotificationsDisabled = FALSE; //intentionally commented out !
  1802. pFilterList->Reference();
  1803. if ( _fNotificationsDisabled )
  1804. {
  1805. if ( !MergeNotificationArrays( pFilterList,
  1806. TRUE ) ||
  1807. !MergeNotificationArrays( pFilterList,
  1808. FALSE ) )
  1809. {
  1810. pFilterList->Dereference( pFilterList );
  1811. return FALSE;
  1812. }
  1813. }
  1814. _pFilterList = pFilterList;
  1815. }
  1816. return TRUE;
  1817. }
  1818. BOOL
  1819. HTTP_FILTER::MergeNotificationArrays(
  1820. FILTER_LIST *pFilterList,
  1821. BOOL fSecure
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. This is called when the filter list for this HTTP_FILTER object needs to be replaced
  1826. with a new list and we need to merge the arrays holding the notification flags. See
  1827. comments in HTTP_FILTER::SetFilterList
  1828. Arguments:
  1829. pFilterList - filter list whose notification flags need to be incorporated
  1830. fSecure - flag indicating whether secure/nonsecure arrays are to be merged
  1831. Returns:
  1832. Nothing
  1833. --*/
  1834. {
  1835. DWORD dwNotifications = 0;
  1836. DWORD *adwOldNotifArray = NULL;
  1837. DWORD *adwMergedArray = NULL;
  1838. DWORD *adwNewNotifArray = NULL;
  1839. DWORD iOldFilterPos = 0;
  1840. HTTP_FILTER_DLL *pFilterDll = NULL;
  1841. BUFFER BuffMergedArray;
  1842. if ( !BuffMergedArray.Resize( fSecure ? pFilterList->QuerySecureArray()->QuerySize() :
  1843. pFilterList->QueryNonSecureArray()->QuerySize() ) )
  1844. {
  1845. return FALSE;
  1846. }
  1847. if ( fSecure )
  1848. {
  1849. if ( !_BuffSecureArray.Resize( pFilterList->QuerySecureArray()->QuerySize() ) )
  1850. {
  1851. return FALSE;
  1852. }
  1853. }
  1854. else
  1855. {
  1856. if ( !_BuffNonSecureArray.Resize( pFilterList->QueryNonSecureArray()->QuerySize() ) )
  1857. {
  1858. return FALSE;
  1859. }
  1860. }
  1861. adwNewNotifArray = (DWORD *) (fSecure ? pFilterList->QuerySecureArray()->QueryPtr() :
  1862. pFilterList->QueryNonSecureArray()->QueryPtr() );
  1863. adwMergedArray = (DWORD *) BuffMergedArray.QueryPtr();
  1864. //
  1865. // This gets a little tricky : we have to walk through the present
  1866. // notification arrays and the notification array for the new filter list
  1867. // and merge them - all the notification flags for the filters in the old
  1868. // list should be preserved, and the notifications for the new filters
  1869. // need to be added to the notification array
  1870. //
  1871. for ( DWORD i = 0; i < pFilterList->QueryFilterCount(); i++ )
  1872. {
  1873. //
  1874. // If the old filter list had an entry for this filter, we want to
  1875. // preserve those notification flags
  1876. //
  1877. if ( ( pFilterDll = QueryFilterList()->HasFilterDll( pFilterList->QueryDll( i ) ) ) )
  1878. {
  1879. adwMergedArray[i] = QueryFilterNotifications( pFilterDll,
  1880. fSecure );
  1881. }
  1882. //
  1883. // New filter
  1884. //
  1885. else
  1886. {
  1887. adwMergedArray[i] = adwNewNotifArray[i];
  1888. }
  1889. }
  1890. //
  1891. // Copy merged array
  1892. //
  1893. memcpy( (fSecure ? _BuffSecureArray.QueryPtr() :
  1894. _BuffNonSecureArray.QueryPtr() ),
  1895. BuffMergedArray.QueryPtr(),
  1896. BuffMergedArray.QuerySize() );
  1897. return TRUE;
  1898. }
  1899. BOOL
  1900. HTTP_FILTER::ParseSendHeaders(
  1901. VOID
  1902. )
  1903. /*++
  1904. Routine Description:
  1905. Parses the list of headers the server is about to send and places them
  1906. in the _SendHeaders parameter list for subsequent retrieval by the ISAPI
  1907. Filter
  1908. --*/
  1909. {
  1910. const CHAR * pch;
  1911. CHAR ch;
  1912. DWORD cbHeaders = strlen( _pchSendHeaders );
  1913. const CHAR * pchEnd = _pchSendHeaders + cbHeaders;
  1914. const CHAR * pchHeader;
  1915. const CHAR * pchEndHeader;
  1916. const CHAR * pchValue;
  1917. const CHAR * pchEndValue;
  1918. const CHAR * pchNext;
  1919. DBG_ASSERT( !_fSendHeadersParsed );
  1920. //
  1921. // We don't want the PARAM_LIST to canon the headers because it
  1922. // will collapse the WWW-Authenticate: headers to a comma separated
  1923. // list which will mess up clients even though technically this is allowed
  1924. // by the HTTP spec
  1925. //
  1926. _SendHeaders.SetIsCanonicalized( TRUE );
  1927. //
  1928. // Grab the first line and add it as a special value "status"
  1929. //
  1930. pch = pchNext = (const CHAR *) memchr( _pchSendHeaders, '\n', cbHeaders );
  1931. if ( !pch )
  1932. return TRUE;
  1933. if ( pch > _pchSendHeaders && pch[-1] == '\r' )
  1934. {
  1935. pch--;
  1936. }
  1937. if ( !_SendHeaders.AddEntry( "status",
  1938. 6,
  1939. _pchSendHeaders,
  1940. DIFF(pch - _pchSendHeaders) ))
  1941. {
  1942. return FALSE;
  1943. }
  1944. //
  1945. // Now deal with the rest of the headers
  1946. //
  1947. pchHeader = pchNext + 1;
  1948. cbHeaders = DIFF(pchEnd - pchHeader);
  1949. while ( pchNext = (LPSTR)memchr( pchHeader, '\n', cbHeaders ) )
  1950. {
  1951. if ( pchValue = (LPSTR)memchr( pchHeader, ':', DIFF(pchNext - pchHeader) ) )
  1952. {
  1953. UINT ch = *(PBYTE)++pchValue;
  1954. pchEndHeader = pchValue;
  1955. int cName = DIFF(pchValue - pchHeader);
  1956. if ( _HTTP_IS_LINEAR_SPACE( (CHAR)ch ) )
  1957. {
  1958. while ( _HTTP_IS_LINEAR_SPACE( *(PBYTE)++pchValue ) )
  1959. ;
  1960. }
  1961. if ( (pchNext > pchValue) && (pchNext[-1] == '\r') )
  1962. {
  1963. pchEndValue = pchNext - 1;
  1964. }
  1965. else
  1966. {
  1967. pchEndValue = pchNext;
  1968. }
  1969. if ( !_SendHeaders.AddEntry( pchHeader,
  1970. DIFF(pchEndHeader - pchHeader),
  1971. pchValue,
  1972. DIFF(pchEndValue - pchValue) ))
  1973. {
  1974. return FALSE;
  1975. }
  1976. }
  1977. else
  1978. {
  1979. if ( (*pchHeader == '\r') || (*pchHeader == '\n') )
  1980. {
  1981. pchHeader = pchNext + 1;
  1982. //
  1983. // If a body was specified, add it as a special value
  1984. //
  1985. if ( pchEnd - pchHeader > 1 )
  1986. {
  1987. if ( !_SendHeaders.AddEntry( "body",
  1988. sizeof("body") - 1,
  1989. pchHeader,
  1990. DIFF(pchEnd - pchHeader) ))
  1991. {
  1992. return FALSE;
  1993. }
  1994. }
  1995. break;
  1996. }
  1997. }
  1998. pchHeader = pchNext + 1;
  1999. cbHeaders = DIFF(pchEnd - pchHeader);
  2000. }
  2001. _fSendHeadersParsed = TRUE;
  2002. return TRUE;
  2003. }
  2004. BOOL
  2005. HTTP_FILTER::BuildNewSendHeaders(
  2006. BUFFER * pHeaderBuff
  2007. )
  2008. /*++
  2009. Routine Description:
  2010. Takes the set of send headers and builds up an HTTP response, only used
  2011. when a header has been changed
  2012. Arguments:
  2013. pHeaderBuff - Receives HTTP response headers
  2014. Return Value:
  2015. TRUE on success, FALSE on failure
  2016. --*/
  2017. {
  2018. PVOID Cookie = NULL;
  2019. CHAR * pch;
  2020. CHAR * pszTail;
  2021. CHAR * pszField;
  2022. DWORD cbField;
  2023. CHAR * pszValue;
  2024. DWORD cbValue;
  2025. pszTail = (CHAR *) pHeaderBuff->QueryPtr();
  2026. *pszTail = '\0';
  2027. pch = _SendHeaders.FindValue( "status", NULL, &cbValue );
  2028. if ( !pch )
  2029. {
  2030. //
  2031. // Somebody deleted the status or this is a point nine request
  2032. // Supply a default and assume the filter really wanted to send a
  2033. // header response
  2034. //
  2035. if (!g_ReplyWith11)
  2036. {
  2037. pch = "HTTP/1.0 200 Ok";
  2038. }
  2039. else
  2040. {
  2041. pch = "HTTP/1.1 200 Ok";
  2042. }
  2043. cbValue = sizeof( "HTTP/1.0 200 Ok" ) - sizeof(CHAR);
  2044. }
  2045. if ( !pHeaderBuff->Resize( cbValue + 1, 512 ))
  2046. {
  2047. return FALSE;
  2048. }
  2049. pszTail = (CHAR *) pHeaderBuff->QueryPtr();
  2050. CopyMemory( pszTail, pch, cbValue + 1 );
  2051. pszTail += cbValue;
  2052. *pszTail = '\r';
  2053. pszTail++;
  2054. *pszTail = '\n';
  2055. pszTail++;
  2056. while ( Cookie = _SendHeaders.NextPair( Cookie,
  2057. &pszField,
  2058. &cbField,
  2059. &pszValue,
  2060. &cbValue ))
  2061. {
  2062. //
  2063. // Ignore "status" and "body"
  2064. //
  2065. if ( !memcmp( pszField, "status", sizeof("status") ) ||
  2066. !memcmp( pszField, "body", sizeof("body") ))
  2067. {
  2068. continue;
  2069. }
  2070. //
  2071. // Make sure there's room for the space, plus two '\r\n'
  2072. //
  2073. pch = (CHAR *) pHeaderBuff->QueryPtr();
  2074. if ( !pHeaderBuff->Resize( DIFF(pszTail - pch) + cbValue + cbField + 6, 128 ))
  2075. {
  2076. return FALSE;
  2077. }
  2078. //
  2079. // Watch for pointer shift
  2080. //
  2081. if ( pch != pHeaderBuff->QueryPtr() )
  2082. {
  2083. pszTail = (CHAR *) pHeaderBuff->QueryPtr() + (pszTail - pch);
  2084. }
  2085. CopyMemory( pszTail, pszField, cbField + 1 );
  2086. pszTail += cbField;
  2087. *pszTail = ' ';
  2088. pszTail++;
  2089. CopyMemory( pszTail, pszValue, cbValue + 1 );
  2090. pszTail += cbValue;
  2091. *pszTail = '\r';
  2092. pszTail++;
  2093. *pszTail = '\n';
  2094. pszTail++;
  2095. }
  2096. *pszTail = '\r';
  2097. pszTail++;
  2098. *pszTail = '\n';
  2099. pszTail++;
  2100. //
  2101. // Add the body if one was specified
  2102. //
  2103. pszValue = _SendHeaders.FindValue( "body", NULL, &cbValue );
  2104. if ( pszValue )
  2105. {
  2106. pch = (CHAR *) pHeaderBuff->QueryPtr();
  2107. if ( !pHeaderBuff->Resize( DIFF(pszTail - pch) + cbValue + 1 ))
  2108. {
  2109. return FALSE;
  2110. }
  2111. if ( pch != pHeaderBuff->QueryPtr() )
  2112. {
  2113. pszTail = (CHAR *) pHeaderBuff->QueryPtr() + (pszTail - pch);
  2114. }
  2115. CopyMemory( pszTail, pszValue, cbValue + 1 );
  2116. }
  2117. else
  2118. {
  2119. *pszTail = '\0';
  2120. }
  2121. return TRUE;
  2122. }
  2123. DWORD
  2124. HTTP_FILTER::QueryFilterNotifications( HTTP_FILTER_DLL *pFilterDll,
  2125. BOOL fSecure )
  2126. /*++
  2127. Routine Description:
  2128. Retrieves the notification flags for a given filter dll
  2129. Arguments:
  2130. pFilterDll - filter dll whose notifications are to be retrieved
  2131. fSecure - flag indicating whether secure/insecure port notifications are to be retrieved
  2132. Return Value:
  2133. Notification flags for filter; zero if filter isn't found
  2134. --*/
  2135. {
  2136. FILTER_LIST *pFilterList = QueryFilterList();
  2137. DWORD cFilterCount = pFilterList->QueryFilterCount();
  2138. for ( DWORD i = 0; i < cFilterCount ; i++ )
  2139. {
  2140. if ( pFilterList->QueryDll( i ) == pFilterDll )
  2141. {
  2142. if ( _fNotificationsDisabled )
  2143. {
  2144. return (((DWORD *) (fSecure ? _BuffSecureArray.QueryPtr() :
  2145. _BuffNonSecureArray.QueryPtr()))[i]);
  2146. }
  2147. else
  2148. {
  2149. return (fSecure ? pFilterDll->QuerySecureFlags() :
  2150. pFilterDll->QueryNonsecureFlags() );
  2151. }
  2152. }
  2153. }
  2154. return 0;
  2155. }
  2156. /*****************************************************************/
  2157. BOOL
  2158. WINAPI
  2159. ServerFilterCallback(
  2160. HTTP_FILTER_CONTEXT * pfc,
  2161. enum SF_REQ_TYPE sf,
  2162. void * pData,
  2163. ULONG_PTR ul1,
  2164. ULONG_PTR ul2
  2165. )
  2166. /*++
  2167. Routine Description:
  2168. This method handles a gateway request to a server extension DLL
  2169. Arguments:
  2170. Return Value:
  2171. TRUE on success, FALSE on failure
  2172. --*/
  2173. {
  2174. HTTP_REQ_BASE * pRequest;
  2175. HTTP_FILTER * pFilter;
  2176. STACK_STR( str, MAX_PATH);;
  2177. STACK_STR( strResp, MAX_PATH);;
  2178. STACK_STR( strURL, MAX_PATH);
  2179. UINT cb;
  2180. int n;
  2181. DWORD CurrentDll;
  2182. HTTP_FILTER_DLL * pFilterDll;
  2183. DWORD dwAuth;
  2184. BOOL fFinished;
  2185. DWORD Status;
  2186. DWORD Win32Status;
  2187. W3_SERVER_INSTANCE* pInst;
  2188. DWORD dwIOFlags;
  2189. //
  2190. // Check for valid parameters
  2191. //
  2192. if ( !pfc ||
  2193. !pfc->ServerContext )
  2194. {
  2195. DBGPRINTF(( DBG_CONTEXT,
  2196. "[ServerExtensionCallback: Extension passed invalid parameters\r\n"));
  2197. SetLastError( ERROR_INVALID_PARAMETER );
  2198. return FALSE;
  2199. }
  2200. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2201. pRequest = pFilter->QueryReq();
  2202. //
  2203. // Handle the server extension's request
  2204. //
  2205. switch ( sf )
  2206. {
  2207. case SF_REQ_SEND_RESPONSE_HEADER:
  2208. //
  2209. // Save the client context context because the client may call
  2210. // Send headers just after changing the context and we're about to
  2211. // write over it when we do the raw send notifications
  2212. //
  2213. CurrentDll = pFilter->QueryCurrentDll();
  2214. DBG_ASSERT( CurrentDll != INVALID_DLL );
  2215. pFilter->SetClientContext( CurrentDll, pfc->pFilterContext );
  2216. //
  2217. // If we're doing a send header from a Raw data notification then we need
  2218. // to notify only the filters down the food chain so save the current
  2219. // filter and set the start point in the list to the next filter (remember
  2220. // raw sends walk the list backwards so encryption filters are last)
  2221. //
  2222. dwIOFlags = IO_FLAG_SYNC;
  2223. if ( pFilter->IsInRawNotification() )
  2224. {
  2225. //
  2226. // If this is the first filter in the list, then there's nobody that
  2227. // needs to be notified
  2228. //
  2229. if ( pFilter->IsFirstFilter( CurrentDll ) )
  2230. {
  2231. dwIOFlags |= IO_FLAG_NO_FILTER;
  2232. }
  2233. else
  2234. {
  2235. pFilter->SetCurrentDll( CurrentDll - 1 );
  2236. }
  2237. }
  2238. if ( pData )
  2239. {
  2240. Status = atoi( (PCSTR)pData );
  2241. if ( Status == HT_DENIED )
  2242. {
  2243. //
  2244. // Only set the reason as denied_filter if we're not doing
  2245. // denied access filter processing.
  2246. //
  2247. if ( !pFilter->ProcessingAccessDenied() )
  2248. {
  2249. pRequest->SetDeniedFlags( SF_DENIED_FILTER );
  2250. }
  2251. Win32Status = ERROR_ACCESS_DENIED;
  2252. pRequest->SetAuthenticationRequested( TRUE );
  2253. //
  2254. // If we do not have Metadata yet but we have an instance
  2255. // then read metadata so that WWW authentication headers can
  2256. // be properly generated
  2257. //
  2258. if ( pRequest->QueryW3Instance() &&
  2259. !pRequest->QueryMetaData() &&
  2260. pRequest->QueryHeaderList()->FastMapQueryValue( HM_URL ) )
  2261. {
  2262. ((HTTP_REQUEST*)pRequest)->OnURL( (LPSTR)pRequest->QueryHeaderList()
  2263. ->FastMapQueryValue( HM_URL ) );
  2264. }
  2265. }
  2266. else
  2267. {
  2268. Win32Status = NO_ERROR;
  2269. }
  2270. }
  2271. else
  2272. {
  2273. Status = HT_OK;
  2274. Win32Status = NO_ERROR;
  2275. }
  2276. pRequest->SetState( pRequest->QueryState(),
  2277. Status,
  2278. Win32Status );
  2279. if ( !pRequest->SendHeader( (CHAR *) pData,
  2280. (((CHAR *) ul1) ? ((CHAR *) ul1) : "\r\n"),
  2281. dwIOFlags,
  2282. &fFinished ))
  2283. {
  2284. pFilter->SetCurrentDll( CurrentDll );
  2285. return FALSE;
  2286. }
  2287. //
  2288. // CODEWORK - need general method of handling an early finish
  2289. // indication (have flag and drop subsequent sends in bit bucket?
  2290. // return an error to filter?)
  2291. //
  2292. DBG_ASSERT( !fFinished );
  2293. pFilter->SetCurrentDll( CurrentDll );
  2294. break;
  2295. case SF_REQ_ADD_HEADERS_ON_DENIAL:
  2296. {
  2297. BOOL fOK = TRUE;
  2298. DWORD cb = 0;
  2299. CHAR *pchHeaders = NULL;
  2300. if ( !pData )
  2301. {
  2302. SetLastError( ERROR_INVALID_PARAMETER );
  2303. return FALSE;
  2304. }
  2305. fOK = pRequest->QueryDenialHeaders()->Append( (CHAR *) pData );
  2306. if ( fOK )
  2307. {
  2308. //
  2309. // Need to make sure that the header ends with a CR-LF
  2310. //
  2311. cb = pRequest->QueryDenialHeaders()->QueryCCH();
  2312. pchHeaders = pRequest->QueryDenialHeaders()->QueryStr();
  2313. if ( cb < 2 ||
  2314. ( !(pchHeaders[cb - 2] == '\r' && pchHeaders[cb - 1] == '\n' ) ) )
  2315. {
  2316. fOK = pRequest->QueryDenialHeaders()->Append( (CHAR *) "\r\n" );
  2317. }
  2318. }
  2319. return fOK;
  2320. }
  2321. case SF_REQ_SET_NEXT_READ_SIZE:
  2322. if ( (ul1 == 0) || (ul1 > 0x8000000) )
  2323. {
  2324. SetLastError( ERROR_INVALID_PARAMETER );
  2325. return FALSE;
  2326. }
  2327. pFilter->SetNextReadSize( (DWORD) ul1 );
  2328. return TRUE;
  2329. case SF_REQ_SET_PROXY_INFO:
  2330. //
  2331. // ul1 contains the proxy flags to set for this request (which right
  2332. // now is only On or Off).
  2333. //
  2334. pRequest->SetProxyRequest( (DWORD) ul1 & 0x00000001 );
  2335. break;
  2336. case SF_REQ_SET_CERTIFICATE_INFO:
  2337. pFilterDll = pFilter->QueryFilterList()->QueryDll(
  2338. pFilter->QueryCurrentDll() );
  2339. return pRequest->SetCertificateInfo(
  2340. (PHTTP_FILTER_CERTIFICATE_INFO)pData,
  2341. (CtxtHandle*)ul1,
  2342. (HANDLE)ul2,
  2343. pFilterDll );
  2344. case SF_REQ_GET_PROPERTY:
  2345. pInst = pRequest->QueryW3InstanceAggressively();
  2346. dwAuth = pRequest->QueryMetaData() ? pRequest->QueryAuthentication() : 0;
  2347. switch ( ul1 )
  2348. {
  2349. case SF_PROPERTY_GET_INSTANCE_ID:
  2350. *(LPVOID*)pData = (LPVOID)pInst;
  2351. break;
  2352. #if 0 // Unused
  2353. case SF_PROPERTY_CLIENT_CERT_ENABLED:
  2354. *(LPBOOL)pData = !!(dwAuth & INET_INFO_AUTH_CERT_AUTH);
  2355. break;
  2356. #endif
  2357. case SF_PROPERTY_MD5_ENABLED:
  2358. *(LPBOOL)pData = !!(dwAuth & INET_INFO_AUTH_MD5_AUTH);
  2359. break;
  2360. #if 0 // Unused
  2361. case SF_PROPERTY_DIR_MAP_CERT:
  2362. *(LPBOOL)pData = !!(dwAuth & INET_INFO_CERT_MAP);
  2363. break;
  2364. #endif
  2365. case SF_PROPERTY_DIGEST_SSP_ENABLED:
  2366. if ( pRequest->QueryMetaData() )
  2367. {
  2368. *(LPBOOL)pData = pRequest->QueryMetaData()->QueryUseDigestSSP();
  2369. }
  2370. else
  2371. {
  2372. *(LPBOOL)pData = FALSE;
  2373. }
  2374. break;
  2375. case SF_PROPERTY_GET_CERT11_MAPPER:
  2376. if ( pInst )
  2377. {
  2378. *(LPVOID*)pData = pInst->QueryMapper( MT_CERT11 );
  2379. }
  2380. else
  2381. {
  2382. SetLastError( ERROR_INVALID_PARAMETER );
  2383. return FALSE;
  2384. }
  2385. break;
  2386. case SF_PROPERTY_GET_RULE_MAPPER:
  2387. if ( pInst )
  2388. {
  2389. *(LPVOID*)pData = pInst->QueryMapper( MT_CERTW );
  2390. }
  2391. else
  2392. {
  2393. SetLastError( ERROR_INVALID_PARAMETER );
  2394. return FALSE;
  2395. }
  2396. break;
  2397. case SF_PROPERTY_GET_MD5_MAPPER:
  2398. if ( pInst )
  2399. {
  2400. *(LPVOID*)pData = pInst->QueryMapper( MT_MD5 );
  2401. }
  2402. else
  2403. {
  2404. SetLastError( ERROR_INVALID_PARAMETER );
  2405. return FALSE;
  2406. }
  2407. break;
  2408. case SF_PROPERTY_GET_ITA_MAPPER:
  2409. if ( pInst )
  2410. {
  2411. *(LPVOID*)pData = pInst->QueryMapper( MT_ITA );
  2412. }
  2413. else
  2414. {
  2415. SetLastError( ERROR_INVALID_PARAMETER );
  2416. return FALSE;
  2417. }
  2418. break;
  2419. case SF_PROPERTY_MD_IF:
  2420. *(LPVOID*)pData = (LPVOID) g_pInetSvc->QueryMDObject();
  2421. break;
  2422. case SF_PROPERTY_SSL_CTXT:
  2423. *(LPVOID*)pData = pRequest->QueryAuthenticationObj()->QuerySslCtxtHandle();
  2424. break;
  2425. case SF_PROPERTY_INSTANCE_NUM_ID:
  2426. *(DWORD*)pData = pInst ? pInst->QueryInstanceId() : 0;
  2427. break;
  2428. case SF_PROPERTY_MD_PATH:
  2429. *(const CHAR**)pData = pInst ? pInst->QueryMDPath() :
  2430. g_pInetSvc->QueryMDPath();
  2431. break;
  2432. default:
  2433. SetLastError( ERROR_INVALID_PARAMETER );
  2434. return FALSE;
  2435. }
  2436. return TRUE;
  2437. case SF_REQ_NORMALIZE_URL:
  2438. return ((HTTP_REQUEST * )pRequest)->NormalizeUrl( (LPSTR)pData );
  2439. case SF_REQ_DONE_RENEGOTIATE:
  2440. ((HTTP_REQUEST * )pRequest)->DoneRenegotiate( *(LPBOOL)pData );
  2441. break;
  2442. case SF_REQ_SET_NOTIFY:
  2443. switch ( ul1 )
  2444. {
  2445. case SF_NOTIFY_MAPPER_MD5_CHANGED:
  2446. case SF_NOTIFY_MAPPER_ITA_CHANGED:
  2447. case SF_NOTIFY_MAPPER_CERT11_CHANGED:
  2448. case SF_NOTIFY_MAPPER_CERTW_CHANGED:
  2449. return SetFlushMapperNotify( (SF_NOTIFY_TYPE)ul1, (PFN_SF_NOTIFY)pData );
  2450. case SF_NOTIFY_MAPPER_SSLKEYS_CHANGED:
  2451. return SetSllKeysNotify( (PFN_SF_NOTIFY)pData );
  2452. }
  2453. return FALSE;
  2454. case SF_REQ_DISABLE_NOTIFICATIONS:
  2455. return pFilter->DisableNotification( (DWORD) ul1 );
  2456. case SF_REQ_COMPRESSION_FILTER_CHECK:
  2457. return CompressionFilterCheck(pfc,pData,ul1,ul2);
  2458. case HSE_REQ_GET_CERT_INFO_EX: {
  2459. //
  2460. // Descrption:
  2461. // Returns the first cert in the request's cert-chain,
  2462. // only used if using an SSPI package
  2463. //
  2464. // Input:
  2465. // pData - ISA-provided struct
  2466. // NOTE ISA must allocate buffer within struct
  2467. //
  2468. // Notes:
  2469. // Works in-proc or out-of-proc
  2470. //
  2471. //
  2472. // cast ISA-provided ptr to our cert struct
  2473. //
  2474. CERT_CONTEXT_EX * pCertContextEx = reinterpret_cast
  2475. <CERT_CONTEXT_EX *>
  2476. ( pData );
  2477. if ( pData == NULL ) {
  2478. DBG_ASSERT( FALSE );
  2479. SetLastError( ERROR_INVALID_PARAMETER );
  2480. return FALSE;
  2481. }
  2482. //
  2483. // pass struct members as individual parameters
  2484. //
  2485. return pRequest->QueryAuthenticationObj()->GetClientCertBlob(
  2486. pCertContextEx->cbAllocated,
  2487. &( pCertContextEx->CertContext.dwCertEncodingType ),
  2488. pCertContextEx->CertContext.pbCertEncoded,
  2489. &( pCertContextEx->CertContext.cbCertEncoded ),
  2490. &( pCertContextEx->dwCertificateFlags ) );
  2491. } // case HSE_REQ_GET_CERT_INFO_EX:
  2492. default:
  2493. SetLastError( ERROR_INVALID_PARAMETER );
  2494. return FALSE;
  2495. }
  2496. return TRUE;
  2497. }
  2498. BOOL
  2499. WINAPI
  2500. GetServerVariable(
  2501. HTTP_FILTER_CONTEXT * pfc,
  2502. LPSTR lpszVariableName,
  2503. LPVOID lpvBuffer,
  2504. LPDWORD lpdwSize
  2505. )
  2506. /*++
  2507. Routine Description:
  2508. Callback for a filter retrieving a server variable. These are mostly
  2509. CGI type varaibles
  2510. Arguments:
  2511. pfc - Pointer to http filter context
  2512. lpszVariableName - Variable to retrieve
  2513. lpvBuffer - Receives value or '\0' if not found
  2514. lpdwSize - Specifies the size of lpvBuffer, gets set to the number of
  2515. bytes transferred including the '\0'
  2516. Return Value:
  2517. TRUE on success, FALSE on failure
  2518. --*/
  2519. {
  2520. BOOL fReturn = TRUE; // fast path value
  2521. if ( !pfc ||
  2522. !pfc->ServerContext )
  2523. {
  2524. DBGPRINTF(( DBG_CONTEXT,
  2525. "[GetServerVariable] Filter sent invalid parameters\n"));
  2526. SetLastError( ERROR_INVALID_PARAMETER );
  2527. fReturn = FALSE;
  2528. } else {
  2529. HTTP_FILTER * pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2530. HTTP_REQ_BASE * pRequest = pFilter->QueryReq();
  2531. CHAR tmpStr[MAX_PATH];
  2532. STR str(tmpStr, MAX_PATH);
  2533. BOOL fFound;
  2534. //
  2535. // Get the requested variable and copy it into the supplied buffer
  2536. //
  2537. if ( fReturn = pRequest->GetInfo( lpszVariableName,
  2538. &str,
  2539. &fFound ) ) {
  2540. DWORD cb;
  2541. if ( !fFound ) {
  2542. SetLastError( ERROR_INVALID_INDEX );
  2543. fReturn = FALSE;
  2544. } else if ( (cb = str.QueryCB() + sizeof(CHAR)) > * lpdwSize) {
  2545. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2546. *lpdwSize = cb;
  2547. fReturn = FALSE;
  2548. } else {
  2549. *lpdwSize = cb;
  2550. CopyMemory( lpvBuffer, str.QueryStr(), cb );
  2551. DBG_ASSERT( fReturn);
  2552. }
  2553. }
  2554. }
  2555. return (fReturn);
  2556. } // GetServerVariable()
  2557. BOOL
  2558. WINAPI
  2559. AddFilterResponseHeaders(
  2560. HTTP_FILTER_CONTEXT * pfc,
  2561. LPSTR lpszHeaders,
  2562. DWORD dwReserved
  2563. )
  2564. /*++
  2565. Routine Description:
  2566. Adds headers specified by the client to send with the response
  2567. Arguments:
  2568. pfc - Pointer to http filter context
  2569. lpszHeaders - List of '\r\n' terminated headers followed by '\0'
  2570. dwReserved - must be zero
  2571. Return Value:
  2572. TRUE on success, FALSE on failure
  2573. --*/
  2574. {
  2575. HTTP_FILTER * pFilter;
  2576. if ( !pfc ||
  2577. !pfc->ServerContext )
  2578. {
  2579. DBGPRINTF(( DBG_CONTEXT,
  2580. "[GetServerVariable] Filter passed invalid parameters\r\n"));
  2581. SetLastError( ERROR_INVALID_PARAMETER );
  2582. return FALSE;
  2583. }
  2584. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2585. return pFilter->QueryReq()->QueryAdditionalRespHeaders()->
  2586. Append( (CHAR*) lpszHeaders );
  2587. }
  2588. BOOL
  2589. WINAPI
  2590. WriteFilterClient(
  2591. HTTP_FILTER_CONTEXT * pfc,
  2592. LPVOID Buffer,
  2593. LPDWORD lpdwBytes,
  2594. DWORD dwReserved
  2595. )
  2596. /*++
  2597. Routine Description:
  2598. Callback for writing data to the client
  2599. Arguments:
  2600. pfc - Pointer to http filter context
  2601. Buffer - Pointer to data to send
  2602. lpdwBytes - Number of bytes to send, receives number of bytes sent
  2603. dwReserved - Not used
  2604. Return Value:
  2605. TRUE on success, FALSE on failure
  2606. --*/
  2607. {
  2608. HTTP_FILTER * pFilter;
  2609. STR str;
  2610. DWORD cb;
  2611. HTTP_FILTER_DLL * pFilterDll;
  2612. DWORD CurrentDll;
  2613. DWORD dwIOFlags = IO_FLAG_SYNC;
  2614. if ( !pfc ||
  2615. !pfc->ServerContext )
  2616. {
  2617. DBGPRINTF(( DBG_CONTEXT,
  2618. "[GetServerVariable] Filter passed invalid parameters\r\n"));
  2619. SetLastError( ERROR_INVALID_PARAMETER );
  2620. return FALSE;
  2621. }
  2622. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2623. //
  2624. // Ignore zero length sends
  2625. //
  2626. if ( !*lpdwBytes )
  2627. {
  2628. return TRUE;
  2629. }
  2630. //
  2631. // Save the client context because the client may call
  2632. // WriteClient just after changing the context and we're about to
  2633. // write over it when we do the raw send notifications
  2634. //
  2635. CurrentDll = pFilter->QueryCurrentDll();
  2636. pFilter->SetClientContext( CurrentDll, pfc->pFilterContext );
  2637. //
  2638. // If we're doing a WriteClient from a Raw data notification then we need
  2639. // to notify only the filters down the food chain so save the current
  2640. // filter and set the start point in the list to the next filter (remember
  2641. // raw sends walk the list backwards to encryption filters are last)
  2642. //
  2643. if ( pFilter->IsInRawNotification() )
  2644. {
  2645. //
  2646. // If this is the first filter in the list, then there's nobody that
  2647. // needs to be notified
  2648. //
  2649. if ( pFilter->IsFirstFilter( CurrentDll ) )
  2650. {
  2651. dwIOFlags |= IO_FLAG_NO_FILTER;
  2652. }
  2653. else
  2654. {
  2655. pFilter->SetCurrentDll( CurrentDll - 1 );
  2656. }
  2657. }
  2658. if ( !pFilter->QueryReq()->WriteFile( Buffer,
  2659. *lpdwBytes,
  2660. lpdwBytes,
  2661. dwIOFlags ))
  2662. {
  2663. pFilter->SetCurrentDll( CurrentDll );
  2664. return FALSE;
  2665. }
  2666. pFilter->SetCurrentDll( CurrentDll );
  2667. return TRUE;
  2668. }
  2669. BOOL
  2670. WINAPI
  2671. GetFilterHeader(
  2672. struct _HTTP_FILTER_CONTEXT * pfc,
  2673. LPSTR lpszName,
  2674. LPVOID lpvBuffer,
  2675. LPDWORD lpdwSize
  2676. )
  2677. /*++
  2678. Routine Description:
  2679. Callback for retrieving unprocessed headers
  2680. Arguments:
  2681. pfc - Pointer to http filter context
  2682. lpszName - Name of header to retrieve ("User-Agent:")
  2683. lpvBuffer - Buffer to receive the value of the header
  2684. lpdwSize - Number of bytes in lpvBuffer, receives number of bytes copied
  2685. including the '\0'
  2686. Return Value:
  2687. TRUE on success, FALSE on failure
  2688. --*/
  2689. {
  2690. HTTP_FILTER * pFilter;
  2691. HTTP_HEADERS * pHeaderList;
  2692. CHAR * pszValue;
  2693. DWORD cbNeeded;
  2694. if ( !pfc ||
  2695. !pfc->ServerContext )
  2696. {
  2697. DBGPRINTF(( DBG_CONTEXT,
  2698. "[GetFilterHeader] Extension passed invalid parameters\r\n"
  2699. ));
  2700. SetLastError( ERROR_INVALID_PARAMETER );
  2701. return FALSE;
  2702. }
  2703. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2704. pHeaderList = pFilter->QueryReq()->QueryHeaderList();
  2705. //
  2706. // First, see if the specified header is in the list
  2707. //
  2708. pszValue = pHeaderList->FindValue( lpszName, &cbNeeded );
  2709. //
  2710. // If not found, terminate the buffer and set the required size to the
  2711. // terminator
  2712. //
  2713. if ( !pszValue )
  2714. {
  2715. SetLastError( ERROR_INVALID_INDEX );
  2716. return FALSE;
  2717. }
  2718. //
  2719. // Found the value, copy it if there's space
  2720. //
  2721. if ( ++cbNeeded > *lpdwSize )
  2722. {
  2723. *lpdwSize = cbNeeded;
  2724. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2725. return FALSE;
  2726. }
  2727. *lpdwSize = cbNeeded;
  2728. memcpy( lpvBuffer, pszValue, cbNeeded );
  2729. return TRUE;
  2730. }
  2731. BOOL
  2732. WINAPI
  2733. SetFilterHeader(
  2734. struct _HTTP_FILTER_CONTEXT * pfc,
  2735. LPSTR lpszName,
  2736. LPSTR lpszValue
  2737. )
  2738. /*++
  2739. Routine Description:
  2740. The specified header is added to the list with the specified value. If
  2741. any other occurrences of the header are found, they are removed from the
  2742. list.
  2743. Specifying a blank value will remove the header from the list
  2744. This will generally be used to replace the value of an existing header
  2745. Arguments:
  2746. pfc - Pointer to http filter context
  2747. lpszName - Name of header to set ("User-Agent:")
  2748. lpszValue - value of lpszValue
  2749. Return Value:
  2750. TRUE on success, FALSE on failure
  2751. --*/
  2752. {
  2753. HTTP_FILTER * pFilter;
  2754. HTTP_HEADERS *pHeaderList;
  2755. VOID * pvCookie = NULL;
  2756. CHAR * pszListHeader;
  2757. CHAR * pszListValue;
  2758. if ( !pfc ||
  2759. !pfc->ServerContext )
  2760. {
  2761. DBGPRINTF(( DBG_CONTEXT,
  2762. "[SetFilterHeader] Extension passed invalid parameters\r\n"));
  2763. SetLastError( ERROR_INVALID_PARAMETER );
  2764. return FALSE;
  2765. }
  2766. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2767. pHeaderList = pFilter->QueryReq()->QueryHeaderList();
  2768. //
  2769. // Remove all occurrences of the value, then add the one we want
  2770. //
  2771. pHeaderList->CancelHeader( lpszName );
  2772. //
  2773. // Only add the value if they specified a replacement
  2774. //
  2775. if ( lpszValue && *lpszValue )
  2776. {
  2777. return pHeaderList->StoreHeader( lpszName, lpszValue );
  2778. }
  2779. return TRUE;
  2780. }
  2781. BOOL
  2782. WINAPI
  2783. AddFilterHeader(
  2784. struct _HTTP_FILTER_CONTEXT * pfc,
  2785. LPSTR lpszName,
  2786. LPSTR lpszValue
  2787. )
  2788. /*++
  2789. Routine Description:
  2790. The specified header is added to the list with the specified value.
  2791. Arguments:
  2792. pfc - Pointer to http filter context
  2793. lpszName - Name of header to set ("User-Agent:")
  2794. lpszValue - value of lpszValue
  2795. Return Value:
  2796. TRUE on success, FALSE on failure
  2797. --*/
  2798. {
  2799. HTTP_FILTER * pFilter;
  2800. HTTP_HEADERS *pHeaderList;
  2801. VOID * pvCookie = NULL;
  2802. CHAR * pszListHeader;
  2803. CHAR * pszListValue;
  2804. if ( !pfc ||
  2805. !pfc->ServerContext )
  2806. {
  2807. DBGPRINTF(( DBG_CONTEXT,
  2808. "[AddFilterHeader] Extension passed invalid parameters\r\n"));
  2809. SetLastError( ERROR_INVALID_PARAMETER );
  2810. return FALSE;
  2811. }
  2812. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2813. pHeaderList = pFilter->QueryReq()->QueryHeaderList();
  2814. return pHeaderList->StoreHeader( lpszName, lpszValue);
  2815. } // AddFilterHeader()
  2816. BOOL
  2817. WINAPI
  2818. GetSendHeader(
  2819. struct _HTTP_FILTER_CONTEXT * pfc,
  2820. LPSTR lpszName,
  2821. LPVOID lpvBuffer,
  2822. LPDWORD lpdwSize
  2823. )
  2824. /*++
  2825. Routine Description:
  2826. Callback for retrieving headers about to be sent to the client
  2827. Arguments:
  2828. pfc - Pointer to http filter context
  2829. lpszName - Name of header to retrieve ("User-Agent:")
  2830. lpvBuffer - Buffer to receive the value of the header
  2831. lpdwSize - Number of bytes in lpvBuffer, receives number of bytes copied
  2832. including the '\0'
  2833. Return Value:
  2834. TRUE on success, FALSE on failure
  2835. --*/
  2836. {
  2837. HTTP_FILTER * pFilter;
  2838. CHAR * pszValue;
  2839. DWORD cbNeeded = 0;
  2840. PARAM_LIST * pHeaderList;
  2841. PVOID Cookie = NULL;
  2842. CHAR * pszField;
  2843. DWORD cbField;
  2844. DWORD cbValue;
  2845. BOOL fFound = FALSE;
  2846. CHAR * pszTail = (CHAR *) lpvBuffer;
  2847. HTTP_REQ_BASE* pRequest;
  2848. if ( !pfc ||
  2849. !pfc->ServerContext )
  2850. {
  2851. DBGPRINTF(( DBG_CONTEXT,
  2852. "[GetFilterHeader] Extension passed invalid parameters\r\n"));
  2853. SetLastError( ERROR_INVALID_PARAMETER );
  2854. return FALSE;
  2855. }
  2856. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2857. DBG_ASSERT( pFilter != NULL );
  2858. pRequest = (HTTP_REQ_BASE*) pFilter->QueryReq();
  2859. DBG_ASSERT( pRequest != NULL );
  2860. if ( pRequest->IsPointNine() )
  2861. {
  2862. SetLastError( ERROR_NOT_SUPPORTED );
  2863. return FALSE;
  2864. }
  2865. if ( !pFilter->AreSendHeadersParsed() &&
  2866. !pFilter->ParseSendHeaders() )
  2867. {
  2868. return FALSE;
  2869. }
  2870. pHeaderList = pFilter->QuerySendHeaders();
  2871. //
  2872. // First, see if the specified header is in the list
  2873. //
  2874. while ( Cookie = pHeaderList->NextPair( Cookie,
  2875. &pszField,
  2876. &cbField,
  2877. &pszValue,
  2878. &cbValue ))
  2879. {
  2880. if ( !_stricmp( pszField, lpszName ))
  2881. {
  2882. //
  2883. // If there is room, copy it in, note we need a comma separator
  2884. // after each subsequent entry
  2885. //
  2886. if ( (cbNeeded + cbValue + 1 + (fFound ? 1 : 0)) <= *lpdwSize )
  2887. {
  2888. if ( fFound )
  2889. {
  2890. *pszTail++ = ',';
  2891. }
  2892. memcpy( pszTail, pszValue, cbValue + 1 );
  2893. pszTail += cbValue;
  2894. }
  2895. cbNeeded += cbValue + (fFound ? 1 : 0);
  2896. fFound = TRUE;
  2897. }
  2898. }
  2899. //
  2900. // If not found, tell the caller
  2901. //
  2902. if ( !fFound )
  2903. {
  2904. SetLastError( ERROR_INVALID_INDEX );
  2905. return FALSE;
  2906. }
  2907. //
  2908. // Found the value, copy it if there's space
  2909. //
  2910. if ( ++cbNeeded > *lpdwSize )
  2911. {
  2912. *lpdwSize = cbNeeded;
  2913. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2914. return FALSE;
  2915. }
  2916. *lpdwSize = cbNeeded;
  2917. return TRUE;
  2918. }
  2919. BOOL
  2920. WINAPI
  2921. SetSendHeader(
  2922. struct _HTTP_FILTER_CONTEXT * pfc,
  2923. LPSTR lpszName,
  2924. LPSTR lpszValue
  2925. )
  2926. /*++
  2927. Routine Description:
  2928. The specified header is added to the list with the specified value. If
  2929. any other occurrences of the header are found, they are removed from the
  2930. list.
  2931. Specifying a blank value will remove the header from the list
  2932. This will generally be used to replace the value of an existing header
  2933. Arguments:
  2934. pfc - Pointer to http filter context
  2935. lpszName - Name of header to set ("User-Agent:")
  2936. lpszValue - value of lpszValue
  2937. Return Value:
  2938. TRUE on success, FALSE on failure
  2939. --*/
  2940. {
  2941. HTTP_FILTER * pFilter;
  2942. PARAM_LIST * pHeaderList;
  2943. HTTP_REQ_BASE * pRequest;
  2944. if ( !pfc ||
  2945. !pfc->ServerContext )
  2946. {
  2947. DBGPRINTF(( DBG_CONTEXT,
  2948. "[SetFilterHeader] Extension passed invalid parameters\r\n"));
  2949. SetLastError( ERROR_INVALID_PARAMETER );
  2950. return FALSE;
  2951. }
  2952. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  2953. DBG_ASSERT( pFilter != NULL );
  2954. pRequest = (HTTP_REQ_BASE*) pFilter->QueryReq();
  2955. DBG_ASSERT( pRequest != NULL );
  2956. if ( pRequest->IsPointNine() )
  2957. {
  2958. SetLastError( ERROR_NOT_SUPPORTED );
  2959. return FALSE;
  2960. }
  2961. if ( !pFilter->AreSendHeadersParsed() &&
  2962. !pFilter->ParseSendHeaders() )
  2963. {
  2964. return FALSE;
  2965. }
  2966. pHeaderList = pFilter->QuerySendHeaders();
  2967. //
  2968. // Remove all occurrences of the value, then add the one we want
  2969. //
  2970. pFilter->SetSendHeadersChanged( TRUE );
  2971. pHeaderList->RemoveEntry( lpszName );
  2972. //
  2973. // Only add the value if they specified a replacement
  2974. //
  2975. if ( lpszValue && *lpszValue )
  2976. {
  2977. return pHeaderList->AddEntry( lpszName, lpszValue );
  2978. }
  2979. return TRUE;
  2980. }
  2981. BOOL
  2982. WINAPI
  2983. AddSendHeader(
  2984. struct _HTTP_FILTER_CONTEXT * pfc,
  2985. LPSTR lpszName,
  2986. LPSTR lpszValue
  2987. )
  2988. /*++
  2989. Routine Description:
  2990. The specified header is added to the list with the specified value.
  2991. Arguments:
  2992. pfc - Pointer to http filter context
  2993. lpszName - Name of header to set ("User-Agent:")
  2994. lpszValue - value of lpszValue
  2995. Return Value:
  2996. TRUE on success, FALSE on failure
  2997. --*/
  2998. {
  2999. HTTP_FILTER * pFilter;
  3000. HTTP_REQ_BASE* pRequest;
  3001. if ( !pfc ||
  3002. !pfc->ServerContext )
  3003. {
  3004. DBGPRINTF(( DBG_CONTEXT,
  3005. "[AddFilterHeader] Extension passed invalid parameters\r\n"));
  3006. SetLastError( ERROR_INVALID_PARAMETER );
  3007. return FALSE;
  3008. }
  3009. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  3010. DBG_ASSERT( pFilter != NULL );
  3011. pRequest = (HTTP_REQ_BASE*) pFilter->QueryReq();
  3012. DBG_ASSERT( pRequest != NULL );
  3013. if ( pRequest->IsPointNine() )
  3014. {
  3015. SetLastError( ERROR_NOT_SUPPORTED );
  3016. return FALSE;
  3017. }
  3018. if ( !pFilter->AreSendHeadersParsed() &&
  3019. !pFilter->ParseSendHeaders() )
  3020. {
  3021. return FALSE;
  3022. }
  3023. pFilter->SetSendHeadersChanged( TRUE );
  3024. return pFilter->QuerySendHeaders()->AddEntry( lpszName, lpszValue );
  3025. }
  3026. VOID *
  3027. WINAPI
  3028. AllocFilterMem(
  3029. struct _HTTP_FILTER_CONTEXT * pfc,
  3030. DWORD cbSize,
  3031. DWORD dwReserved
  3032. )
  3033. {
  3034. HTTP_FILTER * pFilter;
  3035. FILTER_POOL_ITEM * pfpi;
  3036. if ( !pfc ||
  3037. !pfc->ServerContext )
  3038. {
  3039. DBGPRINTF(( DBG_CONTEXT,
  3040. "[GetFilterHeader] Extension passed invalid parameters\r\n"));
  3041. SetLastError( ERROR_INVALID_PARAMETER );
  3042. return NULL;
  3043. }
  3044. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  3045. pfpi = FILTER_POOL_ITEM::CreateMemPoolItem( cbSize );
  3046. if ( pfpi )
  3047. {
  3048. InsertHeadList( pFilter->QueryPoolHead(), &pfpi->_ListEntry );
  3049. return pfpi->_pvData;
  3050. }
  3051. return NULL;
  3052. }
  3053. #if 0
  3054. PVOID
  3055. WINAPI
  3056. ServerFilterResize(
  3057. struct _HTTP_FILTER_CONTEXT * pfc,
  3058. DWORD cbSize
  3059. )
  3060. {
  3061. HTTP_FILTER * pFilter;
  3062. HTTP_FILTER_RAW_DATA * phfrd;
  3063. if ( !pfc ||
  3064. !pfc->ServerContext )
  3065. {
  3066. DBGPRINTF(( DBG_CONTEXT,
  3067. "[ServerFilterResize] Extension passed invalid parameters\r\n"));
  3068. SetLastError( ERROR_INVALID_PARAMETER );
  3069. return NULL;
  3070. }
  3071. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  3072. phfrd = (HTTP_FILTER_RAW_DATA *) pFilter->QueryNotificationStruct();
  3073. //
  3074. // Only reallocate if necessary
  3075. //
  3076. if ( phfrd->cbOutBuffer < cbSize )
  3077. {
  3078. if ( !pFilter->QueryRecvTrans()->Resize( cbSize ) )
  3079. {
  3080. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  3081. return NULL;
  3082. }
  3083. phfrd->pvOutData = pFilter->QueryRecvTrans()->QueryPtr();
  3084. phfrd->cbOutBuffer = cbSize;
  3085. }
  3086. return phfrd->pvOutData;
  3087. }
  3088. #endif
  3089. PATQ_CONTEXT
  3090. HTTP_FILTER::QueryAtqContext(
  3091. VOID
  3092. ) const
  3093. {
  3094. return _pRequest->QueryClientConn()->QueryAtqContext();
  3095. }
  3096. BOOL
  3097. WINAPI
  3098. GetUserToken(
  3099. struct _HTTP_FILTER_CONTEXT * pfc,
  3100. HANDLE * phToken
  3101. )
  3102. /*++
  3103. Routine Description:
  3104. Get impersonated user token
  3105. Arguments:
  3106. pfc - Filter context
  3107. phToken - Filled with impersonation token
  3108. Return Value:
  3109. TRUE on success, FALSE on failure
  3110. --*/
  3111. {
  3112. HTTP_FILTER * pFilter;
  3113. HTTP_REQ_BASE* pRequest;
  3114. if ( !pfc ||
  3115. !pfc->ServerContext ||
  3116. !phToken )
  3117. {
  3118. DBGPRINTF(( DBG_CONTEXT,
  3119. "[AddFilterHeader] Extension passed invalid parameters\r\n"));
  3120. SetLastError( ERROR_INVALID_PARAMETER );
  3121. return FALSE;
  3122. }
  3123. pFilter = (HTTP_FILTER *) pfc->ServerContext;
  3124. DBG_ASSERT( pFilter != NULL );
  3125. pRequest = (HTTP_REQ_BASE*) pFilter->QueryReq();
  3126. DBG_ASSERT( pRequest != NULL );
  3127. *phToken = pRequest->QueryUserImpersonationHandle();
  3128. return TRUE;
  3129. }
  3130. BOOL
  3131. WINAPI
  3132. CompressionFilterCheck(
  3133. HTTP_FILTER_CONTEXT *pfc,
  3134. LPVOID lpszEncodingString,
  3135. ULONG_PTR lpszVerbString,
  3136. ULONG_PTR sizesForBuffers
  3137. )
  3138. /*++
  3139. Routine Description:
  3140. Special server suport function for compression filter to determine the need to
  3141. compress given request
  3142. Arguments:
  3143. pfc - Pointer to http filter context
  3144. lpszEncodingString - String containing accept encoding header if any
  3145. lpszVerbString - String containing method
  3146. sizesForBuffers - max size for buffers
  3147. Return Value:
  3148. TRUE if request is eligible for compression
  3149. --*/
  3150. {
  3151. BOOL fReturn = FALSE; // fast path value
  3152. if ( !pfc ||
  3153. !pfc->ServerContext )
  3154. {
  3155. DBGPRINTF(( DBG_CONTEXT,
  3156. "[CompressionFilterCheck] Filter sent invalid parameters\n"));
  3157. SetLastError( ERROR_INVALID_PARAMETER );
  3158. } else {
  3159. HTTP_FILTER * pFilter = (HTTP_FILTER *) pfc->ServerContext;
  3160. HTTP_REQ_BASE * pRequest = pFilter->QueryReq();
  3161. HTTP_HEADERS *pHttpHeaders;
  3162. DWORD len;
  3163. PCHAR pHdr_HM_ACE, pHdr_HM_MET;
  3164. pHttpHeaders = pRequest->QueryHeaderList();
  3165. *(PCHAR)lpszEncodingString = 0;
  3166. *((PCHAR)lpszVerbString) = 0;
  3167. //
  3168. // Get the Accept-Encoding sent by the client, if any. If we cannot
  3169. // get this header, or if the size of the header is too large, then
  3170. // we will make no effort to compress this request.
  3171. //
  3172. pHdr_HM_ACE = (PCHAR)pHttpHeaders->FastMapQueryValue (HM_ACE);
  3173. if ( pHdr_HM_ACE )
  3174. {
  3175. pHdr_HM_MET = (PCHAR)pHttpHeaders->FastMapQueryValue(HM_MET);
  3176. if (pHdr_HM_MET)
  3177. {
  3178. len = strlen((PCHAR)pHdr_HM_ACE)+1;
  3179. if (len > sizesForBuffers)
  3180. {
  3181. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  3182. goto exit_point;
  3183. }
  3184. else
  3185. {
  3186. strcpy ((PCHAR)lpszEncodingString,pHdr_HM_ACE);
  3187. }
  3188. len = strlen((PCHAR)pHdr_HM_MET)+1;
  3189. if (len > sizesForBuffers)
  3190. {
  3191. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  3192. goto exit_point;
  3193. }
  3194. else
  3195. {
  3196. strcpy ((PCHAR)lpszVerbString,pHdr_HM_MET);
  3197. fReturn = TRUE;
  3198. }
  3199. }
  3200. }
  3201. }
  3202. exit_point:
  3203. return fReturn;
  3204. }