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.

1723 lines
41 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. hinet.cxx
  5. Abstract:
  6. contains methods for INTERNET_HANDLE_BASE class
  7. Contents:
  8. HANDLE_OBJECT::HANDLE_OBJECT()
  9. HANDLE_OBJECT::HANDLE_OBJECT()
  10. HANDLE_OBJECT::Reference()
  11. HANDLE_OBJECT::Dereference()
  12. HANDLE_OBJECT::IsValid()
  13. INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(LPCSTR, ...)
  14. INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(INTERNET_HANDLE_BASE*)
  15. INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE()
  16. INTERNET_HANDLE_BASE::SetAbortHandle(ICSocket)
  17. INTERNET_HANDLE_BASE::ResetAbortHandle()
  18. INTERNET_HANDLE_BASE::AbortSocket()
  19. INTERNET_HANDLE_BASE::SetProxyInfo()
  20. INTERNET_HANDLE_BASE::GetProxyInfo(LPVOID, LPDWORD)
  21. INTERNET_HANDLE_BASE::GetProxyInfo(INTERNET_SCHEME, LPINTERNET_SCHEME, LPSTR *, LPDWORD, LPINTERNET_PORT)
  22. Author:
  23. Madan Appiah (madana) 16-Nov-1994
  24. Environment:
  25. User Mode - Win32
  26. Revision History:
  27. Sophia Chung (sophiac) 14-Feb-1995 (added FTP and Archie class impl.)
  28. (code adopted from madana)
  29. --*/
  30. #include <wininetp.h>
  31. #include <perfdiag.hxx>
  32. //
  33. // private manifests
  34. //
  35. #define PROXY_REGISTRY_STRING_LENGTH (4 K)
  36. //
  37. // methods
  38. //
  39. HANDLE_OBJECT::HANDLE_OBJECT(
  40. IN HANDLE_OBJECT * Parent
  41. )
  42. /*++
  43. Routine Description:
  44. HANDLE_OBJECT constructor
  45. Arguments:
  46. Parent - pointer to parent HANDLE_OBJECT
  47. Return Value:
  48. None.
  49. --*/
  50. {
  51. DEBUG_ENTER((DBG_OBJECTS,
  52. None,
  53. "HANDLE_OBJECT",
  54. "%#x",
  55. this
  56. ));
  57. //InitializeListHead(&_List);
  58. _Parent = Parent;
  59. if (_Parent)
  60. _Parent->Reference();
  61. _Status = AllocateHandle(this, &_Handle);
  62. _ObjectType = TypeGenericHandle;
  63. _ReferenceCount = 1;
  64. _Invalid = FALSE;
  65. _Error = ERROR_SUCCESS;
  66. _Signature = OBJECT_SIGNATURE;
  67. _Context = NULL;
  68. if (!InsertAtTailOfSerializedList(&GlobalObjectList, &_List))
  69. _Status = ERROR_NOT_ENOUGH_MEMORY;
  70. //
  71. // if AllocateHandle() failed then we cannot create this handle object.
  72. // Invalidate it ready for the destructor
  73. //
  74. if (_Status != ERROR_SUCCESS) {
  75. _Invalid = TRUE;
  76. _ReferenceCount = 0;
  77. }
  78. DEBUG_PRINT(OBJECTS,
  79. INFO,
  80. ("handle %#x created; address %#x; %d objects\n",
  81. _Handle,
  82. this,
  83. ElementsOnSerializedList(&GlobalObjectList)
  84. ));
  85. DEBUG_LEAVE(0);
  86. }
  87. HANDLE_OBJECT::~HANDLE_OBJECT(VOID)
  88. /*++
  89. Routine Description:
  90. HANDLE_OBJECT destructor. Virtual function
  91. Arguments:
  92. None.
  93. Return Value:
  94. None.
  95. --*/
  96. {
  97. DEBUG_ENTER((DBG_OBJECTS,
  98. None,
  99. "~HANDLE_OBJECT",
  100. "%#x",
  101. this
  102. ));
  103. //
  104. // remove this object from global object list
  105. //
  106. if (LockSerializedList(&GlobalObjectList))
  107. {
  108. // should always succeed since we already have the lock
  109. RemoveFromSerializedList(&GlobalObjectList, &_List);
  110. UnlockSerializedList(&GlobalObjectList);
  111. }
  112. INET_DEBUG_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
  113. //
  114. // inform the app that this handle is completely closed
  115. //
  116. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  117. HINTERNET hCurrent = _InternetGetObjectHandle(lpThreadInfo);
  118. HINTERNET hCurrentMapped = _InternetGetMappedObjectHandle(lpThreadInfo);
  119. _InternetSetObjectHandle(lpThreadInfo, _Handle, (HINTERNET)this);
  120. HINTERNET hTemp = _Handle;
  121. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING,
  122. (LPVOID)&hTemp,
  123. sizeof(hTemp)
  124. );
  125. _InternetSetObjectHandle(lpThreadInfo, hCurrent, hCurrentMapped);
  126. if (_Parent != NULL)
  127. _Parent->Dereference();
  128. //
  129. // now we can free up the API handle value
  130. //
  131. if (_Handle != NULL) {
  132. _Status = FreeHandle(_Handle);
  133. INET_ASSERT(_Status == ERROR_SUCCESS);
  134. }
  135. //
  136. // set the signature to a value that indicates the handle has been
  137. // destroyed (not useful in debug builds)
  138. //
  139. _Signature = DESTROYED_OBJECT_SIGNATURE;
  140. INET_ASSERT((_ReferenceCount == 0) && _Invalid);
  141. DEBUG_PRINT(OBJECTS,
  142. INFO,
  143. ("handle %#x destroyed; type %s; address %#x; %d objects\n",
  144. _Handle,
  145. InternetMapHandleType(_ObjectType),
  146. this,
  147. ElementsOnSerializedList(&GlobalObjectList)
  148. ));
  149. DEBUG_LEAVE(0);
  150. }
  151. DWORD
  152. HANDLE_OBJECT::Reference(
  153. VOID
  154. )
  155. /*++
  156. Routine Description:
  157. Increases the reference count on the HANDLE_OBJECT
  158. Arguments:
  159. None.
  160. Return Value:
  161. DWORD
  162. Success - ERROR_SUCCESS
  163. Failure - ERROR_INVALID_HANDLE
  164. Handle has already been invalidated
  165. ERROR_ACCESS_DENIED
  166. Handle object is being destroyed, cannot use it
  167. --*/
  168. {
  169. DEBUG_ENTER((DBG_OBJECTS,
  170. Dword,
  171. "HANDLE_OBJECT::Reference",
  172. "{%#x}",
  173. _Handle
  174. ));
  175. DWORD error;
  176. if (_Invalid) {
  177. DEBUG_PRINT(OBJECTS,
  178. INFO,
  179. ("handle object %#x [%#x] is invalid\n",
  180. _Handle,
  181. this
  182. ));
  183. error = ERROR_INVALID_HANDLE;
  184. } else {
  185. error = ERROR_SUCCESS;
  186. }
  187. //
  188. // even if the handle has been invalidated (i.e. closed), we allow it
  189. // to continue to be referenced. The caller should return the fact
  190. // that the handle has been invalidated, but may require information
  191. // from the object in order to do so (e.g. in async thread)
  192. //
  193. do
  194. {
  195. LONG lRefCountBeforeIncrement = _ReferenceCount;
  196. //
  197. // refcount is > 0 means that the object's destructor has not been called yet
  198. //
  199. if (lRefCountBeforeIncrement > 0)
  200. {
  201. //
  202. // try to increment the refcount using compare-exchange
  203. //
  204. #ifndef _WIN64
  205. LONG lRefCountCurrent = (LONG)SHInterlockedCompareExchange((LPVOID*)&_ReferenceCount,
  206. (LPVOID)(lRefCountBeforeIncrement + 1),
  207. (LPVOID)lRefCountBeforeIncrement);
  208. #else
  209. //
  210. // can't use SHInterlockedCompareExchange on win64 because the values are really LONG's (32-bits) but they
  211. // are treated as pointers (64-bits) because SHInterlockedCompareExchange should really be called
  212. // SHInterlockedCompareExchangePointer (sigh...).
  213. //
  214. LONG lRefCountCurrent = InterlockedCompareExchange(&_ReferenceCount,
  215. lRefCountBeforeIncrement + 1,
  216. lRefCountBeforeIncrement);
  217. #endif
  218. if (lRefCountCurrent == lRefCountBeforeIncrement)
  219. {
  220. //
  221. // since SHInterlockedCompareExchange returns the value in _ReferenceCount
  222. // before the exchange, we know the exchange sucessfully took place (i.e. we
  223. // sucessfully incremented the refrence count of the object by one)
  224. //
  225. INET_ASSERT(lRefCountCurrent > 0);
  226. break;
  227. }
  228. }
  229. else
  230. {
  231. //
  232. // the refcount dropped to zero before we could increment it,
  233. // so the object is being destroyed.
  234. //
  235. error = ERROR_ACCESS_DENIED;
  236. break;
  237. }
  238. } while (TRUE);
  239. DEBUG_PRINT(REFCOUNT,
  240. INFO,
  241. ("handle object %#x [%#x] ReferenceCount = %d\n",
  242. _Handle,
  243. this,
  244. _ReferenceCount
  245. ));
  246. DEBUG_LEAVE(error);
  247. return error;
  248. }
  249. BOOL
  250. HANDLE_OBJECT::Dereference(
  251. VOID
  252. )
  253. /*++
  254. Routine Description:
  255. Reduces the reference count on the HANDLE_OBJECT, and if it goes to zero,
  256. the object is deleted
  257. Arguments:
  258. None.
  259. Return Value:
  260. BOOL
  261. TRUE - this object was deleted
  262. FALSE - this object is still valid
  263. --*/
  264. {
  265. DEBUG_ENTER((DBG_OBJECTS,
  266. Bool,
  267. "HANDLE_OBJECT::Dereference",
  268. "{%#x}",
  269. _Handle
  270. ));
  271. //
  272. // by the time we get here, the reference count should not be 0. There
  273. // should be 1 call to Dereference() for each call to Reference()
  274. //
  275. INET_ASSERT(_ReferenceCount != 0);
  276. BOOL deleted = FALSE;
  277. if (InterlockedDecrement(&_ReferenceCount) == 0)
  278. {
  279. deleted = TRUE;
  280. }
  281. if (deleted)
  282. {
  283. //
  284. // if we are calling the destructor, the handle had better be invalid!
  285. //
  286. INET_ASSERT(_Invalid);
  287. //
  288. // this handle has now been closed. If there is no activity on it
  289. // then it will be destroyed
  290. //
  291. DEBUG_PRINT(REFCOUNT,
  292. INFO,
  293. ("handle object %#x [%#x] ReferenceCount = %d\n",
  294. _Handle,
  295. this,
  296. _ReferenceCount
  297. ));
  298. delete this;
  299. } else {
  300. DEBUG_PRINT(REFCOUNT,
  301. INFO,
  302. ("handle object %#x [%#x] ReferenceCount = %d\n",
  303. _Handle,
  304. this,
  305. _ReferenceCount
  306. ));
  307. }
  308. DEBUG_LEAVE(deleted);
  309. return deleted;
  310. }
  311. DWORD
  312. HANDLE_OBJECT::IsValid(
  313. IN HINTERNET_HANDLE_TYPE ExpectedHandleType
  314. )
  315. /*++
  316. Routine Description:
  317. Checks a HANDLE_OBJECT for validity
  318. Arguments:
  319. ExpectedHandleType - type of object we are testing for. Can be
  320. TypeWildHandle which matches any valid handle
  321. Return Value:
  322. DWORD
  323. Success - ERROR_SUCCESS
  324. Failure - ERROR_INVALID_HANDLE
  325. The handle object is invalid
  326. ERROR_WINHTTP_INCORRECT_HANDLE_TYPE
  327. The handle object is valid, but not the type we want
  328. --*/
  329. {
  330. DWORD error;
  331. BOOL IsOkHandle = TRUE;
  332. //
  333. // test handle object within try..except in case we are given a bad address
  334. //
  335. __try {
  336. if (_Signature == OBJECT_SIGNATURE) {
  337. error = ERROR_SUCCESS;
  338. //
  339. // check handle type if we are asked to do so.
  340. //
  341. if (ExpectedHandleType != TypeWildHandle) {
  342. if (ExpectedHandleType != this->GetHandleType()) {
  343. error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
  344. }
  345. }
  346. } else {
  347. error = ERROR_INVALID_HANDLE;
  348. }
  349. } __except (EXCEPTION_EXECUTE_HANDLER) {
  350. error = ERROR_INVALID_HANDLE;
  351. }
  352. ENDEXCEPT
  353. return error;
  354. }
  355. INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(
  356. LPCSTR UserAgent,
  357. DWORD AccessMethod,
  358. LPSTR ProxyServerList,
  359. LPSTR ProxyBypassList,
  360. DWORD Flags
  361. ) : HANDLE_OBJECT(NULL)
  362. /*++
  363. Routine Description:
  364. Creates the handle object for InternetOpen()
  365. Arguments:
  366. UserAgent - name of agent (user-agent string for HTTP)
  367. AccessMethod - DIRECT, PROXY or PRECONFIG
  368. ProxyServerList - one or more proxy servers. The string has the form:
  369. [<scheme>=][<scheme>"://"]<server>[":"<port>][";"*]
  370. ProxyBypassList - zero or more addresses which if matched will result in
  371. requests NOT going via the proxy (only if PROXY access).
  372. The string has the form:
  373. bp_entry ::= [<scheme>"://"]<server>[":"<port>]
  374. bp_macro ::= "<local>"
  375. bp_list ::= [<> | bp_entry bp_macro][";"*]
  376. Flags - various open flags:
  377. WINHTTP_FLAG_ASYNC - not support in WinHttpX
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. DEBUG_ENTER((DBG_OBJECTS,
  383. None,
  384. "INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE",
  385. NULL
  386. ));
  387. //
  388. // if the HANDLE_OBJECT constructor failed then bail out now
  389. //
  390. if (_Status != ERROR_SUCCESS) {
  391. DEBUG_PRINT(OBJECTS,
  392. ERROR,
  393. ("early-exit: _Status = %d\n",
  394. _Status
  395. ));
  396. DEBUG_LEAVE(0);
  397. return;
  398. }
  399. _PPContext = 0;
  400. _ThreadToken = 0;
  401. _IsCopy = FALSE;
  402. _UserAgent = (LPSTR)UserAgent;
  403. _ProxyInfo = NULL;
  404. _dwInternetOpenFlags = Flags;
  405. _WinsockLoaded = FALSE;
  406. _Context = NULL;
  407. _MaxConnectionsPerServer = WINHTTP_CONNS_PER_SERVER_UNLIMITED;
  408. _MaxConnectionsPer1_0Server = WINHTTP_CONNS_PER_SERVER_UNLIMITED;
  409. //
  410. // set _Async based on the WINHTTP_FLAG_ASYNC supplied to InternetOpen()
  411. //
  412. _dwCodePage = CP_UTF8;
  413. _Async = (Flags & WINHTTP_FLAG_ASYNC) ? TRUE : FALSE;
  414. //
  415. // no data available yet
  416. //
  417. SetAvailableDataLength(0);
  418. //
  419. // not yet end of file
  420. //
  421. ResetEndOfFile();
  422. //
  423. // no status callback by default
  424. //
  425. _StatusCallback = NULL;
  426. _StatusCallbackType = FALSE;
  427. _dwStatusCallbackFlags = 0;
  428. SetObjectType(TypeInternetHandle);
  429. _ProxyInfoResourceLock.Initialize();
  430. _Status = SetProxyInfo(AccessMethod, ProxyServerList, ProxyBypassList);
  431. //
  432. // if _pICSocket is not NULL then this is the socket that this object handle
  433. // is currently working on. We close it to cancel the operation
  434. //
  435. _pICSocket = NULL;
  436. if (::OpenThreadToken(
  437. GetCurrentThread(),
  438. TOKEN_READ | TOKEN_IMPERSONATE,
  439. FALSE,
  440. &_ThreadToken
  441. ) == FALSE)
  442. {
  443. _ThreadToken = 0;
  444. }
  445. //
  446. // load winsock now.
  447. //
  448. if (_Status == ERROR_SUCCESS) {
  449. _Status = LoadWinsock();
  450. _WinsockLoaded = (_Status == ERROR_SUCCESS);
  451. if ( _Status == ERROR_SUCCESS )
  452. {
  453. LONG lOpenHandleCnt;
  454. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  455. if ( lpThreadInfo )
  456. {
  457. lOpenHandleCnt = InterlockedIncrement((LPLONG)&GlobalInternetOpenHandleCount);
  458. if ( lOpenHandleCnt == 0 )
  459. {
  460. DWORD fAlreadyInInit = (DWORD) InterlockedExchange((LPLONG) &GlobalAutoProxyInInit, TRUE);
  461. INET_ASSERT (! fAlreadyInInit );
  462. g_pGlobalProxyInfo->ReleaseQueuedRefresh();
  463. InterlockedExchange((LPLONG)&GlobalAutoProxyInInit, FALSE);
  464. }
  465. }
  466. }
  467. }
  468. DEBUG_LEAVE(0);
  469. }
  470. INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE(
  471. INTERNET_HANDLE_BASE *INetObj
  472. ) : HANDLE_OBJECT((HANDLE_OBJECT*)INetObj)
  473. /*++
  474. Routine Description:
  475. Constructor for derived handle object. We are creating this handle as part
  476. of an INTERNET_CONNECT_HANDLE_OBJECT
  477. Arguments:
  478. INetObj - pointer to INTERNET_HANDLE_BASE to copy
  479. Return Value:
  480. None.
  481. --*/
  482. {
  483. DEBUG_ENTER((DBG_OBJECTS,
  484. None,
  485. "INTERNET_HANDLE_BASE::INTERNET_HANDLE_BASE",
  486. "{IsCopy}"
  487. ));
  488. _PPContext = INetObj->_PPContext;
  489. _ThreadToken = INetObj->_ThreadToken;
  490. _IsCopy = TRUE;
  491. //
  492. // copy user agent string
  493. //
  494. //
  495. // BUGBUG - compiler generated copy constructor (no new string)
  496. //
  497. _UserAgent = INetObj->_UserAgent;
  498. //
  499. // do not inherit the proxy info - code must go to parent handle
  500. //
  501. _ProxyInfo = NULL;
  502. _dwInternetOpenFlags = INetObj->_dwInternetOpenFlags;
  503. //
  504. // creating this handle didn't load winsock
  505. //
  506. _WinsockLoaded = FALSE;
  507. //
  508. // inherit the context, async flag and status callback from
  509. // the parent object handle
  510. //
  511. _Context = INetObj->_Context;
  512. _MaxConnectionsPerServer = INetObj->_MaxConnectionsPerServer;
  513. _MaxConnectionsPer1_0Server = INetObj->_MaxConnectionsPer1_0Server;
  514. _dwCodePage = INetObj->_dwCodePage;
  515. _Async = INetObj->_Async;
  516. //
  517. // inherit callback function
  518. //
  519. SetAvailableDataLength(0);
  520. ResetEndOfFile();
  521. _StatusCallback = INetObj->_StatusCallback;
  522. _StatusCallbackType = INetObj->_StatusCallbackType;
  523. _dwStatusCallbackFlags = INetObj->_dwStatusCallbackFlags;
  524. //
  525. // no socket operation to abort yet
  526. //
  527. _pICSocket = NULL;
  528. //
  529. // BUGBUG - this overwrites status set above?
  530. //
  531. _Status = INetObj->_Status;
  532. DEBUG_LEAVE(0);
  533. }
  534. INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE(
  535. VOID
  536. )
  537. /*++
  538. Routine Description:
  539. INTERNET_HANDLE_BASE destructor
  540. Arguments:
  541. None.
  542. Return Value:
  543. None.
  544. --*/
  545. {
  546. DEBUG_ENTER((DBG_OBJECTS,
  547. None,
  548. "INTERNET_HANDLE_BASE::~INTERNET_HANDLE_BASE",
  549. ""
  550. ));
  551. if (_ProxyInfo && !IsProxyGlobal() && (_ProxyInfo != PROXY_INFO_DIRECT))
  552. {
  553. DEBUG_PRINT(OBJECTS,
  554. INFO,
  555. ("Free-ing ProxyInfo\n"
  556. ));
  557. delete _ProxyInfo;
  558. _ProxyInfo = NULL;
  559. }
  560. //
  561. // if this handle is not a copy (i.e., it is a Session handle), then delete
  562. // the Passport context
  563. //
  564. if (!IsCopy()) {
  565. DEBUG_PRINT(OBJECTS,
  566. INFO,
  567. ("Not a Copy...\n"
  568. ));
  569. if (_PPContext)
  570. {
  571. ::PP_FreeContext(_PPContext);
  572. }
  573. //
  574. // don't unload winsock. There really is no need to unload separately
  575. // from process detach and if we do unload, we first have to terminate
  576. // async support. Dynaloading and unloading winsock is vestigial
  577. //
  578. //if (_WinsockLoaded) {
  579. // UnloadWinsock();
  580. //}
  581. if (_ThreadToken)
  582. {
  583. ::CloseHandle(_ThreadToken);
  584. _ThreadToken = NULL;
  585. }
  586. }
  587. DEBUG_LEAVE(0);
  588. }
  589. DWORD
  590. INTERNET_HANDLE_BASE::ExchangeStatusCallback(
  591. LPWINHTTP_STATUS_CALLBACK lpStatusCallback,
  592. BOOL fType,
  593. DWORD dwFlags
  594. )
  595. {
  596. DWORD error;
  597. WINHTTP_STATUS_CALLBACK callback;
  598. // exchange new and current callbacks
  599. callback = _StatusCallback;
  600. _StatusCallback = *lpStatusCallback;
  601. *lpStatusCallback = callback;
  602. _StatusCallbackType = fType;
  603. _dwStatusCallbackFlags = dwFlags;
  604. error = ERROR_SUCCESS;
  605. return error;
  606. }
  607. VOID
  608. INTERNET_HANDLE_BASE::SetAbortHandle(
  609. IN ICSocket * Socket
  610. )
  611. /*++
  612. Routine Description:
  613. Associates with this request handle the ICSocket object currently being used
  614. for network I/O
  615. Arguments:
  616. Socket - pointer to ICSocket
  617. Return Value:
  618. None.
  619. --*/
  620. {
  621. DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
  622. None,
  623. "INTERNET_HANDLE_BASE::SetAbortHandle",
  624. "{%#x} %#x [sock=%#x ref=%d]",
  625. GetPseudoHandle(),
  626. Socket,
  627. Socket ? Socket->GetSocket() : 0,
  628. Socket ? Socket->ReferenceCount() : 0
  629. ));
  630. INET_ASSERT(Socket != NULL);
  631. //
  632. // first off, increase the socket reference count to stop any other threads
  633. // killing it whilst we are performing the socket operation. The only way
  634. // another thread can dereference the socket is by calling our AbortSocket()
  635. // method
  636. //
  637. Socket->Reference();
  638. //
  639. // now associate the socket object with this handle object. We should not
  640. // have a current association
  641. //
  642. ICSocket * pSocket;
  643. pSocket = (ICSocket *) InterlockedExchangePointer((PVOID*)&_pICSocket, Socket);
  644. //
  645. // because ConnectSocket() can call this method multiple times without
  646. // intervening calls to ResetAbortHandle(), pSocket can legitimately be
  647. // non-NULL at this point
  648. //
  649. //INET_ASSERT(pSocket == NULL);
  650. //
  651. // if the handle was invalidated on another thread before we got
  652. // chance to set the socket to close, then abort the request now
  653. //
  654. //
  655. // BUGBUG - screws up normal FTP close handle processing - we
  656. // have to communicate with the server in order to
  657. // drop the connection
  658. //
  659. //if (IsInvalidated()) {
  660. // AbortSocket();
  661. //}
  662. DEBUG_LEAVE(0);
  663. }
  664. VOID
  665. INTERNET_HANDLE_BASE::ResetAbortHandle(
  666. VOID
  667. )
  668. /*++
  669. Routine Description:
  670. Disassociates this request handle and the ICSocket object when the network
  671. operation has completed
  672. Arguments:
  673. None.
  674. Return Value:
  675. None.
  676. --*/
  677. {
  678. DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
  679. None,
  680. "INTERNET_HANDLE_BASE::ResetAbortHandle",
  681. "{%#x}",
  682. GetPseudoHandle()
  683. ));
  684. //
  685. // there really should be a ICSocket associated with this object, otherwise
  686. // our handle close/invalidation logic is broken
  687. //
  688. //
  689. // however, we can call ResetAbortHandle() from paths where we completed
  690. // early, not having called SetAbortHandle()
  691. //
  692. //INET_ASSERT(pSocket != NULL);
  693. //
  694. // so if there was a ICSocket associated with this object then remove the
  695. // reference added in SetAbortHandle()
  696. //
  697. ICSocket * pICSocket;
  698. pICSocket = (ICSocket *)InterlockedExchangePointer((PVOID*)&_pICSocket, NULL);
  699. if (pICSocket != NULL) {
  700. DEBUG_PRINT(SOCKETS,
  701. INFO,
  702. ("socket=%#x ref=%d\n",
  703. pICSocket->GetSocket(),
  704. pICSocket->ReferenceCount()
  705. ));
  706. pICSocket->Dereference();
  707. }
  708. DEBUG_LEAVE(0);
  709. }
  710. VOID
  711. INTERNET_HANDLE_BASE::AbortSocket(
  712. VOID
  713. )
  714. /*++
  715. Routine Description:
  716. If there is a ICSocket associated with this handle object then abort it. This
  717. forces the current network operation aborted and the request to complete
  718. with ERROR_WINHTTP_OPERATION_CANCELLED
  719. Arguments:
  720. None.
  721. Return Value:
  722. None.
  723. --*/
  724. {
  725. DEBUG_ENTER((DBG_OBJECTS | DBG_SOCKETS,
  726. None,
  727. "INTERNET_HANDLE_BASE::AbortSocket",
  728. "{%#x, %#x [sock=%#x, ref=%d]}",
  729. GetPseudoHandle(),
  730. (_pICSocket != NULL)
  731. ? (LPVOID)_pICSocket
  732. : (LPVOID)_pICSocket,
  733. _pICSocket
  734. ? _pICSocket->GetSocket()
  735. : (_pICSocket
  736. ? _pICSocket->GetSocket()
  737. : 0),
  738. _pICSocket
  739. ? _pICSocket->ReferenceCount()
  740. : (_pICSocket
  741. ? _pICSocket->ReferenceCount()
  742. : 0)
  743. ));
  744. //
  745. // get the associated ICSocket. It may have already been removed by a call
  746. // to ResetAbortHandle()
  747. //
  748. //
  749. // if there is an associated ICSocket then abort it (close the socket handle)
  750. // which will complete the current network I/O (if active) with an error.
  751. // Once the ICSocket is aborted, we reduce the reference count that was added
  752. // in SetAbortHandle(). This may cause the ICSocket to be deleted
  753. //
  754. LPVOID pAddr;
  755. pAddr = (LPVOID)InterlockedExchangePointer((PVOID*)&_pICSocket, NULL);
  756. if (pAddr != NULL) {
  757. ICSocket * pSocket = (ICSocket *)pAddr;
  758. //dprintf(">>>>>>>> %#x AbortSocket %#x [%#x]\n", GetCurrentThreadId(), pSocket, pSocket->GetSocket());
  759. pSocket->Abort();
  760. pSocket->Dereference();
  761. }
  762. DEBUG_LEAVE(0);
  763. }
  764. DWORD
  765. INTERNET_HANDLE_BASE::Refresh()
  766. /*++
  767. Routine Description:
  768. Refreshes the proxy info on an InternetOpen() HINTERNET based on the parameters
  769. Assumes: 1. The parameters have already been validated in the API that calls
  770. this method (i.e. InternetOpen(), InternetSetOption())
  771. Return Value:
  772. DWORD
  773. Success - ERROR_SUCCESS
  774. --*/
  775. {
  776. DWORD error;
  777. //
  778. // Reload the proxy info from registry into the GlobalProxyInfo object,
  779. // unless it was changed in-process to something else.
  780. //
  781. if (!g_pGlobalProxyInfo->IsModifiedInProcess()) {
  782. return LoadProxySettings();
  783. } else {
  784. //
  785. // not using global proxy or it has been set to something other
  786. // than the registry contents. Just return success
  787. //
  788. return ERROR_SUCCESS;
  789. }
  790. }
  791. DWORD
  792. INTERNET_HANDLE_BASE::SetProxyInfo(
  793. IN DWORD dwAccessType,
  794. IN LPCSTR lpszProxy OPTIONAL,
  795. IN LPCSTR lpszProxyBypass OPTIONAL
  796. )
  797. /*++
  798. Routine Description:
  799. Sets the proxy info on an InternetOpen() HINTERNET based on the parameters
  800. Assumes: 1. The parameters have already been validated in the API that calls
  801. this method (i.e. InternetOpen(), InternetSetOption())
  802. Arguments:
  803. dwAccessType - type of proxy access required
  804. lpszProxy - pointer to proxy server list
  805. lpszProxyBypass - pointer to proxy bypass list
  806. Return Value:
  807. DWORD
  808. Success - ERROR_SUCCESS
  809. Failure - ERROR_INVALID_PARAMETER
  810. The lpszProxy or lpszProxyBypass list was bad
  811. ERROR_NOT_ENOUGH_MEMORY
  812. Failed to create an object or allocate space for a list,
  813. etc.
  814. --*/
  815. {
  816. DEBUG_ENTER((DBG_INET,
  817. Dword,
  818. "INTERNET_HANDLE_BASE::SetProxyInfo",
  819. "%s (%d), %#x (%q), %#x (%q)",
  820. InternetMapOpenType(dwAccessType),
  821. dwAccessType,
  822. lpszProxy,
  823. lpszProxy,
  824. lpszProxyBypass,
  825. lpszProxyBypass
  826. ));
  827. //
  828. // Session and HTTP Request objects can have proxy information
  829. //
  830. INET_ASSERT((GetHandleType()==TypeInternetHandle) || (GetHandleType()==TypeHttpRequestHandle));
  831. /*
  832. We are setting the proxy information for an InternetOpen() handle. Based on
  833. the current and new settings we do the following (Note: the handle is
  834. initialized to DIRECT operation):
  835. current access
  836. +---------------------------------------------------------------
  837. new | DIRECT | PROXY | PRECONFIG
  838. access | | |
  839. +-----------+--------------------+--------------------+---------------------
  840. | DIRECT | No action | Delete proxy info | Remove reference to
  841. | | | | global proxy info
  842. +-----------+--------------------+--------------------+---------------------
  843. | PROXY | Set new proxy info | Delete proxy info. | Remove reference to
  844. | | | Set new proxy info | global proxy info.
  845. | | | | Set new proxy info
  846. +-----------+--------------------+--------------------+---------------------
  847. | PRECONFIG | Set proxy info to | Delete proxy info. | No action
  848. | | global proxy info | Set proxy info to |
  849. | | | global proxy info |
  850. +-----------+--------------------+--------------------+---------------------
  851. */
  852. DWORD error = ERROR_SUCCESS;
  853. PROXY_INFO * proxyInfo = NULL;
  854. //
  855. // acquire proxy info for exclusive access
  856. //
  857. if (!AcquireProxyInfo(TRUE))
  858. {
  859. error = ERROR_NOT_ENOUGH_MEMORY;
  860. goto quit;
  861. }
  862. if (IsProxy()) {
  863. //
  864. // delete private proxy info, or unlink from global proxy info
  865. //
  866. SafeDeleteProxyInfo();
  867. }
  868. //
  869. // Map Various Proxy types to their internal counterparts,
  870. // note that I've ordered them in what I think is their
  871. // use frequency (how often each one is most likely to get hit).
  872. //
  873. switch (dwAccessType)
  874. {
  875. #ifndef WININET_SERVER_CORE
  876. // In WinHttpX, INTERNET_OPEN_TYPE_PRECONFIG is equivalent
  877. // to INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY.
  878. case INTERNET_OPEN_TYPE_PRECONFIG:
  879. proxyInfo = g_pGlobalProxyInfo;
  880. break;
  881. #endif
  882. case INTERNET_OPEN_TYPE_DIRECT:
  883. proxyInfo = PROXY_INFO_DIRECT;
  884. break;
  885. case INTERNET_OPEN_TYPE_PROXY:
  886. {
  887. INET_ASSERT(!IsProxy());
  888. INTERNET_HANDLE_OBJECT * pSession;
  889. if (IsCopy())
  890. {
  891. pSession = GetRootHandle(this);
  892. }
  893. else
  894. {
  895. pSession = static_cast<INTERNET_HANDLE_OBJECT *>(this);
  896. INET_ASSERT(pSession->IsValid(TypeInternetHandle) == ERROR_SUCCESS);
  897. }
  898. proxyInfo = New PROXY_INFO;
  899. if (proxyInfo != NULL) {
  900. proxyInfo->InitializeProxySettings();
  901. proxyInfo->SetSessionObject(pSession);
  902. error = proxyInfo->GetError();
  903. if (error == ERROR_SUCCESS &&
  904. lpszProxy )
  905. {
  906. INTERNET_PROXY_INFO_EX info;
  907. memset(&info, 0, sizeof(info));
  908. info.dwStructSize = sizeof(info);
  909. info.dwFlags = (PROXY_TYPE_DIRECT | PROXY_TYPE_PROXY);
  910. info.lpszProxy = lpszProxy;
  911. info.lpszProxyBypass = lpszProxyBypass;
  912. error = proxyInfo->SetProxySettings(&info, TRUE /*modified*/);
  913. }
  914. if (error != ERROR_SUCCESS) {
  915. delete proxyInfo;
  916. proxyInfo = NULL;
  917. }
  918. } else {
  919. error = ERROR_NOT_ENOUGH_MEMORY;
  920. }
  921. break;
  922. }
  923. case INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY:
  924. {
  925. // Refresh global proxy info.
  926. Refresh();
  927. proxyInfo = New PROXY_INFO_GLOBAL_WRAPPER;
  928. if (proxyInfo == NULL)
  929. error = ERROR_NOT_ENOUGH_MEMORY;
  930. else
  931. proxyInfo->SetSessionObject(static_cast<INTERNET_HANDLE_OBJECT *>(this));
  932. break;
  933. }
  934. default:
  935. proxyInfo = NULL;
  936. break;
  937. }
  938. SetProxyInfo(proxyInfo);
  939. ReleaseProxyInfo();
  940. quit:
  941. DEBUG_LEAVE(error);
  942. return error;
  943. }
  944. DWORD
  945. INTERNET_HANDLE_BASE::GetProxyStringInfo(
  946. OUT LPVOID lpBuffer,
  947. IN OUT LPDWORD lpdwBufferLength
  948. )
  949. /*++
  950. Routine Description:
  951. Returns the current proxy information for this INTERNET_HANDLE_BASE
  952. Arguments:
  953. lpBuffer - pointer to buffer where WINHTTP_PROXY_INFOA will be
  954. written, and any proxy strings (if sufficient space)
  955. lpdwBufferLength - IN: number of bytes in lpBuffer
  956. OUT: number of bytes returned in lpBuffer
  957. Return Value:
  958. DWORD
  959. Success - ERROR_SUCCESS
  960. Failure - ERROR_INSUFFICIENT_BUFFER
  961. lpBuffer doesn't have enough space to hold the proxy
  962. information. *lpdwBufferLength has the required size
  963. --*/
  964. {
  965. DEBUG_ENTER((DBG_INET,
  966. Dword,
  967. "INTERNET_HANDLE_BASE::GetProxyStringInfo",
  968. "%#x, %#x [%d]",
  969. lpBuffer,
  970. lpdwBufferLength,
  971. lpdwBufferLength ? *lpdwBufferLength : 0
  972. ));
  973. INET_ASSERT(!IsCopy());
  974. AcquireProxyInfo(FALSE);
  975. DWORD error;
  976. if (IsProxy()) {
  977. error = _ProxyInfo->GetProxyStringInfo(lpBuffer, lpdwBufferLength);
  978. } else {
  979. if (*lpdwBufferLength >= sizeof(WINHTTP_PROXY_INFOA)) {
  980. WINHTTP_PROXY_INFOA * lpInfo = (WINHTTP_PROXY_INFOA *)lpBuffer;
  981. lpInfo->dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
  982. lpInfo->lpszProxy = NULL;
  983. lpInfo->lpszProxyBypass = NULL;
  984. error = ERROR_SUCCESS;
  985. } else {
  986. error = ERROR_INSUFFICIENT_BUFFER;
  987. }
  988. *lpdwBufferLength = sizeof(WINHTTP_PROXY_INFOA);
  989. }
  990. ReleaseProxyInfo();
  991. DEBUG_LEAVE(error);
  992. return error;
  993. }
  994. DWORD
  995. INTERNET_HANDLE_BASE::GetProxyInfo(
  996. IN AUTO_PROXY_ASYNC_MSG **ppQueryForProxyInfo
  997. )
  998. /*++
  999. Routine Description:
  1000. Returns all proxy information based on a protocol scheme
  1001. Arguments:
  1002. tProtocol - protocol to get proxy info for
  1003. lptScheme - returned scheme
  1004. lplpszHostName - returned proxy name
  1005. lpdwHostNameLength - returned length of proxy name
  1006. lpHostPort - returned proxy port
  1007. Return Value:
  1008. BOOL
  1009. Success - TRUE
  1010. Failure - FALSE
  1011. --*/
  1012. {
  1013. DEBUG_ENTER((DBG_INET,
  1014. Dword,
  1015. "INTERNET_HANDLE_BASE::GetProxyInfo",
  1016. "%#x",
  1017. ppQueryForProxyInfo
  1018. ));
  1019. INET_ASSERT((GetHandleType() == TypeInternetHandle) ||
  1020. (GetHandleType() == TypeHttpRequestHandle));
  1021. DWORD error;
  1022. BOOL rc;
  1023. AcquireProxyInfo(FALSE);
  1024. if ( _ProxyInfo && _ProxyInfo != PROXY_INFO_DIRECT )
  1025. {
  1026. error = _ProxyInfo->QueryProxySettings(ppQueryForProxyInfo);
  1027. }
  1028. else
  1029. {
  1030. error = ERROR_SUCCESS;
  1031. (*ppQueryForProxyInfo)->SetUseProxy(FALSE);
  1032. }
  1033. ReleaseProxyInfo();
  1034. DEBUG_LEAVE(error);
  1035. return error;
  1036. }
  1037. BOOL
  1038. INTERNET_HANDLE_BASE::RedoSendRequest(
  1039. IN OUT LPDWORD lpdwError,
  1040. IN DWORD dwSecureStatus,
  1041. IN AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo,
  1042. IN CServerInfo *pOriginServer,
  1043. IN CServerInfo *pProxyServer
  1044. )
  1045. {
  1046. INET_ASSERT(!IsCopy());
  1047. BOOL rc;
  1048. AcquireProxyInfo(FALSE);
  1049. if ( _ProxyInfo )
  1050. {
  1051. rc = _ProxyInfo->RedoSendRequest(
  1052. lpdwError,
  1053. dwSecureStatus,
  1054. pQueryForProxyInfo,
  1055. pOriginServer,
  1056. pProxyServer
  1057. );
  1058. }
  1059. else
  1060. {
  1061. rc = FALSE;
  1062. }
  1063. ReleaseProxyInfo();
  1064. return rc;
  1065. }
  1066. INTERNET_HANDLE_OBJECT::INTERNET_HANDLE_OBJECT
  1067. (LPCSTR ua, DWORD access, LPSTR proxy, LPSTR bypass, DWORD flags)
  1068. : INTERNET_HANDLE_BASE (ua, access, proxy, bypass, flags)
  1069. {
  1070. DEBUG_ENTER((DBG_OBJECTS,
  1071. None,
  1072. "INTERNET_HANDLE_OBJECT::INTERNET_HANDLE_OBJECT",
  1073. NULL
  1074. ));
  1075. InterlockedIncrement(&g_cSessionCount);
  1076. if (g_pAsyncCount)
  1077. {
  1078. if (flags & WINHTTP_FLAG_ASYNC)
  1079. {
  1080. g_pAsyncCount->AddRef();
  1081. }
  1082. }
  1083. else
  1084. {
  1085. RIP(FALSE);
  1086. }
  1087. InitializeSerializedList(&_ServerInfoList);
  1088. //
  1089. // WinHttpX supports session cookies. Each session has it's own
  1090. // cookie jar, instead of a shared global cookie jar as in WinInet.
  1091. //
  1092. _CookieJar = NULL;
  1093. _pOptionalParams = NULL;
  1094. _pResolverCache = New CResolverCache(&_Status);
  1095. if (!_pResolverCache)
  1096. {
  1097. _Status = ERROR_NOT_ENOUGH_MEMORY;
  1098. }
  1099. if (_Status == ERROR_SUCCESS)
  1100. {
  1101. _CookieJar = CreateCookieJar();
  1102. if (_CookieJar == NULL)
  1103. _Status = ERROR_NOT_ENOUGH_MEMORY;
  1104. }
  1105. _fUseSessionCertCache = FALSE;
  1106. _SessionCertCache.Initialize();
  1107. DEBUG_LEAVE(0);
  1108. };
  1109. INTERNET_HANDLE_OBJECT::~INTERNET_HANDLE_OBJECT ( )
  1110. {
  1111. DEBUG_ENTER((DBG_OBJECTS,
  1112. None,
  1113. "INTERNET_HANDLE_OBJECT::~INTERNET_HANDLE_OBJECT",
  1114. NULL
  1115. ));
  1116. PurgeServerInfoList(TRUE);
  1117. TerminateSerializedList(&_ServerInfoList);
  1118. if (_pResolverCache)
  1119. {
  1120. _pResolverCache->EmptyHandlesList();
  1121. delete _pResolverCache;
  1122. }
  1123. delete _pOptionalParams;
  1124. _pOptionalParams = NULL;
  1125. // Delete Cookie Jar
  1126. CloseCookieJar(_CookieJar);
  1127. _CookieJar = NULL;
  1128. _SessionCertCache.Terminate();
  1129. if (g_pAsyncCount)
  1130. {
  1131. g_pAsyncCount->Release();
  1132. }
  1133. else
  1134. {
  1135. RIP(FALSE);
  1136. }
  1137. DEBUG_LEAVE(0);
  1138. }
  1139. //
  1140. // This function walks up to the InternetOpen handle from either
  1141. // a connect handle (child) or a request handle (grandchild).
  1142. // We only go one or two hops rather than recurse.
  1143. //
  1144. INTERNET_HANDLE_OBJECT* GetRootHandle (HANDLE_OBJECT* pHandle)
  1145. {
  1146. pHandle = (HANDLE_OBJECT*) pHandle->GetParent();
  1147. INET_ASSERT (pHandle);
  1148. if (pHandle->GetHandleType() == TypeInternetHandle)
  1149. return (INTERNET_HANDLE_OBJECT*) pHandle;
  1150. pHandle = (HANDLE_OBJECT*) pHandle->GetParent();
  1151. INET_ASSERT (pHandle);
  1152. INET_ASSERT (pHandle->GetHandleType() == TypeInternetHandle);
  1153. return (INTERNET_HANDLE_OBJECT*) pHandle;
  1154. }
  1155. /*
  1156. * When called from API functions,
  1157. * caller should SetLastError() in case of failure
  1158. */
  1159. BOOL
  1160. INTERNET_HANDLE_OBJECT::SetTimeout(
  1161. IN DWORD dwTimeoutOption,
  1162. IN DWORD dwTimeoutValue
  1163. )
  1164. {
  1165. BOOL bRetval = TRUE;
  1166. if (!_pOptionalParams)
  1167. {
  1168. _pOptionalParams = New OPTIONAL_SESSION_PARAMS();
  1169. if (!_pOptionalParams)
  1170. {
  1171. bRetval = FALSE;
  1172. goto quit;
  1173. }
  1174. }
  1175. switch (dwTimeoutOption)
  1176. {
  1177. case WINHTTP_OPTION_RESOLVE_TIMEOUT:
  1178. _pOptionalParams->dwResolveTimeout = dwTimeoutValue;
  1179. break;
  1180. case WINHTTP_OPTION_CONNECT_TIMEOUT:
  1181. _pOptionalParams->dwConnectTimeout = dwTimeoutValue;
  1182. break;
  1183. case WINHTTP_OPTION_CONNECT_RETRIES:
  1184. _pOptionalParams->dwConnectRetries = dwTimeoutValue;
  1185. break;
  1186. case WINHTTP_OPTION_SEND_TIMEOUT:
  1187. _pOptionalParams->dwSendTimeout = dwTimeoutValue;
  1188. break;
  1189. case WINHTTP_OPTION_RECEIVE_TIMEOUT:
  1190. _pOptionalParams->dwReceiveTimeout = dwTimeoutValue;
  1191. break;
  1192. default:
  1193. bRetval = FALSE;
  1194. }
  1195. quit:
  1196. return bRetval;
  1197. }
  1198. /*
  1199. * When called from API functions,
  1200. * caller should SetLastError() in case of failure
  1201. */
  1202. BOOL
  1203. INTERNET_HANDLE_OBJECT::SetTimeouts(
  1204. IN DWORD dwResolveTimeout,
  1205. IN DWORD dwConnectTimeout,
  1206. IN DWORD dwSendTimeout,
  1207. IN DWORD dwReceiveTimeout
  1208. )
  1209. {
  1210. BOOL bRetval = TRUE;
  1211. if (!_pOptionalParams)
  1212. {
  1213. _pOptionalParams = New OPTIONAL_SESSION_PARAMS();
  1214. if (!_pOptionalParams)
  1215. {
  1216. bRetval = FALSE;
  1217. goto quit;
  1218. }
  1219. }
  1220. _pOptionalParams->dwResolveTimeout = dwResolveTimeout;
  1221. _pOptionalParams->dwConnectTimeout = dwConnectTimeout;
  1222. _pOptionalParams->dwSendTimeout = dwSendTimeout;
  1223. _pOptionalParams->dwReceiveTimeout = dwReceiveTimeout;
  1224. quit:
  1225. return bRetval;
  1226. }
  1227. /*
  1228. * When called from API functions,
  1229. * caller should SetLastError() in case of failure
  1230. */
  1231. BOOL
  1232. INTERNET_HANDLE_OBJECT::GetTimeout(
  1233. IN DWORD dwTimeoutOption,
  1234. OUT DWORD* pdwTimeoutValue
  1235. )
  1236. {
  1237. BOOL bRetval = TRUE;
  1238. if (!_pOptionalParams)
  1239. {
  1240. bRetval = FALSE;
  1241. goto quit;
  1242. }
  1243. switch (dwTimeoutOption)
  1244. {
  1245. case WINHTTP_OPTION_RESOLVE_TIMEOUT:
  1246. *pdwTimeoutValue = _pOptionalParams->dwResolveTimeout;
  1247. break;
  1248. case WINHTTP_OPTION_CONNECT_TIMEOUT:
  1249. *pdwTimeoutValue = _pOptionalParams->dwConnectTimeout;
  1250. break;
  1251. case WINHTTP_OPTION_CONNECT_RETRIES:
  1252. *pdwTimeoutValue = _pOptionalParams->dwConnectRetries;
  1253. break;
  1254. case WINHTTP_OPTION_SEND_TIMEOUT:
  1255. *pdwTimeoutValue = _pOptionalParams->dwSendTimeout;
  1256. break;
  1257. case WINHTTP_OPTION_RECEIVE_TIMEOUT:
  1258. *pdwTimeoutValue = _pOptionalParams->dwReceiveTimeout;
  1259. break;
  1260. default:
  1261. bRetval = FALSE;
  1262. break;
  1263. }
  1264. quit:
  1265. return bRetval;
  1266. }