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.

744 lines
24 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_WINHTTP_INTERNAL_ERROR;
  57. Fsm->SetDone(ERROR_WINHTTP_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_WINHTTP_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_WINHTTP_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_WINHTTP_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. DWORD dwStatusCode = statusCode;
  368. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE,
  369. &dwStatusCode,
  370. sizeof(dwStatusCode)
  371. );
  372. //
  373. // if there is no more data left in the buffer then we
  374. // can receive the next response at the start of the
  375. // buffer, else continue from where the previous one
  376. // ended
  377. //
  378. if (fsm.m_bDrained || !IsBufferedData()) {
  379. fsm.m_dwResponseLeft = _ResponseBufferLength;
  380. _BytesReceived = 0;
  381. _DataOffset = 0;
  382. _ResponseScanned = 0;
  383. } else {
  384. _ResponseScanned = _DataOffset;
  385. if (IsContentLength()) {
  386. _ResponseScanned += _ContentLength;
  387. }
  388. }
  389. _ResponseHeaders.FreeHeaders();
  390. _ResponseHeaders.Initialize();
  391. ZapFlags();
  392. _ContentLength = 0;
  393. _BytesRemaining = 0;
  394. _BytesInSocket = 0;
  395. fsm.m_bEofResponseHeaders = FALSE;
  396. if (_DataOffset == 0) {
  397. //
  398. // need to read next response - nothing left in
  399. // buffer
  400. //
  401. break;
  402. }
  403. }
  404. // If we have a server authentication context
  405. // and the response is anything but 401, mark
  406. // the socket as authenticated.
  407. AUTHCTX *pAuthCtx;
  408. pAuthCtx = GetAuthCtx();
  409. if (pAuthCtx && !pAuthCtx->_fIsProxy
  410. && (statusCode != HTTP_STATUS_DENIED))
  411. {
  412. #define MICROSOFT_IIS_SERVER_SZ "Microsoft-IIS/"
  413. #define MICROSOFT_PWS_SERVER_SZ "Microsoft-PWS/"
  414. #define MICROSOFT_IIS_SERVER_LEN (sizeof(MICROSOFT_IIS_SERVER_SZ) - 1)
  415. #define MICROSOFT_PWS_SERVER_LEN (sizeof(MICROSOFT_PWS_SERVER_SZ) - 1)
  416. LPSTR pszBuf;
  417. DWORD cbBuf;
  418. cbBuf = MAX_PATH;
  419. if (FastQueryResponseHeader(HTTP_QUERY_SERVER,
  420. (LPVOID*) &pszBuf, &cbBuf, 0) == ERROR_SUCCESS)
  421. {
  422. if (cbBuf >= MICROSOFT_IIS_SERVER_LEN
  423. && (!strncmp(pszBuf, MICROSOFT_IIS_SERVER_SZ, MICROSOFT_IIS_SERVER_LEN)
  424. || !strncmp(pszBuf, MICROSOFT_PWS_SERVER_SZ, MICROSOFT_PWS_SERVER_LEN)))
  425. {
  426. // Found an IIS header. Mark socket as authenticated if
  427. // IIS 1, 2 or 3. Lengths of both strings are same.
  428. CHAR *pVer = pszBuf + MICROSOFT_IIS_SERVER_LEN;
  429. if (*pVer == '1'
  430. || *pVer == '2'
  431. || *pVer == '3'
  432. )
  433. {
  434. // IIS 1, 2 or 3 - mark dirty.
  435. _Socket->SetAuthenticated();
  436. }
  437. }
  438. }
  439. else
  440. {
  441. // Unknown server; may be IIS 1,2 or 3.
  442. _Socket->SetAuthenticated();
  443. }
  444. }
  445. } while (!bHaveFinalResponse);
  446. } else {
  447. error = ERROR_HTTP_INVALID_SERVER_RESPONSE;
  448. }
  449. //
  450. // set state to perform next receive
  451. //
  452. state = FSM_STATE_2;
  453. }
  454. } while ((error == ERROR_SUCCESS) && !fsm.m_bEofResponseHeaders);
  455. //
  456. // we should update the RTT as soon as we get received data from
  457. // the socket, but then we'd have to store the RTT in the socket
  458. // object or access this one, etc. Just keep it here for now -
  459. // its a reasonable approximation in the normal IE case: not too
  460. // much time spent in callbacks etc.
  461. //
  462. UpdateRTT();
  463. //dprintf("RTT for %s = %d\n", GetURL(), GetRTT());
  464. //dprintf("OS = %s, PS = %s\n", ((GetOriginServer() != NULL) ? GetOriginServer()->GetHostName() : "none"),
  465. // ((GetServerInfo() != NULL) ? GetServerInfo()->GetHostName() : "none"));
  466. //
  467. // we have received the headers and possibly some (or all) of the data. The
  468. // app can now query the headers and receive the data
  469. //
  470. SetState(HttpRequestStateObjectData);
  471. //
  472. // record the amount of data immediately available to the app
  473. //
  474. if ( IsChunkEncoding() )
  475. {
  476. DWORD dwChunkBytesRead = 0;
  477. DWORD dwChunkBytesWritten = 0;
  478. error = _ResponseFilterList.Decode(
  479. (LPBYTE) BufferedDataStart(),
  480. BufferedDataLength(),
  481. NULL,
  482. NULL,
  483. &dwChunkBytesRead,
  484. &dwChunkBytesWritten
  485. );
  486. _ResponseBufferDataReadyToRead = dwChunkBytesWritten;
  487. INET_ASSERT(error == ERROR_SUCCESS);
  488. if ( error != ERROR_SUCCESS )
  489. {
  490. goto quit;
  491. }
  492. }
  493. SetAvailableDataLength(BufferDataAvailToRead());
  494. //
  495. // IIS caches authentication credentials on keep-alive sockets.
  496. //
  497. if (_Socket) {
  498. if (IsAuthorized()) {
  499. _Socket->SetAuthorized();
  500. }
  501. }
  502. quit:
  503. if (error != ERROR_IO_PENDING) {
  504. fsm.SetDone();
  505. //
  506. // if we got the socket from the keep-alive pool, but found no keep-
  507. // alive header then we no longer have a keep-alive connection
  508. //
  509. if (_bKeepAliveConnection && !IsKeepAlive()) {
  510. //dprintf("*** %s - NO LONGER K-A socket %#x\n", GetURL(), _Socket->GetSocket());
  511. SetNoLongerKeepAlive();
  512. }
  513. //
  514. // don't maintain the connection if there's no more data to read. UNLESS
  515. // we are in the middle of establishing an authenticated connection
  516. // (implies using keep-alive connection, e.g. NTLM)
  517. // IsData() returns FALSE if there's no data at all, otherwise we
  518. // check to see if we have read all the data already (i.e. with the
  519. // response headers)
  520. //
  521. if ((error != ERROR_SUCCESS)
  522. || (
  523. //
  524. // data-less response (ignoring keep-alive & content-length)
  525. //
  526. (!IsData()
  527. //
  528. // all data body in header buffer
  529. //
  530. || (IsKeepAlive()
  531. && IsContentLength()
  532. && (BufferedDataLength() == GetContentLength())
  533. )
  534. )
  535. //
  536. // but only if not in the middle of auth negotiation and if the
  537. // connection hasn't been dropped by the server
  538. //
  539. && ((GetAuthState() != AUTHSTATE_NEGOTIATE)
  540. || IsNoLongerKeepAlive())
  541. )
  542. ) {
  543. //dprintf("socket %#x [%#x/%d] error=%d, IsData()=%B, K-A=%B, C-L=%d, BDL=%d, AS=%d\n",
  544. // _Socket,
  545. // _Socket ? _Socket->GetSocket() : 0,
  546. // _Socket ? _Socket->GetSourcePort() : 0,
  547. // error,
  548. // IsData(),
  549. // IsKeepAlive(),
  550. // GetContentLength(),
  551. // BufferedDataLength(),
  552. // GetAuthState()
  553. // );
  554. //
  555. // BUGBUG - if this is a new keep-alive connection?
  556. //
  557. DEBUG_PRINT(HTTP,
  558. INFO,
  559. ("closing: error = %d, IsData() = %B, K-A = %B, IsC-L = %B, BDL = %d, C-L = %d\n",
  560. error,
  561. IsData(),
  562. IsKeepAlive(),
  563. IsContentLength(),
  564. BufferedDataLength(),
  565. GetContentLength()
  566. ));
  567. if(GetStatusCode() != HTTP_STATUS_REDIRECT || (HTTP_METHOD_TYPE_HEAD == GetMethodType()))
  568. CloseConnection((error != ERROR_SUCCESS) ? TRUE : FALSE);
  569. else
  570. DEBUG_PRINT(HTTP, INFO, ("Not closing socket, Status code = %d \n", GetStatusCode()));
  571. //
  572. // set the relevant state
  573. //
  574. if (error != ERROR_SUCCESS &&
  575. (error != ERROR_WINHTTP_SECURE_FAILURE ||
  576. GetStatusFlags() & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA |
  577. WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID |
  578. WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID |
  579. WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR |
  580. WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED |
  581. WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)) &&
  582. error != ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )
  583. {
  584. SetState(HttpRequestStateError);
  585. }
  586. }
  587. PERF_LEAVE(ReceiveResponse_Fsm);
  588. }
  589. quit2:
  590. DEBUG_LEAVE(error);
  591. return error;
  592. }