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.

665 lines
14 KiB

  1. #ifndef W3RESPONSE_HXX_INCLUDED
  2. #define W3RESPONSE_HXX_INCLUDED
  3. //
  4. // SEND_RAW_BUFFER
  5. //
  6. // Stupid little helper class which wraps a buffer which is acached
  7. //
  8. class SEND_RAW_BUFFER
  9. {
  10. public:
  11. SEND_RAW_BUFFER()
  12. : _buffSendRaw( _abBuffer, sizeof( _abBuffer ) ),
  13. _cbLen( 0 )
  14. {
  15. }
  16. virtual ~SEND_RAW_BUFFER()
  17. {
  18. }
  19. VOID *
  20. operator new(
  21. size_t size
  22. )
  23. {
  24. DBG_ASSERT( size == sizeof( SEND_RAW_BUFFER ) );
  25. DBG_ASSERT( sm_pachSendRawBuffers != NULL );
  26. return sm_pachSendRawBuffers->Alloc();
  27. }
  28. VOID
  29. operator delete(
  30. VOID * pSendRawBuffer
  31. )
  32. {
  33. DBG_ASSERT( pSendRawBuffer != NULL );
  34. DBG_ASSERT( sm_pachSendRawBuffers != NULL );
  35. DBG_REQUIRE( sm_pachSendRawBuffers->Free( pSendRawBuffer ) );
  36. }
  37. VOID *
  38. QueryPtr(
  39. VOID
  40. )
  41. {
  42. return _buffSendRaw.QueryPtr();
  43. }
  44. DWORD
  45. QueryCB(
  46. VOID
  47. )
  48. {
  49. return _cbLen;
  50. }
  51. DWORD
  52. QuerySize(
  53. VOID
  54. )
  55. {
  56. return _buffSendRaw.QuerySize();
  57. }
  58. VOID
  59. SetLen(
  60. DWORD cbLen
  61. )
  62. {
  63. _cbLen = cbLen;
  64. }
  65. HRESULT
  66. Resize(
  67. DWORD cbLen
  68. )
  69. {
  70. if ( !_buffSendRaw.Resize( cbLen ) )
  71. {
  72. return HRESULT_FROM_WIN32( GetLastError() );
  73. }
  74. else
  75. {
  76. return NO_ERROR;
  77. }
  78. }
  79. static
  80. HRESULT
  81. Initialize(
  82. VOID
  83. );
  84. static
  85. VOID
  86. Terminate(
  87. VOID
  88. );
  89. LIST_ENTRY _listEntry;
  90. private:
  91. BUFFER _buffSendRaw;
  92. BYTE _abBuffer[ 8192 ];
  93. DWORD _cbLen;
  94. static ALLOC_CACHE_HANDLER* sm_pachSendRawBuffers;
  95. };
  96. //
  97. // HTTP status codes
  98. //
  99. #define REASON(x) (x),sizeof(x)-sizeof(CHAR)
  100. struct HTTP_STATUS
  101. {
  102. USHORT statusCode;
  103. PCHAR pszReason;
  104. DWORD cbReason;
  105. };
  106. extern HTTP_STATUS HttpStatusOk;
  107. extern HTTP_STATUS HttpStatusPartialContent;
  108. extern HTTP_STATUS HttpStatusMultiStatus;
  109. extern HTTP_STATUS HttpStatusMovedPermanently;
  110. extern HTTP_STATUS HttpStatusRedirect;
  111. extern HTTP_STATUS HttpStatusMovedTemporarily;
  112. extern HTTP_STATUS HttpStatusNotModified;
  113. extern HTTP_STATUS HttpStatusBadRequest;
  114. extern HTTP_STATUS HttpStatusUnauthorized;
  115. extern HTTP_STATUS HttpStatusForbidden;
  116. extern HTTP_STATUS HttpStatusNotFound;
  117. extern HTTP_STATUS HttpStatusMethodNotAllowed;
  118. extern HTTP_STATUS HttpStatusNotAcceptable;
  119. extern HTTP_STATUS HttpStatusProxyAuthRequired;
  120. extern HTTP_STATUS HttpStatusPreconditionFailed;
  121. extern HTTP_STATUS HttpStatusUrlTooLong;
  122. extern HTTP_STATUS HttpStatusRangeNotSatisfiable;
  123. extern HTTP_STATUS HttpStatusLockedError;
  124. extern HTTP_STATUS HttpStatusServerError;
  125. extern HTTP_STATUS HttpStatusNotImplemented;
  126. extern HTTP_STATUS HttpStatusBadGateway;
  127. extern HTTP_STATUS HttpStatusServiceUnavailable;
  128. extern HTTP_STATUS HttpStatusGatewayTimeout;
  129. //
  130. // HTTP Sub Errors
  131. //
  132. struct HTTP_SUB_ERROR
  133. {
  134. USHORT mdSubError;
  135. DWORD dwStringId;
  136. };
  137. extern HTTP_SUB_ERROR HttpNoSubError;
  138. extern HTTP_SUB_ERROR Http401BadLogon;
  139. extern HTTP_SUB_ERROR Http401Config;
  140. extern HTTP_SUB_ERROR Http401Resource;
  141. extern HTTP_SUB_ERROR Http401Filter;
  142. extern HTTP_SUB_ERROR Http401Application;
  143. extern HTTP_SUB_ERROR Http403ExecAccessDenied;
  144. extern HTTP_SUB_ERROR Http403ReadAccessDenied;
  145. extern HTTP_SUB_ERROR Http403WriteAccessDenied;
  146. extern HTTP_SUB_ERROR Http403SSLRequired;
  147. extern HTTP_SUB_ERROR Http403SSL128Required;
  148. extern HTTP_SUB_ERROR Http403IPAddressReject;
  149. extern HTTP_SUB_ERROR Http403CertRequired;
  150. extern HTTP_SUB_ERROR Http403SiteAccessDenied;
  151. extern HTTP_SUB_ERROR Http403TooManyUsers;
  152. extern HTTP_SUB_ERROR Http403InvalidateConfig;
  153. extern HTTP_SUB_ERROR Http403PasswordChange;
  154. extern HTTP_SUB_ERROR Http403MapperDenyAccess;
  155. extern HTTP_SUB_ERROR Http403CertRevoked;
  156. extern HTTP_SUB_ERROR Http403DirBrowsingDenied;
  157. extern HTTP_SUB_ERROR Http403CertInvalid;
  158. extern HTTP_SUB_ERROR Http403CertTimeInvalid;
  159. extern HTTP_SUB_ERROR Http404SiteNotFound;
  160. extern HTTP_SUB_ERROR Http502Timeout;
  161. extern HTTP_SUB_ERROR Http502PrematureExit;
  162. #define W3_RESPONSE_INLINE_HEADERS 10
  163. #define W3_RESPONSE_INLINE_CHUNKS 5
  164. #define W3_RESPONSE_SIGNATURE ((DWORD) 'PR3W')
  165. #define W3_RESPONSE_SIGNATURE_FREE ((DWORD) 'pr3w')
  166. #define W3_RESPONSE_ASYNC 0x01
  167. #define W3_RESPONSE_MORE_DATA 0x02
  168. #define W3_RESPONSE_DISCONNECT 0x04
  169. #define W3_RESPONSE_UL_CACHEABLE 0x08
  170. #define W3_RESPONSE_SUPPRESS_ENTITY 0x10
  171. #define W3_RESPONSE_SUPPRESS_HEADERS 0x20
  172. enum W3_RESPONSE_MODE
  173. {
  174. RESPONSE_MODE_PARSED,
  175. RESPONSE_MODE_RAW
  176. };
  177. class W3_RESPONSE
  178. {
  179. private:
  180. DWORD _dwSignature;
  181. HTTP_RESPONSE _ulHttpResponse;
  182. HTTP_SUB_ERROR _subError;
  183. //
  184. // Buffer to store any strings for header values/names which are
  185. // referenced in the _ulHttpResponse
  186. //
  187. CHUNK_BUFFER _HeaderBuffer;
  188. HTTP_UNKNOWN_HEADER _rgUnknownHeaders[ W3_RESPONSE_INLINE_HEADERS ];
  189. BUFFER _bufUnknownHeaders;
  190. //
  191. // Buffer to store chunk data structures referenced in calls
  192. // to UlSendHttpResponse or UlSendEntityBody
  193. //
  194. HTTP_DATA_CHUNK _rgChunks[ W3_RESPONSE_INLINE_CHUNKS ];
  195. BUFFER _bufChunks;
  196. DWORD _cChunks;
  197. ULONGLONG _cbContentLength;
  198. //
  199. // Has this response been touched at all?
  200. //
  201. BOOL _fResponseTouched;
  202. //
  203. // Has a response been sent
  204. //
  205. BOOL _fResponseSent;
  206. //
  207. // Some buffers used when in raw mode
  208. //
  209. STRA _strRawCoreHeaders;
  210. //
  211. // Are we in raw mode or parsed mode?
  212. //
  213. W3_RESPONSE_MODE _responseMode;
  214. //
  215. // Does an ISAPI expect to complete headers with WriteClient()
  216. //
  217. BOOL _fIncompleteHeaders;
  218. //
  219. // Which chunk is the first of actual entity
  220. //
  221. DWORD _cFirstEntityChunk;
  222. //
  223. // List of send raw buffers that need to be freed on reset
  224. //
  225. LIST_ENTRY _SendRawBufferHead;
  226. HRESULT
  227. BuildRawCoreHeaders(
  228. W3_CONTEXT * pW3Context
  229. );
  230. HRESULT
  231. SwitchToRawMode(
  232. W3_CONTEXT * pW3Context,
  233. CHAR * pszAdditionalHeaders,
  234. DWORD cchAdditionalHeaders
  235. );
  236. HRESULT
  237. SwitchToParsedMode(
  238. VOID
  239. );
  240. HRESULT
  241. ParseHeadersFromStream(
  242. CHAR * pszStream
  243. );
  244. HRESULT
  245. InsertDataChunk(
  246. HTTP_DATA_CHUNK * pNewChunk,
  247. LONG cPosition
  248. );
  249. HTTP_DATA_CHUNK *
  250. QueryChunks(
  251. VOID
  252. )
  253. {
  254. return (HTTP_DATA_CHUNK*) _bufChunks.QueryPtr();
  255. }
  256. VOID
  257. Reset(
  258. VOID
  259. );
  260. public:
  261. W3_RESPONSE()
  262. : _bufUnknownHeaders( (BYTE*) _rgUnknownHeaders,
  263. sizeof( _rgUnknownHeaders ) ),
  264. _bufChunks( (BYTE*) _rgChunks,
  265. sizeof( _rgChunks ) )
  266. {
  267. InitializeListHead( &_SendRawBufferHead );
  268. Reset();
  269. _dwSignature = W3_RESPONSE_SIGNATURE;
  270. }
  271. ~W3_RESPONSE()
  272. {
  273. SEND_RAW_BUFFER * pBuffer;
  274. while ( !IsListEmpty( &_SendRawBufferHead ) )
  275. {
  276. pBuffer = CONTAINING_RECORD( _SendRawBufferHead.Flink,
  277. SEND_RAW_BUFFER,
  278. _listEntry );
  279. RemoveEntryList( &( pBuffer->_listEntry ) );
  280. delete pBuffer;
  281. }
  282. _dwSignature = W3_RESPONSE_SIGNATURE_FREE;
  283. }
  284. static
  285. HRESULT
  286. Initialize(
  287. VOID
  288. );
  289. static
  290. VOID
  291. Terminate(
  292. VOID
  293. );
  294. static
  295. HRESULT
  296. ReadFileIntoBuffer(
  297. HANDLE hFile,
  298. SEND_RAW_BUFFER * pSendBuffer,
  299. ULONGLONG cbCurrentFileOffset
  300. );
  301. BOOL
  302. CheckSignature(
  303. VOID
  304. ) const
  305. {
  306. return _dwSignature == W3_RESPONSE_SIGNATURE;
  307. }
  308. //
  309. // Core header adding/deleting functions
  310. //
  311. HRESULT
  312. DeleteHeader(
  313. CHAR * pszHeaderName
  314. );
  315. HRESULT
  316. SetHeader(
  317. DWORD headerIndex,
  318. CHAR * pszHeaderValue,
  319. DWORD cchHeaderValue,
  320. BOOL fAppend = FALSE
  321. );
  322. HRESULT
  323. SetHeaderByReference(
  324. DWORD headerIndex,
  325. CHAR * pszHeaderValue,
  326. DWORD cchHeaderValue,
  327. BOOL fForceParsedMode = FALSE
  328. );
  329. HRESULT
  330. SetHeader(
  331. CHAR * pszHeaderName,
  332. DWORD cchHeaderName,
  333. CHAR * pszHeaderValue,
  334. DWORD cchHeaderValue,
  335. BOOL fAppend = FALSE,
  336. BOOL fForceParsedMode = FALSE,
  337. BOOL fAlwaysAddUnknown = FALSE
  338. );
  339. //
  340. // Some friendly SetHeader helpers
  341. //
  342. CHAR *
  343. GetHeader(
  344. DWORD headerIndex
  345. )
  346. {
  347. HRESULT hr;
  348. if ( _responseMode == RESPONSE_MODE_RAW )
  349. {
  350. hr = SwitchToParsedMode();
  351. if ( FAILED( hr ) )
  352. {
  353. return NULL;
  354. }
  355. }
  356. DBG_ASSERT( _responseMode == RESPONSE_MODE_PARSED );
  357. DBG_ASSERT(headerIndex < HttpHeaderResponseMaximum);
  358. return _ulHttpResponse.Headers.pKnownHeaders[headerIndex].pRawValue;
  359. }
  360. HRESULT
  361. GetHeader(
  362. CHAR * pszHeaderName,
  363. STRA * pstrHeaderValue
  364. );
  365. VOID
  366. ClearHeaders(
  367. VOID
  368. );
  369. //
  370. // Chunk management
  371. //
  372. HRESULT
  373. AddFileHandleChunk(
  374. HANDLE hFile,
  375. ULONGLONG cbOffset,
  376. ULONGLONG cbLength
  377. );
  378. HRESULT
  379. AddMemoryChunkByReference(
  380. PVOID pvBuffer,
  381. DWORD cbBuffer
  382. );
  383. HRESULT
  384. GetChunks(
  385. OUT BUFFER *chunkBuffer,
  386. OUT DWORD *pdwNumChunks
  387. );
  388. HRESULT
  389. Clear(
  390. BOOL fClearEntityOnly = FALSE
  391. );
  392. HRESULT
  393. GenerateAutomaticHeaders(
  394. W3_CONTEXT * pW3Context,
  395. DWORD dwFlags
  396. );
  397. //
  398. // ULATQ send APIs
  399. //
  400. HRESULT
  401. SendResponse(
  402. W3_CONTEXT * pW3Context,
  403. DWORD dwResponseFlags,
  404. DWORD * pcbSent,
  405. HTTP_LOG_FIELDS_DATA * pUlLogData
  406. );
  407. HRESULT
  408. SendEntity(
  409. W3_CONTEXT * pW3Context,
  410. DWORD dwResponseFlags,
  411. DWORD * pcbSent,
  412. HTTP_LOG_FIELDS_DATA * pUlLogData
  413. );
  414. HRESULT
  415. ProcessRawChunks(
  416. W3_CONTEXT * pW3Context,
  417. BOOL * pfFinished
  418. );
  419. //
  420. // Setup and send an ISAPI response
  421. //
  422. HRESULT
  423. FilterWriteClient(
  424. W3_CONTEXT * pW3Context,
  425. PVOID pvData,
  426. DWORD cbData
  427. );
  428. HRESULT
  429. BuildResponseFromIsapi(
  430. W3_CONTEXT * pW3Context,
  431. LPSTR pszStatusLine,
  432. LPSTR pszHeaderStream,
  433. DWORD cchHeaderStream
  434. );
  435. HRESULT
  436. BuildStatusFromIsapi(
  437. LPSTR pszStatusLine
  438. );
  439. HRESULT
  440. AppendResponseHeaders(
  441. STRA & strHeaders
  442. );
  443. //
  444. // Get the raw response stream for use by raw data filter
  445. //
  446. HRESULT
  447. GetRawResponseStream(
  448. STRA * pstrResponseStream
  449. );
  450. //
  451. // Status code and reason
  452. //
  453. VOID
  454. SetStatus(
  455. HTTP_STATUS & httpStatus,
  456. HTTP_SUB_ERROR & httpSubError = HttpNoSubError
  457. )
  458. {
  459. _ulHttpResponse.StatusCode = httpStatus.statusCode;
  460. _ulHttpResponse.pReason = httpStatus.pszReason;
  461. _ulHttpResponse.ReasonLength = httpStatus.cbReason;
  462. _subError = httpSubError;
  463. _fResponseTouched = TRUE;
  464. }
  465. VOID
  466. GetStatus(
  467. HTTP_STATUS *phttpStatus
  468. )
  469. {
  470. phttpStatus->statusCode = _ulHttpResponse.StatusCode;
  471. phttpStatus->pszReason = _ulHttpResponse.pReason;
  472. phttpStatus->cbReason = _ulHttpResponse.ReasonLength;
  473. }
  474. HRESULT
  475. SetStatus(
  476. USHORT StatusCode,
  477. STRA & strReason,
  478. HTTP_SUB_ERROR & subError = HttpNoSubError
  479. );
  480. HRESULT
  481. GetStatusLine(
  482. STRA * pstrStatusLine
  483. );
  484. USHORT
  485. QueryStatusCode(
  486. VOID
  487. ) const
  488. {
  489. return _ulHttpResponse.StatusCode;
  490. }
  491. HRESULT
  492. QuerySubError(
  493. HTTP_SUB_ERROR * pSubError
  494. )
  495. {
  496. if ( pSubError == NULL )
  497. {
  498. DBG_ASSERT( FALSE );
  499. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  500. }
  501. pSubError->mdSubError = _subError.mdSubError;
  502. pSubError->dwStringId = _subError.dwStringId;
  503. return NO_ERROR;
  504. }
  505. VOID
  506. SetSubError(
  507. HTTP_SUB_ERROR * pSubError
  508. )
  509. {
  510. if ( pSubError == NULL )
  511. {
  512. DBG_ASSERT( FALSE );
  513. return;
  514. }
  515. _subError.mdSubError = pSubError->mdSubError;
  516. _subError.dwStringId = pSubError->dwStringId;
  517. }
  518. //
  519. // Touched state. Used to determine whether the system needs to send
  520. // an error (500) response due to not state handler creating a response
  521. //
  522. BOOL
  523. QueryResponseTouched(
  524. VOID
  525. ) const
  526. {
  527. return _fResponseTouched;
  528. }
  529. BOOL
  530. QueryResponseSent(
  531. VOID
  532. ) const
  533. {
  534. return _fResponseSent;
  535. }
  536. ULONGLONG
  537. QueryContentLength(
  538. VOID
  539. ) const
  540. {
  541. return _cbContentLength;
  542. }
  543. //
  544. // Is there any entity in this response (used by custom error logic)
  545. //
  546. BOOL
  547. QueryEntityExists(
  548. VOID
  549. )
  550. {
  551. return _cChunks > 0 && _cChunks > _cFirstEntityChunk;
  552. }
  553. };
  554. #endif