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.

802 lines
26 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. response.cxx
  5. Abstract:
  6. This file contains the HTTP Request Handle Object ReceiveResponse method
  7. Contents:
  8. CFsm_ReceiveResponse::RunSM
  9. HTTP_REQUEST_HANDLE_OBJECT::ReceiveResponse_Fsm
  10. Author:
  11. Keith Moore (keithmo) 16-Nov-1994
  12. Revision History:
  13. 29-Apr-97 rfirth
  14. Conversion to FSM
  15. --*/
  16. #include <wininetp.h>
  17. #include <perfdiag.hxx>
  18. #include "httpp.h"
  19. //
  20. // private manifests
  21. //
  22. #define DEFAULT_RESPONSE_BUFFER_LENGTH (1 K)
  23. //
  24. // HTTP Request Handle Object methods
  25. //
  26. DWORD
  27. CFsm_ReceiveResponse::RunSM(
  28. IN CFsm * Fsm
  29. )
  30. /*++
  31. Routine Description:
  32. description-of-function.
  33. Arguments:
  34. Fsm -
  35. Return Value:
  36. DWORD
  37. --*/
  38. {
  39. DEBUG_ENTER((DBG_HTTP,
  40. Dword,
  41. "CFsm_ReceiveResponse::RunSM",
  42. "%#x",
  43. Fsm
  44. ));
  45. CFsm_ReceiveResponse * stateMachine = (CFsm_ReceiveResponse *)Fsm;
  46. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  47. DWORD error;
  48. START_SENDREQ_PERF();
  49. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  50. switch (Fsm->GetState()) {
  51. case FSM_STATE_INIT:
  52. case FSM_STATE_CONTINUE:
  53. error = pRequest->ReceiveResponse_Fsm(stateMachine);
  54. break;
  55. default:
  56. error = ERROR_INTERNET_INTERNAL_ERROR;
  57. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  58. INET_ASSERT(FALSE);
  59. break;
  60. }
  61. STOP_SENDREQ_PERF();
  62. DEBUG_LEAVE(error);
  63. return error;
  64. }
  65. DWORD
  66. HTTP_REQUEST_HANDLE_OBJECT::ReceiveResponse_Fsm(
  67. IN CFsm_ReceiveResponse * Fsm
  68. )
  69. /*++
  70. Routine Description:
  71. description-of-function.
  72. Arguments:
  73. Fsm -
  74. Return Value:
  75. DWORD
  76. --*/
  77. {
  78. #if INET_DEBUG
  79. //#define RLF_TEST_CODE
  80. #ifdef RLF_TEST_CODE
  81. //
  82. // single 100 response
  83. //
  84. #define TEST_HEADER_0 "HTTP/1.1 100 Continue\r\n" \
  85. "\r\n"
  86. //
  87. // single 100 header
  88. //
  89. #define TEST_HEADER_1 "HTTP/1.1 100 Continue\r\n" \
  90. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  91. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  92. "\r\n"
  93. //
  94. // continue header with moderate amount of data
  95. //
  96. #define TEST_HEADER_2 "HTTP/1.1 100 Continue\r\n" \
  97. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  98. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  99. "Content-Length: 128\r\n" \
  100. "Content-Type: octet/shmoctet\r\n" \
  101. "\r\n" \
  102. "0123456789abcdef" \
  103. "0123456789abcdef" \
  104. "0123456789abcdef" \
  105. "0123456789abcdef" \
  106. "0123456789abcdef" \
  107. "0123456789abcdef" \
  108. "0123456789abcdef" \
  109. "0123456789abcdef"
  110. //
  111. // continue header seen from apache server
  112. //
  113. #define TEST_HEADER_3 "HTTP/1.1 100 Continue\r\n" \
  114. "\r\n" \
  115. "\n\n\n\n\n"
  116. //
  117. // multiple continue headers, no data
  118. //
  119. #define TEST_HEADER_4 "HTTP/1.1 100 Continue\r\n" \
  120. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  121. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  122. "\r\n" \
  123. "HTTP/1.1 100 Continue\r\n" \
  124. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  125. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  126. "\r\n" \
  127. "HTTP/1.1 100 Continue\r\n" \
  128. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  129. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  130. "\r\n" \
  131. "HTTP/1.1 100 Continue\r\n" \
  132. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  133. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  134. "\r\n"
  135. //
  136. // single 100 response, preceeded by preamble and containing a chunked response
  137. //
  138. #define TEST_HEADER_5 "!!!! this is a pre-amble, should be ignored even though it includes HTTP !!!!" \
  139. " " \
  140. "HTTP/1.1 100 Go ahead punk, make my day\r\n" \
  141. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  142. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  143. "Transfer-Encoding: chunked\r\n" \
  144. "\r\n" \
  145. "0010 this is the first chunk (16 bytes)\r\n" \
  146. "0123456789abcdef" \
  147. "\r\n" \
  148. " 10; this is the second chunk (16 bytes)\r\n" \
  149. "0123456789abcdef" \
  150. "\r\n" \
  151. "00F3\r\n" \
  152. "0123456789abcdef" \
  153. "0123456789abcdef" \
  154. "0123456789abcdef" \
  155. "0123456789abcdef" \
  156. "0123456789abcdef" \
  157. "0123456789abcdef" \
  158. "0123456789abcdef" \
  159. "0123456789abcdef" \
  160. "0123456789abcdef" \
  161. "0123456789abcdef" \
  162. "0123456789abcdef" \
  163. "0123456789abcdef" \
  164. "0123456789abcdef" \
  165. "0123456789abcdef" \
  166. "0123456789abcdef" \
  167. "012" \
  168. "\r\n" \
  169. "0000; the final chunk\r\n" \
  170. "\r\n" \
  171. "Entity-Header: this is the chunk footer\r\n" \
  172. "\r\n"
  173. //
  174. // enpty chunk encoded response with empty footer
  175. //
  176. #define TEST_HEADER_6 "HTTP/1.1 100 Continue\r\n" \
  177. "Server: Richard's Test-Case Virtual Server/1.0\r\n" \
  178. "Date: Mon, 01 Apr 2000 00:00:01 GMT\r\n" \
  179. "Transfer-Encoding: chunked\r\n" \
  180. "\r\n" \
  181. "0\r\n" \
  182. "\r\n" \
  183. "\r\n"
  184. const struct {LPSTR ptr; DWORD len;} test_cases[] = {
  185. TEST_HEADER_0, sizeof(TEST_HEADER_0) - 1,
  186. TEST_HEADER_1, sizeof(TEST_HEADER_1) - 1,
  187. TEST_HEADER_2, sizeof(TEST_HEADER_2) - 1,
  188. TEST_HEADER_3, sizeof(TEST_HEADER_3) - 1,
  189. TEST_HEADER_4, sizeof(TEST_HEADER_4) - 1,
  190. TEST_HEADER_5, sizeof(TEST_HEADER_5) - 1,
  191. TEST_HEADER_6, sizeof(TEST_HEADER_6) - 1
  192. };
  193. DWORD test_index = 99;
  194. #endif // def RLF_TEST_CODE
  195. #endif // INET_DEBUG
  196. DEBUG_ENTER((DBG_HTTP,
  197. Dword,
  198. "HTTP_REQUEST_HANDLE_OBJECT::ReceiveResponse_Fsm",
  199. "%#x",
  200. Fsm
  201. ));
  202. PERF_ENTER(ReceiveResponse_Fsm);
  203. CFsm_ReceiveResponse & fsm = *Fsm;
  204. DWORD error = fsm.GetError();
  205. FSM_STATE state = fsm.GetState();
  206. if (error != ERROR_SUCCESS) {
  207. if (error == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) {
  208. if ((_Socket != NULL) && _Socket->IsSecure())
  209. {
  210. if(m_pSecurityInfo)
  211. {
  212. /* SCLE ref */
  213. m_pSecurityInfo->Release();
  214. }
  215. /* SCLE ref */
  216. m_pSecurityInfo = ((ICSecureSocket *)_Socket)->GetSecurityEntry();
  217. }
  218. SetState(HttpRequestStateOpen);
  219. CloseConnection(TRUE);
  220. fsm.SetDone();
  221. goto quit2;
  222. }
  223. goto quit;
  224. }
  225. if (state != FSM_STATE_INIT) {
  226. state = fsm.GetFunctionState();
  227. }
  228. do {
  229. switch (state) {
  230. case FSM_STATE_INIT:
  231. if (_ResponseBuffer == NULL) {
  232. _ResponseBufferLength = DEFAULT_RESPONSE_BUFFER_LENGTH;
  233. _ResponseBuffer = (LPBYTE)ALLOCATE_MEMORY(LMEM_FIXED,
  234. _ResponseBufferLength);
  235. if (_ResponseBuffer == NULL) {
  236. _ResponseBufferLength = 0;
  237. error = ERROR_NOT_ENOUGH_MEMORY;
  238. goto quit;
  239. }
  240. }
  241. INET_ASSERT(_BytesReceived == 0);
  242. fsm.m_dwResponseLeft = _ResponseBufferLength;
  243. state = FSM_STATE_2;
  244. //
  245. // fall through
  246. //
  247. #ifdef RLF_TEST_CODE
  248. InternetGetDebugVariable("WininetTestIndex", &test_index);
  249. if (test_index < ARRAY_ELEMENTS(test_cases)) {
  250. _BytesReceived = test_cases[test_index].len;
  251. memcpy(_ResponseBuffer, test_cases[test_index].ptr, _BytesReceived);
  252. fsm.m_dwResponseLeft = _ResponseBufferLength - _BytesReceived;
  253. }
  254. #endif // def RLF_TEST_CODE
  255. case FSM_STATE_2:
  256. //
  257. // we will allow Receive() to expand the buffer (and therefore initially
  258. // allocate it), and to compress the buffer if we receive the end of the
  259. // connection. It is up to UpdateResponseHeaders() to figure out when
  260. // enough data has been read to indicate end of the headers
  261. //
  262. fsm.SetFunctionState(FSM_STATE_3);
  263. INET_ASSERT(_Socket != NULL);
  264. if (_Socket != NULL) {
  265. error = _Socket->Receive((LPVOID *)&_ResponseBuffer,
  266. &_ResponseBufferLength,
  267. &fsm.m_dwResponseLeft,
  268. &_BytesReceived,
  269. 0,
  270. SF_EXPAND
  271. | SF_COMPRESS
  272. | SF_INDICATE,
  273. &fsm.m_bEofResponseHeaders
  274. );
  275. if (error == ERROR_IO_PENDING) {
  276. goto quit;
  277. }
  278. } else {
  279. error = ERROR_INTERNET_OPERATION_CANCELLED;
  280. }
  281. //
  282. // fall through
  283. //
  284. case FSM_STATE_3:
  285. //
  286. // if we are using a keep-alive connection that was previously timed-out
  287. // by the server, we may not find out about it until now
  288. //
  289. // Note: it seems we can get a zero length response at this point also,
  290. // which I take to mean that the server-side socket has been closed
  291. //
  292. INET_ASSERT(_BytesReceived <= _ResponseBufferLength);
  293. if ((error != ERROR_SUCCESS)
  294. || ((_BytesReceived == 0) && IsKeepAlive())) {
  295. //
  296. // We need to reset the state if we got a
  297. // certificate request.
  298. //
  299. if (error == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) {
  300. if ((_Socket != NULL) && _Socket->IsSecure())
  301. {
  302. if(m_pSecurityInfo)
  303. {
  304. /* SCLE ref */
  305. m_pSecurityInfo->Release();
  306. }
  307. /* SCLE ref */
  308. m_pSecurityInfo = ((ICSecureSocket *)_Socket)->GetSecurityEntry();
  309. }
  310. SetState(HttpRequestStateOpen);
  311. }
  312. CloseConnection(TRUE);
  313. goto quit;
  314. }
  315. //
  316. // if we received no data then the server has closed the connection
  317. // already
  318. //
  319. if (_BytesReceived != 0) {
  320. BOOL bHaveFinalResponse;
  321. do {
  322. bHaveFinalResponse = TRUE;
  323. error = UpdateResponseHeaders(&fsm.m_bEofResponseHeaders);
  324. //if (!(rand() % 7)) {
  325. // error = ERROR_HTTP_INVALID_SERVER_RESPONSE;
  326. //}
  327. if (error != ERROR_SUCCESS) {
  328. //dprintf("UpdateResponseHeaders() returns %d\n", error);
  329. break;
  330. }
  331. DWORD statusCode;
  332. statusCode = GetStatusCode();
  333. //
  334. // receive next packet if we didn't get a status code yet
  335. //
  336. if (statusCode == 0) {
  337. break;
  338. }
  339. //
  340. // discard any 1xx responses and get the headers again
  341. //
  342. if (fsm.m_bEofResponseHeaders
  343. && (statusCode >= HTTP_STATUS_CONTINUE)
  344. && (statusCode < HTTP_STATUS_OK)) {
  345. bHaveFinalResponse = FALSE;
  346. fsm.SetFunctionState(FSM_STATE_4);
  347. //
  348. // get any data that came with the header
  349. //
  350. fsm.m_bDrained = FALSE;
  351. if (IsContentLength() && (_BytesInSocket != 0)) {
  352. error = DrainResponse(&fsm.m_bDrained);
  353. if (error != ERROR_SUCCESS) {
  354. goto quit;
  355. }
  356. }
  357. //
  358. // fall through
  359. //
  360. case FSM_STATE_4:
  361. //
  362. // now that we have drained the socket, we can indicate
  363. // the response to the app. This gives apps chance to
  364. // perform progress reporting for each 100 response
  365. // received, e.g.
  366. //
  367. InternetIndicateStatus(INTERNET_STATUS_INTERMEDIATE_RESPONSE,
  368. &statusCode,
  369. sizeof(statusCode)
  370. );
  371. //
  372. // if there is no more data left in the buffer then we
  373. // can receive the next response at the start of the
  374. // buffer, else continue from where the previous one
  375. // ended
  376. //
  377. if (fsm.m_bDrained || !IsBufferedData()) {
  378. fsm.m_dwResponseLeft = _ResponseBufferLength;
  379. _BytesReceived = 0;
  380. _DataOffset = 0;
  381. _ResponseScanned = 0;
  382. } else {
  383. _ResponseScanned = _DataOffset;
  384. if (IsContentLength()) {
  385. _ResponseScanned += _ContentLength;
  386. }
  387. //if (IsChunkEncoding()) {
  388. //
  389. // LPSTR lpszNewBuffer;
  390. // DWORD dwNewBufferLength;
  391. //
  392. // error = _ctChunkInfo.ParseChunkInput(
  393. // (LPSTR) BufferedDataStart(),
  394. // BufferedDataLength(),
  395. // &lpszNewBuffer,
  396. // &dwNewBufferLength
  397. // );
  398. //
  399. // _ResponseBufferDataReadyToRead = dwNewBufferLength;
  400. //
  401. // INET_ASSERT(error == ERROR_SUCCESS);
  402. // if ( error != ERROR_SUCCESS )
  403. // {
  404. // goto quit;
  405. // }
  406. //}
  407. //if (IsChunkEncoding()) {
  408. //
  409. // LPSTR lpszNewBuffer;
  410. // DWORD dwNewBufferLength;
  411. // DWORD nRead = 0;
  412. //
  413. // INET_ASSERT(!IsContentLength());
  414. //
  415. // error = _ctChunkInfo.ParseChunkInput(
  416. // (LPSTR) (_ResponseBuffer + _DataOffset),
  417. // nRead,
  418. // &lpszNewBuffer,
  419. // &dwNewBufferLength
  420. // );
  421. //
  422. // nRead = dwNewBufferLength;
  423. // _BytesReceived = nRead + _DataOffset;
  424. //
  425. // INET_ASSERT(error == ERROR_SUCCESS); // I want to see this happen.
  426. // if ( error != ERROR_SUCCESS )
  427. // {
  428. // break;
  429. // }
  430. //
  431. // if ( IsChunkedEncodingFinished() )
  432. // {
  433. // break;
  434. // }
  435. //}
  436. }
  437. _ResponseHeaders.FreeHeaders();
  438. _ResponseHeaders.Initialize();
  439. ZapFlags();
  440. _ContentLength = 0;
  441. _BytesRemaining = 0;
  442. _BytesInSocket = 0;
  443. fsm.m_bEofResponseHeaders = FALSE;
  444. if (_DataOffset == 0) {
  445. //
  446. // need to read next response - nothing left in
  447. // buffer
  448. //
  449. break;
  450. }
  451. }
  452. // If we have a server authentication context
  453. // and the response is anything but 401, mark
  454. // the socket as authenticated.
  455. AUTHCTX *pAuthCtx;
  456. pAuthCtx = GetAuthCtx();
  457. if (pAuthCtx && !pAuthCtx->_fIsProxy
  458. && (statusCode != HTTP_STATUS_DENIED))
  459. {
  460. #define MICROSOFT_IIS_SERVER_SZ "Microsoft-IIS/"
  461. #define MICROSOFT_PWS_SERVER_SZ "Microsoft-PWS/"
  462. #define MICROSOFT_IIS_SERVER_LEN (sizeof(MICROSOFT_IIS_SERVER_SZ) - 1)
  463. #define MICROSOFT_PWS_SERVER_LEN (sizeof(MICROSOFT_PWS_SERVER_SZ) - 1)
  464. LPSTR pszBuf;
  465. DWORD cbBuf;
  466. cbBuf = MAX_PATH;
  467. if (FastQueryResponseHeader(HTTP_QUERY_SERVER,
  468. (LPVOID*) &pszBuf, &cbBuf, 0) == ERROR_SUCCESS)
  469. {
  470. if (cbBuf >= MICROSOFT_IIS_SERVER_LEN
  471. && (!strncmp(pszBuf, MICROSOFT_IIS_SERVER_SZ, MICROSOFT_IIS_SERVER_LEN)
  472. || !strncmp(pszBuf, MICROSOFT_PWS_SERVER_SZ, MICROSOFT_PWS_SERVER_LEN)))
  473. {
  474. // Found an IIS header. Mark socket as authenticated if
  475. // IIS 1, 2 or 3. Lengths of both strings are same.
  476. CHAR *pVer = pszBuf + MICROSOFT_IIS_SERVER_LEN;
  477. if (*pVer == '1'
  478. || *pVer == '2'
  479. || *pVer == '3'
  480. )
  481. {
  482. // IIS 1, 2 or 3 - mark dirty.
  483. _Socket->SetAuthenticated();
  484. }
  485. }
  486. }
  487. else
  488. {
  489. // Unknown server; may be IIS 1,2 or 3.
  490. _Socket->SetAuthenticated();
  491. }
  492. }
  493. } while (!bHaveFinalResponse);
  494. } else {
  495. error = ERROR_HTTP_INVALID_SERVER_RESPONSE;
  496. }
  497. //
  498. // set state to perform next receive
  499. //
  500. state = FSM_STATE_2;
  501. }
  502. } while ((error == ERROR_SUCCESS) && !fsm.m_bEofResponseHeaders);
  503. //
  504. // we should update the RTT as soon as we get received data from
  505. // the socket, but then we'd have to store the RTT in the socket
  506. // object or access this one, etc. Just keep it here for now -
  507. // its a reasonable approximation in the normal IE case: not too
  508. // much time spent in callbacks etc.
  509. //
  510. UpdateRTT();
  511. //dprintf("RTT for %s = %d\n", GetURL(), GetRTT());
  512. //dprintf("OS = %s, PS = %s\n", ((GetOriginServer() != NULL) ? GetOriginServer()->GetHostName() : "none"),
  513. // ((GetServerInfo() != NULL) ? GetServerInfo()->GetHostName() : "none"));
  514. //
  515. // we have received the headers and possibly some (or all) of the data. The
  516. // app can now query the headers and receive the data
  517. //
  518. SetState(HttpRequestStateObjectData);
  519. //
  520. // record the amount of data immediately available to the app
  521. //
  522. if ( IsChunkEncoding() )
  523. {
  524. LPSTR lpszNewBuffer;
  525. DWORD dwNewBufferLength;
  526. error = _ctChunkInfo.ParseChunkInput(
  527. (LPSTR) BufferedDataStart(),
  528. BufferedDataLength(),
  529. &lpszNewBuffer,
  530. &dwNewBufferLength
  531. );
  532. _ResponseBufferDataReadyToRead = dwNewBufferLength;
  533. INET_ASSERT(error == ERROR_SUCCESS);
  534. if ( error != ERROR_SUCCESS )
  535. {
  536. goto quit;
  537. }
  538. }
  539. SetAvailableDataLength(BufferDataAvailToRead());
  540. //
  541. // IIS caches authentication credentials on keep-alive sockets.
  542. //
  543. if (_Socket) {
  544. if (IsAuthorized()) {
  545. _Socket->SetAuthorized();
  546. }
  547. if (IsPerUserItem()) {
  548. _Socket->SetPerUser();
  549. } else if (_Socket->IsPerUser()) {
  550. SetPerUserItem(TRUE);
  551. }
  552. }
  553. quit:
  554. if (error != ERROR_IO_PENDING) {
  555. fsm.SetDone();
  556. //
  557. // if we got the socket from the keep-alive pool, but found no keep-
  558. // alive header then we no longer have a keep-alive connection
  559. //
  560. if (_bKeepAliveConnection && !IsKeepAlive()) {
  561. //dprintf("*** %s - NO LONGER K-A socket %#x\n", GetURL(), _Socket->GetSocket());
  562. SetNoLongerKeepAlive();
  563. }
  564. //
  565. // don't maintain the connection if there's no more data to read. UNLESS
  566. // we are in the middle of establishing an authenticated connection
  567. // (implies using keep-alive connection, e.g. NTLM)
  568. // IsData() returns FALSE if there's no data at all, otherwise we
  569. // check to see if we have read all the data already (i.e. with the
  570. // response headers)
  571. //
  572. if ((error != ERROR_SUCCESS)
  573. || (
  574. //
  575. // data-less response (ignoring keep-alive & content-length)
  576. //
  577. (!IsData()
  578. //
  579. // all data body in header buffer
  580. //
  581. || (IsKeepAlive()
  582. && IsContentLength()
  583. && (BufferedDataLength() == GetContentLength())
  584. )
  585. )
  586. //
  587. // but only if not in the middle of auth negotiation and if the
  588. // connection hasn't been dropped by the server
  589. //
  590. && ((GetAuthState() != AUTHSTATE_NEGOTIATE)
  591. || IsNoLongerKeepAlive())
  592. && (!((GetStatusCode() == 407) && IsKeepAlive()))
  593. )
  594. ) {
  595. //dprintf("socket %#x [%#x/%d] error=%d, IsData()=%B, K-A=%B, C-L=%d, BDL=%d, AS=%d\n",
  596. // _Socket,
  597. // _Socket ? _Socket->GetSocket() : 0,
  598. // _Socket ? _Socket->GetSourcePort() : 0,
  599. // error,
  600. // IsData(),
  601. // IsKeepAlive(),
  602. // GetContentLength(),
  603. // BufferedDataLength(),
  604. // GetAuthState()
  605. // );
  606. //
  607. // BUGBUG - if this is a new keep-alive connection?
  608. //
  609. DEBUG_PRINT(HTTP,
  610. INFO,
  611. ("closing: error = %d, IsData() = %B, K-A = %B, IsC-L = %B, BDL = %d, C-L = %d AS=%d [%s]\n",
  612. error,
  613. IsData(),
  614. IsKeepAlive(),
  615. IsContentLength(),
  616. BufferedDataLength(),
  617. GetContentLength(),
  618. GetAuthState(),
  619. InternetMapAuthState(GetAuthState())
  620. ));
  621. if(GlobalAlwaysDrainOnRedirect ||
  622. GetStatusCode() != HTTP_STATUS_REDIRECT ||
  623. (HTTP_METHOD_TYPE_HEAD == GetMethodType()))
  624. {
  625. CloseConnection((error != ERROR_SUCCESS) ? TRUE : FALSE);
  626. }
  627. else
  628. DEBUG_PRINT(HTTP, INFO, ("Not closing socket, Status code = %d \n", GetStatusCode()));
  629. //
  630. // set the relevant state
  631. //
  632. if (error != ERROR_SUCCESS &&
  633. error != ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED &&
  634. error != ERROR_INTERNET_INVALID_CA &&
  635. error != ERROR_INTERNET_SEC_CERT_DATE_INVALID &&
  636. error != ERROR_INTERNET_SEC_CERT_CN_INVALID )
  637. {
  638. SetState(HttpRequestStateError);
  639. }
  640. }
  641. PERF_LEAVE(ReceiveResponse_Fsm);
  642. }
  643. quit2:
  644. DEBUG_LEAVE(error);
  645. return error;
  646. }