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.

2861 lines
83 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1994 **/
  4. /**********************************************************************/
  5. /*
  6. httpio.cxx
  7. This module contains the IO related http class methods
  8. FILE HISTORY:
  9. Johnl 09-Feb-1995 Created
  10. */
  11. #include <w3p.hxx>
  12. #include <issperr.h>
  13. //
  14. // Size of read during cert renegotiation phase
  15. //
  16. #define CERT_RENEGO_READ_SIZE (1024*4)
  17. //
  18. // size of buffer for calls to GetTokenInformation
  19. //
  20. #define MAX_TOKEN_USER_INFO (300)
  21. BOOL
  22. HTTP_REQ_BASE::StartNewRequest(
  23. PVOID pvInitialBuff,
  24. DWORD cbInitialBuff,
  25. BOOL fFirst,
  26. BOOL *pfDoAgain
  27. )
  28. /*++
  29. Routine Description:
  30. Sets up this request object for reading a new request and issues the async
  31. read to kick things off.
  32. Arguments:
  33. --*/
  34. {
  35. //
  36. // Set our initial state and variables for a new request, after
  37. // checking to see if we might have a pipelined request.
  38. //
  39. if (!fFirst && (_cbBytesReceived > _cbClientRequest))
  40. {
  41. CHAR *pchRequestPtr;
  42. DWORD dwNextRequestSize = 0;
  43. // Might possibly have a pipelined request. We do if there is
  44. // no entity body or there is but we didn't consume all of
  45. // the entity body on the previous request.
  46. //
  47. if (!IsChunked() && (QueryTotalEntityBodyCB() == 0))
  48. {
  49. //
  50. // Have a pipelined request and the last request wasn't chunked,
  51. // since we read more data than just the request header but there was
  52. // no entity body with the request.
  53. //
  54. dwNextRequestSize = _cbBytesReceived - _cbClientRequest;
  55. pchRequestPtr = (CHAR *)_bufClientRequest.QueryPtr() +
  56. _cbClientRequest;
  57. }
  58. else
  59. {
  60. if (_cbExtraData != 0)
  61. {
  62. // Have extra data in the buffer, so have a pipelined
  63. // request.
  64. pchRequestPtr = _pchExtraData;
  65. dwNextRequestSize = _cbExtraData;
  66. }
  67. }
  68. // Update bytes received to reflect what we would have seen
  69. // in the non-pipelined case.
  70. _cbBytesReceived -= dwNextRequestSize;
  71. //
  72. // If we have a pipelined request, copy the request forward and
  73. // update the counts.
  74. //
  75. if (dwNextRequestSize != 0)
  76. {
  77. Reset(FALSE);
  78. memcpy((CHAR *)_bufClientRequest.QueryPtr(),
  79. pchRequestPtr,
  80. dwNextRequestSize);
  81. _cbBytesWritten = dwNextRequestSize;
  82. // Return, forcing the reprocess.
  83. *pfDoAgain = TRUE;
  84. return TRUE;
  85. }
  86. }
  87. Reset(TRUE);
  88. *pfDoAgain = FALSE;
  89. //
  90. // Prepare a buffer to receive the client's request
  91. //
  92. if ( !_bufClientRequest.Resize( max( W3_DEFAULT_BUFFSIZE, cbInitialBuff )))
  93. {
  94. DBGPRINTF(( DBG_CONTEXT,
  95. "[StartNewRequest] failed to allocate buffer, error %lu\n",
  96. GetLastError()));
  97. return FALSE;
  98. }
  99. //
  100. // Make the IO request if an inital buffer wasn't supplied
  101. //
  102. if ( pvInitialBuff != NULL )
  103. {
  104. CopyMemory(
  105. _bufClientRequest.QueryPtr(),
  106. pvInitialBuff,
  107. cbInitialBuff );
  108. _cbBytesWritten = cbInitialBuff;
  109. }
  110. else
  111. {
  112. SetState( HTR_READING_CLIENT_REQUEST );
  113. IF_DEBUG( CONNECTION )
  114. {
  115. DBGPRINTF(( DBG_CONTEXT,
  116. "[StartNewRequest] Issuing initial read, Conn = %lx, AtqCont = %lx\n",
  117. QueryClientConn(),
  118. QueryClientConn()->QueryAtqContext() ));
  119. }
  120. //
  121. // Do the initial read. We don't go through any filters at this
  122. // point. They'll get notified on the read completion as part of
  123. // the raw data notification.
  124. //
  125. if ( !ReadFile( _bufClientRequest.QueryPtr(),
  126. _bufClientRequest.QuerySize(),
  127. NULL,
  128. IO_FLAG_ASYNC | IO_FLAG_NO_FILTER))
  129. {
  130. DBGPRINTF(( DBG_CONTEXT,
  131. "[StartNewRequest] ReadFile failed, error %lu\n",
  132. GetLastError() ));
  133. return FALSE;
  134. }
  135. }
  136. return TRUE;
  137. }
  138. /*******************************************************************
  139. NAME: HTTP_REQ_BASE::OnFillClientReq
  140. SYNOPSIS: Waits for the full client request packet then decides
  141. the course of action
  142. ENTRY: pfCompleteRequest - Set to TRUE if we've received a full
  143. client request and we can start processing the request
  144. pfFinished - Set to TRUE if no further processing is requred
  145. pfContinueProcessingRequest - Set to FALSE if we must stop processing
  146. request
  147. RETURNS: TRUE if processing should continue, FALSE to abort the
  148. this connection
  149. HISTORY:
  150. Johnl 22-Aug-1994 Created
  151. ********************************************************************/
  152. BOOL
  153. HTTP_REQ_BASE::OnFillClientReq(
  154. BOOL * pfCompleteRequest,
  155. BOOL * pfFinished,
  156. BOOL * pfContinueProcessingRequest
  157. )
  158. {
  159. BYTE * pbData = NULL;
  160. *pfCompleteRequest = FALSE;
  161. *pfContinueProcessingRequest = TRUE;
  162. _cbClientRequest += QueryBytesWritten();
  163. //
  164. // If no bytes were read on the last request, then the socket has been
  165. // closed, so abort everything and get out
  166. //
  167. if ( QueryBytesWritten() == 0 )
  168. {
  169. DBGPRINTF(( DBG_CONTEXT,
  170. "[OnFillClientReq] Client socket closed while reading request (Conn = %lx)\n",
  171. QueryClientConn() ));
  172. SetKeepConn( FALSE );
  173. *pfFinished = TRUE;
  174. return TRUE;
  175. }
  176. //NTBUG 264445 QFE and NTBUG 266474
  177. _msStartRequest = GetCurrentTime();
  178. if ( !UnWrapRequest( pfCompleteRequest,
  179. pfFinished,
  180. pfContinueProcessingRequest))
  181. {
  182. return FALSE;
  183. }
  184. if ( *pfCompleteRequest || *pfFinished || !*pfContinueProcessingRequest)
  185. {
  186. return TRUE;
  187. }
  188. //
  189. // We still don't have a complete header, so keep reading
  190. //
  191. DBG_ASSERT(!*pfCompleteRequest);
  192. if ( !ReadFile( (BYTE *)_bufClientRequest.QueryPtr() + _cbClientRequest,
  193. _bufClientRequest.QuerySize() - _cbClientRequest,
  194. NULL,
  195. IO_FLAG_ASYNC | IO_FLAG_NO_FILTER ))
  196. {
  197. DBGPRINTF(( DBG_CONTEXT,
  198. "[OnFillClientReq] ReadFile failed, error %lu\n",
  199. GetLastError() ));
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. BOOL
  205. HTTP_REQ_BASE::HandleCertRenegotiation(
  206. BOOL * pfFinished,
  207. BOOL * pfContinueProcessingRequest,
  208. DWORD cbData
  209. )
  210. /*++
  211. Routine Description:
  212. Calls the installed read filters
  213. Arguments:
  214. pfFinished - No further processing is required for this request
  215. pfContinueProcessingRequest - Set to FALSE if we have must stop processing request
  216. Return Value:
  217. TRUE on success, FALSE on failure
  218. --*/
  219. {
  220. BYTE * pbData = NULL;
  221. TCHAR * pchOutRequest;
  222. DWORD cbOutRequest;
  223. DWORD cbProcessed;
  224. BOOL fTerminated;
  225. BOOL fReadAgain = FALSE;
  226. TCHAR * pchNewData;
  227. DWORD cbOutRequestSave;
  228. *pfContinueProcessingRequest = TRUE;
  229. //
  230. // If no bytes were read on the last request, then the socket has been
  231. // closed, so abort everything and get out
  232. //
  233. if ( QueryBytesWritten() == 0 )
  234. {
  235. TCP_PRINT(( DBG_CONTEXT,
  236. "[HandleCertRenegotiation] Client socket closed while reading request (Conn = %lx)\n",
  237. QueryClientConn() ));
  238. SetLastError( ERROR_INVALID_PARAMETER );
  239. return FALSE;
  240. }
  241. //
  242. // Notify any opaque filters of the incoming data
  243. //
  244. cbProcessed = _cbClientRequest + _cbEntityBody;
  245. pchNewData = (LPSTR)_bufClientRequest.QueryPtr() + cbProcessed;
  246. if ( !_Filter.NotifyRawReadDataFilters(
  247. pchNewData,
  248. (cbOutRequestSave = _cbOldData + cbData - cbProcessed),
  249. _bufClientRequest.QuerySize() -
  250. cbProcessed, // Usable buffer size
  251. (PVOID *) &pchOutRequest,
  252. &cbOutRequest,
  253. pfFinished,
  254. &fReadAgain ))
  255. {
  256. return FALSE;
  257. }
  258. if ( *pfFinished )
  259. {
  260. return TRUE;
  261. }
  262. //
  263. // If the output buffer is different, then we need to copy
  264. // the data to our output buffer
  265. //
  266. // CODEWORK: Get rid of this buffer copy - there are assumptions the
  267. // incoming data is contained in _bufClientRequest
  268. //
  269. if ( pchOutRequest != NULL &&
  270. pchOutRequest != pchNewData )
  271. {
  272. if ( !_bufClientRequest.Resize( cbOutRequest + cbProcessed + 1 ))
  273. return FALSE;
  274. pchNewData = (LPSTR)_bufClientRequest.QueryPtr() + cbProcessed;
  275. memcpy( pchNewData,
  276. pchOutRequest,
  277. cbOutRequest );
  278. }
  279. if ( fReadAgain )
  280. {
  281. _cbOldData = cbProcessed + cbOutRequest;
  282. goto nextread;
  283. }
  284. //
  285. // A filter may have changed the size of our effective input buffer
  286. //
  287. _cbEntityBody += cbOutRequest;
  288. _cbOldData = _cbClientRequest + _cbEntityBody;
  289. if ( cbOutRequestSave > cbOutRequest )
  290. {
  291. DBG_ASSERT( _cbBytesReceived >= cbOutRequestSave - cbOutRequest );
  292. _cbBytesReceived -= cbOutRequestSave - cbOutRequest;
  293. }
  294. else
  295. {
  296. _cbBytesReceived += cbOutRequest - cbOutRequestSave;
  297. }
  298. if ( _dwRenegotiated )
  299. {
  300. cbData = _cbEntityBody;
  301. _cbRestartBytesWritten = cbData;
  302. _cbEntityBody = 0;
  303. return OnRestartRequest( (LPSTR)_bufClientRequest.QueryPtr(),
  304. cbData,
  305. pfFinished,
  306. pfContinueProcessingRequest );
  307. }
  308. nextread:
  309. DWORD cbNextRead = CERT_RENEGO_READ_SIZE;
  310. if ( !_bufClientRequest.Resize( _cbOldData + cbNextRead ))
  311. {
  312. return FALSE;
  313. }
  314. *pfContinueProcessingRequest = FALSE;
  315. if ( !ReadFile( (BYTE *) _bufClientRequest.QueryPtr() + _cbOldData,
  316. cbNextRead,
  317. NULL,
  318. IO_FLAG_ASYNC|IO_FLAG_NO_FILTER ))
  319. {
  320. return FALSE;
  321. }
  322. return TRUE;
  323. }
  324. BOOL
  325. HTTP_REQ_BASE::UnWrapRequest(
  326. BOOL * pfCompleteRequest,
  327. BOOL * pfFinished,
  328. BOOL * pfContinueProcessingRequest
  329. )
  330. /*++
  331. Routine Description:
  332. Calls the installed filters to unwrap the client request
  333. Arguments:
  334. pfCompleteRequest - Set to TRUE if we've received a full
  335. client request and we can start processing the request
  336. pfFinished - No further processing is required for this request
  337. pfContinueProcessingRequest - Set to FALSE if we're done for now
  338. Return Value:
  339. TRUE on success, FALSE on failure
  340. --*/
  341. {
  342. BOOL fHandled = FALSE;
  343. TCHAR * pchOutRequest;
  344. DWORD cbOutRequest;
  345. BOOL fTerminated = FALSE;
  346. BOOL fReadAgain;
  347. //
  348. // Notify any opaque filters of the incoming data
  349. //
  350. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_READ_RAW_DATA,
  351. IsSecurePort() ))
  352. {
  353. DWORD cbOutRequestSave;
  354. //
  355. // Make sure filters don't see the same data twice unless they
  356. // returned "read again" the last time
  357. //
  358. CHAR * pchNewData = (CHAR *) _bufClientRequest.QueryPtr() +
  359. _cbOldData;
  360. pchOutRequest = pchNewData;
  361. cbOutRequestSave = cbOutRequest = _cbClientRequest - _cbOldData;
  362. fReadAgain = FALSE;
  363. if ( !_Filter.NotifyRawReadDataFilters(
  364. pchNewData,
  365. cbOutRequest,
  366. _bufClientRequest.QuerySize() -
  367. _cbOldData, // Usable buffer size
  368. (PVOID *) &pchOutRequest,
  369. &cbOutRequest,
  370. &fHandled,
  371. &fReadAgain ))
  372. {
  373. return FALSE;
  374. }
  375. if ( fHandled )
  376. {
  377. *pfContinueProcessingRequest = FALSE;
  378. return TRUE;
  379. }
  380. //
  381. // If the output buffer is different, then we need to copy
  382. // the data to our output buffer
  383. //
  384. // CODEWORK: Get rid of this buffer copy - there are assumptions the
  385. // incoming data is contained in _bufClientRequest
  386. //
  387. if ( pchOutRequest != NULL &&
  388. pchOutRequest != pchNewData )
  389. {
  390. if ( !_bufClientRequest.Resize( cbOutRequest + _cbOldData + 1 ))
  391. return FALSE;
  392. pchNewData = (CHAR *) _bufClientRequest.QueryPtr() +
  393. _cbOldData;
  394. memcpy( pchNewData,
  395. pchOutRequest,
  396. cbOutRequest );
  397. }
  398. //
  399. // A filter may have changed the size of our effective input buffer
  400. //
  401. if ( cbOutRequestSave > cbOutRequest )
  402. {
  403. DBG_ASSERT(_cbBytesReceived >= cbOutRequestSave - cbOutRequest);
  404. _cbBytesReceived -= cbOutRequestSave - cbOutRequest;
  405. }
  406. else
  407. {
  408. _cbBytesReceived += cbOutRequest - cbOutRequestSave;
  409. }
  410. //
  411. // Variable names are not consistent with what is used
  412. // in HandleCertRenegotiation : here _cbClientRequest
  413. // indicates where to continue reading data, and _cbOldData
  414. // is # of decoded bytes in client request
  415. //
  416. _cbClientRequest = cbOutRequest + _cbOldData;
  417. //
  418. // Can we continue processing this request? The message just received
  419. // may have been a session negotiation message and we have yet to
  420. // receive the real HTTP request.
  421. //
  422. if ( fReadAgain )
  423. {
  424. //
  425. // Resize the read buffer and issue an async read to get the next
  426. // chunk for the filter. UnwrapRequest uses the size of
  427. // this buffer as the size of data to read
  428. //
  429. if ( !_bufClientRequest.Resize( _cbClientRequest +
  430. _Filter.QueryNextReadSize() ))
  431. {
  432. return FALSE;
  433. }
  434. return TRUE;
  435. }
  436. }
  437. //
  438. // Remember how much data the filter has already seen so we don't
  439. // renotify them with the same data in case we don't have a full
  440. // set of headers
  441. //
  442. _cbOldData = _cbClientRequest;
  443. if ( !CheckForTermination( &fTerminated,
  444. &_bufClientRequest,
  445. _cbClientRequest,
  446. NULL,
  447. NULL,
  448. W3_DEFAULT_BUFFSIZE ) )
  449. {
  450. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  451. {
  452. SetState( HTR_DONE, HT_BAD_REQUEST, ERROR_INSUFFICIENT_BUFFER );
  453. Disconnect( HT_BAD_REQUEST, NO_ERROR, TRUE, pfFinished );
  454. *pfCompleteRequest = TRUE;
  455. *pfContinueProcessingRequest = FALSE;
  456. return TRUE;
  457. }
  458. return FALSE;
  459. }
  460. if ( !fTerminated && !::IsPointNine( (CHAR *) _bufClientRequest.QueryPtr() ) )
  461. {
  462. //
  463. // We don't have a complete request, read more data
  464. //
  465. return TRUE;
  466. }
  467. *pfCompleteRequest = TRUE;
  468. return OnCompleteRequest( (CHAR *) _bufClientRequest.QueryPtr(),
  469. _cbClientRequest,
  470. pfFinished,
  471. pfContinueProcessingRequest );
  472. }
  473. /*******************************************************************
  474. NAME: HTTP_REQ_BASE::ReadMoreEntityBody
  475. SYNOPSIS: Attempts to read more of the entity body, resizing
  476. the buffer if necessary
  477. ENTRY: cbOffset - Offset in the buffer to read at.
  478. cbSize - Size to read.
  479. ********************************************************************/
  480. BOOL
  481. HTTP_REQ_BASE::ReadMoreEntityBody(
  482. DWORD cbOffset,
  483. DWORD cbSize
  484. )
  485. {
  486. if ( cbOffset + cbSize < cbSize )
  487. {
  488. //
  489. // The counter wrapped. Entity Body is greater than the address space !!
  490. //
  491. return FALSE;
  492. }
  493. if ( _bufClientRequest.QuerySize() < (cbOffset + cbSize) )
  494. {
  495. if ( !_bufClientRequest.Resize( cbOffset + cbSize ) )
  496. {
  497. return FALSE;
  498. }
  499. }
  500. if ( !ReadFile( (BYTE *) _bufClientRequest.QueryPtr() + cbOffset,
  501. cbSize,
  502. NULL,
  503. IO_FLAG_ASYNC ))
  504. {
  505. return FALSE;
  506. }
  507. return TRUE;
  508. }
  509. /*******************************************************************
  510. NAME: HTTP_REQ_BASE::ReadEntityBody
  511. SYNOPSIS: Attempts to retrieve an entity body from the remote
  512. client
  513. ENTRY: pfDone - Set to TRUE when _cbContentLength bytes have
  514. been read
  515. fFirstRead - TRUE if this is the first read, FALSE on
  516. subsequent reads.
  517. dwMaxAmmountToRead - Finish when this amount is read
  518. pfDisconnected - Set to TRUE if we disconnected (due to error)
  519. HISTORY:
  520. Johnl 03-Oct-1994 Created
  521. ********************************************************************/
  522. BOOL
  523. HTTP_REQ_BASE::ReadEntityBody(
  524. BOOL *pfDone,
  525. BOOL fFirstRead,
  526. DWORD dwMaxAmountToRead,
  527. BOOL *pfDisconnected
  528. )
  529. {
  530. DWORD cbNextRead;
  531. if ( pfDisconnected )
  532. {
  533. *pfDisconnected = FALSE;
  534. }
  535. if (dwMaxAmountToRead == 0)
  536. {
  537. dwMaxAmountToRead = QueryMetaData()->QueryUploadReadAhead();
  538. }
  539. if (!IsChunked())
  540. {
  541. _cbEntityBody += QueryBytesWritten();
  542. _cbTotalEntityBody += QueryBytesWritten();
  543. if ( _cbTotalEntityBody >= _cbContentLength)
  544. {
  545. //
  546. // Ugh - disgusting, but if we have no content length then
  547. // we take whatever we have in the buffer currently and return
  548. // it. This can lead to random behavior, depending on what
  549. // actually makes it in the first read. I hate to do this, but
  550. // we're doing it this way because of bug-for-bug compatibility
  551. // with IIS 3.0. Probably the right thing to do if we have no
  552. // content length is to keep reading until we get 0 bytes read,
  553. // and return whatever we read as the content length. JohnL
  554. // argues that the right thing is to fail the request in the
  555. // absence of a content length.
  556. if (_fHaveContentLength && (_cbTotalEntityBody > _cbContentLength))
  557. {
  558. _cbExtraData = _cbTotalEntityBody - _cbContentLength;
  559. DBG_ASSERT(_cbExtraData <= _cbEntityBody);
  560. _cbEntityBody -= _cbExtraData;
  561. _pchExtraData = (CHAR *)_bufClientRequest.QueryPtr() +
  562. _cbClientRequest +
  563. _cbEntityBody;
  564. _cbTotalEntityBody = _cbContentLength;
  565. }
  566. *pfDone = TRUE;
  567. return TRUE;
  568. }
  569. if (_cbEntityBody >= dwMaxAmountToRead)
  570. {
  571. *pfDone = TRUE;
  572. return TRUE;
  573. }
  574. //
  575. // If no bytes were read on the last request, then the socket has been
  576. // closed, so abort everything and get out
  577. //
  578. if ( !fFirstRead && QueryBytesWritten() == 0 )
  579. {
  580. DBGPRINTF(( DBG_CONTEXT,
  581. "[ReadEntityBody] Client socket closed while reading request (Conn = %lx)\n",
  582. QueryClientConn() ));
  583. SetLastError( ERROR_INVALID_PARAMETER );
  584. return FALSE;
  585. }
  586. *pfDone = FALSE;
  587. cbNextRead = min( (dwMaxAmountToRead - _cbEntityBody),
  588. (_cbContentLength - _cbTotalEntityBody ));
  589. if ( _bufClientRequest.QuerySize() <
  590. (_cbClientRequest + _cbEntityBody + cbNextRead))
  591. {
  592. if ( !_bufClientRequest.Resize( _cbClientRequest + _cbEntityBody + cbNextRead ))
  593. {
  594. return FALSE;
  595. }
  596. }
  597. if ( !ReadFile( (BYTE *) _bufClientRequest.QueryPtr() + _cbEntityBody +
  598. _cbClientRequest,
  599. cbNextRead,
  600. NULL,
  601. IO_FLAG_ASYNC ))
  602. {
  603. return FALSE;
  604. }
  605. return TRUE;
  606. } else
  607. {
  608. DWORD cbBytesInBuffer;
  609. BYTE *ChunkHeader;
  610. *pfDone = FALSE;
  611. // We'll just return here if the app says they want to
  612. // read it all. This might not be the right thing to do unless
  613. // they also call this routine to read the rest of the data,
  614. // because there could be a partial chunk in here. So we'll
  615. // make sure that there isn't, or force the client to send a
  616. // C-L.
  617. if (dwMaxAmountToRead == 0)
  618. {
  619. if (QueryBytesWritten() != 0)
  620. {
  621. SetState( HTR_DONE, HT_LENGTH_REQUIRED, ERROR_NOT_SUPPORTED );
  622. Disconnect( HT_LENGTH_REQUIRED, IDS_LENGTH_REQUIRED, FALSE, pfDone );
  623. if ( pfDisconnected )
  624. {
  625. *pfDisconnected = TRUE;
  626. }
  627. }
  628. else
  629. {
  630. *pfDone = TRUE;
  631. }
  632. return TRUE;
  633. }
  634. if (_ChunkState == READ_CHUNK_DONE)
  635. {
  636. *pfDone = TRUE;
  637. return TRUE;
  638. }
  639. if ( fFirstRead )
  640. {
  641. // Initialize our state variables, as this is the start of a chunk.
  642. _ChunkState = READ_CHUNK_SIZE;
  643. _dwChunkSize = -1;
  644. _cbChunkHeader = 0;
  645. _cbChunkBytesRead = 0;
  646. _cbEntityBody = 0;
  647. } else
  648. {
  649. if ( QueryBytesWritten() == 0 )
  650. {
  651. DBGPRINTF(( DBG_CONTEXT,
  652. "[ReadEntityBody] Client socket closed while reading request (Conn = %lx)\n",
  653. QueryClientConn() ));
  654. SetLastError( ERROR_INVALID_PARAMETER );
  655. return FALSE;
  656. }
  657. }
  658. *pfDone = FALSE;
  659. cbBytesInBuffer = QueryBytesWritten();
  660. ChunkHeader = (BYTE *)_bufClientRequest.QueryPtr() + _cbChunkHeader +
  661. + _cbEntityBody + _cbClientRequest;
  662. if(!DecodeChunkedBytes(ChunkHeader, &cbBytesInBuffer)) {
  663. // error in chunked data
  664. DBGPRINTF(( DBG_CONTEXT, "Error in chunked data at %d\r\n",
  665. _cbEntityBody ));
  666. SetState( HTR_DONE, HT_BAD_REQUEST, ERROR_NOT_SUPPORTED );
  667. Disconnect( HT_BAD_REQUEST, IDS_HTRESP_BAD_REQUEST, FALSE, pfDone );
  668. if ( pfDisconnected )
  669. {
  670. *pfDisconnected = TRUE;
  671. }
  672. return TRUE;
  673. }
  674. _cbEntityBody += cbBytesInBuffer;
  675. _cbTotalEntityBody += cbBytesInBuffer;
  676. if( _cbEntityBody < dwMaxAmountToRead &&
  677. _ChunkState != READ_CHUNK_DONE )
  678. {
  679. cbNextRead = dwMaxAmountToRead - _cbEntityBody;
  680. if(cbNextRead < CHUNK_READ_SIZE) {
  681. cbNextRead = CHUNK_READ_SIZE;
  682. }
  683. return ReadMoreEntityBody(
  684. _cbClientRequest + _cbChunkHeader + _cbEntityBody,
  685. cbNextRead);
  686. } else {
  687. // We've read enough data
  688. *pfDone = TRUE;
  689. return TRUE;
  690. }
  691. }
  692. return TRUE;
  693. }
  694. /*******************************************************************
  695. NAME: HTTP_REQ_BASE::DecodeChunkedBytes
  696. SYNOPSIS: Decodes specified number of chunked bytes in-place,
  697. using member variables to keep track of the state
  698. ENTRY: lpBuffer - points to first encoded byte
  699. lpnBytes - points to count of encoded bytes
  700. EXIT: lpnBytes - points to count of decoded bytes
  701. ********************************************************************/
  702. BOOL
  703. HTTP_REQ_BASE::DecodeChunkedBytes(
  704. LPBYTE lpBuffer,
  705. LPDWORD pnBytes
  706. )
  707. {
  708. DWORD cbBytesToDecode;
  709. DWORD cbBytesDecoded, cb;
  710. LPBYTE lpCurrent, lpData;
  711. BYTE Current;
  712. BOOL fSuccess = TRUE;
  713. // Cache the count of bytes to decode
  714. cbBytesToDecode = *pnBytes;
  715. // Setup our running buffer pointer and data pointer
  716. lpCurrent = lpBuffer;
  717. lpData = lpBuffer;
  718. // No data decoded
  719. cbBytesDecoded = 0;
  720. // while we have unprocessed data
  721. while( cbBytesToDecode ) {
  722. switch( _ChunkState ) {
  723. case READ_CHUNK_SIZE:
  724. while( cbBytesToDecode ) {
  725. Current = *lpCurrent;
  726. if( isxdigit( (UCHAR)Current ) ) {
  727. if( _dwChunkSize == -1 ) {
  728. _dwChunkSize = 0;
  729. }
  730. // Adjust chunk size, count off consumed byte
  731. _dwChunkSize = (_dwChunkSize * 16) +
  732. ( isdigit( (UCHAR)Current ) ? Current - '0' :
  733. ( Current | 0x20 ) - 'a' + 10 );
  734. lpCurrent++;
  735. cbBytesToDecode--;
  736. } else {
  737. if( _dwChunkSize == -1 ) {
  738. DBGPRINTF(( DBG_CONTEXT,
  739. "[DecodeChunkedBytes] bad chunk size\n" ));
  740. SetLastError( ERROR_INVALID_PARAMETER );
  741. fSuccess = FALSE;
  742. goto done;
  743. }
  744. // Not a hex digit, eat the rest of the line until LF
  745. _CRCount = _LFCount = 0;
  746. _ChunkState = READ_CHUNK_PARAMS;
  747. // Now is a good time to clear the counter
  748. // of chunk data bytes that we've read
  749. _cbChunkBytesRead = 0;
  750. break;
  751. }
  752. }
  753. break;
  754. case READ_CHUNK_PARAMS:
  755. // Eat anything which follows chunk size until LF
  756. while( cbBytesToDecode ) {
  757. Current = *(lpCurrent++);
  758. cbBytesToDecode--;
  759. if( Current == '\r' ) {
  760. _CRCount = 1;
  761. } else {
  762. if( Current == '\n' && _CRCount != 0 ) {
  763. // We got LF, proceed reading chunk data
  764. _ChunkState = READ_CHUNK;
  765. _LFCount = 1;
  766. break;
  767. } else {
  768. //
  769. // No LF -- ignore CR(s)
  770. //
  771. _CRCount = 0;
  772. }
  773. }
  774. }
  775. //
  776. // Shift the data to remove any chunk header
  777. //
  778. if( cbBytesToDecode ) {
  779. memmove( lpData, lpCurrent, cbBytesToDecode );
  780. lpCurrent = lpData;
  781. }
  782. //
  783. // If we have a 0 chunk size, we've read all of the data
  784. // but we may still have some footers to read
  785. //
  786. if( _dwChunkSize == 0 ) {
  787. _ChunkState = READ_CHUNK_FOOTER;
  788. }
  789. break;
  790. case READ_CHUNK:
  791. cb = _dwChunkSize - _cbChunkBytesRead;
  792. if( cb <= cbBytesToDecode ) {
  793. //
  794. // We have the whole chunk
  795. //
  796. //
  797. // Count off chunk worth of bytes to decode
  798. //
  799. cbBytesToDecode -= cb;
  800. //
  801. // Advance current pointer
  802. //
  803. lpCurrent += cb;
  804. //
  805. // Count in decoded bytes
  806. //
  807. cbBytesDecoded += cb;
  808. //
  809. // Notice the position right after the last data byte
  810. //
  811. lpData = lpCurrent;
  812. //
  813. // Prepare CR and LF counters to handle trailing CRLF
  814. //
  815. _CRCount = _LFCount = 0;
  816. //
  817. // Shift to a new state
  818. //
  819. _ChunkState = READ_CHUNK_CRLF;
  820. } else {
  821. //
  822. // All cbBytesToDecode are data bytes
  823. //
  824. //
  825. // Count in decoded bytes
  826. //
  827. cbBytesDecoded += cbBytesToDecode;
  828. //
  829. // Remember number of bytes read by this call - we'll need it
  830. // on next entry to this function
  831. //
  832. _cbChunkBytesRead += cbBytesToDecode;
  833. //
  834. // Nothing left to decode
  835. //
  836. cbBytesToDecode = 0;
  837. }
  838. break;
  839. case READ_CHUNK_FOOTER:
  840. while( cbBytesToDecode ) {
  841. Current = *(lpCurrent++);
  842. cbBytesToDecode--;
  843. if( Current == '\r' ) {
  844. _CRCount++;
  845. } else {
  846. if( Current == '\n' && _CRCount != 0 ) {
  847. _LFCount++;
  848. if( _CRCount == 2 && _LFCount == 2 ) {
  849. //
  850. // CODEWORK
  851. // We may have other footers here...
  852. //
  853. if(_dwChunkSize == 0) {
  854. _ChunkState = READ_CHUNK_DONE;
  855. goto done;
  856. }
  857. _ChunkState = READ_CHUNK_SIZE;
  858. _CRCount = _LFCount = 0;
  859. _dwChunkSize = 0;
  860. break;
  861. }
  862. } else {
  863. _CRCount = _LFCount = 0;
  864. }
  865. }
  866. }
  867. break;
  868. case READ_CHUNK_CRLF:
  869. if( _CRCount == 0 ) {
  870. if( *lpCurrent == '\r' ) {
  871. cbBytesToDecode--;
  872. lpCurrent++;
  873. _CRCount = 1;
  874. } else {
  875. SetLastError( ERROR_INVALID_PARAMETER );
  876. fSuccess = FALSE;
  877. goto done;
  878. }
  879. }
  880. if( cbBytesToDecode != 0 ) {
  881. if( *lpCurrent == '\n' ) {
  882. if( cbBytesToDecode == 1 ) {
  883. _ChunkState = READ_CHUNK_SIZE;
  884. _CRCount = _LFCount = 0;
  885. _dwChunkSize = 0;
  886. goto done;
  887. }
  888. cbBytesToDecode--;
  889. lpCurrent++;
  890. _dwChunkSize = 0;
  891. _CRCount = _LFCount = 0;
  892. _ChunkState = READ_CHUNK_SIZE;
  893. break;
  894. } else {
  895. SetLastError( ERROR_INVALID_PARAMETER );
  896. fSuccess = FALSE;
  897. goto done;
  898. }
  899. }
  900. break;
  901. default:
  902. DBG_ASSERT( 0 );
  903. }
  904. }
  905. done:
  906. *pnBytes = cbBytesDecoded;
  907. return fSuccess;
  908. }
  909. VOID
  910. HttpReqResolveCallback(
  911. ADDRCHECKARG pArg,
  912. BOOL fSt,
  913. LPSTR pName
  914. )
  915. {
  916. // ignore fSt : DNS name is simply unavailable
  917. ((CLIENT_CONN*)pArg)->PostCompletionStatus( 0 );
  918. //((CLIENT_CONN*)pArg)->DoWork( 0, 0, FALSE );
  919. }
  920. BOOL
  921. HTTP_REQ_BASE::OnCompleteRequest(
  922. TCHAR * pchRequest,
  923. DWORD cbData,
  924. BOOL * pfFinished,
  925. BOOL * pfContinueProcessingRequest
  926. )
  927. /*++
  928. Routine Description:
  929. This method takes a complete HTTP 1.0 request and handles the results
  930. of the parsing method
  931. Arguments:
  932. pchRequest - Pointer to first byte of request header
  933. cbData - Number of data bytes in pchRequest
  934. pfFinished - Set to TRUE if no further processing is needed
  935. pfContinueProcessingRequest - Set to FALSE is we must stop processing request
  936. Return Value:
  937. TRUE on success, FALSE on failure
  938. --*/
  939. {
  940. BOOL fRet;
  941. DWORD cbExtraData;
  942. BOOL fNoCert;
  943. BOOL fHandled = FALSE;
  944. LPBYTE pbCaList;
  945. DWORD dwCaList;
  946. LPBYTE pbCa;
  947. DWORD dwCa;
  948. BOOL fDenyOnDnsFail = TRUE;
  949. BOOL fDenyComplete = FALSE;
  950. BOOL fDisconnected = FALSE;
  951. //
  952. // Parse the request
  953. //
  954. fRet = Parse( pchRequest,
  955. cbData,
  956. &cbExtraData,
  957. &fHandled,
  958. pfFinished );
  959. //
  960. // We can process authorization now that virtual root mapping is done
  961. //
  962. if ( fRet && _HeaderList.FastMapQueryValue( HM_AUT ) != NULL &&
  963. !( *pfFinished || fHandled ) )
  964. {
  965. fRet = ProcessAuthorization( (CHAR *)
  966. _HeaderList.FastMapQueryValue( HM_AUT ) );
  967. }
  968. if ( !fRet )
  969. {
  970. DWORD hterr;
  971. DWORD winerr = GetLastError();
  972. DWORD errorResponse = NO_ERROR;
  973. IF_DEBUG(ERROR) {
  974. DBGPRINTF(( DBG_CONTEXT,
  975. "[OnFillClientReq] httpReq.Parse or httpLogonUser failed, error %lu\n",
  976. GetLastError() ));
  977. }
  978. switch ( winerr )
  979. {
  980. case ERROR_INVALID_PARAMETER:
  981. //
  982. // If the request is bad, then indicate that to the client
  983. //
  984. hterr = HT_BAD_REQUEST;
  985. break;
  986. case ERROR_FILE_NOT_FOUND:
  987. case ERROR_PATH_NOT_FOUND:
  988. hterr = HT_NOT_FOUND;
  989. break;
  990. case ERROR_BAD_NET_NAME:
  991. hterr = HT_NOT_FOUND;
  992. errorResponse = IDS_SITE_NOT_FOUND;
  993. break;
  994. case ERROR_NOT_SUPPORTED:
  995. hterr = HT_NOT_SUPPORTED;
  996. break;
  997. case ERROR_PASSWORD_EXPIRED:
  998. case ERROR_PASSWORD_MUST_CHANGE:
  999. if ( !_fAnonymous && !_fMappedAcct )
  1000. {
  1001. if ( !DoChange( &fHandled ) )
  1002. {
  1003. return FALSE;
  1004. }
  1005. if ( fHandled )
  1006. {
  1007. *pfContinueProcessingRequest = FALSE;
  1008. return TRUE;
  1009. }
  1010. }
  1011. if ( !DenyAccess( &fDenyComplete, &fDisconnected ) || fDenyComplete )
  1012. {
  1013. hterr = HT_DENIED;
  1014. winerr = ERROR_ACCESS_DENIED;
  1015. SetLastError( winerr );
  1016. errorResponse = IDS_PWD_CHANGE;
  1017. return FALSE;
  1018. }
  1019. else
  1020. {
  1021. *pfContinueProcessingRequest = FALSE;
  1022. return TRUE;
  1023. }
  1024. case ERROR_ACCESS_DENIED:
  1025. case ERROR_LOGON_FAILURE:
  1026. SetLastError( ERROR_ACCESS_DENIED );
  1027. if ( !DenyAccess( &fDenyComplete, &fDisconnected ) || fDenyComplete )
  1028. {
  1029. return FALSE;
  1030. }
  1031. else
  1032. {
  1033. *pfContinueProcessingRequest = FALSE;
  1034. return TRUE;
  1035. }
  1036. case ERROR_LOGIN_WKSTA_RESTRICTION:
  1037. hterr = HT_FORBIDDEN;
  1038. winerr = ERROR_ACCESS_DENIED;
  1039. errorResponse = IDS_SITE_ACCESS_DENIED;
  1040. break;
  1041. case ERROR_TOO_MANY_SESS:
  1042. hterr = HT_FORBIDDEN;
  1043. winerr = ERROR_ACCESS_DENIED;
  1044. errorResponse = IDS_TOO_MANY_USERS;
  1045. break;
  1046. case ERROR_INVALID_DATA:
  1047. hterr = HT_SERVER_ERROR;
  1048. errorResponse = IDS_INVALID_CNFG;
  1049. break;
  1050. default:
  1051. //
  1052. // Some other fatal error occurred
  1053. //
  1054. hterr = HT_SERVER_ERROR;
  1055. break;
  1056. }
  1057. if ( errorResponse == NO_ERROR ) {
  1058. errorResponse = winerr;
  1059. }
  1060. if (!_fNoDisconnectOnError)
  1061. {
  1062. SetState( HTR_DONE, hterr, winerr );
  1063. if (!_fDiscNoError)
  1064. {
  1065. Disconnect( hterr, errorResponse, FALSE, pfFinished );
  1066. }
  1067. else
  1068. {
  1069. Disconnect( 0, NO_ERROR, FALSE, pfFinished );
  1070. }
  1071. }
  1072. //
  1073. // Since we handled the error ourselves (by issuing a disconnect),
  1074. // we will return success (otherwise another disconnect will
  1075. // occur)
  1076. //
  1077. *pfContinueProcessingRequest = FALSE;
  1078. return TRUE;
  1079. }
  1080. if ( fHandled )
  1081. {
  1082. *pfContinueProcessingRequest = FALSE;
  1083. return TRUE;
  1084. }
  1085. if ( *pfFinished )
  1086. {
  1087. return TRUE;
  1088. }
  1089. //
  1090. // Check to see if encryption is required before we do any processing
  1091. //
  1092. if ( ( ((HTTP_REQUEST*)this)->GetFilePerms() & VROOT_MASK_SSL )
  1093. && !IsSecurePort() )
  1094. {
  1095. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1096. Disconnect( HT_FORBIDDEN, IDS_SSL_REQUIRED, FALSE, pfFinished );
  1097. *pfContinueProcessingRequest = FALSE;
  1098. return TRUE;
  1099. }
  1100. //
  1101. // Check if encryption key size should be at least 128 bits
  1102. //
  1103. if ( ( ((HTTP_REQUEST*)this)->GetFilePerms() & VROOT_MASK_SSL128 ) )
  1104. {
  1105. DWORD dwKeySize;
  1106. if ( !_tcpauth.QueryEncryptionKeySize(&dwKeySize, &fNoCert) || (dwKeySize < 128) )
  1107. {
  1108. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1109. Disconnect( HT_FORBIDDEN, IDS_SSL128_REQUIRED, FALSE, pfFinished );
  1110. *pfContinueProcessingRequest = FALSE;
  1111. return TRUE;
  1112. }
  1113. }
  1114. #if 0
  1115. if ( IsSslCa( &pbCaList, &dwCaList ) )
  1116. {
  1117. if( !_tcpauth.QueryCa( &pbCa, &dwCa, &fNoCert ) )
  1118. {
  1119. if ( !fNoCert )
  1120. {
  1121. goto rjca;
  1122. }
  1123. }
  1124. else if ( IsInCaList( pbCaList, dwCaList, pbCa, dwCa ) )
  1125. {
  1126. rjca:
  1127. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1128. Disconnect( HT_FORBIDDEN, IDS_CA_NOT_ALLOWED, FALSE, pfFinished );
  1129. *pfContinueProcessingRequest = FALSE;
  1130. return TRUE;
  1131. }
  1132. }
  1133. #endif
  1134. #if defined(CAL_ENABLED)
  1135. //
  1136. // Check if CAL granted for SSL access
  1137. //
  1138. if ( IsSecurePort() && !m_pCalSslCtxt )
  1139. {
  1140. if ( !CalConnect( QueryClientConn()->QueryRemoteAddr(),
  1141. strlen( QueryClientConn()->QueryRemoteAddr() ),
  1142. TRUE,
  1143. "",
  1144. 0,
  1145. NULL,
  1146. &m_pCalSslCtxt ) )
  1147. {
  1148. g_pInetSvc->LogEvent( W3_EVENT_CAL_SSL_EXCEEDED,
  1149. 0,
  1150. NULL,
  1151. 0 );
  1152. BOOL bOverTheLimit;
  1153. switch ( ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalMode() )
  1154. {
  1155. case MD_CAL_MODE_LOGCOUNT:
  1156. IncrErrorCount( (IMDCOM*)QueryW3Instance()->m_Service->QueryMDObject(),
  1157. MD_CAL_SSL_ERRORS,
  1158. QueryW3Instance()->m_Service->QueryMDPath(),
  1159. &bOverTheLimit );
  1160. if ( !bOverTheLimit )
  1161. {
  1162. break;
  1163. }
  1164. // fall-through
  1165. case MD_CAL_MODE_HTTPERR:
  1166. SetState( HTR_DONE,
  1167. ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalW3Error(),
  1168. ERROR_ACCESS_DENIED );
  1169. Disconnect( ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalW3Error(),
  1170. IDS_CAL_EXCEEDED,
  1171. FALSE,
  1172. pfFinished );
  1173. *pfContinueProcessingRequest = FALSE;
  1174. return TRUE;
  1175. }
  1176. }
  1177. }
  1178. #endif
  1179. //
  1180. // Check IP access granted
  1181. //
  1182. BOOL fNeedDns = FALSE;
  1183. //
  1184. // do access check once per authenticated request
  1185. //
  1186. if ( !IsIpDnsAccessCheckPresent() )
  1187. {
  1188. _acIpAccess = AC_IN_GRANT_LIST;
  1189. }
  1190. else if ( _acIpAccess == AC_NOT_CHECKED )
  1191. {
  1192. _acIpAccess = QueryClientConn()->CheckIpAccess( &_fNeedDnsCheck );
  1193. fNeedDns = _fNeedDnsCheck;
  1194. if ( (_acIpAccess == AC_IN_DENY_LIST) ||
  1195. ((_acIpAccess == AC_NOT_IN_GRANT_LIST) && !_fNeedDnsCheck) )
  1196. {
  1197. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1198. Disconnect( HT_FORBIDDEN, IDS_ADDR_REJECT, FALSE, pfFinished );
  1199. *pfContinueProcessingRequest = FALSE;
  1200. return TRUE;
  1201. }
  1202. }
  1203. //
  1204. // If DNS name required for further processing and is not already present,
  1205. // request it now.
  1206. //
  1207. if ( !fNeedDns )
  1208. {
  1209. if ( !IsLoggedOn() &&
  1210. (QueryW3Instance()->QueryNetLogonWks() == MD_NETLOGON_WKS_DNS) &&
  1211. (QueryMetaData()->QueryAuthentInfo()->dwLogonMethod == LOGON32_LOGON_NETWORK) )
  1212. {
  1213. fNeedDns = TRUE;
  1214. }
  1215. else if ( QueryMetaData()->QueryDoReverseDns() )
  1216. {
  1217. //
  1218. // We would like to get the host name of the client. But if we
  1219. // can't we shouldn't deny access on the request.
  1220. //
  1221. fNeedDns = TRUE;
  1222. fDenyOnDnsFail = FALSE;
  1223. }
  1224. }
  1225. if ( fNeedDns && !QueryClientConn()->IsDnsResolved() )
  1226. {
  1227. BOOL fSync;
  1228. LPSTR pDns;
  1229. if ( !QueryClientConn()->QueryDnsName( &fSync,
  1230. (ADDRCHECKFUNCEX)HttpReqResolveCallback,
  1231. (ADDRCHECKARG)QueryClientConn(),
  1232. &pDns ) )
  1233. {
  1234. if ( fDenyOnDnsFail )
  1235. {
  1236. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1237. Disconnect( HT_FORBIDDEN, IDS_ADDR_REJECT, FALSE, pfFinished );
  1238. *pfContinueProcessingRequest = FALSE;
  1239. return TRUE;
  1240. }
  1241. else
  1242. {
  1243. //
  1244. // Just fall thru and handle the request.
  1245. //
  1246. fSync = TRUE;
  1247. }
  1248. }
  1249. if ( !fSync )
  1250. {
  1251. SetState( HTR_RESTART_REQUEST );
  1252. *pfContinueProcessingRequest = FALSE;
  1253. return TRUE;
  1254. }
  1255. }
  1256. return OnRestartRequest( pchRequest, cbExtraData, pfFinished, pfContinueProcessingRequest );
  1257. }
  1258. BOOL
  1259. HTTP_REQ_BASE::DoChange(
  1260. LPBOOL pfHandled
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This method handles password expiration notification
  1265. Arguments:
  1266. pfHandled - updated with TRUE if change pwd request handled
  1267. Return Value:
  1268. TRUE on success, FALSE on failure
  1269. --*/
  1270. {
  1271. STR strExpUrl;
  1272. BOOL fSt = TRUE;
  1273. STR strUrlArgs;
  1274. QueryW3Instance()->LockThisForRead();
  1275. fSt = strExpUrl.Copy((TCHAR*)QueryW3Instance()->QueryAuthExpiredUrl() );
  1276. QueryW3Instance()->UnlockThis();
  1277. if ( !fSt || !strExpUrl.QueryCCH() )
  1278. {
  1279. // can't change pwd
  1280. *pfHandled = FALSE;
  1281. return TRUE;
  1282. }
  1283. if ( LogonAsSystem() )
  1284. {
  1285. //
  1286. // Add the arg to be passed to the password-change URL - argument is the URL the
  1287. // user is pointed to after all the password-change processing is done
  1288. //
  1289. if ( fSt = strExpUrl.Append( (TCHAR*)"?" ) )
  1290. {
  1291. fSt = TRUE;
  1292. //
  1293. // If we're changing the password on the proxy, we use the original non-proxy-munged
  1294. // URL
  1295. //
  1296. if ( IsProxyRequest() )
  1297. {
  1298. fSt = strUrlArgs.Append( (TCHAR*) _strOriginalURL.QueryStr() );
  1299. }
  1300. //
  1301. // Can't just use QueryHostAddr() concatentated with
  1302. // _HeaderList.FastMapQueryValue( HM_URL ) because for HTTP 1.1 we might have a fully
  1303. // qualified request as an URL, so we have to build it up piece-meal.
  1304. //
  1305. else
  1306. {
  1307. if ( !strUrlArgs.Append( IsSecurePort() ? (TCHAR*)"https://" :
  1308. (TCHAR*)"http://" ) ||
  1309. !strUrlArgs.Append( (TCHAR*)QueryHostAddr() ) ||
  1310. !strUrlArgs.Append( (TCHAR*) QueryURL() ) ||
  1311. !strUrlArgs.Append( _strURLParams.IsEmpty() ? (TCHAR *) "" : (TCHAR*) "?" ) ||
  1312. !strUrlArgs.Append( _strURLParams.IsEmpty() ? (TCHAR*) "" :
  1313. (TCHAR*) QueryURLParams() ))
  1314. {
  1315. fSt = FALSE;
  1316. }
  1317. }
  1318. if ( fSt )
  1319. {
  1320. fSt = strExpUrl.Append( (TCHAR*) strUrlArgs.QueryStr() );
  1321. }
  1322. }
  1323. if ( !fSt )
  1324. {
  1325. *pfHandled = FALSE;
  1326. return FALSE;
  1327. }
  1328. //
  1329. // We used to call ReprocessURL() here to send back the form that allows users
  1330. // to change their password, but there was a problem with the compression filter
  1331. // [see Bug 120119 in the NT DB for full description] (and potentially other filters
  1332. // as well) that make it better to do a 302 Redirect to the password change URL
  1333. //
  1334. BOOL fFinished = FALSE;
  1335. //
  1336. // Put ourselves in a known state after the redirect - some browsers may close the
  1337. // connection, others may keep it if we don't explicitly close it
  1338. //
  1339. SetKeepConn( FALSE );
  1340. if ( BuildURLMovedResponse( QueryRespBuf(),
  1341. &strExpUrl,
  1342. HT_REDIRECT,
  1343. FALSE ) &&
  1344. ( (HTTP_REQUEST*)this )->SendHeader( QueryRespBufPtr(),
  1345. QueryRespBufCB(),
  1346. IO_FLAG_SYNC,
  1347. &fFinished ) )
  1348. {
  1349. *pfHandled = TRUE;
  1350. return TRUE;
  1351. }
  1352. else
  1353. {
  1354. *pfHandled = FALSE;
  1355. return FALSE;
  1356. }
  1357. }
  1358. SetDeniedFlags( SF_DENIED_LOGON );
  1359. SetLastError( ERROR_ACCESS_DENIED );
  1360. *pfHandled = FALSE;
  1361. return FALSE;
  1362. }
  1363. BOOL
  1364. HTTP_REQ_BASE::DenyAccess(
  1365. BOOL * pfDenyComplete,
  1366. BOOL * pfDisconnected
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. This method prepare the connection for a deny access return status by
  1371. eating any entity body in the denied request
  1372. Arguments:
  1373. pfDenyComplete - Set to true when all entity body is read
  1374. pfDisconnected - Set to true if we disconnected
  1375. Return Value:
  1376. TRUE if successful, else FALSE
  1377. --*/
  1378. {
  1379. HTR_STATE OldState = QueryState();
  1380. BOOL fDisconnected = FALSE;
  1381. SetState( HTR_ACCESS_DENIED );
  1382. if ( !ReadEntityBody( pfDenyComplete,
  1383. TRUE,
  1384. QueryClientContentLength(),
  1385. pfDisconnected ) )
  1386. {
  1387. return FALSE;
  1388. }
  1389. if ( *pfDenyComplete )
  1390. {
  1391. SetState( OldState );
  1392. }
  1393. return TRUE;
  1394. }
  1395. BOOL
  1396. HTTP_REQ_BASE::OnRestartRequest(
  1397. TCHAR * pchRequest,
  1398. DWORD cbData,
  1399. BOOL * pfFinished,
  1400. BOOL * pfContinueProcessingRequest
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. This method takes a complete HTTP 1.0 request and handles the results
  1405. of the parsing method
  1406. Arguments:
  1407. pchRequest - Pointer to first byte of request header
  1408. cbData - Number of read data bytes in message body
  1409. pfFinished - Set to TRUE if no further processing is needed
  1410. pfContinueProcessingRequest - Set to FALSE is we must stop processing request
  1411. Return Value:
  1412. TRUE on success, FALSE on failure
  1413. --*/
  1414. {
  1415. BOOL fGranted;
  1416. LARGE_INTEGER cExpire;
  1417. SYSTEMTIME stExpire;
  1418. FILETIME ftNow;
  1419. BYTE rgbInfo[MAX_TOKEN_USER_INFO];
  1420. DWORD cbTotalRequired;
  1421. STR strExpUrl;
  1422. BOOL fAccepted = FALSE;
  1423. DWORD cbNextRead;
  1424. AC_RESULT acDnsAccess;
  1425. BOOL fHandled;
  1426. DWORD dwCertFlags = 0;
  1427. BOOL fNoCert;
  1428. LPBYTE pbCa;
  1429. DWORD dwCa;
  1430. *pfContinueProcessingRequest = TRUE; // Assume we'll handle this w/o I/O.
  1431. //
  1432. // restore BytesWritten as set by 1st phase of request
  1433. // ( may have been overwritten by reverse DNS lookup phase )
  1434. //
  1435. _cbBytesWritten = _cbRestartBytesWritten;
  1436. //
  1437. // Check if cert renegotiation to be requested
  1438. //
  1439. if ( QueryState() != HTR_CERT_RENEGOTIATE )
  1440. {
  1441. if ( !((HTTP_REQUEST*)this)->RequestRenegotiate( &fAccepted ) )
  1442. {
  1443. if ( GetLastError() == SEC_E_INCOMPLETE_MESSAGE )
  1444. {
  1445. fAccepted = FALSE;
  1446. }
  1447. else
  1448. {
  1449. return FALSE;
  1450. }
  1451. }
  1452. }
  1453. //
  1454. // If requested, begin reading data. Notification will be handled
  1455. // by HandleCertRenegotiation()
  1456. //
  1457. if ( fAccepted )
  1458. {
  1459. _cbEntityBody = cbData;
  1460. _cbOldData = _cbClientRequest + cbData;
  1461. cbNextRead = CERT_RENEGO_READ_SIZE;
  1462. if ( !_bufClientRequest.Resize( _cbOldData + cbNextRead ))
  1463. {
  1464. return FALSE;
  1465. }
  1466. *pfContinueProcessingRequest = FALSE;
  1467. if ( !ReadFile( (BYTE *) _bufClientRequest.QueryPtr() + _cbOldData,
  1468. cbNextRead,
  1469. NULL,
  1470. IO_FLAG_ASYNC|IO_FLAG_NO_FILTER ))
  1471. {
  1472. return FALSE;
  1473. }
  1474. return TRUE;
  1475. }
  1476. if ( _dwRenegotiated == CERT_NEGO_SUCCESS )
  1477. {
  1478. QueryW3Instance()->IsSslCa( &pbCa, &dwCa );
  1479. if ( !_tcpauth.UpdateClientCertFlags( QueryW3Instance()->QueryCertCheckMode(),
  1480. &fNoCert,
  1481. pbCa,
  1482. dwCa ) )
  1483. {
  1484. return FALSE;
  1485. }
  1486. if ( !_tcpauth.QueryCertificateFlags( &dwCertFlags, &fNoCert ) ||
  1487. ( dwCertFlags & ( RCRED_STATUS_UNKNOWN_ISSUER |
  1488. CRED_STATUS_INVALID_TIME |
  1489. CRED_STATUS_REVOKED ) ) )
  1490. {
  1491. goto cert_req;
  1492. }
  1493. }
  1494. else if ( ((HTTP_REQUEST*)this)->GetFilePerms() & VROOT_MASK_NEGO_MANDATORY )
  1495. {
  1496. cert_req:
  1497. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1498. //
  1499. // Several things could go wrong, so order our processing from most to least severe
  1500. // (the order is a little arbitrary, but oh well ...)
  1501. //
  1502. DWORD dwSubStatus = 0;
  1503. if ( dwCertFlags & RCRED_STATUS_UNKNOWN_ISSUER )
  1504. {
  1505. dwSubStatus = IDS_CERT_BAD;
  1506. }
  1507. else if ( dwCertFlags & CRED_STATUS_INVALID_TIME )
  1508. {
  1509. dwSubStatus = IDS_CERT_TIME_INVALID;
  1510. }
  1511. else if ( dwCertFlags & CRED_STATUS_REVOKED )
  1512. {
  1513. dwSubStatus = IDS_CERT_REVOKED;
  1514. }
  1515. else
  1516. {
  1517. dwSubStatus = IDS_CERT_REQUIRED;
  1518. }
  1519. Disconnect( HT_FORBIDDEN, dwSubStatus, FALSE, pfFinished );
  1520. *pfContinueProcessingRequest = FALSE;
  1521. return TRUE;
  1522. }
  1523. if ( _fInvalidAccessToken )
  1524. {
  1525. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1526. Disconnect( HT_FORBIDDEN, IDS_MAPPER_DENY_ACCESS, FALSE, pfFinished );
  1527. *pfContinueProcessingRequest = FALSE;
  1528. return TRUE;
  1529. }
  1530. //
  1531. // If we're having an authentication conversation, then we send an access denied
  1532. // response with the next authentication blob. The client returns the next blob
  1533. // to us in an HTTP request.
  1534. //
  1535. if ( IsAuthenticating() )
  1536. {
  1537. //
  1538. // If no blob to send to client then handle this as
  1539. // a 401 notification with disconnect
  1540. //
  1541. if ( _strAuthInfo.IsEmpty() )
  1542. {
  1543. SetKeepConn( FALSE );
  1544. SetDeniedFlags( SF_DENIED_LOGON );
  1545. _fAuthenticating = FALSE;
  1546. }
  1547. DoAuthentication:
  1548. //
  1549. // An access denied error automatically sends the next part
  1550. // of the authentication conversation
  1551. //
  1552. SetLastError( ERROR_ACCESS_DENIED );
  1553. BOOL fDenyComplete = FALSE;
  1554. BOOL fDisconnected = FALSE;
  1555. if ( !DenyAccess( &fDenyComplete, &fDisconnected ) || fDenyComplete )
  1556. {
  1557. return FALSE;
  1558. }
  1559. else
  1560. {
  1561. *pfContinueProcessingRequest = FALSE;
  1562. return TRUE;
  1563. }
  1564. }
  1565. if ( _fNeedDnsCheck )
  1566. {
  1567. acDnsAccess = QueryClientConn()->CheckDnsAccess();
  1568. _fNeedDnsCheck = FALSE;
  1569. // not checked name should be denied
  1570. if ( acDnsAccess == AC_NOT_CHECKED ||
  1571. acDnsAccess == AC_IN_DENY_LIST ||
  1572. acDnsAccess == AC_NOT_IN_GRANT_LIST ||
  1573. (_acIpAccess == AC_NOT_IN_GRANT_LIST && acDnsAccess != AC_IN_GRANT_LIST) )
  1574. {
  1575. SetState( HTR_DONE, HT_FORBIDDEN, ERROR_ACCESS_DENIED );
  1576. Disconnect( HT_FORBIDDEN, IDS_ADDR_REJECT, FALSE, pfFinished );
  1577. *pfContinueProcessingRequest = FALSE;
  1578. return TRUE;
  1579. }
  1580. }
  1581. ((HTTP_REQUEST*)this)->CheckValidAuth();
  1582. //
  1583. // If we have all the authentication information we need and we're
  1584. // not already logged on, try to log the user on
  1585. //
  1586. if ( !IsLoggedOn() && !LogonUser( pfFinished ) )
  1587. {
  1588. LogonErr:
  1589. if ( (GetLastError() == ERROR_ACCESS_DENIED) ||
  1590. (GetLastError() == ERROR_LOGON_FAILURE))
  1591. {
  1592. goto DoAuthentication;
  1593. }
  1594. if ( (GetLastError() == ERROR_PASSWORD_EXPIRED ||
  1595. GetLastError() == ERROR_PASSWORD_MUST_CHANGE) )
  1596. {
  1597. BOOL fDenyComplete = FALSE;
  1598. SetLastError( ERROR_ACCESS_DENIED );
  1599. if ( !DoChange( &fHandled ) )
  1600. {
  1601. return FALSE;
  1602. }
  1603. if ( !fHandled )
  1604. {
  1605. #if 0
  1606. SetState( HTR_DONE, HT_DENIED, ERROR_ACCESS_DENIED );
  1607. Disconnect( HT_DENIED, IDS_PWD_CHANGE, FALSE, pfFinished );
  1608. #else
  1609. SetDeniedFlags( SF_DENIED_LOGON );
  1610. goto DoAuthentication;
  1611. #endif
  1612. }
  1613. else
  1614. {
  1615. *pfFinished = TRUE;
  1616. }
  1617. return TRUE;
  1618. }
  1619. return FALSE;
  1620. }
  1621. else if ( (QueryNotifyExAuth() & MD_NOTIFEXAUTH_NTLMSSL ) &&
  1622. _Filter.IsNotificationNeeded( SF_NOTIFY_AUTHENTICATIONEX,
  1623. IsSecurePort() ) )
  1624. {
  1625. HANDLE hTok;
  1626. if ( !_Filter.NotifyAuthInfoFiltersEx( _strUserName.QueryStr(),
  1627. _strUserName.QueryCCH(),
  1628. _strUserName.QueryStr(),
  1629. _strUserName.QueryCCH(),
  1630. "",
  1631. "",
  1632. QueryMetaData()->QueryAuthentInfo()->
  1633. strDefaultLogonDomain.QueryStr(),
  1634. _strAuthType.QueryStr(),
  1635. _strAuthType.QueryCCH(),
  1636. &hTok,
  1637. &hTok,
  1638. pfFinished ))
  1639. {
  1640. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_FILTER );
  1641. goto LogonErr;
  1642. }
  1643. }
  1644. if ( *pfFinished )
  1645. {
  1646. return TRUE;
  1647. }
  1648. //
  1649. // Call SF_NOTIFY_AUTH_COMPLETE filters if we're logged on now
  1650. //
  1651. if ( IsLoggedOn() &&
  1652. _Filter.IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE,
  1653. IsSecurePort() ) )
  1654. {
  1655. HTTP_FILTER_AUTH_COMPLETE_INFO AuthInfo;
  1656. STACK_STR( strOriginal, MAX_PATH );
  1657. //
  1658. // Store away the original URL
  1659. //
  1660. if ( !strOriginal.Copy( _HeaderList.FastMapQueryValue( HM_URL ) ) )
  1661. {
  1662. return FALSE;
  1663. }
  1664. if ( !_Filter.NotifyAuthComplete( pfFinished,
  1665. &AuthInfo ) )
  1666. {
  1667. return FALSE;
  1668. }
  1669. if ( *pfFinished )
  1670. {
  1671. return TRUE;
  1672. }
  1673. if ( _stricmp( strOriginal.QueryStr(),
  1674. _HeaderList.FastMapQueryValue( HM_URL ) ) )
  1675. {
  1676. BOOL fRet;
  1677. //
  1678. // Filter changed the URL. Reprocess the URL
  1679. //
  1680. if ( AuthInfo.fResetAuth )
  1681. {
  1682. ResetAuth( FALSE );
  1683. }
  1684. fRet = ((HTTP_REQUEST*)this)->ReprocessURL(
  1685. (char*) _HeaderList.FastMapQueryValue( HM_URL ),
  1686. HTV_UNKNOWN );
  1687. *pfContinueProcessingRequest = FALSE;
  1688. return fRet;
  1689. }
  1690. }
  1691. #if defined(CAL_ENABLED)
  1692. //
  1693. // Check if CAL granted for authenticated access
  1694. //
  1695. if ( !_fAnonymous && !m_pCalAuthCtxt )
  1696. {
  1697. if ( !CalConnect( QueryClientConn()->QueryRemoteAddr(),
  1698. strlen( QueryClientConn()->QueryRemoteAddr() ),
  1699. FALSE,
  1700. _strUserName.QueryStr(),
  1701. _strUserName.QueryCCH(),
  1702. _tcpauth.QueryImpersonationToken(),
  1703. &m_pCalAuthCtxt ) )
  1704. {
  1705. BOOL bOverTheLimit;
  1706. switch ( ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalMode() )
  1707. {
  1708. case MD_CAL_MODE_LOGCOUNT:
  1709. IncrErrorCount( (IMDCOM*)QueryW3Instance()->m_Service->QueryMDObject(),
  1710. MD_CAL_AUTH_ERRORS,
  1711. QueryW3Instance()->m_Service->QueryMDPath(),
  1712. &bOverTheLimit );
  1713. if ( !bOverTheLimit )
  1714. {
  1715. break;
  1716. }
  1717. // fall-through
  1718. case MD_CAL_MODE_HTTPERR:
  1719. SetState( HTR_DONE,
  1720. ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalW3Error(),
  1721. ERROR_ACCESS_DENIED );
  1722. Disconnect( ((W3_IIS_SERVICE*)(QueryW3Instance()->m_Service))->QueryCalW3Error(),
  1723. IDS_CAL_EXCEEDED,
  1724. FALSE,
  1725. pfFinished );
  1726. *pfContinueProcessingRequest = FALSE;
  1727. return TRUE;
  1728. }
  1729. }
  1730. }
  1731. #endif
  1732. //
  1733. // Query pwd expiration time.
  1734. // if available, check if in notification range as defined by configuration
  1735. // if in range, call configured URL
  1736. //
  1737. if ( !_fMappedAcct &&
  1738. !_fAnonymous &&
  1739. _tcpauth.QueryExpiry( (PTimeStamp)&cExpire ) )
  1740. {
  1741. if ( cExpire.HighPart == 0x7fffffff )
  1742. {
  1743. IF_DEBUG(REQUEST) {
  1744. DBGPRINTF( ( DBG_CONTEXT, "No expiration time\r\n" ) );
  1745. }
  1746. }
  1747. else
  1748. {
  1749. ::IISGetCurrentTimeAsFileTime( &ftNow );
  1750. {
  1751. if ( *(__int64*)&cExpire > *(__int64*)&ftNow )
  1752. {
  1753. _dwExpireInDay = (DWORD)((*(__int64*)&cExpire
  1754. - *(__int64*)&ftNow)
  1755. / ((__int64)10000000*86400));
  1756. if ( QueryW3Instance()->QueryAdvNotPwdExpInDays()
  1757. && _dwExpireInDay
  1758. <= QueryW3Instance()->
  1759. QueryAdvNotPwdExpInDays()
  1760. && QueryW3Instance()->QueryAdvNotPwdExpUrl() )
  1761. {
  1762. //
  1763. // Check this SID has not already been notified
  1764. // of pwd expiration
  1765. //
  1766. if ( GetTokenInformation( _tcpauth.QueryPrimaryToken(),
  1767. TokenUser,
  1768. (LPVOID ) rgbInfo,
  1769. sizeof(rgbInfo),
  1770. &cbTotalRequired) )
  1771. {
  1772. TOKEN_USER * pTokenUser = (TOKEN_USER *) rgbInfo;
  1773. PSID pSid = pTokenUser->User.Sid;
  1774. if( !PenCheckPresentAndResetTtl( pSid,
  1775. QueryW3Instance()
  1776. ->QueryAdvCacheTTL() ) )
  1777. {
  1778. PenAddToCache( pSid,
  1779. QueryW3Instance()
  1780. ->QueryAdvCacheTTL() );
  1781. //
  1782. // flush cache when connection close
  1783. // so that account change will not be masked
  1784. // by cached information
  1785. //
  1786. _tcpauth.DeleteCachedTokenOnReset();
  1787. QueryW3Instance()->LockThisForRead();
  1788. BOOL fSt = strExpUrl.Copy( (TCHAR*)QueryW3Instance()
  1789. ->QueryAdvNotPwdExpUrl() );
  1790. QueryW3Instance()->UnlockThis();
  1791. if ( !fSt )
  1792. {
  1793. return FALSE;
  1794. }
  1795. if ( strExpUrl.QueryStr()[0] )
  1796. {
  1797. //
  1798. // Add the arg to be passed to the password-change URL -
  1799. // argument is the URL the user is pointed to after all the
  1800. // password-change processing is done
  1801. //
  1802. if ( fSt = strExpUrl.Append( (TCHAR*)"?" ) )
  1803. {
  1804. fSt = TRUE;
  1805. STR strUrlArgs;
  1806. //
  1807. // If we're changing the password on the proxy, we use
  1808. // the original non-proxy-munged URL
  1809. //
  1810. if ( IsProxyRequest() )
  1811. {
  1812. fSt = strUrlArgs.Append( (TCHAR*)
  1813. _strOriginalURL.QueryStr() );
  1814. }
  1815. //
  1816. // Can't just use QueryHostAddr() concatentated with
  1817. // _HeaderList.FastMapQueryValue( HM_URL ) because for
  1818. // HTTP 1.1 we might have a fully qualified request as an
  1819. // URL, so we have to build it up piece-meal.
  1820. //
  1821. else
  1822. {
  1823. if ( !strUrlArgs.Append( IsSecurePort() ?
  1824. (TCHAR*)"https://" :
  1825. (TCHAR*)"http://" ) ||
  1826. !strUrlArgs.Append( (TCHAR*)QueryHostAddr() ) ||
  1827. !strUrlArgs.Append( (TCHAR*) QueryURL() ) ||
  1828. !strUrlArgs.Append( _strURLParams.IsEmpty() ? (TCHAR *) "" : (TCHAR*) "?" ) ||
  1829. !strUrlArgs.Append( _strURLParams.IsEmpty() ? (TCHAR*) "" :
  1830. (TCHAR*) QueryURLParams() ))
  1831. {
  1832. fSt = FALSE;
  1833. }
  1834. }
  1835. if ( fSt )
  1836. {
  1837. fSt = strExpUrl.Append( (TCHAR*)
  1838. strUrlArgs.QueryStr() );
  1839. }
  1840. }
  1841. if ( !fSt )
  1842. {
  1843. return FALSE;
  1844. }
  1845. _tcpauth.QueryFullyQualifiedUserName(
  1846. _strUnmappedUserName.QueryStr(),
  1847. &_strUnmappedUserName,
  1848. QueryW3Instance(),
  1849. QueryMetaData()->QueryAuthentInfo());
  1850. //
  1851. // process new URL
  1852. //
  1853. SetKeepConn( FALSE ); // to resync input flow
  1854. //
  1855. // We used to call ReprocessURL() here to send back the form
  1856. // that allows users to change their password, but there was
  1857. // a problem with the compression filter
  1858. // [see Bug 120119 in the NT DB for full description]
  1859. // (and potentially other filters as well) that make it
  1860. // better to do a 302 Redirect to the password change URL
  1861. //
  1862. // We're guaranteed not to get into an infinite loop with the
  1863. // redirect because we check whether or not the given SID
  1864. // has already been notified about the password expiration
  1865. // [ see call to PenCheckPresentAndResetTtl() call above]
  1866. //
  1867. #if 1
  1868. BOOL fFinished = FALSE;
  1869. if ( BuildURLMovedResponse( QueryRespBuf(),
  1870. &strExpUrl,
  1871. HT_REDIRECT,
  1872. FALSE ) &&
  1873. ( (HTTP_REQUEST*)this )->SendHeader( QueryRespBufPtr(),
  1874. QueryRespBufCB(),
  1875. IO_FLAG_SYNC,
  1876. &fFinished ) )
  1877. {
  1878. *pfFinished = TRUE;
  1879. return TRUE;
  1880. }
  1881. else
  1882. {
  1883. return FALSE;
  1884. }
  1885. #else
  1886. if ( !((HTTP_REQUEST*)this)->CancelPreconditions() )
  1887. {
  1888. return FALSE;
  1889. }
  1890. if ( ((HTTP_REQUEST*)this)->ReprocessURL(
  1891. strExpUrl.QueryStr(),
  1892. HTV_GET ) )
  1893. {
  1894. *pfFinished = TRUE;
  1895. return TRUE;
  1896. }
  1897. else
  1898. {
  1899. return FALSE;
  1900. }
  1901. #endif
  1902. }
  1903. }
  1904. }
  1905. }
  1906. }
  1907. else
  1908. {
  1909. _dwExpireInDay = 0;
  1910. }
  1911. }
  1912. #if DBG
  1913. IF_DEBUG(REQUEST) {
  1914. FileTimeToSystemTime( (FILETIME*)&cExpire, &stExpire );
  1915. DBGPRINTF( ( DBG_CONTEXT,
  1916. "Expiration date: %2d-%2d-%4d, %02d:%02d\r\n",
  1917. stExpire.wMonth, stExpire.wDay, stExpire.wYear,
  1918. stExpire.wHour, stExpire.wMinute ) );
  1919. }
  1920. #endif
  1921. }
  1922. }
  1923. //
  1924. // Check to see if the client specified any additional data
  1925. // that we need to pickup. We want to do this if there is an entity
  1926. // body, so _fHaveContentLength should be TRUE,
  1927. // and this is either a request destined for an ISAPI app or a
  1928. // non-PUT request that the server will handle. We do it this way
  1929. // to handle weird error cases, like GETs with entity bodies. We
  1930. // don't do this for unknown verbs that we're not going to handle
  1931. // anyways, since those will generate an error and we don't need
  1932. // to bother reading the entity body.
  1933. //
  1934. // Note also that this approach won't handle those cases of an
  1935. // entity body without a content-length or transfer-encoding. It's
  1936. // hard to distinguish those cases from pipelined requests. If we
  1937. // need to handle this we can check for cbData being non-zero and
  1938. // the request being for a verb that could have an entity body, i.e.
  1939. // HTV_UNKNOWN or HTV_POST. This checked would be or'ed with the check
  1940. // for _fHaveContentLength.
  1941. //
  1942. // If the server is changed such that requests with entity bodies
  1943. // other than PUT are handled then the 'if' statement below will need
  1944. // to be modified, most likely to check for verbs other than PUT.
  1945. //
  1946. if ( _fHaveContentLength &&
  1947. (IsProbablyGatewayRequest() ||
  1948. (QueryVerb() != HTV_PUT && QueryVerb() != HTV_UNKNOWN)
  1949. )
  1950. )
  1951. {
  1952. //
  1953. // If we've got a 1.1 client, and we're reading some data for the app,
  1954. // and this is a PUT or a POST, we've got to send the 100 Continue
  1955. // response here. Note: it's possible that the 100 response should
  1956. // be sent for any request that has an entity body. If we decide
  1957. // to do that then just remove the last part of the following 'if'
  1958. // statement.
  1959. if (IsAtLeastOneOne() &&
  1960. (QueryMetaData()->QueryUploadReadAhead() != 0) &&
  1961. ((QueryVerb() == HTV_PUT) || (QueryVerb() == HTV_POST)))
  1962. {
  1963. if ( !SendHeader( "100 Continue", "\r\n", IO_FLAG_SYNC, pfFinished,
  1964. HTTPH_NO_CONNECTION) )
  1965. {
  1966. // An error on the header send. Abort this request.
  1967. return FALSE;
  1968. }
  1969. if ( *pfFinished )
  1970. {
  1971. return TRUE;
  1972. }
  1973. }
  1974. //
  1975. // Now let's pickup the rest of the data.
  1976. //
  1977. SetState( HTR_READING_GATEWAY_DATA );
  1978. //
  1979. // We're all set, read the entity body now.
  1980. //
  1981. if ( !ReadEntityBody( pfContinueProcessingRequest, TRUE ))
  1982. {
  1983. return FALSE;
  1984. }
  1985. if ( !*pfContinueProcessingRequest )
  1986. return TRUE;
  1987. //
  1988. // else Fall through as we have all of the gateway data
  1989. //
  1990. }
  1991. SetState( HTR_DOVERB );
  1992. return TRUE;
  1993. }
  1994. BOOL
  1995. HTTP_REQ_BASE::ReadFile(
  1996. LPVOID lpBuffer,
  1997. DWORD nBytesToRead,
  1998. DWORD * pnBytesRead,
  1999. DWORD dwFlags )
  2000. {
  2001. //
  2002. // If no filters are installed, do the normal thing
  2003. //
  2004. if ( (dwFlags & IO_FLAG_NO_FILTER) ||
  2005. !_Filter.IsNotificationNeeded( SF_NOTIFY_READ_RAW_DATA,
  2006. IsSecurePort() ))
  2007. {
  2008. if ( dwFlags & IO_FLAG_ASYNC )
  2009. {
  2010. return _pClientConn->ReadFile( lpBuffer,
  2011. nBytesToRead );
  2012. }
  2013. else
  2014. {
  2015. DWORD nBytes = 0;
  2016. BOOL fRet;
  2017. DWORD err;
  2018. //
  2019. // Bogus hack - server relies on GetLastError() too much
  2020. // select() and recv() both reset the last error which hoses
  2021. // us on some error cleanup paths
  2022. //
  2023. err = GetLastError();
  2024. fRet = TcpSockRecv( _pClientConn->QuerySocket(),
  2025. (char *) lpBuffer,
  2026. nBytesToRead,
  2027. &nBytes,
  2028. 60 // 60s timeout
  2029. );
  2030. if ( pnBytesRead != NULL ) {
  2031. *pnBytesRead = nBytes;
  2032. }
  2033. if ( fRet ) {
  2034. SetLastError( err );
  2035. }
  2036. return fRet;
  2037. }
  2038. }
  2039. else
  2040. {
  2041. //
  2042. // We don't need to up the ref-count because the filter
  2043. // will eventually post an async-completion with the connection
  2044. // object
  2045. //
  2046. if ( _Filter.ReadData( lpBuffer,
  2047. nBytesToRead,
  2048. pnBytesRead,
  2049. dwFlags ))
  2050. {
  2051. return TRUE;
  2052. }
  2053. return FALSE;
  2054. }
  2055. } // HTTP_REQ_BASE::ReadFile
  2056. BOOL
  2057. HTTP_REQ_BASE::WriteFile(
  2058. LPVOID lpBuffer,
  2059. DWORD nBytesToWrite,
  2060. DWORD * pnBytesWritten,
  2061. DWORD dwFlags )
  2062. {
  2063. //
  2064. // Don't use WriteFileAndRecv unless we're told to
  2065. //
  2066. if (! g_fUseAndRecv ) {
  2067. dwFlags &= ~IO_FLAG_AND_RECV;
  2068. }
  2069. AtqSetSocketOption(_pClientConn->QueryAtqContext(),
  2070. TCP_NODELAY,
  2071. (dwFlags & IO_FLAG_NO_DELAY) ? 1 : 0
  2072. );
  2073. if ( (dwFlags & IO_FLAG_NO_FILTER ) ||
  2074. !_Filter.IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA,
  2075. IsSecurePort() ))
  2076. {
  2077. if ( dwFlags & IO_FLAG_ASYNC )
  2078. {
  2079. _fAsyncSendPosted = TRUE;
  2080. if ( dwFlags & IO_FLAG_AND_RECV ) {
  2081. return _pClientConn->WriteFileAndRecv( lpBuffer,
  2082. nBytesToWrite,
  2083. _bufClientRequest.QueryPtr(),
  2084. _bufClientRequest.QuerySize() );
  2085. } else {
  2086. return _pClientConn->WriteFile( lpBuffer,
  2087. nBytesToWrite );
  2088. }
  2089. }
  2090. else
  2091. {
  2092. DWORD nBytes = 0;
  2093. BOOL fRet;
  2094. DWORD err;
  2095. err = GetLastError();
  2096. fRet = TcpSockSend( _pClientConn->QuerySocket(),
  2097. lpBuffer,
  2098. nBytesToWrite,
  2099. &nBytes,
  2100. 60 // 60s timeout
  2101. );
  2102. _cbBytesSent += nBytes;
  2103. if ( pnBytesWritten != NULL ) {
  2104. *pnBytesWritten = nBytes;
  2105. }
  2106. if ( fRet ) {
  2107. SetLastError( err );
  2108. }
  2109. return fRet;
  2110. }
  2111. }
  2112. else
  2113. {
  2114. //
  2115. // We don't need to up the ref-count because the filter
  2116. // will eventually post an async-completion with the connection
  2117. // object
  2118. //
  2119. if ( _Filter.SendData( lpBuffer,
  2120. nBytesToWrite,
  2121. pnBytesWritten,
  2122. dwFlags ))
  2123. {
  2124. return TRUE;
  2125. }
  2126. return FALSE;
  2127. }
  2128. }
  2129. BOOL
  2130. HTTP_REQ_BASE::TestConnection( VOID )
  2131. {
  2132. return TcpSockTest( _pClientConn->QuerySocket() );
  2133. }
  2134. BOOL
  2135. HTTP_REQ_BASE::TransmitFile(
  2136. TS_OPEN_FILE_INFO * pOpenFile,
  2137. HANDLE hFile,
  2138. DWORD Offset,
  2139. DWORD BytesToWrite,
  2140. DWORD dwFlags,
  2141. PVOID pHead,
  2142. DWORD HeadLength,
  2143. PVOID pTail,
  2144. DWORD TailLength
  2145. )
  2146. {
  2147. //
  2148. // Either a file handle or a TS_OPEN_FILE_INFO* must be passed in
  2149. //
  2150. // We want to support Transmit file with out a file handle.
  2151. // DBG_ASSERT( hFile || pOpenFile );
  2152. DBG_CODE(
  2153. if( hFile == NULL && !pOpenFile )
  2154. {
  2155. // This is the no file handle case
  2156. DBG_ASSERT( Offset == 0 );
  2157. DBG_ASSERT( BytesToWrite == 0 );
  2158. }
  2159. );
  2160. //
  2161. // File sends must always be async
  2162. //
  2163. DBG_ASSERT( !(dwFlags & IO_FLAG_SYNC));
  2164. //
  2165. // Don't use TransmitFileAndRecv unless we're told to
  2166. //
  2167. if (! g_fUseAndRecv ) {
  2168. dwFlags |= IO_FLAG_NO_RECV;
  2169. }
  2170. //
  2171. // Don't count filter bytes
  2172. //
  2173. if ( !(dwFlags & IO_FLAG_NO_FILTER ))
  2174. {
  2175. _cFilesSent++;
  2176. }
  2177. if ( (dwFlags & IO_FLAG_NO_FILTER) ||
  2178. !_Filter.IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA,
  2179. IsSecurePort() ))
  2180. {
  2181. _fAsyncSendPosted = TRUE;
  2182. if ( dwFlags & (TF_DISCONNECT|IO_FLAG_NO_RECV) ) {
  2183. if ( pOpenFile )
  2184. {
  2185. return TransmitFileTs( pOpenFile,
  2186. Offset,
  2187. BytesToWrite,
  2188. dwFlags,
  2189. pHead,
  2190. HeadLength,
  2191. pTail,
  2192. TailLength );
  2193. }
  2194. else
  2195. {
  2196. return _pClientConn->TransmitFile( hFile,
  2197. Offset,
  2198. BytesToWrite,
  2199. dwFlags,
  2200. pHead,
  2201. HeadLength,
  2202. pTail,
  2203. TailLength );
  2204. }
  2205. } else {
  2206. return _pClientConn->TransmitFileAndRecv( hFile ? hFile :
  2207. GetFileHandle( pOpenFile ),
  2208. Offset,
  2209. BytesToWrite,
  2210. dwFlags,
  2211. pHead,
  2212. HeadLength,
  2213. pTail,
  2214. TailLength,
  2215. _bufClientRequest.QueryPtr(),
  2216. _bufClientRequest.QuerySize() );
  2217. }
  2218. }
  2219. else
  2220. {
  2221. if ( _Filter.SendFile( pOpenFile,
  2222. hFile,
  2223. Offset,
  2224. BytesToWrite,
  2225. dwFlags,
  2226. pHead,
  2227. HeadLength,
  2228. pTail,
  2229. TailLength ))
  2230. {
  2231. return TRUE;
  2232. }
  2233. return FALSE;
  2234. }
  2235. }
  2236. BOOL
  2237. HTTP_REQ_BASE::TransmitFileTs(
  2238. TS_OPEN_FILE_INFO * pOpenFile,
  2239. DWORD Offset,
  2240. DWORD BytesToWrite,
  2241. DWORD dwFlags,
  2242. PVOID pHead,
  2243. DWORD HeadLength,
  2244. PVOID pTail,
  2245. DWORD TailLength
  2246. )
  2247. {
  2248. BOOL fRet;
  2249. PBYTE pFileBuf = pOpenFile->QueryFileBuffer();
  2250. if (pFileBuf &&
  2251. !(HeadLength && TailLength) ) {
  2252. //
  2253. // Do the fast path by sending file through
  2254. // head or tail buffer
  2255. //
  2256. if (TailLength) {
  2257. fRet = _pClientConn->TransmitFile(
  2258. NULL,
  2259. 0,
  2260. 0,
  2261. dwFlags,
  2262. pFileBuf + Offset,
  2263. BytesToWrite,
  2264. pTail,
  2265. TailLength
  2266. );
  2267. } else {
  2268. fRet = _pClientConn->TransmitFile(
  2269. NULL,
  2270. 0,
  2271. 0,
  2272. dwFlags,
  2273. pHead,
  2274. HeadLength,
  2275. pFileBuf + Offset,
  2276. BytesToWrite
  2277. );
  2278. }
  2279. } else {
  2280. //
  2281. // Do the slow path
  2282. //
  2283. fRet = _pClientConn->TransmitFile(
  2284. GetFileHandle( pOpenFile ),
  2285. Offset,
  2286. BytesToWrite,
  2287. dwFlags,
  2288. pHead,
  2289. HeadLength,
  2290. pTail,
  2291. TailLength
  2292. );
  2293. }
  2294. return fRet;
  2295. }
  2296. BOOL
  2297. HTTP_REQ_BASE::SyncWsaSend(
  2298. WSABUF * rgWsaBuffers,
  2299. DWORD cWsaBuffers,
  2300. LPDWORD pcbWritten
  2301. )
  2302. {
  2303. BOOL fRet;
  2304. DBG_ASSERT( pcbWritten );
  2305. fRet = _pClientConn->SyncWsaSend( rgWsaBuffers,
  2306. cWsaBuffers,
  2307. pcbWritten );
  2308. if( pcbWritten )
  2309. {
  2310. _cbBytesSent += *pcbWritten;
  2311. }
  2312. return fRet;
  2313. }
  2314. BOOL
  2315. HTTP_REQ_BASE::PostCompletionStatus(
  2316. DWORD cbBytesTransferred
  2317. )
  2318. {
  2319. return _pClientConn->PostCompletionStatus( cbBytesTransferred );
  2320. }