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.

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