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.

1555 lines
40 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. socket.cxx
  5. Abstract:
  6. This file contains general socket utilities.
  7. Contents:
  8. HTTP_REQUEST_HANDLE_OBJECT::OpenConnection
  9. CFsm_OpenConnection::RunSM
  10. HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm
  11. HTTP_REQUEST_HANDLE_OBJECT::CloseConnection
  12. HTTP_REQUEST_HANDLE_OBJECT::ReleaseConnection
  13. HTTP_REQUEST_HANDLE_OBJECT::AbortConnection
  14. HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel
  15. CFsm_OpenProxyTunnel::RunSM
  16. HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel_Fsm
  17. HTTP_REQUEST_HANDLE_OBJECT::CloneResponseBuffer
  18. Author:
  19. Keith Moore (keithmo) 16-Nov-1994
  20. Revision History:
  21. 18-Dec-1995 rfirth
  22. Reworked for C++
  23. 27-Mar-1996 arthurbi
  24. Added OpenProxyTunnel Method
  25. --*/
  26. #include <wininetp.h>
  27. #include <perfdiag.hxx>
  28. #include "httpp.h"
  29. //
  30. // functions
  31. //
  32. DWORD
  33. HTTP_REQUEST_HANDLE_OBJECT::OpenConnection(
  34. IN BOOL bNewConnection,
  35. IN BOOL fNoCreate /* = FALSE */
  36. )
  37. /*++
  38. Routine Description:
  39. Get a connection to the web server. Either use a pre-existing keep-alive
  40. connection from the global pool or create a new connection
  41. Arguments:
  42. bNewConnection - TRUE if we are NOT to get a connection from the keep-alive
  43. pool
  44. fNoCreate - TRUE if we should NOT create a new socket if a k-a isn't found.
  45. This is currently for the SSL tunneling case where we want to break
  46. and send a CONNECT if a k-a doesn't match our criteria.
  47. Return Value:
  48. DWORD
  49. Success - ERROR_SUCCESS
  50. Opened connection
  51. ERROR_IO_PENDING
  52. Operation will complete asynchronously
  53. Failure -
  54. --*/
  55. {
  56. DEBUG_ENTER((DBG_HTTP,
  57. Dword,
  58. "HTTP_REQUEST_HANDLE_OBJECT::OpenConnection",
  59. "%B",
  60. bNewConnection
  61. ));
  62. DWORD error = DoFsm(new CFsm_OpenConnection(bNewConnection, this, fNoCreate));
  63. DEBUG_LEAVE(error);
  64. return error;
  65. }
  66. DWORD
  67. CFsm_OpenConnection::RunSM(
  68. IN CFsm * Fsm
  69. )
  70. /*++
  71. Routine Description:
  72. Runs next OpenConnection state
  73. Arguments:
  74. Fsm - containing open connection state info
  75. Return Value:
  76. DWORD
  77. Success - ERROR_SUCCESS
  78. Failure -
  79. --*/
  80. {
  81. DEBUG_ENTER((DBG_HTTP,
  82. Dword,
  83. "CFsm_OpenConnection::RunSM",
  84. "%#x",
  85. Fsm
  86. ));
  87. DWORD error;
  88. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  89. CFsm_OpenConnection * stateMachine = (CFsm_OpenConnection *)Fsm;
  90. START_SENDREQ_PERF();
  91. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  92. switch (Fsm->GetState()) {
  93. case FSM_STATE_INIT:
  94. case FSM_STATE_CONTINUE:
  95. case FSM_STATE_ERROR:
  96. error = pRequest->OpenConnection_Fsm(stateMachine);
  97. break;
  98. default:
  99. error = ERROR_INTERNET_INTERNAL_ERROR;
  100. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  101. INET_ASSERT(FALSE);
  102. break;
  103. }
  104. STOP_SENDREQ_PERF();
  105. DEBUG_LEAVE(error);
  106. return error;
  107. }
  108. DWORD
  109. HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm(
  110. IN CFsm_OpenConnection * Fsm
  111. )
  112. /*++
  113. Routine Description:
  114. Open connection FSM
  115. Arguments:
  116. Fsm - containing state info
  117. Return Value:
  118. DWORD
  119. Success - ERROR_SUCCESS
  120. Failure -
  121. --*/
  122. {
  123. DEBUG_ENTER((DBG_HTTP,
  124. Dword,
  125. "HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm",
  126. "%#x",
  127. Fsm
  128. ));
  129. CFsm_OpenConnection & fsm = *Fsm;
  130. DWORD error = fsm.GetError();
  131. CServerInfo * pServerInfo = GetServerInfo();
  132. if (error != ERROR_SUCCESS) {
  133. goto quit;
  134. }
  135. //
  136. // BUGBUG - redundancy. Either put these in the FSM or figure out why we need
  137. // to do proxy name processing here
  138. //
  139. //
  140. // if this object was created from an InternetOpen() handle which specified
  141. // INTERNET_OPEN_TYPE_PROXY then we connect to the proxy, otherwise we
  142. // connect to the server specified in InternetConnect()
  143. //
  144. LPSTR hostName;
  145. LPSTR hostNameServer;
  146. DWORD hostLength;
  147. INTERNET_PORT hostPort;
  148. hostName = hostNameServer = GetHostName(&hostLength);
  149. hostPort = GetHostPort();
  150. LPSTR proxyHostName;
  151. DWORD proxyHostNameLength;
  152. INTERNET_PORT proxyHostPort;
  153. GetProxyName(&proxyHostName,
  154. &proxyHostNameLength,
  155. &proxyHostPort
  156. );
  157. if ((proxyHostName != NULL) && (proxyHostNameLength > 0)) {
  158. SetViaProxy(TRUE);
  159. hostName = proxyHostName;
  160. hostLength = proxyHostNameLength;
  161. hostPort = proxyHostPort;
  162. }
  163. INET_ASSERT(hostName != NULL);
  164. INET_ASSERT(hostPort != INTERNET_INVALID_PORT_NUMBER);
  165. if (fsm.GetState() != FSM_STATE_INIT) {
  166. switch (fsm.GetFunctionState()) {
  167. case FSM_STATE_1:
  168. goto get_continue;
  169. case FSM_STATE_2:
  170. goto connect_continue;
  171. default:
  172. INET_ASSERT(FALSE);
  173. error = ERROR_INTERNET_INTERNAL_ERROR;
  174. goto quit;
  175. }
  176. }
  177. //
  178. // we may already have a keep-alive connection - don't ask for a new one.
  179. // This happens in the challenge phase of a multi-part (e.g. NTLM) auth
  180. // negotiation over keep-alive
  181. //
  182. if (IsWantKeepAlive() && !fsm.m_bNewConnection && (_Socket != NULL)
  183. && _Socket->IsOpen()) {
  184. //INET_ASSERT(_bKeepAliveConnection);
  185. //if ( IsTunnel() )
  186. //{
  187. // dprintf("Tunnel for nested req=%#x, ALREADY open on Socket=%#x\n", this, _Socket );
  188. //}
  189. error = ERROR_SUCCESS;
  190. goto quit;
  191. }
  192. INET_ASSERT(pServerInfo != NULL);
  193. if (pServerInfo == NULL) {
  194. error = ERROR_INTERNET_INTERNAL_ERROR;
  195. goto quit;
  196. }
  197. //
  198. // if this request wants a keep-alive connection AND we are allowed to use
  199. // one (i.e. not forced to generate a new connection) AND we can find one
  200. // then we're done, otherwise we have to generate a new connection
  201. //
  202. DWORD dwSocketFlags;
  203. dwSocketFlags = IsAsyncHandle() ? SF_NON_BLOCKING : 0;
  204. if ((IsWantKeepAlive() || (GetOpenFlags() & INTERNET_FLAG_KEEP_CONNECTION))
  205. && !fsm.m_bNewConnection) {
  206. dwSocketFlags |= SF_KEEP_ALIVE;
  207. }
  208. if (GetOpenFlags() & INTERNET_FLAG_SECURE) {
  209. dwSocketFlags |= SF_SECURE;
  210. if (m_pSecurityInfo && !m_pSecurityInfo->InCache()) {
  211. // Don't grab a keep-alive if a fully verified cert
  212. // hasn't been cached. VerifyTrust only caches after
  213. // verification has been done with no errors ignored.
  214. dwSocketFlags &= ~SF_KEEP_ALIVE;
  215. }
  216. }
  217. if ( IsTunnel() )
  218. {
  219. dwSocketFlags |= SF_TUNNEL;
  220. // dprintf("Opening Tunnel for nested req=%#x, Socket Flags=%#x, K-A=%B, Secure=%B, N-B=%B\n",
  221. // this, dwSocketFlags, (dwSocketFlags & SF_KEEP_ALIVE), (dwSocketFlags & SF_SECURE),
  222. // (dwSocketFlags & SF_NON_BLOCKING));
  223. }
  224. INET_ASSERT(_Socket == NULL);
  225. _Socket = NULL;
  226. fsm.SetFunctionState(FSM_STATE_1);
  227. // If m_fNoCreate flag is set, then we're attempting to find
  228. // a matching SSL tunnel that's already been established.
  229. error = DoFsm(new CFsm_GetConnection(
  230. dwSocketFlags,
  231. fsm.m_fNoCreate ? GetHostPort() : hostPort,
  232. GetTimeoutValue(INTERNET_OPTION_CONNECT_TIMEOUT),
  233. 10000, // dwLimitTimeout
  234. &_Socket,
  235. pServerInfo,
  236. fsm.m_fNoCreate ? hostNameServer : NULL
  237. ));
  238. get_continue:
  239. if (error != ERROR_SUCCESS) {
  240. goto quit;
  241. }
  242. if (_Socket != NULL) {
  243. //
  244. // _bKeepAliveConnection now means "this is a pre-existing k-a socket".
  245. // Only meaningful when re-establishing connect when dropped by server
  246. //
  247. //if ( IsTunnel() )
  248. //{
  249. // dprintf("Tunnel for nested req=%#x\n opened on K-A Socket=%#x\n", this, _Socket );
  250. //}
  251. //dprintf("%s existing K-A connection %#x\n", GetURL(), _Socket->GetSocket());
  252. _bKeepAliveConnection = TRUE;
  253. //
  254. // Get any security Info
  255. //
  256. if (_Socket->IsSecure()) {
  257. if (m_pSecurityInfo != NULL) {
  258. /* SCLE ref */
  259. m_pSecurityInfo->Release();
  260. }
  261. /* SCLE ref */
  262. m_pSecurityInfo = ((ICSecureSocket *)_Socket)->GetSecurityEntry();
  263. ((ICSecureSocket*)_Socket)->SetSecureFlags(SECURITY_FLAG_SECURE);
  264. }
  265. //
  266. // successfully got keep-alive connection from the pool
  267. //
  268. DEBUG_PRINT(HTTP,
  269. INFO,
  270. ("%skeep-alive connection: socket %#x, port %d\n",
  271. _Socket->IsSecure() ? "SSL " : "",
  272. _Socket->GetSocket(),
  273. _Socket->GetSourcePort()
  274. ));
  275. goto quit;
  276. }
  277. else if (fsm.m_fNoCreate)
  278. {
  279. goto quit;
  280. }
  281. //
  282. // the socket didn't come from the pool
  283. //
  284. _bKeepAliveConnection = FALSE;
  285. //
  286. // we may already have a socket if we're reusing the object
  287. //
  288. if (GetOpenFlags() & INTERNET_FLAG_SECURE) {
  289. _Socket = new ICSecureSocket(GetErrorMask());
  290. if (m_pSecurityInfo == NULL) {
  291. /* SCLE ref */
  292. if (NULL == (m_pSecurityInfo = GlobalCertCache.Find(GetHostName()))) {
  293. /* SCLE ref */
  294. m_pSecurityInfo = new SECURITY_CACHE_LIST_ENTRY(GetHostName());
  295. }
  296. }
  297. if (_Socket != NULL) {
  298. _Socket->SetEncryption();
  299. /* SCLE ref */
  300. ((ICSecureSocket *)_Socket)->SetSecurityEntry(&m_pSecurityInfo);
  301. /* SCLE ref */
  302. ((ICSecureSocket *)_Socket)->SetHostName(GetHostName());
  303. ((ICSecureSocket *)_Socket)->SetSecureFlags(GetOpenFlags() & SECURITY_INTERNET_MASK);
  304. }
  305. } else {
  306. _Socket = new ICSocket;
  307. }
  308. if (_Socket != NULL) {
  309. fsm.m_bCreatedSocket = TRUE;
  310. // If app asks to exempt connection limit for this session,
  311. // we mark the Socket accordingly.
  312. if (ConnLimitExempted())
  313. {
  314. _Socket->ExemptConnLimit();
  315. }
  316. } else {
  317. //
  318. // balance number of available connections
  319. //
  320. ReleaseConnection(FALSE, FALSE, FALSE);
  321. error = ERROR_NOT_ENOUGH_MEMORY;
  322. goto quit;
  323. }
  324. //
  325. // Turn on Socks, if needed.
  326. //
  327. GetSocksProxyName(&proxyHostName,
  328. &proxyHostNameLength,
  329. &proxyHostPort
  330. );
  331. if ((proxyHostName != NULL) && (proxyHostNameLength > 0)) {
  332. _Socket->EnableSocks(proxyHostName, proxyHostPort);
  333. }
  334. //
  335. // NOTE: if secure connection is required, TargetServer must
  336. // be a fully qualified domain name.
  337. // The hostname is used in comparison with CN found in
  338. // the certificate. The hostname MUST NOT BE the
  339. // result of a DNS lookup. DNS lookups are open to
  340. // spoofing, and that may prevent a security from
  341. // being detected.
  342. //
  343. //
  344. // If we're Posting or sending data, make sure
  345. // the SSL connection code knows about it. Therefore we set
  346. // the flag "SF_SENDING_DATA" for the purposes of
  347. // generating errors if found while making the connection.
  348. //
  349. _Socket->SetPort(hostPort);
  350. fsm.SetFunctionState(FSM_STATE_2);
  351. error = _Socket->Connect(GetTimeoutValue(INTERNET_OPTION_CONNECT_TIMEOUT),
  352. GetTimeoutValue(INTERNET_OPTION_CONNECT_RETRIES),
  353. SF_INDICATE
  354. | (IsAsyncHandle() ? SF_NON_BLOCKING : 0)
  355. | (((GetMethodType() == HTTP_METHOD_TYPE_POST)
  356. || (GetMethodType() == HTTP_METHOD_TYPE_PUT))
  357. ? SF_SENDING_DATA
  358. : 0)
  359. );
  360. connect_continue:
  361. if (error == ERROR_SUCCESS) {
  362. //dprintf("%s NEW connection %#x\n", GetURL(), _Socket->GetSocket());
  363. DEBUG_PRINT(HTTP,
  364. INFO,
  365. ("new connection: socket %#x\n",
  366. _Socket->GetSocket()
  367. ));
  368. //if ( IsTunnel() )
  369. //{
  370. // dprintf("Tunnel for nested req=%#x opened for Socket=%#x\n", this, _Socket );
  371. //}
  372. // This assert is not strictly valid - there is a window in which the Request handle
  373. // could be closed, invalidating the m_Socket member of ICSocket. (IEv6 bug 24918)
  374. // Code downstream of this accounts for that possibility.
  375. // for eg. SetTimeout would lead to a WSA_NOT_SOCK error and the error is replaced with
  376. // ERROR_CANCELLED. and SetLinger has an Exc. Handler around the winsock call.
  377. //INET_ASSERT(_Socket->IsOpen());
  378. //pServerInfo->AddActiveConnection();
  379. //
  380. // enable receive timeout - ignore any errors
  381. //
  382. _Socket->SetTimeout(RECEIVE_TIMEOUT,
  383. GetTimeoutValue(INTERNET_OPTION_RECEIVE_TIMEOUT)
  384. );
  385. //
  386. // set zero linger: force connection closed at transport level when
  387. // we close the socket. Ignore the error
  388. //
  389. _Socket->SetLinger(TRUE, 0);
  390. }
  391. quit:
  392. if (error != ERROR_IO_PENDING) {
  393. //
  394. // if we created the socket but failed to connect then delete the socket
  395. // object
  396. //
  397. if ((error != ERROR_SUCCESS) && fsm.m_bCreatedSocket) {
  398. //
  399. // we created a socket so we must increase the available connection
  400. // count on failure
  401. //
  402. if (fsm.IsInvalid() && fsm.GetState() == FSM_STATE_ERROR)
  403. {
  404. DEBUG_PRINT(
  405. HTTP,
  406. INFO,
  407. ("Fsm in invalid state"));
  408. }
  409. else
  410. {
  411. INET_ASSERT(_Socket != NULL);
  412. ReleaseConnection(TRUE, // close socket (if open)
  413. FALSE, // don't indicate
  414. TRUE // dispose of socket object
  415. );
  416. }
  417. }
  418. //dprintf("%s get/connect pending socket %#x\n", GetURL(), _Socket ? _Socket->GetSocket() : 0);
  419. fsm.SetDone();
  420. }
  421. DEBUG_LEAVE(error);
  422. return error;
  423. }
  424. DWORD
  425. HTTP_REQUEST_HANDLE_OBJECT::CloseConnection(
  426. IN BOOL bForceClosed
  427. )
  428. /*++
  429. Routine Description:
  430. Performs the opposite of OpenConnection(), i.e. closes the socket or marks
  431. it not in use if keep-alive
  432. Arguments:
  433. bForceClosed - TRUE if we are to forcibly release a keep-alive connection
  434. (i.e. the server timed out before we did)
  435. Return Value:
  436. DWORD
  437. Success - ERROR_SUCCESS
  438. Failure - WSA error
  439. --*/
  440. {
  441. DEBUG_ENTER((DBG_HTTP,
  442. Dword,
  443. "HTTP_REQUEST_HANDLE_OBJECT::CloseConnection",
  444. "%B",
  445. bForceClosed
  446. ));
  447. //dprintf("*** closing %s%s socket %#x\n",
  448. // (_bKeepAliveConnection || IsKeepAlive()) ? "K-A " : "",
  449. // GetURL(),
  450. // _Socket ? _Socket->GetSocket() : 0
  451. // );
  452. DWORD error = ERROR_SUCCESS;
  453. BOOL bClose = TRUE;
  454. BOOL bDelete = TRUE;
  455. if (_Socket == NULL) {
  456. DEBUG_PRINT(HTTP,
  457. WARNING,
  458. ("socket already deleted\n"
  459. ));
  460. goto quit;
  461. }
  462. if (_bKeepAliveConnection || IsKeepAlive()) {
  463. //
  464. // keep-alive connection: just return the connection to the pool
  465. //
  466. if ((IsContentLength() && (GetBytesInSocket() != 0))
  467. || (IsChunkEncoding() && !IsChunkedEncodingFinished())
  468. || IsNoLongerKeepAlive() || _Socket->IsClosed()
  469. || ((_State & 0x0F) < (HttpRequestStateObjectData & 0x0F))) {
  470. DEBUG_PRINT(HTTP,
  471. INFO,
  472. ("forcing %#x [%#x] closed: bytes left = %d/%d; no longer k-a = %B; closed = %B\n",
  473. _Socket,
  474. _Socket->GetSocket(),
  475. GetBytesInSocket(),
  476. GetContentLength(),
  477. IsNoLongerKeepAlive(),
  478. _Socket->IsClosed()
  479. ));
  480. //dprintf("forcing k-a %#x closed - bytes=%d/%d, no longer=%B, chunked=%B, chunk-finished=%B\n",
  481. // _Socket->GetSocket(),
  482. // GetBytesInSocket(),
  483. // GetContentLength(),
  484. // IsNoLongerKeepAlive(),
  485. // IsChunkEncoding(),
  486. // IsChunkedEncodingFinished()
  487. // );
  488. bForceClosed = TRUE;
  489. }
  490. if (!bForceClosed) {
  491. bClose = FALSE;
  492. bDelete = FALSE;
  493. } else {
  494. //dprintf("%#x forced close\n", _Socket->GetSocket());
  495. }
  496. }
  497. ReleaseConnection(bClose, TRUE, bDelete);
  498. _Socket = NULL;
  499. _bKeepAliveConnection = FALSE;
  500. _bNoLongerKeepAlive = FALSE;
  501. quit:
  502. DEBUG_LEAVE(error);
  503. return error;
  504. }
  505. VOID
  506. HTTP_REQUEST_HANDLE_OBJECT::ReleaseConnection(
  507. IN BOOL bClose,
  508. IN BOOL bIndicate,
  509. IN BOOL bDispose
  510. )
  511. /*++
  512. Routine Description:
  513. Releases the connection back to the server limited pool and optionally
  514. closes the socket handle and destroys the socket object
  515. Arguments:
  516. bClose - if TRUE, increments the available connection count in the
  517. server info object and closes the handle, else we are
  518. returning a keep-alive connection; after this call we no
  519. longer have a socket object owned by this request handle
  520. object
  521. bIndicate - TRUE if we indicate to the user when we close the socket
  522. handle
  523. bDispose - TRUE if we are disposing of the socket object (mutually
  524. exclusive with !bClose), in which case we will no longer have
  525. a socket object after this call returns
  526. Return Value:
  527. None.
  528. --*/
  529. {
  530. DEBUG_ENTER((DBG_HTTP,
  531. None,
  532. "HTTP_REQUEST_HANDLE_OBJECT::ReleaseConnection",
  533. "%B, %B, %B",
  534. bClose,
  535. bIndicate,
  536. bDispose
  537. ));
  538. INET_ASSERT(_Socket != NULL);
  539. //INET_ASSERT(_Socket->IsOpen());
  540. BOOL fExemptConnLimit = _Socket->ConnLimitExempted();
  541. CServerInfo * pServerInfo = GetServerInfo();
  542. // Always disconnect sockets which have been marked as authenticated.
  543. // This is to avoid posting data to IIS4 while preauthenticating
  544. // and inducing the server to close the connection.
  545. if (_Socket)
  546. bClose = (bClose || _Socket->IsAuthenticated());
  547. ICSocket * pSocket = bClose ? NULL : _Socket;
  548. INET_ASSERT(pServerInfo != NULL);
  549. if (pServerInfo != NULL) {
  550. if (bClose && (_Socket != NULL)) {
  551. //
  552. // BUGBUG - this should be set based on bGraceful parameter
  553. //
  554. _Socket->SetLinger(FALSE, 0);
  555. //INET_ASSERT(!_bKeepAliveConnection || _bNoLongerKeepAlive);
  556. _Socket->Disconnect(bIndicate ? SF_INDICATE : 0);
  557. if (bDispose) {
  558. _Socket->Dereference();
  559. _Socket = NULL;
  560. }
  561. } else {
  562. _Socket = NULL;
  563. }
  564. //if (IsResponseHttp1_1() && IsKeepAlive()) {
  565. // pServerInfo->ReleasePipelinedConnection(pSocket);
  566. //} else {
  567. pServerInfo->ReleaseConnection(pSocket, fExemptConnLimit);
  568. //}
  569. }
  570. DEBUG_LEAVE(0);
  571. }
  572. DWORD
  573. HTTP_REQUEST_HANDLE_OBJECT::AbortConnection(
  574. IN BOOL bForce
  575. )
  576. /*++
  577. Routine Description:
  578. Aborts the current connection. Closes the socket and frees up all receive
  579. buffers. If the connection is keep-alive, we have the option to forcefully
  580. terminate the connection, or just return the socket to the keep-alive pool
  581. Arguments:
  582. bForce - if TRUE and keep-alive, forcefully close the keep-alive socket
  583. Return Value:
  584. DWORD
  585. Success - ERROR_SUCCESS
  586. Failure - WSA error
  587. --*/
  588. {
  589. DEBUG_ENTER((DBG_HTTP,
  590. Dword,
  591. "HTTP_REQUEST_HANDLE_OBJECT::AbortConnection",
  592. "%B",
  593. bForce
  594. ));
  595. DWORD error;
  596. error = CloseConnection(bForce);
  597. if (error == ERROR_SUCCESS) {
  598. //
  599. // destroy all response variables. This is similar to ReuseObject()
  600. // except we don't change the object state, or reset the end-of-file
  601. // state
  602. //
  603. _ResponseHeaders.FreeHeaders();
  604. FreeResponseBuffer();
  605. ResetResponseVariables();
  606. _dwCurrentStreamPosition = 0;
  607. }
  608. DEBUG_LEAVE(error);
  609. return error;
  610. }
  611. DWORD
  612. HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel(
  613. VOID
  614. )
  615. /*++
  616. Routine Description:
  617. Creates a connection with the requested server via a Proxy
  618. tunnelling method.
  619. Works by creating a nested child HTTP and Connect request object.
  620. These objects send a "CONNECT" verb to the proxy server asking for
  621. a connection to made with the destination server. Upon completion the
  622. child objects are discarded. If a class 200 response is not received from
  623. proxy server, the proxy response is copied into this object
  624. and returned to the user.
  625. Arguments:
  626. none.
  627. Return Value:
  628. DWORD
  629. Success - ERROR_SUCCESS
  630. Failure -
  631. ERROR_NOT_ENOUGH_MEMORY
  632. Ran out of resources
  633. --*/
  634. {
  635. DEBUG_ENTER((DBG_HTTP,
  636. Dword,
  637. "HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel",
  638. NULL
  639. ));
  640. DWORD error = DoFsm(new CFsm_OpenProxyTunnel(this));
  641. DEBUG_LEAVE(error);
  642. return error;
  643. }
  644. DWORD
  645. CFsm_OpenProxyTunnel::RunSM(
  646. IN CFsm * Fsm
  647. )
  648. /*++
  649. Routine Description:
  650. Runs next OpenProxyTunnel state
  651. Arguments:
  652. Fsm - contains state info
  653. Return Value:
  654. DWORD
  655. Success - ERROR_SUCCESS
  656. Failure -
  657. --*/
  658. {
  659. DEBUG_ENTER((DBG_HTTP,
  660. Dword,
  661. "CFsm_OpenProxyTunnel::RunSM",
  662. "%#x",
  663. Fsm
  664. ));
  665. DWORD error;
  666. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  667. CFsm_OpenProxyTunnel * stateMachine = (CFsm_OpenProxyTunnel *)Fsm;
  668. START_SENDREQ_PERF();
  669. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  670. switch (Fsm->GetState()) {
  671. case FSM_STATE_INIT:
  672. case FSM_STATE_CONTINUE:
  673. case FSM_STATE_ERROR:
  674. error = pRequest->OpenProxyTunnel_Fsm(stateMachine);
  675. break;
  676. default:
  677. error = ERROR_INTERNET_INTERNAL_ERROR;
  678. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  679. INET_ASSERT(FALSE);
  680. break;
  681. }
  682. STOP_SENDREQ_PERF();
  683. DEBUG_LEAVE(error);
  684. return error;
  685. }
  686. DWORD
  687. HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel_Fsm(
  688. IN CFsm_OpenProxyTunnel * Fsm
  689. )
  690. /*++
  691. Routine Description:
  692. State machine for OpenProxyTunnel
  693. Arguments:
  694. Fsm - contains state info
  695. Return Value:
  696. DWORD
  697. Success - ERROR_SUCCESS
  698. Failure -
  699. --*/
  700. {
  701. DEBUG_ENTER((DBG_HTTP,
  702. Dword,
  703. "HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel_Fsm",
  704. "%#x",
  705. Fsm
  706. ));
  707. CFsm_OpenProxyTunnel & fsm = *Fsm;
  708. DWORD error = fsm.GetError();
  709. LPINTERNET_THREAD_INFO lpThreadInfo = fsm.GetThreadInfo();
  710. // Need to bury error on blocked item that failed to find
  711. // established SSL tunnel
  712. if (error != ERROR_SUCCESS && fsm.GetFunctionState() != FSM_STATE_2) {
  713. goto quit;
  714. }
  715. if (lpThreadInfo == NULL) {
  716. INET_ASSERT(FALSE);
  717. error = ERROR_INTERNET_INTERNAL_ERROR;
  718. goto quit;
  719. }
  720. if (fsm.GetState() != FSM_STATE_INIT) {
  721. switch (fsm.GetFunctionState()) {
  722. case FSM_STATE_1:
  723. goto send_continue;
  724. case FSM_STATE_2:
  725. goto keep_alive_tunnel;
  726. default:
  727. error = ERROR_INTERNET_INTERNAL_ERROR;
  728. INET_ASSERT(FALSE);
  729. goto quit;
  730. }
  731. }
  732. // Do not continue if handle is in NTLM challenge state - we
  733. // already have a valid socket set up for tunnelling.
  734. if ((_Socket != NULL) && (GetAuthState() == AUTHSTATE_CHALLENGE))
  735. {
  736. DEBUG_PRINT(
  737. HTTP,
  738. INFO,
  739. ("authstate is %s, completing auth over existing tunnel\n", InternetMapAuthState(GetAuthState()))
  740. );
  741. error = ERROR_SUCCESS;
  742. goto quit;
  743. }
  744. // First, try and fetch an already established tunnel
  745. // from the keep-alive pool. If so, we can avoid the nested
  746. // CONNECT request.
  747. //
  748. if (_Socket == NULL)
  749. {
  750. error = OpenConnection(FALSE, TRUE);
  751. if (error == ERROR_IO_PENDING)
  752. {
  753. fsm.SetFunctionState(FSM_STATE_2);
  754. goto quit;
  755. }
  756. keep_alive_tunnel:
  757. if (error == ERROR_SUCCESS && _Socket != NULL)
  758. {
  759. // No need to create nested request. We found an active SSL tunnel
  760. // for this server in the keep-alive pool.
  761. goto quit;
  762. }
  763. else
  764. {
  765. // Start over as normal tunnel since bypass to find
  766. // keep-alive failed.
  767. error = ERROR_SUCCESS;
  768. }
  769. }
  770. //
  771. // Handle Magic... Get the Internet Handle Object,
  772. // then constuct a new Connect Object, and new HttpRequest Object.
  773. //
  774. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  775. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)GetParent();
  776. INET_ASSERT(pConnect != NULL);
  777. INTERNET_HANDLE_OBJECT * pInternet;
  778. pInternet = (INTERNET_HANDLE_OBJECT *)pConnect->GetParent();
  779. INET_ASSERT(pInternet != NULL);
  780. //
  781. // increment the nested request level around InternetConnect(). This is
  782. // required to stop InternetConnect() believing this is the async part of
  783. // a two-part (FTP) request (original async hackery)
  784. //
  785. _InternetIncNestingCount();
  786. fsm.m_hConnect = InternetConnect(pInternet->GetPseudoHandle(),
  787. GetHostName(),
  788. GetHostPort(),
  789. NULL,
  790. NULL,
  791. INTERNET_SERVICE_HTTP,
  792. 0, // no flags
  793. INTERNET_NO_CALLBACK
  794. );
  795. _InternetDecNestingCount(1);
  796. if (!fsm.m_hConnect) {
  797. error = GetLastError();
  798. INET_ASSERT(error != ERROR_IO_PENDING);
  799. goto quit;
  800. }
  801. //
  802. // Now do an Open Request. This will pick up the secure proxy flag.
  803. //
  804. fsm.m_hRequest = HttpOpenRequest(fsm.m_hConnect,
  805. "CONNECT",
  806. "/", // we don't need this for a CONNECT
  807. NULL,
  808. NULL,
  809. NULL,
  810. (GetInternetOpenFlags() & INTERNET_FLAG_ASYNC)
  811. | INTERNET_FLAG_RELOAD
  812. | INTERNET_FLAG_NO_CACHE_WRITE
  813. | INTERNET_FLAG_NO_AUTO_REDIRECT
  814. | INTERNET_FLAG_NO_COOKIES
  815. | INTERNET_FLAG_KEEP_CONNECTION,
  816. INTERNET_NO_CALLBACK // should be _Context?
  817. //_Context
  818. );
  819. if (!fsm.m_hRequest) {
  820. error = GetLastError();
  821. goto quit;
  822. }
  823. //
  824. // map the handle
  825. //
  826. error = MapHandleToAddress(fsm.m_hRequest,
  827. (LPVOID *)&fsm.m_hRequestMapped,
  828. FALSE);
  829. if ((error != ERROR_SUCCESS) || (fsm.m_hRequestMapped == NULL)) {
  830. goto quit;
  831. }
  832. fsm.m_pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)fsm.m_hRequestMapped;
  833. //
  834. // we need to set the special secure proxy flag in the request object
  835. //
  836. fsm.m_pRequest->SetTunnel();
  837. LPSTR proxyHostName;
  838. DWORD proxyHostNameLength;
  839. INTERNET_PORT proxyHostPort;
  840. GetProxyName(&proxyHostName,
  841. &proxyHostNameLength,
  842. &proxyHostPort
  843. );
  844. fsm.m_pRequest->SetProxyName(proxyHostName,
  845. proxyHostNameLength,
  846. proxyHostPort
  847. );
  848. //
  849. // Transfer any proxy user/pass from the handle.
  850. //
  851. LPSTR lpszUser, lpszPass = NULL;
  852. // Get and invalidate username + password off of outer handle.
  853. if (GetUserAndPass(IS_PROXY, &lpszUser, &lpszPass))
  854. {
  855. // This will automatically re-validate the username/password
  856. // on the tunneling handle.
  857. fsm.m_pRequest->SetUserOrPass (lpszUser, IS_USER, IS_PROXY);
  858. fsm.m_pRequest->SetUserOrPass (lpszPass, IS_PASS, IS_PROXY);
  859. if (lpszPass)
  860. {
  861. SecureZeroMemory(lpszPass, strlen(lpszPass));
  862. FREE_MEMORY(lpszPass);
  863. lpszPass = NULL;
  864. }
  865. }
  866. //
  867. // Transfer any authentication context to the tunnelling handle.
  868. //
  869. //fsm.m_pRequest->SetAuthCtx (_pTunnelAuthCtx);
  870. //dprintf("New tunnel request %#x making nested request= %#x\n", this, fsm.m_pRequest);
  871. //
  872. // Do the Nested SendRequest to the Proxy Server.
  873. // ie send the CONNECT method.
  874. //
  875. if (ShouldSendUTF8ServerNameToProxy())
  876. {
  877. DWORD dwSendUTF8 = 1;
  878. DWORD dwCodePage = GetCodePage();
  879. InternetSetOption(fsm.m_hRequest, INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY, &dwSendUTF8, sizeof(DWORD));
  880. InternetSetOption(fsm.m_hRequest, INTERNET_OPTION_CODEPAGE, &dwCodePage, sizeof(DWORD));
  881. }
  882. fsm.SetFunctionState(FSM_STATE_1);
  883. if (!HttpSendRequest(fsm.m_hRequest, NULL, 0, NULL, 0)) {
  884. error = GetLastError();
  885. if (error == ERROR_IO_PENDING) {
  886. goto done;
  887. }
  888. goto quit;
  889. }
  890. send_continue:
  891. //
  892. // Check Status Code Returned from proxy Server Here.
  893. // If its not 200 we let the user view it as a Proxy Error
  894. // and DON'T continue our connection to the SSL/PCT Server.
  895. //
  896. //dprintf("Received Nested Response, Socket=%#x, org request=%#x, nested request=%#x\n", fsm.m_pRequest->_Socket, this, fsm.m_pRequest);
  897. _StatusCode = fsm.m_pRequest->GetStatusCode();
  898. switch (_StatusCode) {
  899. case HTTP_STATUS_OK:
  900. break;
  901. case HTTP_STATUS_PROXY_AUTH_REQ:
  902. if ((error = CloneResponseBuffer(fsm.m_pRequest)) != ERROR_SUCCESS)
  903. goto quit;
  904. break;
  905. default:
  906. if ((error = CloneResponseBuffer(fsm.m_pRequest)) != ERROR_SUCCESS)
  907. goto quit;
  908. goto quit;
  909. }
  910. //
  911. // Transfer any authentication context back to the outer handle.
  912. //
  913. if ( _pTunnelAuthCtx ) {
  914. delete _pTunnelAuthCtx;
  915. }
  916. _pTunnelAuthCtx = fsm.m_pRequest->GetAuthCtx();
  917. if (_pTunnelAuthCtx)
  918. {
  919. _pTunnelAuthCtx->_pRequest = NULL;
  920. }
  921. fsm.m_pRequest->SetAuthCtx (NULL);
  922. //
  923. // pull the socket handle from the socket object used to communicate with
  924. // the proxy
  925. //
  926. INET_ASSERT(fsm.m_pRequest->_Socket != NULL);
  927. /*
  928. if server returned anything other than 200 then we failed; revert to non-
  929. secure socket
  930. */
  931. if (_Socket == NULL) {
  932. _Socket = new ICSecureSocket(GetErrorMask());
  933. }
  934. if(m_pSecurityInfo == NULL)
  935. {
  936. /* SCLE ref */
  937. if(NULL == (m_pSecurityInfo = GlobalCertCache.Find(GetHostName())))
  938. {
  939. /* SCLE ref */
  940. m_pSecurityInfo = new SECURITY_CACHE_LIST_ENTRY(GetHostName());
  941. }
  942. }
  943. if (_Socket != NULL) {
  944. INET_ASSERT(_Socket->IsSecure());
  945. INET_ASSERT(_Socket->IsClosed());
  946. /* SCLE ref */
  947. ((ICSecureSocket *)_Socket)->SetSecurityEntry(&m_pSecurityInfo);
  948. /* SCLE ref */
  949. ((ICSecureSocket *)_Socket)->SetHostName(GetHostName());
  950. ((ICSecureSocket *)_Socket)->SetSecureFlags(GetOpenFlags() & SECURITY_INTERNET_MASK);
  951. } else {
  952. error = ERROR_NOT_ENOUGH_MEMORY;
  953. goto quit;
  954. }
  955. _Socket->SetSocket(fsm.m_pRequest->_Socket->GetSocket());
  956. _Socket->SetSourcePort(fsm.m_pRequest->_Socket->GetSourcePort());
  957. _Socket->SetPort(fsm.m_pRequest->GetHostPort());
  958. if (fsm.m_pRequest->_Socket->ConnLimitExempted())
  959. {
  960. _Socket->ExemptConnLimit();
  961. }
  962. //
  963. // we need to destroy the ICSocket object in the tunnelled request handle
  964. // because we don't want to influence the available connection count when
  965. // we close the connection when we close the handle below
  966. //
  967. fsm.m_pRequest->_Socket->SetLinger(FALSE, 0);
  968. fsm.m_pRequest->_Socket->SetSocket(INVALID_SOCKET);
  969. fsm.m_pRequest->_Socket->Destroy();
  970. fsm.m_pRequest->_Socket = NULL;
  971. quit:
  972. if (fsm.m_hRequestMapped != NULL) {
  973. DereferenceObject((LPVOID)fsm.m_hRequestMapped);
  974. }
  975. if (fsm.m_hRequest != NULL) {
  976. BOOL bOk;
  977. bOk = InternetCloseHandle(fsm.m_hRequest);
  978. INET_ASSERT(bOk);
  979. }
  980. if (fsm.m_hConnect != NULL) {
  981. BOOL bOk;
  982. bOk = InternetCloseHandle(fsm.m_hConnect);
  983. INET_ASSERT(bOk);
  984. }
  985. //
  986. // We Reset the ThreadInfo back to the the previous
  987. // object handle, and context values.
  988. //
  989. if (lpThreadInfo != NULL) {
  990. _InternetSetObjectHandle(lpThreadInfo, GetPseudoHandle(), (HINTERNET)this);
  991. _InternetClearLastError(lpThreadInfo);
  992. _InternetSetContext(lpThreadInfo, GetContext());
  993. }
  994. done:
  995. if (error != ERROR_IO_PENDING) {
  996. fsm.SetDone();
  997. }
  998. DEBUG_LEAVE(error);
  999. return error;
  1000. }
  1001. //
  1002. // private methods
  1003. //
  1004. PRIVATE
  1005. DWORD
  1006. HTTP_REQUEST_HANDLE_OBJECT::CloneResponseBuffer(
  1007. IN HTTP_REQUEST_HANDLE_OBJECT *pChildRequestObj
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. HTTP_REQUEST_HANDLE_OBJECT CloneResponseBuffer method.
  1012. Copies a Child Request Object's Response Buffer into "this"
  1013. request object. Also forces header parsing to be rerun on
  1014. the header.
  1015. Arguments:
  1016. none.
  1017. Return Value:
  1018. DWORD
  1019. Success - ERROR_SUCCESS
  1020. Failure - ERROR_NOT_ENOUGH_MEMORY
  1021. Ran out of resources
  1022. --*/
  1023. {
  1024. DEBUG_ENTER((DBG_HTTP,
  1025. Dword,
  1026. "HTTP_REQUEST_HANDLE_OBJECT::CloneResponseBuffer",
  1027. "%#x",
  1028. pChildRequestObj
  1029. ));
  1030. DWORD error;
  1031. LPBYTE lpBuffer;
  1032. error = ERROR_SUCCESS;
  1033. lpBuffer = (LPBYTE)ALLOCATE_FIXED_MEMORY(pChildRequestObj->_BytesReceived);
  1034. if ( lpBuffer == NULL )
  1035. {
  1036. error = ERROR_NOT_ENOUGH_MEMORY;
  1037. goto quit;
  1038. }
  1039. //
  1040. // pull out headers, and data from Child Request into our request.
  1041. //
  1042. CopyMemory(
  1043. lpBuffer,
  1044. pChildRequestObj->_ResponseBuffer,
  1045. pChildRequestObj->_BytesReceived
  1046. );
  1047. //
  1048. // Recreate and reparse our header structure into our Object,
  1049. // this is kindof inefficent, but it only happens on errors
  1050. //
  1051. error = CreateResponseHeaders(
  1052. (LPSTR*) &lpBuffer,
  1053. pChildRequestObj->_BytesReceived
  1054. );
  1055. if (error != ERROR_SUCCESS) {
  1056. goto quit;
  1057. }
  1058. SetState(HttpRequestStateObjectData);
  1059. //
  1060. // record the amount of data immediately available to the app
  1061. //
  1062. SetAvailableDataLength(BufferedDataLength());
  1063. //
  1064. // Copy any chunk-transfer information.
  1065. //
  1066. if ( pChildRequestObj->IsChunkEncoding() )
  1067. {
  1068. _ctChunkInfo = pChildRequestObj->_ctChunkInfo;
  1069. _ResponseBufferDataReadyToRead = pChildRequestObj->_ResponseBufferDataReadyToRead;
  1070. SetHaveChunkEncoding(TRUE);
  1071. }
  1072. quit:
  1073. if (lpBuffer) {
  1074. FREE_MEMORY (lpBuffer);
  1075. }
  1076. DEBUG_LEAVE(error);
  1077. return error;
  1078. }
  1079. PRIVATE
  1080. DWORD
  1081. HTTP_REQUEST_HANDLE_OBJECT::CloneResponseBuffer(
  1082. IN LPBYTE pBuffer,
  1083. IN DWORD dwBufferLen
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. HTTP_REQUEST_HANDLE_OBJECT CloneResponseBuffer method.
  1088. Copies a Child Request Object's Response Buffer into "this"
  1089. request object. Also forces header parsing to be rerun on
  1090. the header.
  1091. Arguments:
  1092. none.
  1093. Return Value:
  1094. DWORD
  1095. Success - ERROR_SUCCESS
  1096. Failure - ERROR_NOT_ENOUGH_MEMORY
  1097. Ran out of resources
  1098. --*/
  1099. {
  1100. DEBUG_ENTER((DBG_HTTP,
  1101. Dword,
  1102. "HTTP_REQUEST_HANDLE_OBJECT::CloneResponseBuffer",
  1103. "%#x",
  1104. 0
  1105. ));
  1106. DWORD error;
  1107. LPBYTE lpBuffer;
  1108. error = ERROR_SUCCESS;
  1109. lpBuffer = (LPBYTE)ALLOCATE_FIXED_MEMORY(dwBufferLen);
  1110. if ( lpBuffer == NULL )
  1111. {
  1112. error = ERROR_NOT_ENOUGH_MEMORY;
  1113. goto quit;
  1114. }
  1115. //
  1116. // pull out headers, and data from Child Request into our request.
  1117. //
  1118. CopyMemory(
  1119. lpBuffer,
  1120. pBuffer,
  1121. dwBufferLen
  1122. );
  1123. //
  1124. // Recreate and reparse our header structure into our Object,
  1125. // this is kindof inefficent, but it only happens on errors
  1126. //
  1127. error = CreateResponseHeaders(
  1128. (LPSTR*) &lpBuffer,
  1129. dwBufferLen
  1130. );
  1131. if (error != ERROR_SUCCESS) {
  1132. goto quit;
  1133. }
  1134. SetState(HttpRequestStateObjectData);
  1135. //
  1136. // record the amount of data immediately available to the app
  1137. //
  1138. SetAvailableDataLength(BufferedDataLength());
  1139. //
  1140. // Copy any chunk-transfer information.
  1141. //
  1142. /*
  1143. if ( pChildRequestObj->IsChunkEncoding() )
  1144. {
  1145. _ctChunkInfo = pChildRequestObj->_ctChunkInfo;
  1146. _ResponseBufferDataReadyToRead = pChildRequestObj->_ResponseBufferDataReadyToRead;
  1147. SetHaveChunkEncoding(TRUE);
  1148. }
  1149. */
  1150. quit:
  1151. if (lpBuffer) {
  1152. FREE_MEMORY (lpBuffer);
  1153. }
  1154. DEBUG_LEAVE(error);
  1155. return error;
  1156. }