Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1988 lines
52 KiB

  1. /*++
  2. Copyright (c) 1994-1997 Microsoft Corporation
  3. Module Name:
  4. read.cxx
  5. Abstract:
  6. This file contains the implementation of the HttpReadData API.
  7. Contents:
  8. HttpReadData
  9. CFsm_HttpReadData::RunSM
  10. HTTP_REQUEST_HANDLE_OBJECT::HttpReadData_Fsm
  11. HTTP_REQUEST_HANDLE_OBJECT::ReadData
  12. CFsm_ReadData::RunSM
  13. HTTP_REQUEST_HANDLE_OBJECT::ReadData_Fsm
  14. HTTP_REQUEST_HANDLE_OBJECT::QueryDataAvailable
  15. CFsm_HttpQueryAvailable::RunSM
  16. HTTP_REQUEST_HANDLE_OBJECT::QueryAvailable_Fsm
  17. HTTP_REQUEST_HANDLE_OBJECT::DrainResponse
  18. CFsm_DrainResponse::RunSM
  19. HTTP_REQUEST_HANDLE_OBJECT::DrainResponse_Fsm
  20. Author:
  21. Keith Moore (keithmo) 16-Nov-1994
  22. Revision History:
  23. Modified to make HttpReadData remotable. madana (2/8/95)
  24. --*/
  25. #include <wininetp.h>
  26. #include <perfdiag.hxx>
  27. #include "httpp.h"
  28. //
  29. // private prototypes
  30. //
  31. PRIVATE
  32. VOID
  33. FilterHeaders(
  34. IN LPSTR lpszHeaderInfo,
  35. OUT LPDWORD lpdwLen
  36. );
  37. //
  38. // functions
  39. //
  40. DWORD
  41. HttpReadData(
  42. IN HINTERNET hRequest,
  43. OUT LPVOID lpBuffer,
  44. IN DWORD dwNumberOfBytesToRead,
  45. OUT LPDWORD lpdwNumberOfBytesRead,
  46. IN DWORD dwSocketFlags
  47. )
  48. /*++
  49. Routine Description:
  50. Reads a block of data from an outstanding HTTP request
  51. Assumes: 1. this function can only be called from InternetReadFile() which
  52. globally validates parameters for all Internet data read
  53. functions
  54. 2. We will never get a request for 0 bytes at this level. This
  55. request will have been handled in InternetReadFile()
  56. Arguments:
  57. hRequest - mapped HTTP request handle
  58. lpBuffer - pointer to the buffer to receive the data
  59. dwNumberOfBytesToRead - number of bytes to read into lpBuffer
  60. lpdwNumberOfBytesRead - number of bytes read into lpBuffer
  61. dwSocketFlags - controlling socket operation
  62. Return Value:
  63. TRUE - The data was read successfully. lpdwNumberOfBytesRead points to the
  64. number of BYTEs actually read. This value will be set to zero
  65. when the transfer has completed.
  66. FALSE - The operation failed. Error status is available by calling
  67. GetLastError().
  68. --*/
  69. {
  70. DEBUG_ENTER((DBG_HTTP,
  71. Dword,
  72. "HttpReadData",
  73. "%#x, %#x, %d, %#x, %#x",
  74. hRequest,
  75. lpBuffer,
  76. dwNumberOfBytesToRead,
  77. lpdwNumberOfBytesRead,
  78. dwSocketFlags
  79. ));
  80. DWORD error;
  81. HTTP_REQUEST_HANDLE_OBJECT* pRequest =
  82. (HTTP_REQUEST_HANDLE_OBJECT*) hRequest;
  83. if (pRequest->IsReadRequest()) {
  84. //
  85. // Invoke ReadLoop fsm only if the read and write positions
  86. // are different, otherwise older code is more efficient.
  87. //
  88. error = DoFsm (new CFsm_ReadLoop (pRequest, dwSocketFlags,
  89. (PBYTE) lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead));
  90. } else {
  91. error = DoFsm(new CFsm_HttpReadData(lpBuffer,
  92. dwNumberOfBytesToRead,
  93. lpdwNumberOfBytesRead,
  94. dwSocketFlags,
  95. pRequest
  96. ));
  97. }
  98. DEBUG_LEAVE(error);
  99. return error;
  100. }
  101. DWORD
  102. CFsm_HttpReadData::RunSM(
  103. IN CFsm * Fsm
  104. )
  105. /*++
  106. Routine Description:
  107. description-of-function.
  108. Arguments:
  109. Fsm -
  110. Return Value:
  111. DWORD
  112. --*/
  113. {
  114. DEBUG_ENTER((DBG_HTTP,
  115. Dword,
  116. "CFsm_HttpReadData::RunSM",
  117. "%#x",
  118. Fsm
  119. ));
  120. DWORD error;
  121. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  122. CFsm_HttpReadData * stateMachine = (CFsm_HttpReadData *)Fsm;
  123. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  124. switch (Fsm->GetState()) {
  125. case FSM_STATE_INIT:
  126. case FSM_STATE_CONTINUE:
  127. error = pRequest->HttpReadData_Fsm(stateMachine);
  128. break;
  129. default:
  130. error = ERROR_INTERNET_INTERNAL_ERROR;
  131. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  132. INET_ASSERT(FALSE);
  133. break;
  134. }
  135. DEBUG_LEAVE(error);
  136. return error;
  137. }
  138. DWORD
  139. HTTP_REQUEST_HANDLE_OBJECT::HttpReadData_Fsm(
  140. IN CFsm_HttpReadData * Fsm
  141. )
  142. /*++
  143. Routine Description:
  144. description-of-function.
  145. Arguments:
  146. Fsm -
  147. Return Value:
  148. DWORD
  149. --*/
  150. {
  151. DEBUG_ENTER((DBG_HTTP,
  152. Dword,
  153. "HTTP_REQUEST_HANDLE_OBJECT::HttpReadData_Fsm",
  154. "%#x",
  155. Fsm
  156. ));
  157. CFsm_HttpReadData & fsm = *Fsm;
  158. DWORD error = fsm.GetError();
  159. if (fsm.GetState() == FSM_STATE_INIT) {
  160. if (!IsValidHttpState(READ)) {
  161. error = ERROR_INTERNET_INCORRECT_HANDLE_STATE;
  162. goto quit;
  163. }
  164. error = ReadData(fsm.m_lpBuffer,
  165. fsm.m_dwNumberOfBytesToRead,
  166. fsm.m_lpdwNumberOfBytesRead,
  167. FALSE, // BUGBUG RFirthRemove on chkin
  168. fsm.m_dwSocketFlags
  169. );
  170. if (error != ERROR_SUCCESS) {
  171. goto quit;
  172. }
  173. }
  174. if (IsCacheWriteInProgress()) {
  175. if (*fsm.m_lpdwNumberOfBytesRead == 0) {
  176. DEBUG_PRINT(CACHE,
  177. INFO,
  178. ("Cache write complete\r\n"
  179. ));
  180. LocalEndCacheWrite((error == ERROR_SUCCESS)
  181. && (GetBytesInSocket() == 0));
  182. } else if (!HaveReadFileExData()) {
  183. INET_ASSERT(!IsCacheReadInProgress());
  184. if (WriteCache((LPBYTE)fsm.m_lpBuffer,
  185. *fsm.m_lpdwNumberOfBytesRead) != ERROR_SUCCESS) {
  186. DEBUG_PRINT(CACHE,
  187. ERROR,
  188. ("Error in Cache write\n"
  189. ));
  190. LocalEndCacheWrite(FALSE);
  191. }
  192. }
  193. }
  194. quit:
  195. if (error != ERROR_IO_PENDING) {
  196. fsm.SetDone();
  197. }
  198. PERF_LOG(PE_TRACE, 0x1002);
  199. DEBUG_LEAVE(error);
  200. return error;
  201. }
  202. //
  203. // HTTP_REQUEST_HANDLE_OBJECT methods
  204. //
  205. DWORD
  206. HTTP_REQUEST_HANDLE_OBJECT::ReadData(
  207. OUT LPVOID lpBuffer,
  208. IN DWORD dwNumberOfBytesToRead,
  209. OUT LPDWORD lpdwNumberOfBytesRead,
  210. IN BOOL fNoAsync, // BUGBUG RFirthRemove on DrainSocket checkin
  211. IN DWORD dwSocketFlags
  212. )
  213. /*++
  214. Routine Description:
  215. HTTP_REQUEST_HANDLE_OBJECT ReadData method
  216. Reads data into users buffer. Reads from header buffer if data exists
  217. there, or reads from the socket
  218. Arguments:
  219. lpBuffer - pointer to users buffer
  220. dwNumberOfBytesToRead - size of buffer/number of bytes to read
  221. lpdwNumberOfBytesRead - pointer to returned number of bytes read
  222. fNoAsync - TRUE if we want to override defaults and have
  223. no Async Read.
  224. dwSocketFlags - controlling socket operation
  225. Return Value:
  226. DWORD
  227. Success - ERROR_SUCCESS
  228. Failure - WSA error
  229. --*/
  230. {
  231. DEBUG_ENTER((DBG_HTTP,
  232. Dword,
  233. "HTTP_REQUEST_HANDLE_OBJECT::ReadData",
  234. "%#x, %d, %#x, %B, %#x",
  235. lpBuffer,
  236. dwNumberOfBytesToRead,
  237. lpdwNumberOfBytesRead,
  238. fNoAsync,
  239. dwSocketFlags
  240. ));
  241. DWORD error = DoFsm(new CFsm_ReadData(lpBuffer,
  242. dwNumberOfBytesToRead,
  243. lpdwNumberOfBytesRead,
  244. fNoAsync,
  245. dwSocketFlags,
  246. this
  247. ));
  248. DEBUG_LEAVE(error);
  249. return error;
  250. }
  251. DWORD
  252. CFsm_ReadData::RunSM(
  253. IN CFsm * Fsm
  254. )
  255. /*++
  256. Routine Description:
  257. description-of-function.
  258. Arguments:
  259. Fsm -
  260. Return Value:
  261. DWORD
  262. --*/
  263. {
  264. DEBUG_ENTER((DBG_HTTP,
  265. Dword,
  266. "CFsm_ReadData::RunSM",
  267. "%#x",
  268. Fsm
  269. ));
  270. DWORD error;
  271. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  272. CFsm_ReadData * stateMachine = (CFsm_ReadData *)Fsm;
  273. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  274. switch (Fsm->GetState()) {
  275. case FSM_STATE_INIT:
  276. case FSM_STATE_CONTINUE:
  277. error = pRequest->ReadData_Fsm(stateMachine);
  278. break;
  279. default:
  280. error = ERROR_INTERNET_INTERNAL_ERROR;
  281. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  282. INET_ASSERT(FALSE);
  283. break;
  284. }
  285. DEBUG_LEAVE(error);
  286. return error;
  287. }
  288. DWORD
  289. HTTP_REQUEST_HANDLE_OBJECT::ReadData_Fsm(
  290. IN CFsm_ReadData * Fsm
  291. )
  292. /*++
  293. Routine Description:
  294. description-of-function.
  295. Arguments:
  296. Fsm -
  297. Return Value:
  298. DWORD
  299. --*/
  300. {
  301. DEBUG_ENTER((DBG_HTTP,
  302. Dword,
  303. "HTTP_REQUEST_HANDLE_OBJECT::ReadData_Fsm",
  304. "%#x",
  305. Fsm
  306. ));
  307. PERF_LOG(PE_TRACE, 0x6001);
  308. CFsm_ReadData & fsm = *Fsm;
  309. DWORD error = ERROR_SUCCESS;
  310. if (fsm.GetState() == FSM_STATE_CONTINUE) {
  311. PERF_LOG(PE_TRACE, 0x6101);
  312. error = fsm.GetError();
  313. goto receive_continue;
  314. }
  315. fsm.m_dwBytesRead = 0;
  316. fsm.m_dwBufferLeft = fsm.m_dwNumberOfBytesToRead;
  317. fsm.m_nBytesCopied = 0;
  318. //
  319. // if there's no data then we're done
  320. //
  321. if (!IsData()) {
  322. DEBUG_PRINT(HTTP,
  323. ERROR,
  324. ("!IsData()\n"
  325. ));
  326. SetState(HttpRequestStateReopen);
  327. INET_ASSERT(error == ERROR_SUCCESS);
  328. goto quit;
  329. }
  330. //
  331. // If using keep-alive, reduce output buffer so we don't over-read.
  332. //
  333. if (IsKeepAlive() && IsContentLength()) {
  334. if (_BytesRemaining == 0) {
  335. INET_ASSERT(error == ERROR_SUCCESS);
  336. PERF_LOG(PE_TRACE, 0x6102);
  337. goto done;
  338. }
  339. PERF_LOG(PE_TRACE, 0x6103);
  340. fsm.m_dwBufferLeft = min(fsm.m_dwBufferLeft, _BytesRemaining);
  341. }
  342. //
  343. // if there's data left in the response buffer then copy it
  344. //
  345. fsm.m_bEof = FALSE;
  346. if (IsBufferedData()) {
  347. DWORD amountToCopy = min(fsm.m_dwNumberOfBytesToRead, BufferDataAvailToRead());
  348. if (amountToCopy != 0) {
  349. PERF_LOG(PE_TRACE, 0x6104);
  350. DEBUG_PRINT(HTTP,
  351. INFO,
  352. ("Copying %d (%#x) bytes from header buffer @ %#x - %d left\n",
  353. amountToCopy,
  354. amountToCopy,
  355. BufferedDataStart(),
  356. BufferDataAvailToRead() - amountToCopy
  357. ));
  358. memcpy(fsm.m_lpBuffer, BufferedDataStart(), amountToCopy);
  359. ReduceDataAvailToRead(amountToCopy);
  360. fsm.m_dwBytesRead += amountToCopy;
  361. fsm.m_dwBufferLeft -= amountToCopy;
  362. fsm.m_nBytesCopied += amountToCopy;
  363. //
  364. // we don't update lpBuffer here. Receive() takes the address of
  365. // the start of the buffer
  366. //
  367. }
  368. //
  369. // if we exhausted all the buffer space, then we're done
  370. //
  371. if (fsm.m_dwBufferLeft == 0) {
  372. PERF_LOG(PE_TRACE, 0x6105);
  373. goto done;
  374. }
  375. }
  376. //
  377. // find out if we're async. Even though the handle was created for async I/O
  378. // the request may be satisfied immediately
  379. //
  380. DWORD asyncFlags;
  381. if ( fsm.m_fNoAsync ) // BUGBUG RFirthRemove on Checkin of DrainSocket
  382. asyncFlags = 0;
  383. else
  384. asyncFlags = (IsAsyncHandle()
  385. && (fsm.m_dwBufferLeft > AvailableDataLength()))
  386. ? SF_NON_BLOCKING
  387. : 0
  388. ;
  389. //
  390. // if we have data already received in the query buffer, then return that
  391. //
  392. if (HaveQueryData()) {
  393. PERF_LOG(PE_TRACE, 0x6106);
  394. DWORD nCopied;
  395. nCopied = CopyQueriedData((LPVOID)((LPBYTE)fsm.m_lpBuffer + fsm.m_dwBytesRead),
  396. fsm.m_dwBufferLeft
  397. );
  398. DEBUG_PRINT(HTTP,
  399. INFO,
  400. ("Copied %d (%#x) bytes from query buffer @ %#x - %d left\n",
  401. nCopied,
  402. nCopied,
  403. (LPBYTE)_QueryBuffer - _QueryOffset,
  404. _QueryBytesAvailable
  405. ));
  406. fsm.m_dwBytesRead += nCopied;
  407. fsm.m_dwBufferLeft -= nCopied;
  408. fsm.m_nBytesCopied += nCopied;
  409. if (fsm.m_dwBufferLeft == 0) {
  410. goto done;
  411. }
  412. }
  413. //
  414. // If the Chunk parser claims we're done, then we're done,
  415. // stop ready and tell the reader
  416. //
  417. //if ( IsChunkEncoding() && IsChunkedEncodingFinished() )
  418. //{
  419. // fsm.m_bEof = TRUE;
  420. // goto done;
  421. //}
  422. if (HaveReadFileExData()) {
  423. PERF_LOG(PE_TRACE, 0x6107);
  424. *(LPBYTE)fsm.m_lpBuffer = GetReadFileExData();
  425. --fsm.m_dwNumberOfBytesToRead;
  426. --fsm.m_dwBufferLeft;
  427. ++fsm.m_dwBytesRead;
  428. DEBUG_PRINT(HTTP,
  429. INFO,
  430. ("Copied 1 byte (%#x) from ReadFileEx buffer %#x\n",
  431. (BYTE)_ReadFileExData & 0xff,
  432. &_ReadFileExData
  433. ));
  434. if (fsm.m_dwBufferLeft == 0) {
  435. goto done;
  436. }
  437. }
  438. //
  439. // If the Chunk parser claims we're done, then we're done,
  440. // stop ready and tell the reader
  441. //
  442. if ( IsChunkEncoding() && IsChunkedEncodingFinished() )
  443. {
  444. PERF_LOG(PE_TRACE, 0x6108);
  445. fsm.m_bEof = TRUE;
  446. goto done;
  447. }
  448. //
  449. // we're about to check the socket. Make sure its valid to do so
  450. //
  451. //INET_ASSERT(_Socket != NULL);
  452. if ((_Socket == NULL) || !_Socket->IsOpen()) {
  453. //
  454. // socket was closed - no more data
  455. //
  456. //
  457. // there is no more data to be received on this object
  458. //
  459. SetData(FALSE);
  460. //
  461. // this object can now be re-used
  462. //
  463. SetState(HttpRequestStateReopen);
  464. fsm.m_bEof = TRUE;
  465. PERF_LOG(PE_TRACE, 0x6109);
  466. goto quit;
  467. }
  468. read_again:
  469. fsm.m_nBytes = fsm.m_dwBytesRead;
  470. //
  471. // if we had a content-length and we don't think there is any data left to
  472. // read then we're done
  473. //
  474. if (IsContentLength() && (_BytesInSocket == 0)) {
  475. fsm.m_bEof = TRUE;
  476. PERF_LOG(PE_TRACE, 0x6110);
  477. goto done;
  478. }
  479. //
  480. // receive data into user's buffer. Because we don't own the buffer, we
  481. // cannot resize it
  482. //
  483. LPVOID lpBuffer;
  484. DWORD dwBytesToRead;
  485. DWORD dwBufferLeft;
  486. DWORD dwBytesRead;
  487. lpBuffer = fsm.m_lpBuffer;
  488. dwBytesToRead = fsm.m_dwNumberOfBytesToRead;
  489. dwBufferLeft = fsm.m_dwBufferLeft;
  490. dwBytesRead = fsm.m_dwBytesRead;
  491. //INET_ASSERT(!(fsm.m_dwSocketFlags & SF_NO_WAIT)
  492. // ? (fsm.m_dwBufferLeft <= _BytesRemaining)
  493. // : TRUE);
  494. PERF_LOG(PE_TRACE, 0x6111);
  495. if (IsBadNSServer() && !IsConnCloseResponse()) {
  496. SetBadNSReceiveTimeout();
  497. }
  498. error = _Socket->Receive(&fsm.m_lpBuffer,
  499. &fsm.m_dwNumberOfBytesToRead,
  500. &fsm.m_dwBufferLeft,
  501. &fsm.m_dwBytesRead,
  502. 0,
  503. SF_INDICATE
  504. | ((fsm.m_dwSocketFlags & SF_NO_WAIT)
  505. ? SF_NO_WAIT
  506. : (IsChunkEncoding() ? 0 : SF_RECEIVE_ALL)),
  507. &fsm.m_bEof
  508. );
  509. //
  510. // only if we performed an asynchronous no-wait receive and there was no
  511. // data available in the socket will we get WSAEWOULDBLOCK. Make another
  512. // receive request, this time without no-wait. It will complete
  513. // asynchronously and the app must make another no-wait request
  514. //
  515. if (error == WSAEWOULDBLOCK) {
  516. PERF_LOG(PE_TRACE, 0x6112);
  517. INET_ASSERT(fsm.m_dwSocketFlags & SF_NO_WAIT);
  518. INET_ASSERT(!fsm.m_bEof);
  519. //
  520. // BUGBUG - IsAsyncHandle() || IsAsyncRequest()
  521. //
  522. if ((fsm.m_dwBytesRead == 0) && IsAsyncHandle()) {
  523. DEBUG_PRINT(HTTP,
  524. INFO,
  525. ("Initiating wait-for-data (1-byte read)\n"
  526. ));
  527. fsm.m_lpBuffer = (LPVOID)&_ReadFileExData;
  528. fsm.m_dwNumberOfBytesToRead = 1;
  529. fsm.m_dwBufferLeft = 1;
  530. fsm.m_dwSocketFlags &= ~SF_NO_WAIT;
  531. INET_ASSERT(!_HaveReadFileExData);
  532. SetReadFileExData();
  533. _ReadFileExData = 0;
  534. //INET_ASSERT(fsm.m_dwBufferLeft <= _BytesRemaining);
  535. PERF_LOG(PE_TRACE, 0x6113);
  536. if (IsBadNSServer() && !IsConnCloseResponse()) {
  537. SetBadNSReceiveTimeout();
  538. }
  539. error = _Socket->Receive(&fsm.m_lpBuffer,
  540. &fsm.m_dwNumberOfBytesToRead,
  541. &fsm.m_dwBufferLeft,
  542. &fsm.m_dwBytesRead,
  543. 0,
  544. fsm.m_dwSocketFlags,
  545. &fsm.m_bEof
  546. );
  547. if (error == ERROR_SUCCESS) {
  548. PERF_LOG(PE_TRACE, 0x6114);
  549. BOOL fReadNothing = (fsm.m_dwBytesRead == 0 ? TRUE : FALSE);
  550. //
  551. // we have successfully read a single byte from the socket.
  552. //
  553. //INET_ASSERT(FALSE);
  554. fsm.m_lpBuffer = lpBuffer;
  555. fsm.m_dwNumberOfBytesToRead = dwBytesToRead;
  556. fsm.m_dwBufferLeft = dwBufferLeft;
  557. fsm.m_dwBytesRead = dwBytesRead;
  558. if (fReadNothing) {
  559. // Don't copy if nothing was actually read.
  560. ResetReadFileExData();
  561. }
  562. else {
  563. *(LPBYTE)fsm.m_lpBuffer = GetReadFileExData();
  564. --fsm.m_dwBufferLeft;
  565. ++fsm.m_dwBytesRead;
  566. }
  567. //
  568. // BUGBUG - if socket unblocked already, should go round & read
  569. // again, not just return 1 byte
  570. //
  571. }
  572. PERF_LOG(PE_TRACE, 0x6115);
  573. } else {
  574. PERF_LOG(PE_TRACE, 0x6116);
  575. DEBUG_PRINT(HTTP,
  576. WARNING,
  577. ("Not initiating wait-for-data: bytesRead = %d, asyncHandle = %B\n",
  578. fsm.m_dwBytesRead,
  579. IsAsyncHandle()
  580. ));
  581. //
  582. // read data from buffers but nothing available from socket
  583. //
  584. error = ERROR_SUCCESS;
  585. }
  586. }
  587. if (error == ERROR_IO_PENDING) {
  588. PERF_LOG(PE_TRACE, 0x6117);
  589. goto quit_pending;
  590. }
  591. receive_continue:
  592. PERF_LOG(PE_TRACE, 0x6118);
  593. //
  594. // if we timed-out while talking to 'bad' NS server (returns HTTP/1.1 but
  595. // content-length or chunked encoding info) then close the connection and
  596. // reset any RFX status. We return SUCCESS in this case
  597. //
  598. if ((error == ERROR_INTERNET_TIMEOUT) && IsBadNSServer()) {
  599. DEBUG_PRINT(HTTP,
  600. INFO,
  601. ("Bad NS server: Closing connection %#x/%d on timeout\n",
  602. _Socket ? _Socket->GetSocket() : -1,
  603. _Socket ? _Socket->GetSourcePort() : -1
  604. ));
  605. CloseConnection(TRUE);
  606. ResetReadFileExData();
  607. SetData(FALSE);
  608. _dwCurrentStreamPosition += fsm.m_dwBytesRead;
  609. fsm.m_bEof = TRUE;
  610. error = ERROR_SUCCESS;
  611. goto quit;
  612. }
  613. if (error == ERROR_SUCCESS) {
  614. if (IsContentLength()) {
  615. INET_ASSERT(fsm.m_dwBytesRead >= fsm.m_nBytes);
  616. _BytesInSocket -= fsm.m_dwBytesRead - fsm.m_nBytes;
  617. INET_ASSERT((int)_BytesInSocket >= 0);
  618. if ((int)_BytesInSocket < 0) {
  619. _BytesInSocket = 0;
  620. }
  621. }
  622. if ( IsChunkEncoding() && !(HaveReadFileExData()))
  623. {
  624. PERF_LOG(PE_TRACE, 0x6119);
  625. LPSTR lpszNewBuffer;
  626. DWORD dwNewBufferLength;
  627. DWORD dwBytesJustRead = (fsm.m_dwBytesRead - fsm.m_nBytes);
  628. error = _ctChunkInfo.ParseChunkInput(
  629. (((LPSTR) fsm.m_lpBuffer) + fsm.m_nBytesCopied),
  630. (fsm.m_dwBytesRead - fsm.m_nBytesCopied),
  631. &lpszNewBuffer,
  632. &dwNewBufferLength
  633. );
  634. //
  635. // hack - wait for more data
  636. //
  637. if ((error == ERROR_SUCCESS)
  638. && (dwNewBufferLength == 0)
  639. && !IsChunkedEncodingFinished()
  640. && (fsm.m_nBytesCopied == 0)) {
  641. PERF_LOG(PE_TRACE, 0x6120);
  642. fsm.m_dwBufferLeft += fsm.m_dwBytesRead;
  643. fsm.m_dwBytesRead = 0;
  644. struct fd_set read_fds;
  645. struct fd_set write_fds;
  646. struct fd_set except_fds;
  647. FD_ZERO(&read_fds);
  648. FD_ZERO(&write_fds);
  649. FD_ZERO(&except_fds);
  650. FD_SET(_Socket->GetSocket(), &read_fds);
  651. struct timeval to;
  652. to.tv_sec = 30;
  653. to.tv_usec = 0;
  654. int n = _I_select(1, &read_fds, &write_fds, &except_fds, &to);
  655. goto read_again;
  656. }
  657. fsm.m_dwBufferLeft += (fsm.m_dwBytesRead - fsm.m_nBytesCopied);
  658. fsm.m_dwBytesRead -= (fsm.m_dwBytesRead - fsm.m_nBytesCopied);
  659. fsm.m_dwBufferLeft -= dwNewBufferLength;
  660. fsm.m_dwBytesRead += dwNewBufferLength;
  661. fsm.m_nBytesCopied += dwNewBufferLength;
  662. INET_ASSERT(error == ERROR_SUCCESS); // I want to see this happen.
  663. if ( error != ERROR_SUCCESS )
  664. {
  665. goto quit;
  666. }
  667. if ( IsChunkedEncodingFinished() )
  668. {
  669. fsm.m_bEof = TRUE;
  670. }
  671. }
  672. } else {
  673. PERF_LOG(PE_TRACE, 0x6121);
  674. DEBUG_PRINT(HTTP,
  675. ERROR,
  676. ("error %d on socket %#x\n",
  677. error,
  678. _Socket->GetSocket()
  679. ));
  680. //
  681. // socket error
  682. //
  683. SetState(HttpRequestStateError);
  684. //
  685. // cause connection to be closed/released
  686. //
  687. fsm.m_bEof = TRUE;
  688. }
  689. done:
  690. //
  691. // only update bytes remaining, EOF and the current stream position values
  692. // if we're returning data. If we just completed reading ReadFileEx data
  693. // then don't update. The 1 byte of ReadFileEx data will be read on the next
  694. // read proper
  695. //
  696. if (HaveReadFileExData()) {
  697. goto quit;
  698. }
  699. //
  700. // whether the data came from the response buffer or the socket, if we have
  701. // a content-length, update the amount of data left to retrieve
  702. //
  703. if (IsChunkEncoding()
  704. && IsChunkedEncodingFinished()
  705. && (_QueryBytesAvailable == 0)
  706. && (BufferDataAvailToRead() == 0)) {
  707. fsm.m_bEof = TRUE;
  708. } else if (IsKeepAlive() && IsContentLength()) {
  709. _BytesRemaining -= fsm.m_dwBytesRead;
  710. INET_ASSERT((int)_BytesRemaining >= 0);
  711. //
  712. // if we have read all the entity-body then we can release the keep-alive
  713. // connection, or close the socket
  714. //
  715. if (_BytesRemaining<=0 && ((int)_BytesRemaining>=-2)) {
  716. // We might overshoot by 1 or 2 because of server misinformation.
  717. fsm.m_bEof = TRUE;
  718. }
  719. }
  720. DEBUG_PRINT(HTTP,
  721. INFO,
  722. ("read %d bytes\n",
  723. fsm.m_dwBytesRead
  724. ));
  725. _dwCurrentStreamPosition += fsm.m_dwBytesRead;
  726. //
  727. // if we reached the end of the connection - either the end of the server
  728. // connection for real, or we received all indicated data on a keep-alive
  729. // connection - then close the connection
  730. //
  731. if (fsm.m_bEof) {
  732. PERF_LOG(PE_TRACE, 0x6122);
  733. //
  734. // if we don't need to keep hold of the connection, release it. In the
  735. // case of multi-part authentication (NTLM) over keep-alive connection
  736. // we need to keep the connection. With Kerberos, we don't need to keep
  737. // the connection.
  738. //
  739. if (GetAuthState() != AUTHSTATE_CHALLENGE) {
  740. DEBUG_PRINT(HTTP,
  741. INFO,
  742. ("end of data - freeing connection %#x (Auth State = %s)\n",
  743. _Socket ? _Socket->GetSocket() : 0,
  744. InternetMapAuthState(GetAuthState())
  745. ));
  746. if (!((GetStatusCode() == 407) && IsKeepAlive()))
  747. CloseConnection(FALSE);
  748. } else {
  749. // AUTHSTATE_CHALLENGE - check if request is through proxy or is kerberos.
  750. // When IsRequestUsingProxy returns TRUE, there are three types of connections possible:
  751. // 1) http request forwarded by the proxy to the server
  752. // 2) connect request to proxy to establish https tunnel
  753. // 3) using https tunnel through proxy to the server
  754. // I believe the various methods return:
  755. //��������������������������������������������� http��� conn.�� tunnel
  756. // IsRequestUsingProxy 1����� 1������� 1
  757. // IsViaProxy������������ 1����� 1������� 0
  758. // IsTunnel������������������������������������ 0��� 1������� 0
  759. // IsTalkingToSecureServerViaProxy������������� 0����� 0������� 1
  760. INET_ASSERT(_pAuthCtx->GetSchemeType() != AUTHCTX::SCHEME_NEGOTIATE);
  761. if (GetAuthCtx()->GetSchemeType() == AUTHCTX::SCHEME_KERBEROS)
  762. {
  763. DEBUG_PRINT(HTTP,
  764. INFO,
  765. ("freeing connection - kerberos and auth state challenge\n"
  766. ));
  767. CloseConnection(FALSE);
  768. }
  769. else if (IsRequestUsingProxy()
  770. && !(IsTunnel() || IsTalkingToSecureServerViaProxy())
  771. && (_pAuthCtx->GetFlags() & PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED)
  772. && !_pAuthCtx->_fIsProxy)
  773. {
  774. // Ordinarily, if the auth state is AUTHSTATE_CHALLENGE we wish to keep
  775. // the current connection open (keep alive) so that the response will go
  776. // out on the same socket. NTLM, which requires keep-alive, does not
  777. // work when going through a proxy. DPA on the other hand can work through
  778. // a proxy. In the case that the proxy does not return keep-alive with the
  779. // challenge (Catapult appears to be the only proxy that does) we want to
  780. // close the socket to ensure that it is not subsequently used for the response.
  781. DEBUG_PRINT(HTTP,
  782. INFO,
  783. ("freeing connection - auth state challenge\n"
  784. ));
  785. CloseConnection(FALSE);
  786. }
  787. else
  788. {
  789. // Keep alive required - don't close socket.
  790. DEBUG_PRINT(HTTP,
  791. INFO,
  792. ("not freeing connection - auth state challenge\n"
  793. ));
  794. }
  795. }
  796. //
  797. // there is no more data to be received on this object
  798. //
  799. SetData(FALSE);
  800. //
  801. // this object can now be re-used
  802. //
  803. SetState(HttpRequestStateReopen);
  804. }
  805. quit:
  806. //
  807. // update the amount of data returned then we're outta here
  808. //
  809. *fsm.m_lpdwNumberOfBytesRead = fsm.m_dwBytesRead;
  810. if (error != ERROR_IO_PENDING) {
  811. fsm.SetDone();
  812. }
  813. quit_pending:
  814. PERF_LOG(PE_TRACE, 0x6002);
  815. DEBUG_LEAVE(error);
  816. return error;
  817. }
  818. DWORD
  819. HTTP_REQUEST_HANDLE_OBJECT::QueryDataAvailable(
  820. OUT LPDWORD lpdwNumberOfBytesAvailable
  821. )
  822. /*++
  823. Routine Description:
  824. Determines how much data is available to be read by the caller
  825. BUGBUG - need cache case
  826. Arguments:
  827. lpdwNumberOfBytesAvailable - returned number of bytes available
  828. Return Value:
  829. DWORD
  830. Success - ERROR_SUCCESS
  831. Failure - ERROR_INTERNET_INCORRECT_HANDLE_STATE
  832. --*/
  833. {
  834. DEBUG_ENTER((DBG_HTTP,
  835. Dword,
  836. "HTTP_REQUEST_HANDLE_OBJECT::QueryDataAvailable",
  837. "%#x",
  838. lpdwNumberOfBytesAvailable
  839. ));
  840. DWORD error = DoFsm(new CFsm_HttpQueryAvailable(lpdwNumberOfBytesAvailable,
  841. this
  842. ));
  843. DEBUG_LEAVE(error);
  844. return error;
  845. }
  846. DWORD
  847. CFsm_HttpQueryAvailable::RunSM(
  848. IN CFsm * Fsm
  849. )
  850. /*++
  851. Routine Description:
  852. description-of-function.
  853. Arguments:
  854. Fsm -
  855. Return Value:
  856. DWORD
  857. --*/
  858. {
  859. DEBUG_ENTER((DBG_HTTP,
  860. Dword,
  861. "CFsm_HttpQueryAvailable::RunSM",
  862. "%#x",
  863. Fsm
  864. ));
  865. DWORD error;
  866. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  867. CFsm_HttpQueryAvailable * stateMachine = (CFsm_HttpQueryAvailable *)Fsm;
  868. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  869. switch (Fsm->GetState()) {
  870. case FSM_STATE_INIT:
  871. case FSM_STATE_CONTINUE:
  872. error = pRequest->QueryAvailable_Fsm(stateMachine);
  873. break;
  874. default:
  875. error = ERROR_INTERNET_INTERNAL_ERROR;
  876. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  877. INET_ASSERT(FALSE);
  878. break;
  879. }
  880. DEBUG_LEAVE(error);
  881. return error;
  882. }
  883. DWORD
  884. HTTP_REQUEST_HANDLE_OBJECT::QueryAvailable_Fsm(
  885. IN CFsm_HttpQueryAvailable * Fsm
  886. )
  887. /*++
  888. Routine Description:
  889. description-of-function.
  890. Arguments:
  891. Fsm -
  892. Return Value:
  893. DWORD
  894. --*/
  895. {
  896. DEBUG_ENTER((DBG_HTTP,
  897. Dword,
  898. "QueryAvailable_Fsm",
  899. "%#x",
  900. Fsm
  901. ));
  902. CFsm_HttpQueryAvailable & fsm = *Fsm;
  903. DWORD error = fsm.GetError();
  904. DWORD bytesAvailable = 0;
  905. if (fsm.GetState() == FSM_STATE_CONTINUE) {
  906. goto fsm_continue;
  907. }
  908. INET_ASSERT(fsm.GetState() == FSM_STATE_INIT);
  909. if (IsReadRequest()) {
  910. *fsm.m_lpdwNumberOfBytesAvailable = 0;
  911. if (_Socket != NULL) {
  912. //
  913. // Invoked ReadLoop fsm only if the read and write positions
  914. // are different, otherwise older code is more efficient.
  915. //
  916. error = DoFsm (new CFsm_ReadLoop (this, 0, NULL, 1, NULL));
  917. if (error == ERROR_SUCCESS) {
  918. *fsm.m_lpdwNumberOfBytesAvailable = AvailableDataLength();
  919. }
  920. } else {
  921. DEBUG_PRINT(HTTP,
  922. INFO,
  923. ("no socket\n"
  924. ));
  925. fsm.m_bEof = TRUE;
  926. }
  927. goto done;
  928. }
  929. //
  930. // the handle must be readable
  931. //
  932. if (!IsValidHttpState(READ)) {
  933. error = ERROR_INTERNET_INCORRECT_HANDLE_STATE;
  934. goto quit;
  935. }
  936. fsm.m_bEof = FALSE;
  937. //
  938. // error must be ERROR_SUCCESS - we just read it out of FSM & didn't jump
  939. // anywhere
  940. //
  941. INET_ASSERT(error == ERROR_SUCCESS);
  942. //
  943. // first check if there is data to receive at all
  944. //
  945. if (IsData()) {
  946. //
  947. // if there's buffered data still available from receiving the headers,
  948. // then return that length, else query the information from the socket
  949. //
  950. if (IsBufferedData()) {
  951. bytesAvailable = BufferDataAvailToRead();
  952. DEBUG_PRINT(HTTP,
  953. INFO,
  954. ("%d bytes available in buffer\n",
  955. bytesAvailable
  956. ));
  957. } else if (_Socket != NULL) {
  958. //
  959. // the rest of the data must be read from the socket
  960. //
  961. BOOL checkSocket;
  962. if (IsKeepAlive() && IsContentLength()) {
  963. checkSocket = ((int)_BytesInSocket > 0) ? TRUE : FALSE;
  964. } else if (IsChunkEncoding()) {
  965. checkSocket = !IsChunkedEncodingFinished();
  966. } else {
  967. checkSocket = TRUE;
  968. }
  969. if (checkSocket) {
  970. if (_QueryBuffer != NULL) {
  971. bytesAvailable = _QueryBytesAvailable;
  972. checkSocket = (bytesAvailable == 0) ? TRUE : FALSE;
  973. } else {
  974. error = _Socket->AllocateQueryBuffer(&_QueryBuffer,
  975. &_QueryBufferLength
  976. );
  977. if (error != ERROR_SUCCESS) {
  978. checkSocket = FALSE;
  979. }
  980. }
  981. } else if (IsKeepAlive() && IsContentLength() && (_BytesRemaining == 0)) {
  982. fsm.m_bEof = TRUE;
  983. } else if (IsChunkEncoding() && IsChunkedEncodingFinished()) {
  984. fsm.m_bEof = TRUE;
  985. }
  986. if (checkSocket) {
  987. INET_ASSERT(_Socket->IsValid());
  988. INET_ASSERT(_QueryBytesAvailable == 0);
  989. //
  990. // reset the query buffer offset
  991. //
  992. _QueryOffset = 0;
  993. //
  994. // don't create another FSM just for the DataAvailable2 wrapper.
  995. // If it ever becomes more than a call to Receive() then create
  996. // an FSM
  997. //
  998. read_again:
  999. fsm.m_lpBuffer = _QueryBuffer;
  1000. fsm.m_dwBufferLength = (IsKeepAlive() && IsContentLength())
  1001. ? min(_BytesRemaining, _QueryBufferLength)
  1002. : _QueryBufferLength;
  1003. fsm.m_dwBufferLeft = fsm.m_dwBufferLength;
  1004. //INET_ASSERT(fsm.m_dwBufferLeft <= _BytesRemaining);
  1005. if (IsBadNSServer() && !IsConnCloseResponse()) {
  1006. SetBadNSReceiveTimeout();
  1007. }
  1008. error = _Socket->Receive(&fsm.m_lpBuffer,
  1009. &fsm.m_dwBufferLength,
  1010. &fsm.m_dwBufferLeft, // don't care about this
  1011. &_QueryBytesAvailable,
  1012. 0,
  1013. 0,
  1014. &fsm.m_bEof
  1015. );
  1016. if (error == ERROR_IO_PENDING) {
  1017. goto done;
  1018. }
  1019. fsm_continue:
  1020. if ((error == ERROR_INTERNET_TIMEOUT) && IsBadNSServer()) {
  1021. DEBUG_PRINT(HTTP,
  1022. INFO,
  1023. ("Bad NS server: Closing connection %#x/%d on timeout\n",
  1024. _Socket ? _Socket->GetSocket() : -1,
  1025. _Socket ? _Socket->GetSourcePort() : -1
  1026. ));
  1027. CloseConnection(TRUE);
  1028. _QueryBytesAvailable = 0;
  1029. error = ERROR_SUCCESS;
  1030. }
  1031. if (error == ERROR_SUCCESS) {
  1032. //if ( IsChunkEncoding() )
  1033. if ( IsChunkEncoding() && (_QueryBytesAvailable != 0))
  1034. {
  1035. LPSTR lpszNewBuffer;
  1036. DWORD dwNewBufferLength = 0;
  1037. error = _ctChunkInfo.ParseChunkInput(
  1038. (LPSTR) _QueryBuffer,
  1039. _QueryBytesAvailable,
  1040. &lpszNewBuffer,
  1041. &dwNewBufferLength
  1042. );
  1043. _QueryBytesAvailable = dwNewBufferLength;
  1044. INET_ASSERT(error == ERROR_SUCCESS); // I want to see this.
  1045. if ( error != ERROR_SUCCESS )
  1046. {
  1047. goto quit;
  1048. }
  1049. //
  1050. // hack - wait for more data
  1051. //
  1052. if ((dwNewBufferLength == 0) && !IsChunkedEncodingFinished()) {
  1053. struct fd_set read_fds;
  1054. struct fd_set write_fds;
  1055. struct fd_set except_fds;
  1056. FD_ZERO(&read_fds);
  1057. FD_ZERO(&write_fds);
  1058. FD_ZERO(&except_fds);
  1059. FD_SET(_Socket->GetSocket(), &read_fds);
  1060. struct timeval to;
  1061. to.tv_sec = 30;
  1062. to.tv_usec = 0;
  1063. int n = _I_select(1, &read_fds, &write_fds, &except_fds, &to);
  1064. if (n > 0) {
  1065. goto read_again;
  1066. }
  1067. }
  1068. }
  1069. bytesAvailable = _QueryBytesAvailable;
  1070. //
  1071. // note the amount of data that is available immediately.
  1072. // This allows e.g. async InternetReadFile() to complete
  1073. // synchronously if the next request is for <= bytesAvailable
  1074. //
  1075. //SetAvailableDataLength(bytesAvailable);
  1076. DEBUG_PRINT(HTTP,
  1077. INFO,
  1078. ("%d bytes available in socket %#x\n",
  1079. bytesAvailable,
  1080. (_Socket ? _Socket->GetSocket() : 0)
  1081. ));
  1082. if ((bytesAvailable == 0)
  1083. && (IsChunkEncoding() ? IsChunkedEncodingFinished() : TRUE)) {
  1084. fsm.m_bEof = TRUE;
  1085. }
  1086. if (IsKeepAlive() && IsContentLength()) {
  1087. _BytesInSocket -= bytesAvailable;
  1088. INET_ASSERT((int)_BytesInSocket >= 0);
  1089. if ((int)_BytesInSocket < 0) {
  1090. _BytesInSocket = 0;
  1091. }
  1092. }
  1093. }
  1094. }
  1095. } else {
  1096. //
  1097. // all data read from socket & socket released
  1098. //
  1099. INET_ASSERT(error == ERROR_SUCCESS);
  1100. INET_ASSERT(bytesAvailable == 0);
  1101. DEBUG_PRINT(HTTP,
  1102. INFO,
  1103. ("no socket\n"
  1104. ));
  1105. fsm.m_bEof = TRUE;
  1106. }
  1107. } else {
  1108. INET_ASSERT(error == ERROR_SUCCESS);
  1109. //
  1110. // we may have already removed all the data from the socket
  1111. //
  1112. DEBUG_PRINT(HTTP,
  1113. INFO,
  1114. ("all data has been read\n"
  1115. ));
  1116. fsm.m_bEof = TRUE;
  1117. }
  1118. quit:
  1119. if ((error == ERROR_SUCCESS) && (bytesAvailable == 0)) {
  1120. if (IsCacheWriteInProgress()) {
  1121. LocalEndCacheWrite(TRUE);
  1122. }
  1123. }
  1124. *fsm.m_lpdwNumberOfBytesAvailable = bytesAvailable;
  1125. //
  1126. // if we have reached the end of the data then we can release the connection
  1127. //
  1128. /*
  1129. if (fsm.m_bEof || (bytesAvailable >= _BytesRemaining)) {
  1130. if (_Socket != NULL) {
  1131. CloseConnection(FALSE);
  1132. }
  1133. }
  1134. */
  1135. if (fsm.m_bEof) {
  1136. if (_Socket != NULL) {
  1137. CloseConnection(FALSE);
  1138. }
  1139. }
  1140. done:
  1141. if (error != ERROR_IO_PENDING) {
  1142. fsm.SetDone();
  1143. }
  1144. DEBUG_LEAVE(error);
  1145. return error;
  1146. }
  1147. DWORD
  1148. HTTP_REQUEST_HANDLE_OBJECT::DrainResponse(
  1149. OUT LPBOOL lpbDrained
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Receives any remaining response data into the buffer we allocated for the
  1154. headers. Used in redirection: if the server returns some HTML page (e.g.)
  1155. with the redirection response, we give the app a chance to read it. This
  1156. way, we allow the app to retrieve the data immediately during the status
  1157. callback in which we indicate that the request has been redirected
  1158. Arguments:
  1159. lpbDrained - TRUE if we really drained the socket else FALSE
  1160. Return Value:
  1161. DWORD
  1162. Success - ERROR_SUCCESS
  1163. Failure - WSA error mapped to ERROR_INTERNET_XXX
  1164. --*/
  1165. {
  1166. DEBUG_ENTER((DBG_HTTP,
  1167. Dword,
  1168. "HTTP_REQUEST_HANDLE_OBJECT::DrainResponse",
  1169. "%#x",
  1170. lpbDrained
  1171. ));
  1172. DWORD error = DoFsm(new CFsm_DrainResponse(lpbDrained, this));
  1173. DEBUG_LEAVE(error);
  1174. return error;
  1175. }
  1176. DWORD
  1177. CFsm_DrainResponse::RunSM(
  1178. IN CFsm * Fsm
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. description-of-function.
  1183. Arguments:
  1184. Fsm -
  1185. Return Value:
  1186. DWORD
  1187. --*/
  1188. {
  1189. DEBUG_ENTER((DBG_HTTP,
  1190. Dword,
  1191. "CFsm_DrainResponse::RunSM",
  1192. "%#x",
  1193. Fsm
  1194. ));
  1195. DWORD error;
  1196. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  1197. CFsm_DrainResponse * stateMachine = (CFsm_DrainResponse *)Fsm;
  1198. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  1199. switch (Fsm->GetState()) {
  1200. case FSM_STATE_INIT:
  1201. case FSM_STATE_CONTINUE:
  1202. error = pRequest->DrainResponse_Fsm(stateMachine);
  1203. break;
  1204. default:
  1205. error = ERROR_INTERNET_INTERNAL_ERROR;
  1206. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  1207. INET_ASSERT(FALSE);
  1208. break;
  1209. }
  1210. DEBUG_LEAVE(error);
  1211. return error;
  1212. }
  1213. DWORD
  1214. HTTP_REQUEST_HANDLE_OBJECT::DrainResponse_Fsm(
  1215. IN CFsm_DrainResponse * Fsm
  1216. )
  1217. /*++
  1218. Routine Description:
  1219. description-of-function.
  1220. Arguments:
  1221. Fsm -
  1222. Return Value:
  1223. DWORD
  1224. --*/
  1225. {
  1226. DEBUG_ENTER((DBG_HTTP,
  1227. Dword,
  1228. "HTTP_REQUEST_HANDLE_OBJECT::DrainResponse_Fsm",
  1229. "%#x",
  1230. Fsm
  1231. ));
  1232. CFsm_DrainResponse & fsm = *Fsm;
  1233. DWORD error = fsm.GetError();
  1234. BOOL drainIt = FALSE;
  1235. if (error != ERROR_SUCCESS) {
  1236. goto quit;
  1237. }
  1238. if (fsm.GetState() == FSM_STATE_CONTINUE) {
  1239. drainIt = TRUE;
  1240. goto fsm_continue;
  1241. }
  1242. PERF_LOG(PE_TRACE, 0x8001);
  1243. drainIt = TRUE;
  1244. //
  1245. // if the socket is already closed, we can't drain it
  1246. //
  1247. if ((_Socket == NULL) || !_Socket->IsValid()) {
  1248. drainIt = FALSE;
  1249. } else if (IsWantKeepAlive()) {
  1250. //
  1251. // IIS 1.0 has a bug where it can return a failure indication to a
  1252. // request that was made using a keep-alive connection. The response
  1253. // doesn't contain a keep-alive header but the server has left open the
  1254. // connection AND it has returned us fewer bytes than was claimed in
  1255. // the content-length header. If we try to drain the response buffer at
  1256. // this point, we will wait a long time waiting for the server to send
  1257. // us the non-existent additional bytes. Therefore, if we are talking
  1258. // to an IIS 1.0 server, we don't drain the response buffer
  1259. //
  1260. LPSTR lpszServerBuf;
  1261. DWORD serverBufferLength;
  1262. _ResponseHeaders.LockHeaders();
  1263. error = FastQueryResponseHeader(HTTP_QUERY_SERVER,
  1264. (LPVOID *)&lpszServerBuf,
  1265. &serverBufferLength,
  1266. 0
  1267. );
  1268. if (error == ERROR_SUCCESS) {
  1269. #define IIS "Microsoft-IIS/"
  1270. #define IIS_LEN (sizeof(IIS) - 1)
  1271. #define PWS "Microsoft-PWS/"
  1272. #define PWS_LEN (sizeof(PWS) - 1)
  1273. #define PWS95 "Microsoft-PWS-95/"
  1274. #define PWS95_LEN (sizeof(PWS95) - 1)
  1275. #define IIS10 "Microsoft-Internet-Information-Server/"
  1276. #define IIS10_LEN (sizeof(IIS10) - 1)
  1277. if ((serverBufferLength > IIS_LEN)
  1278. && !strnicmp(lpszServerBuf, IIS, IIS_LEN)) {
  1279. int major_num = 0;
  1280. for (DWORD i = IIS_LEN; i < serverBufferLength; ++i) {
  1281. char ch = lpszServerBuf[i];
  1282. if (isdigit(ch)) {
  1283. major_num = major_num * 10 + (int)(ch - '0');
  1284. } else {
  1285. break;
  1286. }
  1287. }
  1288. if (major_num < 4) {
  1289. drainIt = FALSE;
  1290. }
  1291. } else if (IsBadNSServer()) {
  1292. drainIt = FALSE;
  1293. } else if (((serverBufferLength > IIS10_LEN)
  1294. && !strncmp(lpszServerBuf, IIS10, IIS10_LEN))
  1295. || ((serverBufferLength > PWS_LEN)
  1296. && !strncmp(lpszServerBuf, PWS, PWS_LEN))
  1297. || ((serverBufferLength > PWS95_LEN)
  1298. && !strncmp(lpszServerBuf, PWS95, PWS95_LEN))) {
  1299. drainIt = FALSE;
  1300. }
  1301. }
  1302. _ResponseHeaders.UnlockHeaders();
  1303. }
  1304. error = ERROR_SUCCESS;
  1305. if (drainIt) {
  1306. fsm.m_dwAsyncFlags = IsAsyncHandle() ? SF_WAIT : 0;
  1307. fsm.m_dwAmountToRead = IsContentLength() ? _BytesInSocket : (DWORD)-1;
  1308. //DWORD bufferLeft = _ResponseBufferLength - _BytesReceived;
  1309. fsm.m_dwBufferLeft = min(fsm.m_dwAmountToRead, _ResponseBufferLength - _BytesReceived);
  1310. if (IsChunkEncoding() && IsChunkedEncodingFinished()) {
  1311. fsm.m_dwAmountToRead = 0;
  1312. fsm.m_bEof = TRUE;
  1313. INET_ASSERT(fsm.m_dwBytesReceived == 0);
  1314. }
  1315. //
  1316. // either receive the amount specified in the "Content-Length" header, or
  1317. // receive until we hit the end of the connection. We may have already
  1318. // received the entire response
  1319. //
  1320. while ((fsm.m_dwAmountToRead != 0) && !fsm.m_bEof && (error == ERROR_SUCCESS)) {
  1321. fsm.m_dwPreviousBytesReceived = _BytesReceived;
  1322. //
  1323. // receive the rest of the data. We are assuming here that it is a
  1324. // couple of K at the most. Notice that we don't care to make status
  1325. // callbacks to the app while we are doing this
  1326. //
  1327. //INET_ASSERT(fsm.m_dwBufferLeft <= _BytesRemaining);
  1328. error = _Socket->Receive((LPVOID *)&_ResponseBuffer,
  1329. &_ResponseBufferLength,
  1330. &fsm.m_dwBufferLeft,
  1331. &_BytesReceived,
  1332. 0, // dwExtraSpace
  1333. SF_EXPAND
  1334. | SF_COMPRESS
  1335. | fsm.m_dwAsyncFlags,
  1336. &fsm.m_bEof
  1337. );
  1338. if (error == ERROR_IO_PENDING) {
  1339. goto quit;
  1340. }
  1341. fsm_continue:
  1342. if (error == ERROR_SUCCESS) {
  1343. DWORD nRead = _BytesReceived - fsm.m_dwPreviousBytesReceived;
  1344. if (IsContentLength()) {
  1345. fsm.m_dwAmountToRead -= nRead;
  1346. INET_ASSERT((int)fsm.m_dwAmountToRead >= 0);
  1347. _BytesInSocket -= nRead;
  1348. INET_ASSERT((int)_BytesInSocket >= 0);
  1349. if (IsKeepAlive()) {
  1350. _BytesRemaining -= nRead;
  1351. INET_ASSERT((int)_BytesRemaining >= 0);
  1352. //
  1353. // if we have read all the entity-body then we can
  1354. // release the keep-alive connection, or close the
  1355. // socket
  1356. //
  1357. //
  1358. // BUGBUG - put back post-ie30a
  1359. //
  1360. //if (_BytesRemaining == 0) {
  1361. // fsm.m_bEof = TRUE;
  1362. //}
  1363. }
  1364. }
  1365. if ( IsChunkEncoding() )
  1366. {
  1367. LPSTR lpszNewBuffer;
  1368. DWORD dwNewBufferLength;
  1369. INET_ASSERT(!IsContentLength());
  1370. error = _ctChunkInfo.ParseChunkInput(
  1371. (LPSTR) (_ResponseBuffer + fsm.m_dwPreviousBytesReceived),
  1372. nRead,
  1373. &lpszNewBuffer,
  1374. &dwNewBufferLength
  1375. );
  1376. nRead = dwNewBufferLength;
  1377. _BytesReceived = nRead + fsm.m_dwPreviousBytesReceived;
  1378. INET_ASSERT(error == ERROR_SUCCESS); // I want to see this happen.
  1379. if ( error != ERROR_SUCCESS )
  1380. {
  1381. break;
  1382. }
  1383. if ( IsChunkedEncodingFinished() )
  1384. {
  1385. fsm.m_bEof = TRUE;
  1386. break;
  1387. }
  1388. }
  1389. fsm.m_dwBytesReceived += nRead;
  1390. fsm.m_dwPreviousBytesReceived = _BytesReceived;
  1391. }
  1392. }
  1393. }
  1394. if (error == ERROR_SUCCESS) {
  1395. //
  1396. // update the amount of data immediately available to the caller
  1397. //
  1398. IncreaseAvailableDataLength(fsm.m_dwBytesReceived);
  1399. //
  1400. // and set the end-of-file indication in the top level handle object
  1401. //
  1402. SetEndOfFile();
  1403. //
  1404. // there is no more data to be received on this HTTP object
  1405. //
  1406. //SetData(FALSE);
  1407. //
  1408. // this object can now be re-used
  1409. //
  1410. SetState(HttpRequestStateReopen);
  1411. }
  1412. //
  1413. // return indication that we drained the socket
  1414. //
  1415. DEBUG_PRINT(HTTP,
  1416. INFO,
  1417. ("returning *lpbDrained = %B\n",
  1418. drainIt
  1419. ));
  1420. quit:
  1421. if (error != ERROR_IO_PENDING) {
  1422. fsm.SetDone();
  1423. *fsm.m_lpbDrained = drainIt;
  1424. }
  1425. PERF_LOG(PE_TRACE, 0x8002);
  1426. DEBUG_LEAVE(error);
  1427. return error;
  1428. }
  1429. VOID
  1430. HTTP_REQUEST_HANDLE_OBJECT::SetBadNSReceiveTimeout(
  1431. VOID
  1432. )
  1433. {
  1434. DEBUG_ENTER((DBG_HTTP,
  1435. None,
  1436. "HTTP_REQUEST_HANDLE_OBJECT::SetBadNSReceiveTimeout",
  1437. NULL
  1438. ));
  1439. if ((_Socket != NULL)
  1440. && !IsContentLength()
  1441. && !IsChunkEncoding()) {
  1442. CServerInfo * pServerInfo = GetServerInfo();
  1443. if (pServerInfo) {
  1444. DWORD timeout = max(5000, 5 * pServerInfo->GetRTT());
  1445. _Socket->SetTimeout(RECEIVE_TIMEOUT, timeout);
  1446. SetTimeout(INTERNET_OPTION_RECEIVE_TIMEOUT, timeout);
  1447. }
  1448. }
  1449. DEBUG_LEAVE(0);
  1450. }