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.

2408 lines
69 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. send.cxx
  5. Abstract:
  6. This file contains the implementation of the HttpSendRequestA API.
  7. Contents:
  8. HTTP_REQUEST_HANDLE_OBJECT::InitBeginSendRequest
  9. HTTP_REQUEST_HANDLE_OBJECT::CheckClientRequestHeaders
  10. CFsm_HttpSendRequest::RunSM
  11. HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start
  12. HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Finish
  13. HTTP_REQUEST_HANDLE_OBJECT::UpdateProxyInfo
  14. HTTP_REQUEST_HANDLE_OBJECT::FindConnCloseRequestHeader
  15. Author:
  16. Keith Moore (keithmo) 16-Nov-1994
  17. Revision History:
  18. 29-Apr-97 rfirth
  19. Conversion to FSM
  20. --*/
  21. #include <wininetp.h>
  22. #include <perfdiag.hxx>
  23. #include "httpp.h"
  24. //
  25. // HTTP Request Handle Object methods
  26. //
  27. DWORD
  28. HTTP_REQUEST_HANDLE_OBJECT::InitBeginSendRequest(
  29. IN LPCSTR lpszHeaders OPTIONAL,
  30. IN DWORD dwHeadersLength,
  31. IN LPVOID *lplpOptional,
  32. IN LPDWORD lpdwOptionalLength,
  33. IN DWORD dwOptionalLengthTotal
  34. )
  35. /*++
  36. Routine Description:
  37. Performs Initiatization of the HTTP Request by setting up the necessary
  38. headers and preparing the POST data.
  39. Arguments:
  40. lpszHeaders - Additional headers to be appended to the request.
  41. This may be NULL if there are no additional
  42. headers to append
  43. dwHeadersLength - The length (in characters) of the additional
  44. headers. If this is -1L and lpszAdditional is
  45. non-NULL, then lpszAdditional is assumed to be
  46. zero terminated (ASCIIZ)
  47. lpOptionalData - Any optional data to send immediately after the
  48. request headers. This is typically used for POST
  49. operations. This may be NULL if there is no
  50. optional data to send
  51. dwOptionalDataLength - The length (in BYTEs) of the optional data. This
  52. may be zero if there is no optional data to send
  53. dwOptionalLengthTotal - Total Length for File Upload.
  54. Return Value:
  55. DWORD
  56. Success - ERROR_SUCCESS
  57. Failure - One of the Win32 Error values.
  58. Comments:
  59. --*/
  60. {
  61. DEBUG_ENTER((DBG_HTTP,
  62. Dword,
  63. "HTTP_REQUEST_HANDLE_OBJECT::InitBeginSendRequest",
  64. "%#x, %d, %d, %#x",
  65. lplpOptional ? *lplpOptional : NULL,
  66. lpdwOptionalLength ? *lpdwOptionalLength : NULL,
  67. dwOptionalLengthTotal
  68. ));
  69. DWORD error = ERROR_SUCCESS;
  70. LPVOID lpOptional = *lplpOptional;
  71. DWORD dwOptionalLength = *lpdwOptionalLength;
  72. //
  73. // validate parameters
  74. //
  75. if ((lpOptional == NULL) || (dwOptionalLength == 0)) {
  76. lpOptional = NULL;
  77. dwOptionalLength = 0;
  78. }
  79. //
  80. // the headers lengths can be -1 meaning that we should calculate the
  81. // string lengths. We must do this before calling MakeAsyncRequest()
  82. // which is expecting the parameters to be correct
  83. //
  84. if (dwHeadersLength == -1)
  85. {
  86. dwHeadersLength = lstrlen((LPCSTR)lpszHeaders);
  87. }
  88. //
  89. // if the caller specified some additional headers, then add them before
  90. // we make the request asynchronously
  91. //
  92. if (ARGUMENT_PRESENT(lpszHeaders) && (*lpszHeaders != '\0')) {
  93. //
  94. // we use the API here because the headers came from the app, and
  95. // we don't trust it
  96. //
  97. if (!HttpAddRequestHeaders(GetPseudoHandle(),
  98. lpszHeaders,
  99. dwHeadersLength,
  100. //
  101. // if the object is being re-used then
  102. // replace the headers to avoid
  103. // duplicating original headers
  104. //
  105. IS_VALID_HTTP_STATE(this, REUSE, TRUE)
  106. ? ( HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD ): 0
  107. //? HTTP_ADDREQ_FLAG_REPLACE : 0
  108. )) {
  109. error = GetLastError();
  110. goto quit;
  111. }
  112. }
  113. //
  114. // If we fall through then we are connected and a) either the thing
  115. // is not in the cache or we did a conditional get or c) there was
  116. // some cache error
  117. //
  118. error = ERROR_SUCCESS;
  119. //
  120. // if the app supplied a user-agent string to InternetOpen() AND hasn't
  121. // added a "User-Agent:" header, then add it
  122. //
  123. LPSTR userAgent;
  124. DWORD userAgentLength;
  125. userAgent = GetUserAgent(&userAgentLength);
  126. if (userAgent != NULL) {
  127. ReplaceRequestHeader(HTTP_QUERY_USER_AGENT,
  128. userAgent,
  129. userAgentLength,
  130. 0, // dwIndex,
  131. ADD_HEADER_IF_NEW
  132. );
  133. }
  134. //
  135. // do the same thing with the "Host:" header. The header-value is the host
  136. // name supplied to InternetConnect() (or the name of the redirected host)
  137. //
  138. LPSTR hostName;
  139. DWORD hostNameLength;
  140. INTERNET_PORT hostPort;
  141. hostName = GetHostName(&hostNameLength);
  142. hostPort = GetHostPort();
  143. INET_ASSERT((hostName != NULL) && (hostNameLength > 0));
  144. char hostValue[INTERNET_MAX_HOST_NAME_LENGTH + sizeof(":4294967295")];
  145. if ((hostPort != INTERNET_DEFAULT_HTTP_PORT)
  146. && (hostPort != INTERNET_DEFAULT_HTTPS_PORT)) {
  147. if (lstrlen(hostName) > INTERNET_MAX_HOST_NAME_LENGTH)
  148. {
  149. error = ERROR_INVALID_PARAMETER;
  150. goto quit;
  151. }
  152. hostNameLength = wsprintf(hostValue, "%s:%d", hostName, (hostPort & 0xffff));
  153. hostName = hostValue;
  154. }
  155. ReplaceRequestHeader(HTTP_QUERY_HOST,
  156. hostName,
  157. hostNameLength,
  158. 0, // dwIndex,
  159. ADD_HEADER_IF_NEW
  160. );
  161. //
  162. // if the app requested keep-alive then add the header; if we're going via
  163. // proxy then use the proxy-connection header
  164. //
  165. //if (pRequest->GetOpenFlags() & INTERNET_FLAG_KEEP_CONNECTION) {
  166. // pRequest->SetWantKeepAlive(TRUE);
  167. //}
  168. //
  169. // add the content-length header IF we are sending data OR this is a POST,
  170. // AND ONLY if the app has not already added the header
  171. //
  172. if (dwOptionalLength || dwOptionalLengthTotal)
  173. SetMethodBody();
  174. if (((dwOptionalLength != 0) || (dwOptionalLengthTotal != 0))
  175. //
  176. // BUGBUG - just comparing against a method type is insufficient. We need
  177. // a test of whether the method implies sending data (PUT, etc).
  178. // We make the same test in other places
  179. //
  180. || (GetMethodType() != HTTP_METHOD_TYPE_GET)) {
  181. DWORD dwContentLength;
  182. char number[sizeof("4294967295")];
  183. //
  184. // For File Upload we need to add the Content-Length
  185. // header off of the Total Length, Not the current
  186. // data size. Since we get more data via InternetWriteFile
  187. //
  188. if ( dwOptionalLengthTotal != 0 )
  189. {
  190. dwContentLength = dwOptionalLengthTotal;
  191. }
  192. else
  193. {
  194. dwContentLength = dwOptionalLength;
  195. }
  196. // _itoa(dwOptionalLength, number, 10);
  197. wsprintf(number, "%d", dwContentLength);
  198. DWORD numberLength = lstrlen(number);
  199. /*----------------------------------------------------------------------
  200. #62953 NOTE -- Authstate can never be in the AUTHSTATE_NEGOTIATE
  201. state here. It is not necessary to zero out the content length
  202. header here when omitting post data on NTLM negotiate since this
  203. will be done later in the request. The commented-out code is not
  204. necessary.
  205. if ((GetMethodType() == HTTP_METHOD_TYPE_POST)
  206. && (GetAuthState() == AUTHSTATE_NEGOTIATE))
  207. {
  208. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  209. "0",
  210. 1,
  211. 0, // dwIndex
  212. ADD_HEADER
  213. );
  214. }
  215. ---------------------------------------------------------------------*/
  216. // Normally we don't over-write the content-length
  217. // header if one already exists.
  218. DWORD dwAddHeader;
  219. dwAddHeader = ADD_HEADER_IF_NEW;
  220. // But if we're posting data and have an auth ctx
  221. // over-write the content-length header which will
  222. // have been reset to 0 to omit post data on the
  223. // negotiate phase.
  224. AUTHCTX *pAuthCtx;
  225. pAuthCtx = GetAuthCtx();
  226. if (pAuthCtx)
  227. {
  228. dwAddHeader = ADD_HEADER;
  229. }
  230. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  231. (LPSTR)number,
  232. numberLength,
  233. 0, // dwIndex
  234. dwAddHeader
  235. );
  236. }
  237. quit:
  238. *lplpOptional = lpOptional;
  239. *lpdwOptionalLength = dwOptionalLength;
  240. DEBUG_LEAVE(error);
  241. return error;
  242. }
  243. DWORD
  244. CFsm_HttpSendRequest::RunSM(
  245. IN CFsm * Fsm
  246. )
  247. /*++
  248. Routine Description:
  249. description-of-function.
  250. Arguments:
  251. Fsm -
  252. Return Value:
  253. DWORD
  254. --*/
  255. {
  256. DEBUG_ENTER((DBG_HTTP,
  257. Dword,
  258. "CFsm_HttpSendRequest::RunSM",
  259. "%#x",
  260. Fsm
  261. ));
  262. DWORD error;
  263. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  264. START_SENDREQ_PERF();
  265. CFsm_HttpSendRequest * stateMachine = (CFsm_HttpSendRequest *)Fsm;
  266. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  267. switch (Fsm->GetState()) {
  268. case FSM_STATE_INIT:
  269. case FSM_STATE_CONTINUE:
  270. //CHECK_FSM_OWNED(Fsm);
  271. error = pRequest->HttpSendRequest_Start(stateMachine);
  272. break;
  273. case FSM_STATE_FINISH:
  274. //CHECK_FSM_OWNED(Fsm);
  275. error = pRequest->HttpSendRequest_Finish(stateMachine);
  276. break;
  277. case FSM_STATE_ERROR:
  278. //CHECK_FSM_OWNED(Fsm);
  279. error = Fsm->GetError();
  280. //
  281. // If we block to call GetProxyInfo async, then
  282. // we may get unblocked during a cancel. We need to
  283. // handle it by freeing the object in our destructor.
  284. //
  285. INET_ASSERT( (!stateMachine->m_fOwnsProxyInfoQueryObj) ?
  286. ( error == ERROR_WINHTTP_OPERATION_CANCELLED ||
  287. error == ERROR_WINHTTP_TIMEOUT ) :
  288. TRUE );
  289. Fsm->SetDone();
  290. break;
  291. default:
  292. //CHECK_FSM_OWNED(Fsm);
  293. stateMachine->m_fOwnsProxyInfoQueryObj = TRUE;
  294. error = ERROR_WINHTTP_INTERNAL_ERROR;
  295. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  296. INET_ASSERT(FALSE);
  297. break;
  298. }
  299. DEBUG_LEAVE(error);
  300. STOP_SENDREQ_PERF();
  301. return error;
  302. }
  303. DWORD
  304. HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start(
  305. IN CFsm_HttpSendRequest * Fsm
  306. )
  307. /*++
  308. Routine Description:
  309. Calls SendData() method in a loop, handling redirects (& authentications?)
  310. until we have successfully started to retrieve what was originally requested
  311. Arguments:
  312. Fsm - HTTP send request FSM
  313. Return Value:
  314. DWORD
  315. Success - ERROR_SUCCESS
  316. Operation completed successfully
  317. ERROR_IO_PENDING
  318. Operation will complete asynchronously
  319. Failure - ERROR_WINHTTP_INCORRECT_HANDLE_STATE
  320. The HTTP request handle is in the wrong state for this
  321. request
  322. ERROR_NOT_ENOUGH_MEMORY
  323. Ran out of resources
  324. --*/
  325. {
  326. DEBUG_ENTER((DBG_HTTP,
  327. Dword,
  328. "HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start",
  329. "%#x",
  330. Fsm
  331. ));
  332. PERF_ENTER(HttpSendRequest_Start);
  333. //CHECK_FSM_OWNED(Fsm);
  334. CFsm_HttpSendRequest & fsm = *Fsm;
  335. //
  336. // we must loop here while the server redirects us or while we authenticate
  337. // the user
  338. //
  339. FSM_STATE state = fsm.GetState();
  340. DWORD error = fsm.GetError();
  341. //
  342. // We set m_fOwnsProxyInfoObj TRUE, because by virtue of being here
  343. // we have know that we now own the pointer in our fsm, pointed to by
  344. // fsm.m_pProxyInfoQuery.
  345. //
  346. // This boolean is used to know when we are allowed to FREE and ACCESS
  347. // this pointer. If FALSE, we CANNOT touch this pointer because
  348. // the auto-proxy thread may be accessing it. The auto-proxy thread
  349. // will unblock us, this releasing its "un-offical" lock on this pointer.
  350. //
  351. fsm.m_fOwnsProxyInfoQueryObj = TRUE;
  352. if (state == FSM_STATE_INIT)
  353. {
  354. if ( fsm.m_arRequest == AR_HTTP_END_SEND_REQUEST )
  355. {
  356. state = FSM_STATE_4;
  357. fsm.SetFunctionState(FSM_STATE_4);
  358. }
  359. }
  360. else
  361. {
  362. state = fsm.GetFunctionState();
  363. }
  364. retry_send_request:
  365. do {
  366. switch (state) {
  367. case FSM_STATE_INIT:
  368. case FSM_STATE_1:
  369. //CHECK_FSM_OWNED(Fsm);
  370. fsm.m_iRetries = 2;
  371. fsm.m_bAuthNotFinished = FALSE;
  372. fsm.m_dwCookieIndex = 0;
  373. //
  374. // Terrible bug that afflicts NS servers while doing SSL,
  375. // they lie (those buggers), and claim they do keep-alive,
  376. // but when we attempt to reuse their Keep-Alive sockets,
  377. // they all fail, so we therefore must increase the retry count
  378. // so we can empty all the bad keep-alive sockets out of the pool
  379. //
  380. if ( (GetOpenFlags() & WINHTTP_FLAG_SECURE) )
  381. {
  382. CServerInfo * pServerInfo = GetServerInfo();
  383. if ( pServerInfo && pServerInfo->IsBadNSServer() )
  384. {
  385. fsm.m_iRetries = 5;
  386. }
  387. }
  388. //
  389. // if we're not in the right state to send, drain the socket
  390. //
  391. if (!IsValidHttpState(SEND)) {
  392. #define DRAIN_SOCKET_BUFFER_LENGTH (1 K)
  393. if (fsm.m_pBuffer == NULL) {
  394. fsm.m_pBuffer = (LPVOID)ALLOCATE_MEMORY(
  395. LMEM_FIXED,
  396. DRAIN_SOCKET_BUFFER_LENGTH);
  397. if (fsm.m_pBuffer == NULL) {
  398. error = ERROR_NOT_ENOUGH_MEMORY;
  399. goto quit;
  400. }
  401. }
  402. do {
  403. if (!fsm.m_bSink) {
  404. fsm.m_bSink = TRUE;
  405. fsm.SetFunctionState(FSM_STATE_2);
  406. error = ReadData(fsm.m_pBuffer,
  407. DRAIN_SOCKET_BUFFER_LENGTH,
  408. &fsm.m_dwBytesDrained,
  409. TRUE,
  410. 0);
  411. if (error == ERROR_IO_PENDING) {
  412. goto quit;
  413. }
  414. }
  415. //
  416. // fall through to state 2
  417. //
  418. case FSM_STATE_2:
  419. fsm.m_bSink = FALSE;
  420. } while ((error == ERROR_SUCCESS) && (fsm.m_dwBytesDrained != 0));
  421. if (error != ERROR_SUCCESS) {
  422. goto quit;
  423. }
  424. if (fsm.m_pBuffer != NULL) {
  425. fsm.m_pBuffer = (LPVOID)FREE_MEMORY(fsm.m_pBuffer);
  426. INET_ASSERT(fsm.m_pBuffer == NULL);
  427. }
  428. ReuseObject();
  429. INET_ASSERT(!IsData());
  430. INET_ASSERT(IS_VALID_HTTP_STATE(this, SEND, TRUE));
  431. //
  432. // BUGBUG - if we're not in the right state?
  433. //
  434. }
  435. //
  436. // generate the correct request headers based
  437. // on what types, or whether we're using
  438. // proxies
  439. //
  440. fsm.SetFunctionState(FSM_STATE_3);
  441. error = UpdateProxyInfo(Fsm, FALSE);
  442. if (error == ERROR_IO_PENDING) {
  443. goto done;
  444. }
  445. //
  446. // set function state to not-FSM_STATE_3 to differentiate interrupted
  447. // path in FSM_STATE_3
  448. //
  449. fsm.SetFunctionState(FSM_STATE_BAD);
  450. //
  451. // fall through
  452. //
  453. case FSM_STATE_3:
  454. if ((error == ERROR_SUCCESS)
  455. && (fsm.GetFunctionState() == FSM_STATE_3)) {
  456. error = UpdateProxyInfo(Fsm, TRUE);
  457. }
  458. if (error != ERROR_SUCCESS) {
  459. fsm.m_bCancelRedoOfProxy = TRUE;
  460. goto quit;
  461. }
  462. //
  463. // get any cookies required for this site, but only if app didn't
  464. // tell us it will handle cookies
  465. //
  466. if (!(GetOpenFlags() & INTERNET_FLAG_NO_COOKIES) )
  467. {
  468. if (CreateCookieHeaderIfNeeded())
  469. {
  470. // SetPerUserItem(TRUE);
  471. }
  472. }
  473. //
  474. // if this URL requires authentication then add its header here, but
  475. // only if the app didn't tell us not to
  476. //
  477. if (!(GetOpenFlags() & INTERNET_FLAG_NO_AUTH))
  478. {
  479. SetPPAbort(FALSE); // let's assume Passport is not going to abort the send.
  480. error = AuthOnRequest(this);
  481. if (error != ERROR_SUCCESS)
  482. {
  483. goto quit;
  484. }
  485. if (PPAbort())
  486. {
  487. // Passport needed to abort the send cuz the DA wanted to redirect
  488. // the App to an different site *AND* the app wanted to handle the
  489. // redirect itself.
  490. error = ERROR_WINHTTP_LOGIN_FAILURE;
  491. goto quit;
  492. }
  493. }
  494. try_again:
  495. fsm.SetFunctionState(FSM_STATE_4);
  496. DEBUG_PRINT(HTTP, INFO, ("State_3_Start: lpOptional = 0x%x deOptionalLength = %d\n", fsm.m_lpOptional, fsm.m_dwOptionalLength));
  497. error = DoFsm(New CFsm_SendRequest(fsm.m_lpOptional,
  498. fsm.m_dwOptionalLength,
  499. this
  500. ));
  501. if (error == ERROR_IO_PENDING) {
  502. goto quit;
  503. }
  504. //
  505. // fall through
  506. //
  507. case FSM_STATE_4:
  508. DEBUG_PRINT(HTTP, INFO, ("State_4_start: lpOptional = 0x%x deOptionalLength = %d\n", fsm.m_lpOptional, fsm.m_dwOptionalLength));
  509. //CHECK_FSM_OWNED(Fsm);
  510. //
  511. // This adds CR-LF for the File Upload case
  512. //
  513. //if (_RequestMethod == HTTP_METHOD_TYPE_POST && _AddCRLFToPOST && fsm.m_arRequest == AR_HTTP_END_SEND_REQUEST)
  514. //{
  515. // error = _Socket->Send(gszCRLF, 2, 0);
  516. // if (error != ERROR_SUCCESS) {
  517. // goto quit;
  518. // }
  519. //}
  520. fsm.m_bWasKeepAlive = (_bKeepAliveConnection || IsKeepAlive());
  521. if ((error != ERROR_SUCCESS)
  522. || ((GetStatusCode() != HTTP_STATUS_OK) && (GetStatusCode() != 0))) {
  523. //
  524. // must be doing proxy tunnelling request if status code set
  525. //
  526. INET_ASSERT(((GetStatusCode() != HTTP_STATUS_OK)
  527. && (GetStatusCode() != 0))
  528. ? IsTalkingToSecureServerViaProxy()
  529. : TRUE
  530. );
  531. //
  532. // server may have reset keep-alive connection
  533. //
  534. if ((error == ERROR_WINHTTP_CONNECTION_ERROR)
  535. && fsm.m_bWasKeepAlive
  536. && (--fsm.m_iRetries != 0)) {
  537. DEBUG_PRINT(HTTP,
  538. INFO,
  539. ("keep-alive connection failed after send. Retrying\n"
  540. ));
  541. //dprintf("*** retrying k-a connection after send\n");
  542. CloseConnection(TRUE);
  543. goto try_again;
  544. }
  545. goto quit;
  546. }
  547. if (fsm.m_arRequest == AR_HTTP_BEGIN_SEND_REQUEST) {
  548. goto quit;
  549. }
  550. fsm.SetFunctionState(FSM_STATE_5);
  551. error = DoFsm(New CFsm_ReceiveResponse(this));
  552. if (error == ERROR_IO_PENDING) {
  553. goto quit;
  554. }
  555. //
  556. // fall through
  557. //
  558. case FSM_STATE_5:
  559. DEBUG_PRINT(HTTP, INFO, ("State_5_Start: lpOptional = 0x%x deOptionalLength = %d\n", fsm.m_lpOptional, fsm.m_dwOptionalLength));
  560. //CHECK_FSM_OWNED(Fsm);
  561. if (error != ERROR_SUCCESS) {
  562. //dprintf("*** post-receive: error=%d, retries=%d\n", error, fsm.m_iRetries);
  563. //
  564. // server may have reset keep-alive connection
  565. //
  566. if (((error == ERROR_WINHTTP_CONNECTION_ERROR)
  567. || (error == ERROR_HTTP_INVALID_SERVER_RESPONSE))
  568. && fsm.m_bWasKeepAlive
  569. && (--fsm.m_iRetries != 0)) {
  570. DEBUG_PRINT(HTTP,
  571. INFO,
  572. ("keep-alive connection failed after receive. Retrying\n"
  573. ));
  574. //dprintf("*** retrying k-a connection after receive\n");
  575. CloseConnection(TRUE);
  576. _ResponseHeaders.FreeHeaders();
  577. ResetResponseVariables();
  578. _ResponseHeaders.Initialize();
  579. goto try_again;
  580. }
  581. goto quit;
  582. }
  583. fsm.SetFunctionState(FSM_STATE_6);
  584. case FSM_STATE_6:
  585. DEBUG_PRINT(HTTP, INFO, ("State_6_Start: lpOptional = 0x%x deOptionalLength = %d\n", fsm.m_lpOptional, fsm.m_dwOptionalLength));
  586. //
  587. // put any received cookie headers in the cookie jar, but only if the
  588. // app didn't tell us not to
  589. //
  590. if (!(GetOpenFlags() & INTERNET_FLAG_NO_COOKIES)
  591. && IsResponseHeaderPresent(HTTP_QUERY_SET_COOKIE) )
  592. {
  593. DWORD dwError;
  594. dwError = ExtractSetCookieHeaders(&fsm.m_dwCookieIndex);
  595. if ( dwError == ERROR_IO_PENDING )
  596. {
  597. error = ERROR_IO_PENDING;
  598. goto quit;
  599. }
  600. }
  601. //
  602. // we need to handle various intermediary return codes:
  603. //
  604. // 30x - redirection
  605. // 40x - authentication
  606. //
  607. // BUT ONLY if the app didn't tell us it wanted to handle these itself
  608. //
  609. DWORD statusCode;
  610. BOOL bNoAuth;
  611. statusCode = GetStatusCode();
  612. bNoAuth = (GetOpenFlags() & INTERNET_FLAG_NO_AUTH) ? TRUE : FALSE;
  613. //
  614. // if the status is 200 (most frequently return header == success)
  615. // and we are not authenticating all responses then we're done
  616. //
  617. if ((statusCode == HTTP_STATUS_OK) && bNoAuth) {
  618. goto quit;
  619. }
  620. //
  621. // handle authentication before checking the cache
  622. //
  623. if (!bNoAuth) {
  624. //
  625. // call packages for basic, ntlm
  626. //
  627. error = AuthOnResponse(this);
  628. // passport1.4 auth could change the status code from 302 to 401 here
  629. statusCode = GetStatusCode();
  630. if (error == ERROR_WINHTTP_FORCE_RETRY) {
  631. // Force a retry error only if Writes are required, otherwise we have all the data for a redirect:
  632. if ( fsm.m_arRequest == AR_HTTP_END_SEND_REQUEST && IsWriteRequired())
  633. {
  634. goto quit;
  635. }
  636. //
  637. // the object has been updated with new info - try again
  638. //
  639. fsm.m_bFinished = FALSE;
  640. fsm.m_bAuthNotFinished = TRUE;
  641. error = ERROR_SUCCESS;
  642. //
  643. // Reset auto-proxy info so we can retry the connection
  644. //
  645. if ( fsm.m_fOwnsProxyInfoQueryObj && fsm.m_pProxyInfoQuery && fsm.m_pProxyInfoQuery->IsAlloced())
  646. {
  647. delete fsm.m_pProxyInfoQuery;
  648. fsm.m_pProxyInfoQuery = NULL;
  649. }
  650. } else if (error == ERROR_WINHTTP_INCORRECT_PASSWORD) {
  651. //
  652. // just return success to the app which will have to check the
  653. // headers and make the request again, with the right password
  654. //
  655. error = ERROR_SUCCESS;
  656. goto quit;
  657. }
  658. }
  659. //
  660. // if we can read from the cache then let us try
  661. //
  662. if ((statusCode == HTTP_STATUS_OK)
  663. || (statusCode == HTTP_STATUS_NOT_MODIFIED)
  664. || (statusCode == HTTP_STATUS_PRECOND_FAILED)
  665. || (statusCode == HTTP_STATUS_PARTIAL_CONTENT)
  666. || (statusCode == 0)) {
  667. }
  668. BOOL fMustRedirect;
  669. fMustRedirect = FALSE;
  670. if (_pAuthCtx)
  671. {
  672. if (_pAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_PASSPORT)
  673. {
  674. PASSPORT_CTX* pPPCtx = (PASSPORT_CTX*)_pAuthCtx;
  675. if (pPPCtx->m_lpszRetUrl)
  676. {
  677. fMustRedirect = TRUE;
  678. }
  679. }
  680. }
  681. //
  682. // handle redirection
  683. //
  684. fsm.m_tMethodRedirect = HTTP_METHOD_TYPE_UNKNOWN;
  685. fsm.m_bRedirected = FALSE;
  686. if (((statusCode == HTTP_STATUS_AMBIGUOUS) // 300
  687. || (statusCode == HTTP_STATUS_MOVED) // 301
  688. || (statusCode == HTTP_STATUS_REDIRECT) // 302
  689. || (statusCode == HTTP_STATUS_REDIRECT_METHOD) // 303
  690. || (statusCode == HTTP_STATUS_REDIRECT_KEEP_VERB)) // 307
  691. && (fMustRedirect || !(GetOpenFlags() & INTERNET_FLAG_NO_AUTO_REDIRECT))) {
  692. //
  693. // Clean out expired PROXY_STATE
  694. //
  695. error = ERROR_SUCCESS;
  696. if ( fsm.m_fOwnsProxyInfoQueryObj && fsm.m_pProxyInfoQuery && fsm.m_pProxyInfoQuery->IsAlloced())
  697. {
  698. delete fsm.m_pProxyInfoQuery;
  699. fsm.m_pProxyInfoQuery = NULL;
  700. }
  701. //fsm.m_pProxyState = NULL;
  702. SetProxyName(NULL, 0, 0);
  703. //
  704. // if we've already had the max allowable redirects then quit
  705. //
  706. if (fsm.m_dwRedirectCount == 0) {
  707. error = ERROR_HTTP_REDIRECT_FAILED;
  708. fsm.m_bRedirectCountedOut = TRUE;
  709. goto quit;
  710. }
  711. //
  712. // we got 300 (ambiguous), 301 (permanent move), 302 (temporary
  713. // move), or 303 (redirection using new method)
  714. //
  715. switch (statusCode) {
  716. case HTTP_STATUS_AMBIGUOUS:
  717. //
  718. // 300 - multiple choice
  719. //
  720. //
  721. // If there is a Location header, we do an "automatic" redirect
  722. //
  723. if (_ResponseHeaders.LockHeaders())
  724. {
  725. if (! IsResponseHeaderPresent(HTTP_QUERY_LOCATION)) {
  726. _ResponseHeaders.UnlockHeaders();
  727. fsm.m_bFinished = TRUE;
  728. break;
  729. }
  730. _ResponseHeaders.UnlockHeaders();
  731. }
  732. else
  733. {
  734. error = ERROR_NOT_ENOUGH_MEMORY;
  735. goto quit;
  736. }
  737. //
  738. // fall through
  739. //
  740. case HTTP_STATUS_MOVED:
  741. // Table View:
  742. //Method 301 302 303 307
  743. // * * * GET *
  744. //POST GET GET GET POST
  745. //
  746. //Put another way:
  747. //301 & 302 - All methods are redirected to the same method but POST. POST is
  748. // redirected to a GET.
  749. //303 - All methods are redirected to GET
  750. //307 - All methods are redirected to the same method.
  751. //
  752. // 301 - permanently moved
  753. //
  754. //
  755. // fall through
  756. //
  757. case HTTP_STATUS_REDIRECT:
  758. //
  759. // 302 - temporarily moved (POST => GET, everything stays the same)
  760. //
  761. fsm.m_tMethodRedirect = GetMethodType();
  762. if (fsm.m_tMethodRedirect == HTTP_METHOD_TYPE_POST)
  763. //
  764. // A POST change method to a GET
  765. //
  766. {
  767. fsm.m_tMethodRedirect = HTTP_METHOD_TYPE_GET;
  768. // force no optional data on second and subsequent sends
  769. fsm.m_dwOptionalLength = 0;
  770. _fOptionalSaved = FALSE;
  771. }
  772. INET_ASSERT(((fsm.m_tMethodRedirect == HTTP_METHOD_TYPE_GET)
  773. || (fsm.m_tMethodRedirect == HTTP_METHOD_TYPE_HEAD))
  774. ? (fsm.m_dwOptionalLength == 0) : TRUE);
  775. fsm.m_bRedirected = TRUE;
  776. --fsm.m_dwRedirectCount;
  777. break;
  778. case HTTP_STATUS_REDIRECT_METHOD:
  779. //
  780. // 303 - see other (POST => GET)
  781. //
  782. fsm.m_tMethodRedirect = (GetMethodType() == HTTP_METHOD_TYPE_HEAD) ?
  783. HTTP_METHOD_TYPE_HEAD :
  784. HTTP_METHOD_TYPE_GET;
  785. //
  786. // force no optional data on second and subsequent sends
  787. //
  788. fsm.m_dwOptionalLength = 0;
  789. _fOptionalSaved = FALSE;
  790. fsm.m_bRedirected = TRUE;
  791. --fsm.m_dwRedirectCount;
  792. break;
  793. case HTTP_STATUS_REDIRECT_KEEP_VERB:
  794. //
  795. // 307 - see other (POST => POST)
  796. //
  797. //if (IsHttp1_1()) {
  798. fsm.m_tMethodRedirect = GetMethodType();
  799. INET_ASSERT(((fsm.m_tMethodRedirect == HTTP_METHOD_TYPE_GET)
  800. || (fsm.m_tMethodRedirect == HTTP_METHOD_TYPE_HEAD))
  801. ? (fsm.m_dwOptionalLength == 0) : TRUE);
  802. fsm.m_bRedirected = TRUE;
  803. --fsm.m_dwRedirectCount;
  804. break;
  805. default:
  806. fsm.m_tMethodRedirect = HTTP_METHOD_TYPE_GET;
  807. //
  808. // BUGBUG - force no optional data on second and subsequent
  809. // sends
  810. //
  811. fsm.m_dwOptionalLength = 0;
  812. fsm.m_bRedirected = TRUE;
  813. --fsm.m_dwRedirectCount;
  814. break;
  815. }
  816. //
  817. // Only allow redirect to continue if we are successful.
  818. //
  819. if (fsm.m_bRedirected
  820. && ((fsm.m_tMethodRedirect != HTTP_METHOD_TYPE_UNKNOWN)
  821. || (fsm.m_tMethodRedirect == GetMethodType()))) {
  822. fsm.SetFunctionState(FSM_STATE_7);
  823. error = Redirect(fsm.m_tMethodRedirect, FALSE);
  824. if (error != ERROR_SUCCESS) {
  825. goto quit;
  826. }
  827. }
  828. } else {
  829. //
  830. // not a status that we handle. We're done
  831. // BUT WAIT, we're only finshed if also
  832. // finished retrying HTTP authentication.
  833. //
  834. // if the app told us not to handle authentication auth_not_finished
  835. // will be FALSE
  836. //
  837. if (!fsm.m_bAuthNotFinished) {
  838. fsm.m_bFinished = TRUE;
  839. }
  840. }
  841. //
  842. // fall through
  843. //
  844. case FSM_STATE_7:
  845. DEBUG_PRINT(HTTP, INFO, ("State_7_Start: lpOptional = 0x%x deOptionalLength = %d\n", fsm.m_lpOptional, fsm.m_dwOptionalLength));
  846. //CHECK_FSM_OWNED(Fsm);
  847. if (fsm.m_bRedirected) {
  848. if (error != ERROR_SUCCESS) {
  849. goto quit;
  850. }
  851. INET_ASSERT(error == ERROR_SUCCESS);
  852. //
  853. // cleanup response headers from redirection
  854. //
  855. ReuseObject();
  856. //
  857. // Allow Redirects to exit out and force the HttpEndRequestA
  858. // caller to notice.
  859. //
  860. if ( fsm.m_arRequest == AR_HTTP_END_SEND_REQUEST &&
  861. fsm.m_tMethodRedirect != HTTP_METHOD_TYPE_GET &&
  862. fsm.m_tMethodRedirect != HTTP_METHOD_TYPE_HEAD &&
  863. // Force a retry error only if Writes are required, otherwise we have all the data for a redirect:
  864. IsWriteRequired()
  865. )
  866. {
  867. error = ERROR_WINHTTP_FORCE_RETRY;
  868. }
  869. }
  870. }
  871. state = FSM_STATE_INIT;
  872. } while (!fsm.m_bFinished && (error == ERROR_SUCCESS));
  873. quit:
  874. DEBUG_PRINT(HTTP, INFO, ("Quit1: error = 0x%x\r\n", error));
  875. if (error == ERROR_IO_PENDING) {
  876. goto done;
  877. }
  878. {
  879. AUTHCTX* pAuthCtx = GetAuthCtx();
  880. DWORD eAuthScheme = 0;
  881. if (pAuthCtx != NULL)
  882. {
  883. eAuthScheme = pAuthCtx->GetSchemeType();
  884. }
  885. if (!fsm.m_bCancelRedoOfProxy &&
  886. //(GetStatusCode() != HTTP_STATUS_DENIED) &&
  887. ((eAuthScheme != WINHTTP_AUTH_SCHEME_PASSPORT) || (GetStatusCode() != HTTP_STATUS_DENIED)) && // this is safer
  888. fsm.m_pInternet->RedoSendRequest(&error, fsm.m_pRequest->GetSecureFlags(), fsm.m_pProxyInfoQuery, GetOriginServer(), GetServerInfo()))
  889. {
  890. fsm.m_bFinished = FALSE;
  891. fsm.m_bRedirectCountedOut = FALSE;
  892. fsm.m_dwRedirectCount = GlobalMaxHttpRedirects;
  893. fsm.SetState(FSM_STATE_INIT);
  894. state = FSM_STATE_INIT;
  895. DEBUG_PRINT(HTTP, INFO, ("Quit2: error = 0x%x\r\n", error));
  896. goto retry_send_request;
  897. }
  898. else
  899. {
  900. //SetProxyName(NULL, 0, 0);
  901. DEBUG_PRINT(HTTP, INFO, ("Quit3: error = 0x%x\r\n", error));
  902. }
  903. }
  904. //
  905. // if ERROR_HTTP_REDIRECT_FAILED then we tried to redirect, but found that
  906. // we couldn't do it (e.g. http:// to ftp:// or file://, etc.) We need to
  907. // defer this to the caller to clean up & make the new request. They will
  908. // have all the header info (plus we probably already indicated the new
  909. // URL during the redirect callback). Rather than returning ERROR_SUCCESS,
  910. // we will now fail with this error.
  911. //
  912. // Cases where we are redirected to the same site will return ERROR_SUCCESS.
  913. //
  914. if ((error == ERROR_HTTP_NOT_REDIRECTED)
  915. && !fsm.m_bRedirectCountedOut) {
  916. error = ERROR_SUCCESS;
  917. }
  918. fsm.SetNextState(FSM_STATE_FINISH);
  919. done:
  920. PERF_LEAVE(HttpSendRequest_Start);
  921. DEBUG_LEAVE(error);
  922. return error;
  923. }
  924. DWORD
  925. HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Finish(
  926. IN CFsm_HttpSendRequest * Fsm
  927. )
  928. /*++
  929. Routine Description:
  930. description-of-function.
  931. Arguments:
  932. Fsm -
  933. Return Value:
  934. DWORD
  935. --*/
  936. {
  937. DEBUG_ENTER((DBG_HTTP,
  938. Dword,
  939. "HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Finish",
  940. "%#x",
  941. Fsm
  942. ));
  943. PERF_ENTER(HttpSendRequest_Finish);
  944. CFsm_HttpSendRequest & fsm = *Fsm;
  945. DWORD error = fsm.GetError();
  946. fsm.m_fOwnsProxyInfoQueryObj = TRUE;
  947. INET_ASSERT(fsm.m_hRequestMapped != NULL);
  948. //if (!IsAsyncHandle() && (fsm.m_hRequestMapped != NULL)) {
  949. // DereferenceObject((LPVOID)fsm.m_hRequestMapped);
  950. //}
  951. //
  952. // we will return FALSE even if this is an async operation and the error is
  953. // ERROR_IO_PENDING
  954. //
  955. fsm.SetDone(error);
  956. //fsm.SetApiResult(error == ERROR_SUCCESS);
  957. PERF_LEAVE(HttpSendRequest_Finish);
  958. DEBUG_LEAVE(error);
  959. return error;
  960. }
  961. DWORD
  962. HTTP_REQUEST_HANDLE_OBJECT::BuildProxyMessage(
  963. IN CFsm_HttpSendRequest * Fsm,
  964. AUTO_PROXY_ASYNC_MSG * pProxyMsg,
  965. IN OUT URL_COMPONENTS * pUrlComponents
  966. )
  967. /*++
  968. Routine Description:
  969. Calls CrackUrl to parses request URL, and
  970. transfers the information to the AUTO_PROXY_ASYNC_MSG
  971. Arguments:
  972. Fsm - HTTP send request FSM
  973. Return Value:
  974. DWORD
  975. Success - ERROR_SUCCESS
  976. Failure -
  977. ERROR_NOT_ENOUGH_MEMORY
  978. Ran out of resources
  979. --*/
  980. {
  981. DWORD error = ERROR_SUCCESS;
  982. LPSTR currentUrl;
  983. DWORD currentUrlLength;
  984. //
  985. // Gather the URL off the handle
  986. //
  987. currentUrl = GetURL();
  988. if (currentUrl) {
  989. currentUrlLength = lstrlen(currentUrl);
  990. //
  991. // BUGBUG [arthurbi] the following can be a slow call,
  992. // but its too risky to change the complete behavior where
  993. // we cache it
  994. //
  995. //
  996. // crack the current URL
  997. //
  998. memset(pUrlComponents, 0, sizeof(URL_COMPONENTS));
  999. pUrlComponents->dwStructSize = sizeof(URL_COMPONENTS);
  1000. error = CrackUrl(currentUrl,
  1001. currentUrlLength,
  1002. FALSE, // don't escape URL-path
  1003. &(pUrlComponents->nScheme),
  1004. NULL, // don't care about Scheme Name
  1005. NULL,
  1006. &(pUrlComponents->lpszHostName),
  1007. &(pUrlComponents->dwHostNameLength),
  1008. &(pUrlComponents->nPort),
  1009. NULL, // don't care about user name
  1010. NULL,
  1011. NULL, // or password
  1012. NULL,
  1013. &(pUrlComponents->lpszUrlPath),
  1014. &(pUrlComponents->dwUrlPathLength),
  1015. NULL, // no extra
  1016. NULL,
  1017. NULL
  1018. );
  1019. pProxyMsg->SetProxyMsg(
  1020. pUrlComponents->nScheme,
  1021. currentUrl,
  1022. currentUrlLength,
  1023. pUrlComponents->lpszHostName,
  1024. pUrlComponents->dwHostNameLength,
  1025. pUrlComponents->nPort
  1026. );
  1027. } else {
  1028. INET_ASSERT(FALSE);
  1029. error = ERROR_WINHTTP_INVALID_URL;
  1030. }
  1031. return error;
  1032. }
  1033. DWORD
  1034. HTTP_REQUEST_HANDLE_OBJECT::QueryProxySettings(
  1035. IN CFsm_HttpSendRequest * Fsm,
  1036. INTERNET_HANDLE_OBJECT * pInternet,
  1037. IN OUT URL_COMPONENTS * pUrlComponents
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Wrapper over GetProxyInfo call to determine proxy
  1042. settings on our given object
  1043. Arguments:
  1044. Fsm - HTTP send request FSM
  1045. Return Value:
  1046. DWORD
  1047. Success - ERROR_SUCCESS
  1048. Failure -
  1049. ERROR_NOT_ENOUGH_MEMORY
  1050. Ran out of resources
  1051. --*/
  1052. {
  1053. DWORD error = ERROR_SUCCESS;
  1054. CFsm_HttpSendRequest & fsm = *Fsm;
  1055. INET_ASSERT(fsm.m_pProxyInfoQuery);
  1056. INET_ASSERT(pInternet);
  1057. SetProxyName(NULL, 0, 0);
  1058. fsm.m_fOwnsProxyInfoQueryObj = FALSE;
  1059. if (IsProxy() || (GetProxyInfo() == PROXY_INFO_DIRECT))
  1060. {
  1061. error = GetProxyInfo(&fsm.m_pProxyInfoQuery);
  1062. }
  1063. else
  1064. {
  1065. error = pInternet->GetProxyInfo(&fsm.m_pProxyInfoQuery);
  1066. }
  1067. //
  1068. // If GetProxyInfo returns pending, then we no longer have
  1069. // access to the pointer that we've passed.
  1070. //
  1071. if ( error == ERROR_IO_PENDING )
  1072. {
  1073. //
  1074. // Bail out, DO NOT TOUCH any OBJECTS or FSMs
  1075. //
  1076. goto quit;
  1077. }
  1078. // then regardless we own it unless GetProxyInfo went pending with the FSM
  1079. fsm.m_fOwnsProxyInfoQueryObj = TRUE;
  1080. if ( error != ERROR_SUCCESS )
  1081. {
  1082. goto quit;
  1083. }
  1084. INET_ASSERT( error == ERROR_SUCCESS );
  1085. if ( ! ((fsm.m_pProxyInfoQuery)->IsUseProxy()) )
  1086. {
  1087. SetIsTalkingToSecureServerViaProxy(FALSE);
  1088. }
  1089. quit:
  1090. return error;
  1091. }
  1092. DWORD
  1093. HTTP_REQUEST_HANDLE_OBJECT::CheckForCachedProxySettings(
  1094. IN AUTO_PROXY_ASYNC_MSG *pProxyMsg,
  1095. OUT CServerInfo **ppProxyServerInfo
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Attempts to determine and then resolve if there are cached
  1100. proxy settings saved away in the CServerInfo object,
  1101. which is found in our HTTP_REQUEST_ object. This can
  1102. be very useful since calling off to an auto-proxy thread
  1103. can be quite expensive in terms of performance.
  1104. Arguments:
  1105. pProxyMsg - the object containing our current proxy message
  1106. information, that we use to scripple our proxy state for
  1107. a given request
  1108. ppProxyServerInfo - on return, may contain the resultant
  1109. cached ServerInfo object.
  1110. Return Value:
  1111. DWORD
  1112. Success - ERROR_SUCCESS
  1113. Failure -
  1114. ERROR_NOT_ENOUGH_MEMORY
  1115. Ran out of resources
  1116. --*/
  1117. {
  1118. DWORD error = ERROR_WINHTTP_INTERNAL_ERROR;
  1119. CServerInfo * pOriginServer = GetOriginServer();
  1120. CServerInfo * pProxyServer;
  1121. INET_ASSERT(pProxyMsg);
  1122. *ppProxyServerInfo = NULL;
  1123. if (pOriginServer)
  1124. {
  1125. BOOL fCachedEntry;
  1126. pProxyServer =
  1127. pOriginServer->GetCachedProxyServerInfo(
  1128. pProxyMsg->_tUrlProtocol,
  1129. pProxyMsg->_nUrlPort,
  1130. &fCachedEntry
  1131. );
  1132. if (fCachedEntry)
  1133. {
  1134. if ( pProxyServer )
  1135. {
  1136. if (pProxyServer->CopyCachedProxyInfoToProxyMsg(pProxyMsg))
  1137. {
  1138. SetOriginServer();
  1139. *ppProxyServerInfo = pProxyServer;
  1140. error = ERROR_SUCCESS;
  1141. goto quit;
  1142. }
  1143. // nuke extra ref, sideeffect of GetCachedProxy... call
  1144. ::ReleaseServerInfo(pProxyServer);
  1145. }
  1146. else
  1147. {
  1148. // DIRECT, no-proxy cached.
  1149. pProxyMsg->SetUseProxy(FALSE);
  1150. pProxyMsg->_lpszProxyHostName = NULL;
  1151. error = ERROR_SUCCESS;
  1152. goto quit;
  1153. }
  1154. }
  1155. }
  1156. pProxyMsg->SetVersion();
  1157. quit:
  1158. return error;
  1159. }
  1160. DWORD
  1161. HTTP_REQUEST_HANDLE_OBJECT::ProcessProxySettings(
  1162. IN CFsm_HttpSendRequest * Fsm,
  1163. IN OUT URL_COMPONENTS * pUrlComponents,
  1164. OUT LPSTR * lplpszRequestObject,
  1165. OUT DWORD * lpdwRequestObjectSize
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. Armed with the results of the proxy query, this method takes care of
  1170. assembling the various variables and states to deal with various
  1171. types of proxies.
  1172. More specifally, this handles HTTP Cern Proxies, SOCKS proxies,
  1173. SSL-CONNECT/HTTP proxies, and special cases such as FTP URLs
  1174. with passwords through an HTTP Cern Proxy.
  1175. Arguments:
  1176. Fsm - HTTP send request FSM
  1177. Return Value:
  1178. DWORD
  1179. Success - ERROR_SUCCESS
  1180. Failure -
  1181. ERROR_NOT_ENOUGH_MEMORY
  1182. Ran out of resources
  1183. --*/
  1184. {
  1185. DWORD error = ERROR_SUCCESS;
  1186. CFsm_HttpSendRequest & fsm = *Fsm;
  1187. LPSTR lpszUrlObject = NULL;
  1188. LPSTR lpszObject = pUrlComponents->lpszUrlPath;
  1189. DWORD dwcbObject = pUrlComponents->dwUrlPathLength;
  1190. if ((fsm.m_pProxyInfoQuery)->GetProxyScheme() == INTERNET_SCHEME_SOCKS)
  1191. {
  1192. SetSocksProxyName((fsm.m_pProxyInfoQuery)->_lpszProxyHostName,
  1193. (fsm.m_pProxyInfoQuery)->_dwProxyHostNameLength,
  1194. (fsm.m_pProxyInfoQuery)->_nProxyHostPort
  1195. );
  1196. (fsm.m_pProxyInfoQuery)->_lpszProxyHostName = NULL;
  1197. (fsm.m_pProxyInfoQuery)->_dwProxyHostNameLength = 0;
  1198. }
  1199. else if (pUrlComponents->nScheme == INTERNET_SCHEME_HTTPS)
  1200. {
  1201. SetIsTalkingToSecureServerViaProxy(TRUE);
  1202. }
  1203. else
  1204. {
  1205. SetIsTalkingToSecureServerViaProxy(FALSE); // default value.
  1206. //
  1207. // if this request is going via proxy then we send the entire URL as the
  1208. // request
  1209. //
  1210. DWORD urlLength;
  1211. //
  1212. // in secure proxy tunnelling case we are going to send the request
  1213. // "CONNECT <host>:<port>"
  1214. //
  1215. if (IsTunnel()) {
  1216. urlLength = pUrlComponents->dwHostNameLength + sizeof(":65535");
  1217. } else {
  1218. urlLength = INTERNET_MAX_URL_LENGTH;
  1219. }
  1220. lpszUrlObject = (LPSTR)ResizeBuffer(NULL, urlLength, FALSE);
  1221. if (lpszUrlObject == NULL)
  1222. {
  1223. error = ERROR_NOT_ENOUGH_MEMORY;
  1224. goto quit;
  1225. }
  1226. if (IsTunnel())
  1227. {
  1228. // When tunneling, the scheme is http for the CONNECT and the port
  1229. // info may be stripped to 0 if the default http port was specified
  1230. // in the original SSL tunneling URL.
  1231. if (pUrlComponents->nPort == INTERNET_INVALID_PORT_NUMBER)
  1232. {
  1233. INET_ASSERT (pUrlComponents->nScheme == INTERNET_SCHEME_HTTP);
  1234. pUrlComponents->nPort = INTERNET_DEFAULT_HTTP_PORT;
  1235. }
  1236. memcpy (lpszUrlObject, pUrlComponents->lpszHostName, pUrlComponents->dwHostNameLength);
  1237. wsprintf (lpszUrlObject + pUrlComponents->dwHostNameLength, ":%d", pUrlComponents->nPort);
  1238. }
  1239. else
  1240. {
  1241. //
  1242. // there may be a user name & password (only if FTP)
  1243. //
  1244. LPSTR userName;
  1245. DWORD userNameLength;
  1246. LPSTR password;
  1247. DWORD passwordLength;
  1248. userName = NULL;
  1249. userNameLength = 0;
  1250. password = NULL;
  1251. passwordLength = 0;
  1252. if (pUrlComponents->nPort == INTERNET_INVALID_PORT_NUMBER)
  1253. {
  1254. switch (pUrlComponents->nScheme)
  1255. {
  1256. case INTERNET_SCHEME_HTTP:
  1257. pUrlComponents->nPort = INTERNET_DEFAULT_HTTP_PORT;
  1258. break;
  1259. case INTERNET_SCHEME_HTTPS:
  1260. pUrlComponents->nPort = INTERNET_DEFAULT_HTTPS_PORT;
  1261. break;
  1262. default:
  1263. INET_ASSERT(FALSE);
  1264. break;
  1265. }
  1266. }
  1267. pUrlComponents->lpszUserName = userName;
  1268. pUrlComponents->dwUserNameLength = userNameLength;
  1269. pUrlComponents->lpszPassword = password;
  1270. pUrlComponents->dwPasswordLength = passwordLength;
  1271. for (int i=0; i<2; i++)
  1272. {
  1273. if (!WinHttpCreateUrlA(pUrlComponents, 0, lpszUrlObject, &urlLength))
  1274. {
  1275. error = GetLastError();
  1276. if ((error == ERROR_INSUFFICIENT_BUFFER)
  1277. && (i==0))
  1278. {
  1279. LPSTR pTemp = (LPSTR)ResizeBuffer(lpszUrlObject,
  1280. urlLength,
  1281. FALSE);
  1282. if (pTemp)
  1283. {
  1284. lpszUrlObject = pTemp;
  1285. continue;
  1286. }
  1287. else
  1288. {
  1289. error = ERROR_NOT_ENOUGH_MEMORY;
  1290. }
  1291. }
  1292. goto quit;
  1293. }
  1294. else
  1295. {
  1296. error = ERROR_SUCCESS;
  1297. break;
  1298. }
  1299. }
  1300. //
  1301. // shrink the buffer to fit
  1302. //
  1303. lpszUrlObject = (LPSTR)ResizeBuffer(lpszUrlObject,
  1304. (urlLength + 1) * sizeof(TCHAR),
  1305. FALSE
  1306. );
  1307. INET_ASSERT(lpszUrlObject != NULL);
  1308. if (lpszUrlObject == NULL)
  1309. {
  1310. error = ERROR_NOT_ENOUGH_MEMORY;
  1311. goto quit;
  1312. }
  1313. }
  1314. SetRequestUsingProxy(TRUE);
  1315. lpszObject = lpszUrlObject;
  1316. dwcbObject = lstrlen(lpszUrlObject);
  1317. }
  1318. quit:
  1319. *lplpszRequestObject = lpszObject;
  1320. *lpdwRequestObjectSize = dwcbObject;
  1321. return error;
  1322. }
  1323. DWORD
  1324. HTTP_REQUEST_HANDLE_OBJECT::UpdateRequestInfo(
  1325. IN CFsm_HttpSendRequest * Fsm,
  1326. IN LPSTR lpszObject,
  1327. IN DWORD dwcbObject,
  1328. IN OUT URL_COMPONENTS * pUrlComponents,
  1329. IN OUT CServerInfo **ppProxyServerInfo
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. Based on object and URL information, for a given HTTP request,
  1334. this function assembles the "special cases" and modifes the
  1335. request headers in prepartion of making the actual request.
  1336. The "special cases" includes the handling of HTTP versioning,
  1337. HTTP 1.0/1.1 keep-alives, and Pragma headers.
  1338. This function also deals with the update the ServerInfo object
  1339. that contains the host resolution information.
  1340. Arguments:
  1341. Fsm - HTTP send request FSM
  1342. Return Value:
  1343. DWORD
  1344. Success - ERROR_SUCCESS
  1345. Failure -
  1346. ERROR_NOT_ENOUGH_MEMORY
  1347. Ran out of resources
  1348. --*/
  1349. {
  1350. DWORD error = ERROR_SUCCESS;
  1351. LPSTR lpszVersion = NULL;
  1352. DWORD dwVersionLen = 0;
  1353. CFsm_HttpSendRequest & fsm = *Fsm;
  1354. if ( lpszObject == NULL)
  1355. {
  1356. lpszObject = pUrlComponents->lpszUrlPath;
  1357. dwcbObject = pUrlComponents->dwUrlPathLength;
  1358. }
  1359. INET_ASSERT(dwcbObject > 0 );
  1360. if (!_RequestHeaders.LockHeaders())
  1361. {
  1362. error = ERROR_NOT_ENOUGH_MEMORY;
  1363. goto quit;
  1364. }
  1365. //
  1366. // if we are going via proxy and HTTP 1.1 through proxy is disabled
  1367. // then modify the request version to HTTP/1.0
  1368. //
  1369. if ((fsm.m_pProxyInfoQuery)->IsUseProxy() &&
  1370. ((fsm.m_pProxyInfoQuery)->_lpszProxyHostName != NULL) &&
  1371. !GlobalEnableProxyHttp1_1 || GetMethodType() == HTTP_METHOD_TYPE_CONNECT) {
  1372. lpszVersion = "HTTP/1.0";
  1373. dwVersionLen = sizeof("HTTP/1.0") - 1;
  1374. }
  1375. ModifyRequest(GetMethodType(),
  1376. lpszObject,
  1377. dwcbObject,
  1378. lpszVersion,
  1379. dwVersionLen
  1380. );
  1381. if ((fsm.m_pProxyInfoQuery)->IsUseProxy() )
  1382. {
  1383. SetProxyName( (fsm.m_pProxyInfoQuery)->_lpszProxyHostName,
  1384. (fsm.m_pProxyInfoQuery)->_dwProxyHostNameLength,
  1385. (fsm.m_pProxyInfoQuery)->_nProxyHostPort
  1386. );
  1387. if ((fsm.m_pProxyInfoQuery)->_lpszProxyHostName != NULL) {
  1388. if (_ServerInfo != NULL)
  1389. {
  1390. _ServerInfo->SetProxyByPassed(FALSE);
  1391. }
  1392. //
  1393. // changing server info from origin server to proxy server. Keep
  1394. // pointer to origin server so that we can update connect and
  1395. // round-trip times
  1396. //
  1397. SetOriginServer();
  1398. if (*ppProxyServerInfo) {
  1399. // cached server info
  1400. SetServerInfo(*ppProxyServerInfo);
  1401. *ppProxyServerInfo = NULL;
  1402. }
  1403. else
  1404. {
  1405. error = SetServerInfo((fsm.m_pProxyInfoQuery)->_lpszProxyHostName,
  1406. (fsm.m_pProxyInfoQuery)->_dwProxyHostNameLength
  1407. );
  1408. if (error != ERROR_SUCCESS) {
  1409. goto Cleanup;
  1410. }
  1411. }
  1412. }
  1413. }
  1414. else
  1415. {
  1416. if (_ServerInfo != NULL)
  1417. {
  1418. _ServerInfo->SetProxyByPassed(TRUE);
  1419. if ( pUrlComponents->lpszHostName )
  1420. {
  1421. error = SetServerInfo(pUrlComponents->lpszHostName,
  1422. pUrlComponents->dwHostNameLength
  1423. );
  1424. if (error != ERROR_SUCCESS) {
  1425. goto Cleanup;
  1426. }
  1427. }
  1428. }
  1429. }
  1430. //
  1431. // determine whether we use persistent connections and ensure the correct
  1432. // type and number of keep-alive headers are present
  1433. //
  1434. //
  1435. // BUGBUG - we need to check for "Connection: keep-alive". There may be
  1436. // other types of "Connection" header, and the keep-alive header
  1437. // may contain additional information
  1438. //
  1439. DWORD bufferLength;
  1440. DWORD index;
  1441. DWORD dwHeaderNameIndex;
  1442. if (IsRequestUsingProxy()) {
  1443. RemoveAllRequestHeadersByName(HTTP_QUERY_CONNECTION);
  1444. dwHeaderNameIndex = HTTP_QUERY_PROXY_CONNECTION;
  1445. } else {
  1446. RemoveAllRequestHeadersByName(HTTP_QUERY_PROXY_CONNECTION);
  1447. dwHeaderNameIndex = HTTP_QUERY_CONNECTION;
  1448. }
  1449. if (IsRequestHeaderPresent(dwHeaderNameIndex)) {
  1450. SetWantKeepAlive(TRUE);
  1451. SetOpenFlags(
  1452. GetOpenFlags() | INTERNET_FLAG_KEEP_CONNECTION);
  1453. }
  1454. error = ERROR_SUCCESS;
  1455. //
  1456. // if the global keep-alive switch
  1457. // is off then we don't want any keep-alive headers
  1458. //
  1459. if (GlobalDisableKeepAlive)
  1460. {
  1461. RemoveAllRequestHeadersByName(HTTP_QUERY_CONNECTION);
  1462. RemoveAllRequestHeadersByName(HTTP_QUERY_PROXY_CONNECTION);
  1463. if (IsRequestHttp1_1())
  1464. {
  1465. //
  1466. // Add "Connection: Close" header because we're not doing
  1467. // keep-alive on this Request, needed for HTTP 1.1
  1468. //
  1469. (void)ReplaceRequestHeader(HTTP_QUERY_CONNECTION,
  1470. CLOSE_SZ,
  1471. CLOSE_LEN,
  1472. 0,
  1473. REPLACE_HEADER
  1474. );
  1475. }
  1476. SetOpenFlags(
  1477. GetOpenFlags() & ~INTERNET_FLAG_KEEP_CONNECTION);
  1478. }
  1479. //
  1480. // if the app requested keep-alive then add the header; if we're going via
  1481. // proxy then use the proxy-connection header
  1482. //
  1483. if (GetOpenFlags() & INTERNET_FLAG_KEEP_CONNECTION)
  1484. {
  1485. SetWantKeepAlive(TRUE);
  1486. (void)ReplaceRequestHeader(dwHeaderNameIndex,
  1487. KEEP_ALIVE_SZ,
  1488. KEEP_ALIVE_LEN,
  1489. 0,
  1490. ADD_HEADER_IF_NEW
  1491. );
  1492. }
  1493. //
  1494. // if app added "connection: close" then we don't want keep-alive
  1495. //
  1496. if (IsRequestHttp1_1()) {
  1497. BOOL bClose = FindConnCloseRequestHeader(dwHeaderNameIndex);
  1498. BOOL bWantKeepAlive;
  1499. DWORD dwOpenFlags = GetOpenFlags();
  1500. if (bClose || (IsTunnel() && GetAuthState() != AUTHSTATE_CHALLENGE)) {
  1501. RemoveAllRequestHeadersByName(dwHeaderNameIndex);
  1502. //
  1503. // For a Tunnel to a proxy we want to make sure that
  1504. // keep-alive is off since is does not make sense
  1505. // to do keep-alive with in a HTTP CONNECT request
  1506. //
  1507. // Note: we do not add the Connection: close header
  1508. // because of its amphorus definition in this case.
  1509. //
  1510. if (!IsTunnel()) {
  1511. (void)ReplaceRequestHeader(dwHeaderNameIndex,
  1512. CLOSE_SZ,
  1513. CLOSE_LEN,
  1514. 0,
  1515. REPLACE_HEADER
  1516. );
  1517. }
  1518. bWantKeepAlive= FALSE;
  1519. dwOpenFlags &= ~INTERNET_FLAG_KEEP_CONNECTION;
  1520. } else {
  1521. bWantKeepAlive = TRUE;
  1522. dwOpenFlags |= INTERNET_FLAG_KEEP_CONNECTION;
  1523. }
  1524. SetWantKeepAlive(bWantKeepAlive);
  1525. SetOpenFlags(dwOpenFlags);
  1526. }
  1527. if (GetOpenFlags() & WINHTTP_FLAG_BYPASS_PROXY_CACHE)
  1528. {
  1529. // add "Pragma: No-Cache" header
  1530. ReplaceRequestHeader(HTTP_QUERY_CACHE_CONTROL,
  1531. NO_CACHE_SZ,
  1532. NO_CACHE_LEN,
  1533. 0, // dwIndex
  1534. ADD_HEADER_IF_NEW
  1535. );
  1536. // add "Cache-Control: No-Cache" header for HTTP 1.1
  1537. if (IsRequestHttp1_1())
  1538. {
  1539. ReplaceRequestHeader(HTTP_QUERY_PRAGMA,
  1540. NO_CACHE_SZ,
  1541. NO_CACHE_LEN,
  1542. 0, // dwIndex
  1543. ADD_HEADER_IF_NEW
  1544. );
  1545. }
  1546. }
  1547. Cleanup:
  1548. _RequestHeaders.UnlockHeaders();
  1549. quit:
  1550. return error;
  1551. }
  1552. DWORD
  1553. HTTP_REQUEST_HANDLE_OBJECT::UpdateProxyInfo(
  1554. IN CFsm_HttpSendRequest * Fsm,
  1555. IN BOOL fCallback
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. Queries Proxy Information, and based on the proxy info it assembles the appropriate
  1560. HTTP request.
  1561. Arguments:
  1562. Fsm - HTTP send request FSM
  1563. Return Value:
  1564. DWORD
  1565. Success - ERROR_SUCCESS
  1566. Failure -
  1567. ERROR_NOT_ENOUGH_MEMORY
  1568. Ran out of resources
  1569. --*/
  1570. {
  1571. DEBUG_ENTER((DBG_HTTP,
  1572. Dword,
  1573. "HTTP_REQUEST_HANDLE_OBJECT::UpdateProxyInfo",
  1574. "%#x, %B",
  1575. Fsm,
  1576. fCallback
  1577. ));
  1578. PERF_ENTER(UpdateProxyInfo);
  1579. DWORD error = ERROR_SUCCESS;
  1580. CFsm_HttpSendRequest & fsm = *Fsm;
  1581. CServerInfo *pProxyServer = NULL;
  1582. INTERNET_HANDLE_OBJECT * pInternet;
  1583. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  1584. AUTO_PROXY_ASYNC_MSG proxyInfoQuery;
  1585. URL_COMPONENTS urlComponents;
  1586. LPSTR lpszObject = NULL;
  1587. DWORD dwcbObject = 0;
  1588. // once we're woken up, we own the obj stored in our FSM.
  1589. INET_ASSERT(fsm.m_fOwnsProxyInfoQueryObj);
  1590. //
  1591. // Get the Obj Pointers we care about
  1592. //
  1593. pInternet = GetRootHandle (this);
  1594. //
  1595. // Clear our handle state in regards to proxy settings
  1596. //
  1597. SetSocksProxyName(NULL, NULL, NULL);
  1598. SetRequestUsingProxy(FALSE);
  1599. //
  1600. // Parse URL, I have to do this every time,
  1601. // and even worse we need to do this before our caching code
  1602. // gets hit, but we can't move it because the quit code
  1603. // depends on the parsed URL. In the future we should cache this!!
  1604. //
  1605. error = BuildProxyMessage(
  1606. Fsm,
  1607. &proxyInfoQuery,
  1608. &urlComponents
  1609. );
  1610. if (error != ERROR_SUCCESS) {
  1611. goto quit;
  1612. }
  1613. //
  1614. // No proxy installed on this object, bail out
  1615. //
  1616. if ( ((GetProxyInfo() == PROXY_INFO_DIRECT) || (!IsProxy() && ! pInternet->IsProxy()))
  1617. && ! IsOverrideProxyMode() )
  1618. {
  1619. INET_ASSERT(fsm.m_pProxyInfoQuery == NULL);
  1620. fsm.m_pProxyInfoQuery = &proxyInfoQuery; // !!! put our local in the FSM
  1621. goto quit;
  1622. }
  1623. //
  1624. // If we're in the callback, just retrieve the results,
  1625. // from the orginal blocking call to proxy code
  1626. //
  1627. if ( fsm.m_pProxyInfoQuery )
  1628. {
  1629. fCallback = TRUE;
  1630. if ( ! (fsm.m_pProxyInfoQuery)->IsBackroundDetectionPending()) {
  1631. (fsm.m_pProxyInfoQuery)->SetQueryOnCallback(TRUE);
  1632. }
  1633. error = QueryProxySettings(Fsm, pInternet, &urlComponents);
  1634. if ( error != ERROR_SUCCESS || !(fsm.m_pProxyInfoQuery)->IsUseProxy())
  1635. {
  1636. goto quit;
  1637. }
  1638. }
  1639. else
  1640. {
  1641. fsm.m_pProxyInfoQuery = &proxyInfoQuery; // !!! put our local in the FSM
  1642. proxyInfoQuery.SetBlockUntilCompletetion(TRUE);
  1643. proxyInfoQuery.SetShowIndication(TRUE);
  1644. if (!IsTunnel() && !IsOverrideProxyMode())
  1645. {
  1646. error = QueryProxySettings(Fsm, pInternet, &urlComponents);
  1647. if ( error != ERROR_SUCCESS || !(fsm.m_pProxyInfoQuery)->IsUseProxy()) {
  1648. goto quit;
  1649. }
  1650. }
  1651. else // fall-back
  1652. {
  1653. //
  1654. // Get the current proxy information,
  1655. // if we're in an nested SSL tunnell
  1656. //
  1657. GetProxyName(&(fsm.m_pProxyInfoQuery)->_lpszProxyHostName,
  1658. &(fsm.m_pProxyInfoQuery)->_dwProxyHostNameLength,
  1659. &(fsm.m_pProxyInfoQuery)->_nProxyHostPort
  1660. );
  1661. (fsm.m_pProxyInfoQuery)->_tProxyScheme = INTERNET_SCHEME_DEFAULT;
  1662. (fsm.m_pProxyInfoQuery)->SetUseProxy(TRUE);
  1663. }
  1664. }
  1665. //
  1666. // Need to figure out whether we're actually talking
  1667. // to a Server via proxy. In this case we need to
  1668. // special case some logic in the Send so we create
  1669. // a sub-request to the proxy-server, and then do this
  1670. // request to the main SSL server.
  1671. //
  1672. if ( (fsm.m_pProxyInfoQuery)->IsUseProxy() )
  1673. {
  1674. error = ProcessProxySettings(
  1675. Fsm,
  1676. &urlComponents,
  1677. &lpszObject,
  1678. &dwcbObject
  1679. );
  1680. }
  1681. else
  1682. {
  1683. // Ensure this is false in case of very slim chance of
  1684. // redirect from internet https to intranet http
  1685. SetIsTalkingToSecureServerViaProxy(FALSE);
  1686. }
  1687. quit:
  1688. //
  1689. // If we didn't fail with pending,
  1690. // go ahead and process the request headers
  1691. //
  1692. if ( error != ERROR_IO_PENDING)
  1693. {
  1694. if ( error == ERROR_SUCCESS ) {
  1695. error = UpdateRequestInfo(Fsm, lpszObject, dwcbObject, &urlComponents, &pProxyServer);
  1696. }
  1697. //
  1698. // Now, Unlink the proxyinfomsg struc from the fsm,
  1699. // if its our stack based variable that we used as a temp
  1700. //
  1701. if ( fsm.m_fOwnsProxyInfoQueryObj &&
  1702. fsm.m_pProxyInfoQuery &&
  1703. ! (fsm.m_pProxyInfoQuery)->IsAlloced() )
  1704. {
  1705. fsm.m_pProxyInfoQuery = NULL;
  1706. }
  1707. }
  1708. //
  1709. // Don't leak objects, Give a hoot, don't pollute !!
  1710. //
  1711. if ( pProxyServer != NULL )
  1712. {
  1713. ::ReleaseServerInfo(pProxyServer);
  1714. }
  1715. if ( lpszObject != NULL &&
  1716. lpszObject != urlComponents.lpszUrlPath)
  1717. {
  1718. FREE_MEMORY(lpszObject);
  1719. }
  1720. PERF_LEAVE(UpdateProxyInfo);
  1721. DEBUG_LEAVE(error);
  1722. return error;
  1723. }
  1724. BOOL
  1725. HTTP_REQUEST_HANDLE_OBJECT::FindConnCloseRequestHeader(
  1726. IN DWORD dwIndex
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. Determine if Connection: Close added to request headers
  1731. Arguments:
  1732. dwIndex - id of Connection header to search for (Connection or
  1733. Proxy-Connection)
  1734. Return Value:
  1735. BOOL
  1736. TRUE - header found
  1737. FALSE - header not found
  1738. --*/
  1739. {
  1740. DEBUG_ENTER((DBG_HTTP,
  1741. Bool,
  1742. "HTTP_REQUEST_HANDLE_OBJECT::FindConnCloseRequestHeader",
  1743. "%d [%s]",
  1744. dwIndex,
  1745. InternetMapHttpOption(dwIndex)
  1746. ));
  1747. BOOL bFound = FALSE;
  1748. if (CheckedConnCloseRequest()) {
  1749. bFound = IsConnCloseRequest(dwIndex == HTTP_QUERY_PROXY_CONNECTION);
  1750. } else {
  1751. LPSTR ptr;
  1752. DWORD len;
  1753. DWORD index = 0;
  1754. while (FastQueryRequestHeader(dwIndex,
  1755. (LPVOID *)&ptr,
  1756. &len,
  1757. index) == ERROR_SUCCESS) {
  1758. if ((len == CLOSE_LEN) && (strnicmp(ptr, CLOSE_SZ, len) == 0)) {
  1759. bFound = TRUE;
  1760. break;
  1761. }
  1762. index++;
  1763. }
  1764. SetCheckedConnCloseRequest(dwIndex == HTTP_QUERY_PROXY_CONNECTION, bFound);
  1765. }
  1766. DEBUG_LEAVE(bFound);
  1767. return bFound;
  1768. }
  1769. /*
  1770. * When called from API functions,
  1771. * caller should SetLastError() in case of failure
  1772. */
  1773. BOOL
  1774. HTTP_REQUEST_HANDLE_OBJECT::SetTimeout(
  1775. IN DWORD dwTimeoutOption,
  1776. IN DWORD dwTimeoutValue
  1777. )
  1778. {
  1779. BOOL bRetval = TRUE;
  1780. switch (dwTimeoutOption)
  1781. {
  1782. case WINHTTP_OPTION_RESOLVE_TIMEOUT:
  1783. _dwResolveTimeout = dwTimeoutValue;
  1784. break;
  1785. case WINHTTP_OPTION_CONNECT_TIMEOUT:
  1786. _dwConnectTimeout = dwTimeoutValue;
  1787. break;
  1788. case WINHTTP_OPTION_CONNECT_RETRIES:
  1789. _dwConnectRetries = dwTimeoutValue;
  1790. break;
  1791. case WINHTTP_OPTION_SEND_TIMEOUT:
  1792. _dwSendTimeout = dwTimeoutValue;
  1793. break;
  1794. case WINHTTP_OPTION_RECEIVE_TIMEOUT:
  1795. _dwReceiveTimeout = dwTimeoutValue;
  1796. break;
  1797. default:
  1798. INET_ASSERT(FALSE);
  1799. bRetval = FALSE;
  1800. break;
  1801. }
  1802. return bRetval;
  1803. }
  1804. /*
  1805. * When called from API functions,
  1806. * caller should SetLastError() in case of failure
  1807. */
  1808. DWORD
  1809. HTTP_REQUEST_HANDLE_OBJECT::GetTimeout(
  1810. IN DWORD dwTimeoutOption
  1811. )
  1812. {
  1813. switch (dwTimeoutOption)
  1814. {
  1815. case WINHTTP_OPTION_RESOLVE_TIMEOUT:
  1816. return _dwResolveTimeout;
  1817. case WINHTTP_OPTION_CONNECT_TIMEOUT:
  1818. return _dwConnectTimeout;
  1819. case WINHTTP_OPTION_CONNECT_RETRIES:
  1820. return _dwConnectRetries;
  1821. case WINHTTP_OPTION_SEND_TIMEOUT:
  1822. return _dwSendTimeout;
  1823. case WINHTTP_OPTION_RECEIVE_TIMEOUT:
  1824. return _dwReceiveTimeout;
  1825. }
  1826. INET_ASSERT(FALSE);
  1827. // we should not be here, but in case we are, return 0
  1828. return 0;
  1829. }
  1830. /*
  1831. * When called from API functions,
  1832. * caller should SetLastError() in case of failure
  1833. */
  1834. BOOL
  1835. HTTP_REQUEST_HANDLE_OBJECT::SetTimeouts(
  1836. IN DWORD dwResolveTimeout,
  1837. IN DWORD dwConnectTimeout,
  1838. IN DWORD dwSendTimeout,
  1839. IN DWORD dwReceiveTimeout
  1840. )
  1841. {
  1842. _dwResolveTimeout = dwResolveTimeout;
  1843. _dwConnectTimeout = dwConnectTimeout;
  1844. _dwSendTimeout = dwSendTimeout;
  1845. _dwReceiveTimeout = dwReceiveTimeout;
  1846. return TRUE;
  1847. }