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.

2557 lines
65 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. connect.cxx
  5. Abstract:
  6. Contains methods for INTERNET_CONNECT_HANDLE_OBJECT class
  7. Contents:
  8. RMakeInternetConnectObjectHandle
  9. FindExistingConnectObject
  10. FlushExistingConnectObjects
  11. INTERNET_CONNECT_HANDLE_OBJECT::INTERNET_CONNECT_HANDLE_OBJECT
  12. INTERNET_CONNECT_HANDLE_OBJECT::~INTERNET_CONNECT_HANDLE_OBJECT
  13. INTERNET_CONNECT_HANDLE_OBJECT::AttachLastResponseInfo
  14. INTERNET_CONNECT_HANDLE_OBJECT::SetOriginServer
  15. INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo(INTERNET_SCHEME, BOOL, BOOL)
  16. INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo(LPSTR, DWORD)
  17. Author:
  18. Madan Appiah (madana) 16-Nov-1994
  19. Environment:
  20. User Mode - Win32
  21. Revision History:
  22. Sophia Chung (sophiac) 14-Feb-1995 (added FTP and Archie class impl.)
  23. (code adopted from madana)
  24. --*/
  25. #include <wininetp.h>
  26. #define DEFAULT_VARIABLE_CACHE_INFO_SIZE 512
  27. //
  28. // data
  29. //
  30. LONG GlobalExistingConnectHandles = 0;
  31. extern DWORD dwCacheWriteBufferSize;
  32. BOOL
  33. GetCanonicalizedParentUrl(
  34. LPSTR lpszChildUrl,
  35. LPSTR lpszParentUrlBuff,
  36. DWORD dwBuffSize);
  37. //
  38. // functions
  39. //
  40. DWORD
  41. RMakeInternetConnectObjectHandle(
  42. IN HINTERNET ParentHandle,
  43. IN OUT HINTERNET * ChildHandle,
  44. IN CONNECT_CLOSE_HANDLE_FUNC wCloseFunc,
  45. IN LPSTR lpszServerName,
  46. IN INTERNET_PORT nServerPort,
  47. IN LPSTR lpszUserName OPTIONAL,
  48. IN LPSTR lpszPassword OPTIONAL,
  49. IN DWORD ServiceType,
  50. IN DWORD dwFlags,
  51. IN DWORD_PTR dwContext
  52. )
  53. /*++
  54. Routine Description:
  55. Creates an INTERNET_CONNECT_HANDLE_OBJECT. Wrapper function callable from
  56. C code
  57. Arguments:
  58. ParentHandle - parent InternetOpen() handle
  59. ChildHandle - IN: protocol-specific child handle
  60. OUT: address of handle object
  61. wCloseFunc - pointer to function to close when object deleted
  62. lpszServerName - pointer to server name
  63. nServerPort - server port to connect to
  64. lpszUserName - optional user name
  65. lpszPassword - optional password
  66. ServiceType - type of service required, e.g. INTERNET_SERVICE_HTTP
  67. dwFlags - various open flags from InternetConnect()
  68. dwContext - app-supplied context value to associate with the handle
  69. Return Value:
  70. DWORD
  71. Success - ERROR_SUCCESS
  72. Failure - ERROR_NOT_ENOUGH_MEMORY
  73. --*/
  74. {
  75. DWORD error;
  76. INTERNET_CONNECT_HANDLE_OBJECT * hConnect;
  77. hConnect = new INTERNET_CONNECT_HANDLE_OBJECT(
  78. (INTERNET_HANDLE_OBJECT *)ParentHandle,
  79. *ChildHandle,
  80. wCloseFunc,
  81. lpszServerName,
  82. nServerPort,
  83. lpszUserName,
  84. lpszPassword,
  85. ServiceType,
  86. dwFlags,
  87. dwContext
  88. );
  89. if (hConnect != NULL) {
  90. error = hConnect->GetStatus();
  91. if (error == ERROR_SUCCESS) {
  92. //
  93. // inform the app of the new handle
  94. //
  95. error = InternetIndicateStatusNewHandle((LPVOID)hConnect);
  96. //
  97. // ERROR_INTERNET_OPERATION_CANCELLED is the only error that we are
  98. // expecting here. If we get this error then the app has cancelled
  99. // the operation. Either way, the handle we just generated will be
  100. // already deleted
  101. //
  102. if (error != ERROR_SUCCESS) {
  103. INET_ASSERT(error == ERROR_INTERNET_OPERATION_CANCELLED);
  104. hConnect = NULL;
  105. }
  106. } else {
  107. delete hConnect;
  108. hConnect = NULL;
  109. }
  110. } else {
  111. error = ERROR_NOT_ENOUGH_MEMORY;
  112. }
  113. *ChildHandle = (HINTERNET)hConnect;
  114. return error;
  115. }
  116. HINTERNET
  117. FindExistingConnectObject(
  118. IN HINTERNET hInternet,
  119. IN LPSTR lpHostName,
  120. IN INTERNET_PORT nPort,
  121. IN LPSTR lpszUserName,
  122. IN LPSTR lpszPassword,
  123. IN DWORD dwServiceType,
  124. IN DWORD dwFlags,
  125. IN DWORD_PTR dwContext
  126. )
  127. /*++
  128. Routine Description:
  129. Attempts to find an existing INTERNET_CONNECT_HANDLE_OBJECT with the
  130. desired attributes
  131. Arguments:
  132. hInternet - required parent handle
  133. lpHostName - pointer to host name to connect to
  134. nPort - port at server to connect to
  135. lpszUserName - name of user making requests
  136. lpszPassword - password required to establish connection
  137. dwServiceType - type of service required
  138. dwFlags - extra control information
  139. dwContext - required context value
  140. Return Value:
  141. HINTERNET
  142. Success - handle of found object
  143. Failure - NULL
  144. --*/
  145. {
  146. DEBUG_ENTER((DBG_OBJECTS,
  147. Handle,
  148. "FindExistingConnectObject",
  149. "%#x, %q, %d, %q, %q, %s (%d), %#x, %#x",
  150. hInternet,
  151. lpHostName,
  152. nPort,
  153. lpszUserName,
  154. lpszPassword,
  155. InternetMapService(dwServiceType),
  156. dwServiceType,
  157. dwFlags,
  158. dwContext
  159. ));
  160. HINTERNET hConnect = NULL;
  161. HINTERNET_HANDLE_TYPE handleType;
  162. INTERNET_PORT defaultPort;
  163. switch (dwServiceType) {
  164. case INTERNET_SERVICE_FTP:
  165. handleType = TypeFtpConnectHandle;
  166. defaultPort = INTERNET_DEFAULT_FTP_PORT;
  167. break;
  168. case INTERNET_SERVICE_GOPHER:
  169. handleType = TypeGopherConnectHandle;
  170. defaultPort = INTERNET_DEFAULT_GOPHER_PORT;
  171. break;
  172. case INTERNET_SERVICE_HTTP:
  173. handleType = TypeHttpConnectHandle;
  174. defaultPort = (dwFlags & INTERNET_FLAG_SECURE)
  175. ? INTERNET_DEFAULT_HTTPS_PORT
  176. : INTERNET_DEFAULT_HTTP_PORT;
  177. break;
  178. default:
  179. INET_ASSERT(FALSE);
  180. break;
  181. }
  182. if (nPort == INTERNET_INVALID_PORT_NUMBER) {
  183. nPort = defaultPort;
  184. }
  185. LockSerializedList(&GlobalObjectList);
  186. PLIST_ENTRY entry;
  187. for (entry = HeadOfSerializedList(&GlobalObjectList);
  188. entry != (PLIST_ENTRY)SlSelf(&GlobalObjectList);
  189. entry = entry->Flink) {
  190. HANDLE_OBJECT * pObject = CONTAINING_RECORD(entry, HANDLE_OBJECT, _List);
  191. //
  192. // check elements of the HANDLE_OBJECT first (DWORDs)
  193. //
  194. HANDLE_OBJECT * pParent = (HANDLE_OBJECT *)pObject->GetParent();
  195. if ((pObject->GetHandleType() == handleType)
  196. && ((pParent != NULL) && (pParent->GetPseudoHandle() == hInternet))
  197. && (pObject->GetContext() == dwContext)
  198. //
  199. // the handle may be invalidated - its been closed, but is still alive
  200. // because it has children which are in the process of being closed
  201. //
  202. && !pObject->IsInvalidated()) {
  203. //
  204. // handle is correct type & has the right parent & context values.
  205. // Next, check if its reusable and currently unused, and has the
  206. // correct destination attributes
  207. //
  208. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  209. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)pObject;
  210. if (!pConnect->IsInUse() && (pConnect->GetHostPort() == nPort)) {
  211. LPSTR hostName = pConnect->GetHostName();
  212. if (((lpHostName == NULL) && (hostName == NULL))
  213. || ((lpHostName != NULL) && (hostName != NULL)
  214. && !stricmp(lpHostName, hostName))) {
  215. //
  216. // must have same name and password, or no name and/or
  217. // password
  218. //
  219. LPSTR userName = pConnect->GetUserOrPass (TRUE, IS_SERVER);
  220. if (((lpszUserName == NULL) && (userName == NULL))
  221. || ((lpszUserName != NULL) && (userName != NULL)
  222. && !strcmp(lpszUserName, userName))) {
  223. LPSTR password = pConnect->GetUserOrPass (FALSE, IS_SERVER);
  224. if (((lpszPassword == NULL) && (password == NULL))
  225. || ((lpszPassword != NULL) && (password != NULL)
  226. && !strcmp(lpszPassword, password))) {
  227. //
  228. // this one will do - should be no other users
  229. //
  230. //INET_ASSERT(pConnect->ReferenceCount() == 1);
  231. //{
  232. // if (pConnect->ReferenceCount() != 1) {
  233. // dprintf("handle %#x [%#x]: refcount = %d\n",
  234. // pConnect,
  235. // pConnect->GetPseudoHandle(),
  236. // pConnect->ReferenceCount()
  237. // );
  238. // }
  239. //}
  240. if (pConnect->ReferenceCount() == 1) {
  241. //
  242. // reset the CWD - ignore any error
  243. //
  244. DWORD error = pConnect->SetCurrentWorkingDirectory("/");
  245. INET_ASSERT(error == ERROR_SUCCESS);
  246. //
  247. // this handle is back in use
  248. //
  249. pConnect->SetInUse();
  250. hConnect = (HINTERNET)pConnect;
  251. break;
  252. }
  253. }
  254. }
  255. }
  256. }
  257. }
  258. }
  259. UnlockSerializedList(&GlobalObjectList);
  260. DEBUG_LEAVE(hConnect);
  261. return hConnect;
  262. }
  263. INT
  264. FlushExistingConnectObjects(
  265. IN HINTERNET hInternet
  266. )
  267. /*++
  268. Routine Description:
  269. Closes all unused EXISTING_CONNECT objects that are children of hInternet
  270. Arguments:
  271. hInternet - parent handle
  272. Return Value:
  273. INT
  274. Number of handles flushed
  275. --*/
  276. {
  277. DEBUG_ENTER((DBG_OBJECTS,
  278. Int,
  279. "FlushExistingConnectObjects",
  280. "%#x",
  281. hInternet
  282. ));
  283. INT nFlushed = 0;
  284. if (GlobalExistingConnectHandles > 0) {
  285. LockSerializedList(&GlobalObjectList);
  286. PLIST_ENTRY previous = (PLIST_ENTRY)SlSelf(&GlobalObjectList);
  287. PLIST_ENTRY entry = HeadOfSerializedList(&GlobalObjectList);
  288. while (entry != (PLIST_ENTRY)SlSelf(&GlobalObjectList)) {
  289. HANDLE_OBJECT * pObject = CONTAINING_RECORD(entry, HANDLE_OBJECT, _List);
  290. HANDLE_OBJECT * pParent = (HANDLE_OBJECT *)pObject->GetParent();
  291. BOOL flushed = FALSE;
  292. if ((pParent != NULL) && (pParent->GetPseudoHandle() == hInternet)) {
  293. HINTERNET_HANDLE_TYPE handleType = pObject->GetHandleType();
  294. if ((handleType == TypeFtpConnectHandle)
  295. || (handleType == TypeGopherConnectHandle)
  296. || (handleType == TypeHttpConnectHandle)) {
  297. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  298. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)pObject;
  299. if (!pConnect->IsInUse() && !pConnect->IsInvalidated()) {
  300. //INET_ASSERT(pConnect->ReferenceCount() == 1);
  301. IF_DEBUG_CONTROL(ANY) {
  302. if (pConnect->ReferenceCount() != 1) {
  303. DEBUG_PRINT(OBJECTS,
  304. WARNING,
  305. ("handle %#x [%#x]: refcount = %d\n",
  306. pConnect,
  307. pConnect->GetPseudoHandle(),
  308. pConnect->ReferenceCount()
  309. ));
  310. //dprintf("handle %#x [%#x]: refcount = %d\n",
  311. // pConnect,
  312. // pConnect->GetPseudoHandle(),
  313. // pConnect->ReferenceCount()
  314. // );
  315. }
  316. }
  317. //
  318. // invalidate the object (stops an assert - we normally
  319. // expect the handle to be invalidated by
  320. // MapHandleToAddress(), but we're simply dereferencing
  321. // the object, which would usually be done by the second
  322. // of 2 calls to DereferenceObject(), so we save ourselves
  323. // from jumping through hoops just to destroy the object)
  324. //
  325. pConnect->Invalidate();
  326. flushed = pConnect->Dereference();
  327. //
  328. // the entry was unused; it should have been destroyed
  329. //
  330. //INET_ASSERT(flushed);
  331. DEBUG_PRINT(OBJECTS,
  332. INFO,
  333. ("flushed object %#x\n",
  334. pConnect
  335. ));
  336. }
  337. }
  338. }
  339. //
  340. // if we just destroyed the object pointed at by entry then we need
  341. // to dereference the previous pointer for the next object
  342. //
  343. if (flushed) {
  344. ++nFlushed;
  345. entry = previous->Flink;
  346. } else {
  347. previous = entry;
  348. entry = entry->Flink;
  349. }
  350. }
  351. UnlockSerializedList(&GlobalObjectList);
  352. }
  353. DEBUG_LEAVE(nFlushed);
  354. //dprintf("*** flushed %d objects\n", nFlushed);
  355. return nFlushed;
  356. }
  357. //
  358. // INTERNET_CONNECT_HANDLE_OBJECT class implementation
  359. //
  360. INTERNET_CONNECT_HANDLE_OBJECT::INTERNET_CONNECT_HANDLE_OBJECT(
  361. INTERNET_CONNECT_HANDLE_OBJECT *InternetConnectObj
  362. ) : INTERNET_HANDLE_OBJECT((INTERNET_HANDLE_OBJECT *)InternetConnectObj)
  363. /*++
  364. Routine Description:
  365. Constructor that creates a copy of an INTERNET_CONNECT_HANDLE_OBJECT when
  366. generating a derived handle object, such as a HTTP_REQUEST_HANDLE_OBJECT
  367. Arguments:
  368. InternetConnectObj - INTERNET_CONNECT_HANDLE_OBJECT to copy
  369. Return Value:
  370. None.
  371. --*/
  372. {
  373. DEBUG_ENTER((DBG_OBJECTS,
  374. None,
  375. "INTERNET_CONNECT_HANDLE_OBJECT::INTERNET_CONNECT_HANDLE_OBJECT",
  376. "%#x",
  377. InternetConnectObj
  378. ));
  379. _InternetConnectHandle = InternetConnectObj->_InternetConnectHandle;
  380. _wCloseFunction = InternetConnectObj->_wCloseFunction;
  381. _HandleType = InternetConnectObj->_HandleType;
  382. _ServiceType = InternetConnectObj->_ServiceType;
  383. _IsCopy = TRUE;
  384. //
  385. // copy the flags except EXISTING_CONNECT - we don't want to influence the
  386. // number of flushable handles just by closing a request handle
  387. //
  388. _Flags = InternetConnectObj->_Flags & ~INTERNET_FLAG_EXISTING_CONNECT;
  389. //
  390. // in this case, we are not dealing with a real connect handle object, but a
  391. // derived object, hence _InUse is FALSE
  392. //
  393. _InUse = FALSE;
  394. _ReadBufferSize = InternetConnectObj->_ReadBufferSize;
  395. _WriteBufferSize = InternetConnectObj->_WriteBufferSize;
  396. //
  397. // copy the name objects and server port
  398. //
  399. _HostName = InternetConnectObj->_HostName;
  400. _HostPort = InternetConnectObj->_HostPort;
  401. //
  402. // _SchemeType is actual scheme we use. May be different than original
  403. // object type when going via CERN proxy. Initially set to default (HTTP)
  404. //
  405. _SchemeType = InternetConnectObj->_SchemeType;
  406. //
  407. // _LastResponseInfo points to a buffer containing the last response info
  408. // from an FTP URL operation
  409. //
  410. _LastResponseInfo = NULL;
  411. InitCacheVariables();
  412. if (InternetConnectObj->_CacheUrlName != NULL) {
  413. SetURL (InternetConnectObj->_CacheUrlName);
  414. }
  415. if (InternetConnectObj->_CacheCWD != NULL) {
  416. _CacheCWD = NEW_STRING(InternetConnectObj->_CacheCWD);
  417. }
  418. // Inherit the PerUserItem status of the parent
  419. _CachePerUserItem = InternetConnectObj->_CachePerUserItem;
  420. _bViaProxy = InternetConnectObj->_bViaProxy;
  421. _bNoHeaders = InternetConnectObj->_bNoHeaders;
  422. _bNetFailed = InternetConnectObj->_bNetFailed;
  423. _ServerInfo = InternetConnectObj->_ServerInfo;
  424. _OriginServer = InternetConnectObj->_OriginServer;
  425. _dwErrorMask = 0;
  426. _pwcServerCreds = NULL;
  427. _pwcProxyCreds = NULL;
  428. //
  429. // reference the server info to balance the deref in our destructor
  430. //
  431. if (_ServerInfo != NULL) {
  432. //
  433. // could be cache-only handle
  434. //
  435. _ServerInfo->Reference();
  436. }
  437. if (_OriginServer != NULL) {
  438. _OriginServer->Reference();
  439. }
  440. DEBUG_LEAVE(0);
  441. }
  442. INTERNET_CONNECT_HANDLE_OBJECT::INTERNET_CONNECT_HANDLE_OBJECT(
  443. INTERNET_HANDLE_OBJECT * Parent,
  444. HINTERNET Child,
  445. CONNECT_CLOSE_HANDLE_FUNC wCloseFunc,
  446. LPTSTR lpszServerName,
  447. INTERNET_PORT nServerPort,
  448. LPTSTR lpszUsername OPTIONAL,
  449. LPTSTR lpszPassword OPTIONAL,
  450. DWORD SrvType,
  451. DWORD dwFlags,
  452. DWORD_PTR dwContext
  453. ) : INTERNET_HANDLE_OBJECT(Parent)
  454. /*++
  455. Routine Description:
  456. Constructor for direct-to-net INTERNET_CONNECT_HANDLE_OBJECT
  457. Arguments:
  458. Parent - pointer to parent handle (INTERNET_HANDLE_OBJECT as
  459. created by InternetOpen())
  460. Child - handle of child object - typically an identifying value
  461. for the protocol-specific code
  462. wCloseFunc - pointer to function that handles closes when
  463. InternetCloseHandle() called for this object
  464. lpszServerName - name of the server we are connecting to. May also be the
  465. IP address expressed as a string
  466. nServerPort - the port number at the server to which we connect
  467. lpszUsername - user name for logon at server (if required)
  468. lpszPassword - password for logon at server (if required)
  469. SrvType - Type of service, e.g. INTERNET_SERVICE_HTTP that this
  470. object represents
  471. dwFlags - creation flags from InternetConnect():
  472. - INTERNET_FLAG_PASSIVE
  473. dwContext - context value for call-backs
  474. Return Value:
  475. None.
  476. --*/
  477. {
  478. DEBUG_ENTER((DBG_OBJECTS,
  479. None,
  480. "INTERNET_CONNECT_HANDLE_OBJECT::INTERNET_CONNECT_HANDLE_OBJECT",
  481. "%#x, %#x, %#x, %q, %d, %q, %q, %s (%d), %#x, %#x",
  482. Parent,
  483. Child,
  484. wCloseFunc,
  485. lpszServerName,
  486. nServerPort,
  487. lpszUsername,
  488. lpszPassword,
  489. InternetMapService(SrvType),
  490. SrvType,
  491. dwFlags,
  492. dwContext
  493. ));
  494. _pwcServerCreds = NULL;
  495. _pwcProxyCreds = NULL;
  496. _fHasCredsTimestamp = FALSE;
  497. _InternetConnectHandle = Child;
  498. _wCloseFunction = wCloseFunc;
  499. _ServiceType = SrvType;
  500. _Context = dwContext;
  501. _IsCopy = FALSE;
  502. SetHandleType(SrvType);
  503. //
  504. // remember the creation flags. Mainly (currently) for HTTP Keep-Alive
  505. //
  506. _Flags = dwFlags;
  507. //
  508. // setting _InUse to TRUE stops any EXISTING_CONNECT requests from acquiring
  509. // it
  510. //
  511. _InUse = TRUE;
  512. InitCacheVariables();
  513. //
  514. // set the read/write buffer sizes to the default values (4K)
  515. //
  516. _ReadBufferSize = (4 K);
  517. _WriteBufferSize = (4 K);
  518. //
  519. // create the string buffer and copy the port number
  520. //
  521. _HostName = lpszServerName;
  522. if (lpszUsername) {
  523. SetUserOrPass(lpszUsername, TRUE, FALSE);
  524. }
  525. if (lpszPassword) {
  526. SetUserOrPass(lpszPassword, FALSE, FALSE);
  527. TimeStampCreds();
  528. }
  529. _HostPort = nServerPort;
  530. //
  531. // set the scheme and object types based on the service type
  532. //
  533. INTERNET_SCHEME schemeType;
  534. HINTERNET_HANDLE_TYPE handleType;
  535. switch (_ServiceType) {
  536. case INTERNET_SERVICE_HTTP:
  537. schemeType = INTERNET_SCHEME_HTTP;
  538. handleType = TypeHttpConnectHandle;
  539. break;
  540. case INTERNET_SERVICE_FTP:
  541. schemeType = INTERNET_SCHEME_FTP;
  542. handleType = TypeFtpConnectHandle;
  543. break;
  544. case INTERNET_SERVICE_GOPHER:
  545. schemeType = INTERNET_SCHEME_GOPHER;
  546. handleType = TypeGopherConnectHandle;
  547. break;
  548. default:
  549. schemeType = INTERNET_SCHEME_DEFAULT;
  550. handleType = TypeWildHandle;
  551. break;
  552. }
  553. SetSchemeType(schemeType);
  554. SetObjectType(handleType);
  555. //
  556. // _LastResponseInfo points to a buffer containing the last response info
  557. // from an FTP URL operation
  558. //
  559. _LastResponseInfo = NULL;
  560. _bViaProxy = FALSE;
  561. _bNoHeaders = TRUE;
  562. _bNetFailed = FALSE;
  563. _HandleFlags.fServerUserPassValid = TRUE;
  564. _HandleFlags.fProxyUserPassValid = TRUE;
  565. //
  566. // we need to get the server info that we are going to connect to. In the
  567. // HTTPS case, we don't yet have enough info to make a proper decision, so
  568. // we defer that until HttpOpenRequest() at which point we may get another
  569. // SERVER_INFO
  570. //
  571. _ServerInfo = NULL;
  572. _OriginServer = NULL;
  573. _Status = SetServerInfo(schemeType, FALSE);
  574. DEBUG_LEAVE(0);
  575. }
  576. INTERNET_CONNECT_HANDLE_OBJECT::~INTERNET_CONNECT_HANDLE_OBJECT(VOID)
  577. /*++
  578. Routine Description:
  579. Destructor for INTERNET_CONNECT_HANDLE_OBJECT
  580. Arguments:
  581. None.
  582. Return Value:
  583. None.
  584. --*/
  585. {
  586. DEBUG_ENTER((DBG_OBJECTS,
  587. None,
  588. "INTERNET_CONNECT_HANDLE_OBJECT::~INTERNET_CONNECT_HANDLE_OBJECT",
  589. NULL
  590. ));
  591. if ((!_IsCopy) && (_InternetConnectHandle != INET_INVALID_HANDLE_VALUE)) {
  592. HINTERNET _INetHandle;
  593. DWORD LocalError = ERROR_SUCCESS;
  594. _INetHandle = this->GetInternetHandle();
  595. if (_INetHandle == LOCAL_INET_HANDLE) {
  596. if (_wCloseFunction != NULL) {
  597. LocalError = ERROR_SUCCESS;
  598. if (!(this->GetInternetOpenFlags() & INTERNET_FLAG_OFFLINE)) {
  599. LocalError = _wCloseFunction(_InternetConnectHandle,
  600. _ServiceType
  601. );
  602. }
  603. } else {
  604. INET_ASSERT(LocalError == ERROR_SUCCESS);
  605. }
  606. }
  607. //INET_ASSERT( LocalError == ERROR_SUCCESS );
  608. }
  609. if (_CacheReadInProgress) {
  610. INET_ASSERT(_CacheWriteInProgress == FALSE);
  611. EndCacheRetrieval();
  612. } else if (_CacheWriteInProgress) {
  613. // Abort cache write operation
  614. //
  615. EndCacheWrite(NULL, NULL, NULL, 0xffffffff, 0, NULL, NULL);
  616. }
  617. // background update if the flag is set
  618. if( _fLazyUpdate )
  619. {
  620. LazyUpdate();
  621. }
  622. if (_hLockRequestInfo) {
  623. //
  624. // If the request is locked, the last InternetUnlockRequestFile
  625. // will clean up so there is no need to check _fDeleteDataFile.
  626. //
  627. if (_fDeleteDataFile) {
  628. // We let InternetUnlockRequestFile know that it doesn't
  629. // have to do a cache lookup and if DeleteFile fails that
  630. // it should add the file to the leaked list.
  631. LPLOCK_REQUEST_INFO pLock = (LPLOCK_REQUEST_INFO) _hLockRequestInfo;
  632. pLock->fNoCacheLookup = TRUE;
  633. }
  634. InternetUnlockRequestFile(_hLockRequestInfo);
  635. } else if (_fDeleteDataFile) {
  636. //
  637. // This flag is set if we are not committing a download file to cache,
  638. // either because we never intended to or the download was aborted.
  639. //
  640. if (!DeleteFile (_CacheFileName)) {
  641. switch (GetLastError()) {
  642. case ERROR_SHARING_VIOLATION:
  643. case ERROR_ACCESS_DENIED:
  644. UrlCacheAddLeakFile (_CacheFileName);
  645. }
  646. }
  647. }
  648. // delete the staled entry (to prevent back/fwd see the staled entry)
  649. if( _fDeleteDataFile && _CacheUrlName ) {
  650. DeleteUrlCacheEntry(_CacheUrlName);
  651. }
  652. FreeCacheFileName();
  653. INET_ASSERT(_CacheFileName == NULL);
  654. INET_ASSERT(_CacheFileHandle == INVALID_HANDLE_VALUE);
  655. if (_CacheCWD) {
  656. _CacheCWD = (LPSTR)FREE_MEMORY((HLOCAL)_CacheCWD);
  657. INET_ASSERT(_CacheCWD == NULL);
  658. }
  659. // if there is refcount, then remove it
  660. FreeURL();
  661. SetOriginalUrl(NULL);
  662. #ifdef LAZY_WRITE
  663. if (_CacheScratchBuf) {
  664. _CacheScratchBuf = (LPBYTE)FREE_MEMORY((HLOCAL)_CacheScratchBuf);
  665. INET_ASSERT(_CacheScratchBuf == NULL);
  666. }
  667. #endif
  668. FreeLastResponseInfo();
  669. if ((_Flags & INTERNET_FLAG_EXISTING_CONNECT) && !_InUse) {
  670. //
  671. // one less handle that can be flushed right now
  672. //
  673. //dprintf("GlobalExistingConnectHandles = %d\n", GlobalExistingConnectHandles);
  674. if (InterlockedDecrement(&GlobalExistingConnectHandles) < 0) {
  675. INET_ASSERT(FALSE);
  676. GlobalExistingConnectHandles = 0;
  677. }
  678. }
  679. PWC_Free(_pwcServerCreds);
  680. PWC_Free(_pwcProxyCreds);
  681. if (_ServerInfo != NULL) {
  682. _ServerInfo->Dereference();
  683. }
  684. if (_OriginServer != NULL) {
  685. _OriginServer->Dereference();
  686. }
  687. DEBUG_LEAVE(0);
  688. }
  689. BOOL INTERNET_CONNECT_HANDLE_OBJECT::SetURL (LPSTR lpszUrl)
  690. {
  691. LPSTR lpszNew;
  692. if (!_xsSecondaryCacheKey.GetPtr()) {
  693. // Make an undecorated copy of the URL.
  694. lpszNew = NewString(lpszUrl);
  695. if (!lpszNew) {
  696. return FALSE;
  697. }
  698. } else {
  699. // Decorate the URL by appending the secondary cache key.
  700. lpszNew = CatString (lpszUrl, _xsSecondaryCacheKey.GetPtr());
  701. if (!lpszNew) {
  702. return FALSE;
  703. }
  704. // Restore the undecorated URL as the primary cache key.
  705. if (!_xsPrimaryCacheKey.SetData (lpszUrl)) {
  706. FREE_MEMORY (lpszNew);
  707. return FALSE;
  708. }
  709. }
  710. // Clear any previous cache key and record the new one.
  711. FreeURL();
  712. INET_ASSERT (lpszNew);
  713. _CacheUrlName = lpszNew;
  714. return TRUE;
  715. }
  716. BOOL INTERNET_CONNECT_HANDLE_OBJECT::SetURLPtr(LPSTR* ppszUrl)
  717. {
  718. LPSTR lpszNew;
  719. if (!_xsSecondaryCacheKey.GetPtr()) {
  720. // Swap in the new URL as the cache key.
  721. FreeURL();
  722. _CacheUrlName = *ppszUrl;
  723. *ppszUrl = NULL;
  724. } else {
  725. // Decorate the URL by appending the secondary cache key.
  726. lpszNew = CatString (*ppszUrl, _xsSecondaryCacheKey.GetPtr());
  727. if (!lpszNew) {
  728. return FALSE;
  729. }
  730. // Back up the undecorated URL as the primary cache key.
  731. _xsPrimaryCacheKey.SetPtr (ppszUrl);
  732. INET_ASSERT (!*ppszUrl);
  733. // Clear any previous cache key and record the new one.
  734. FreeURL();
  735. _CacheUrlName = lpszNew;
  736. }
  737. return TRUE;
  738. }
  739. BOOL INTERNET_CONNECT_HANDLE_OBJECT::SetSecondaryCacheKey (LPSTR lpszKey)
  740. {
  741. LPSTR lpszTemp = NULL;
  742. if (_CacheUrlName) {
  743. // Decorate the URL by appending the secondary cache key.
  744. // BUGBUG: what if it is already decorated? The app
  745. // better not set the secondary cache key more than once.
  746. lpszTemp = CatString (_CacheUrlName, lpszKey);
  747. if (!lpszTemp)
  748. return FALSE;
  749. }
  750. // Save the secondary cache key in case we later change the URL.
  751. if (!_xsSecondaryCacheKey.SetData (lpszKey)) {
  752. if (lpszTemp) {
  753. FREE_MEMORY (lpszTemp);
  754. }
  755. return FALSE;
  756. }
  757. if (lpszTemp)
  758. {
  759. // Back up the undecorated URL as the primary cache key.
  760. _xsPrimaryCacheKey.SetPtr (&_CacheUrlName);
  761. INET_ASSERT (!_CacheUrlName);
  762. _CacheUrlName = lpszTemp;
  763. }
  764. return TRUE;
  765. }
  766. void INTERNET_CONNECT_HANDLE_OBJECT::FreeSecondaryCacheKey (void)
  767. {
  768. if (_xsSecondaryCacheKey.GetPtr()) {
  769. // Free the secondary key and the decorated URL.
  770. _xsSecondaryCacheKey.Free();
  771. FreeURL();
  772. // Back up the cache key from the undecorated URL.
  773. LPSTR lpszOld = _xsPrimaryCacheKey.ClearPtr();
  774. _CacheUrlName = lpszOld;
  775. }
  776. }
  777. HINTERNET
  778. INTERNET_CONNECT_HANDLE_OBJECT::GetHandle(
  779. VOID
  780. )
  781. {
  782. return _InternetConnectHandle;
  783. }
  784. //
  785. // Cache methods.
  786. //
  787. char* back_up(char* stopper, char* ptr) {
  788. INET_ASSERT(stopper <= ptr);
  789. while ((*ptr != '/') && (ptr >= stopper)) --ptr;
  790. return ((ptr >= stopper) && (*ptr == '/')) ? ptr : NULL;
  791. }
  792. char* convert_macros(char* path) {
  793. char* ls = NULL; // last slash
  794. char* pls = NULL; // previous last slash
  795. char* p = path;
  796. while (*p) {
  797. if (*p == '/') {
  798. pls = ls;
  799. ls = p;
  800. }
  801. if (*p == '.') {
  802. if (*(p + 1) == '/') {
  803. p = lstrcpy(ls, p + 1);
  804. } else if (*(p + 1) == '\0') {
  805. if (*(p - 1) == '/') {
  806. *p = '\0';
  807. }
  808. } else if (!strncmp(p, "../", 3)) {
  809. if ((!pls) || (ls != p - 1)) {
  810. return NULL;
  811. }
  812. p = lstrcpy(pls, p + 2);
  813. ls = pls;
  814. pls = back_up(path, max(path, pls - 1));
  815. } else if (!lstrcmp(p, "..")) {
  816. if ((*(p - 1) != '/') || !pls) {
  817. return NULL;
  818. } else {
  819. *(pls + 1) = 0;
  820. p = pls - 1;
  821. }
  822. }
  823. }
  824. ++p;
  825. }
  826. return path;
  827. }
  828. DWORD
  829. INTERNET_CONNECT_HANDLE_OBJECT::SetCurrentWorkingDirectory(
  830. IN LPSTR lpszCWD
  831. )
  832. {
  833. INET_ASSERT(lpszCWD != NULL);
  834. //
  835. // BUGBUG - we assume lpszCWD is clean which might not be true....
  836. //
  837. int clen;
  838. int slen;
  839. LPSTR cwd;
  840. if (*lpszCWD == '/') {
  841. cwd = NULL;
  842. ++lpszCWD;
  843. } else {
  844. cwd = _CacheCWD;
  845. }
  846. if (!cwd) {
  847. clen = 1;
  848. } else {
  849. clen = lstrlen(cwd);
  850. }
  851. slen = lstrlen(lpszCWD);
  852. LPSTR buffer = (LPSTR)ALLOCATE_FIXED_MEMORY(clen + 1 + slen + 1);
  853. if (buffer == NULL) {
  854. return ERROR_NOT_ENOUGH_MEMORY;
  855. }
  856. if (clen == 1) {
  857. buffer[0] = '/';
  858. } else {
  859. memcpy(buffer, _CacheCWD, clen);
  860. }
  861. memcpy(&buffer[clen], lpszCWD, slen);
  862. clen += slen;
  863. if ((clen > 1) && (lpszCWD[slen - 1] != '/')) {
  864. buffer[clen++] = '/';
  865. }
  866. buffer[clen] = '\0';
  867. LPSTR p = convert_macros(buffer);
  868. if (p) {
  869. if (_CacheCWD != NULL) {
  870. FREE_MEMORY(_CacheCWD);
  871. _CacheCWD = NULL;
  872. }
  873. _CacheCWD = NewString(p);
  874. }
  875. FREE_MEMORY(buffer);
  876. return (p == NULL) ? ERROR_INVALID_PARAMETER : ERROR_SUCCESS;
  877. }
  878. DWORD
  879. INTERNET_CONNECT_HANDLE_OBJECT::GetCurrentWorkingDirectory(
  880. LPSTR lpszCWD,
  881. LPDWORD lpdwLen
  882. )
  883. {
  884. DWORD dwlenCWD;
  885. if (!_CacheCWD) {
  886. *lpdwLen = 0;
  887. }
  888. else {
  889. // do something if the guy gave us any buffer
  890. if (*lpdwLen) {
  891. dwlenCWD = lstrlen(_CacheCWD);
  892. // if the buffer is not enough, copy the size of the buffer
  893. if (dwlenCWD >= *lpdwLen) {
  894. memcpy(lpszCWD, _CacheCWD, *lpdwLen);
  895. }
  896. else {
  897. strcpy(lpszCWD, _CacheCWD);
  898. *lpdwLen = dwlenCWD;
  899. }
  900. }
  901. }
  902. return (ERROR_SUCCESS);
  903. }
  904. DWORD
  905. INTERNET_CONNECT_HANDLE_OBJECT::SetObjectName(
  906. LPSTR lpszObjectName,
  907. LPSTR lpszExtension,
  908. URLGEN_FUNC * procProtocolUrl
  909. )
  910. {
  911. DWORD dwLen, dwError;
  912. INTERNET_SCHEME schemeType;
  913. // BUGBUG move this to protocol specific object
  914. //
  915. // if there is already an object name, then free it. We are replacing it
  916. //
  917. //
  918. // BUGBUG - make _CacheUrlString an ICSTRING
  919. //
  920. FreeURL();
  921. //
  922. // get protocol specific url
  923. //
  924. if (procProtocolUrl) {
  925. //
  926. // if we are going via proxy AND this is an FTP object AND the user name
  927. // consists of <username>@<servername> then <servername> is the real
  928. // server name, and _HostName is the name of the proxy
  929. //
  930. //
  931. // BUGBUG - this is a bit of a hack(!)
  932. //
  933. LPSTR target = _HostName.StringAddress();
  934. if (IsProxy()
  935. && (GetSchemeType() == INTERNET_SCHEME_FTP)
  936. && (_pwcServerCreds && _pwcServerCreds->lpszUser)) {
  937. LPSTR at = strchr(_pwcServerCreds->lpszUser, '@');
  938. if (at != NULL) {
  939. target = at + 1;
  940. INET_ASSERT(*target);
  941. }
  942. }
  943. schemeType = GetSchemeType();
  944. // make the scheme type https if necessary
  945. schemeType = (((schemeType == INTERNET_SCHEME_DEFAULT)||
  946. (schemeType == INTERNET_SCHEME_HTTP)) &&
  947. (_dwCacheFlags & INTERNET_FLAG_SECURE))?
  948. INTERNET_SCHEME_HTTPS: schemeType;
  949. LPSTR lpszNewUrl = NULL;
  950. dwError = (*procProtocolUrl)(schemeType,
  951. target,
  952. _CacheCWD,
  953. lpszObjectName,
  954. lpszExtension,
  955. _HostPort,
  956. &lpszNewUrl,
  957. &dwLen
  958. );
  959. if (dwError == ERROR_SUCCESS) {
  960. if (!SetURLPtr (&lpszNewUrl)) {
  961. FREE_MEMORY (lpszNewUrl);
  962. dwError = ERROR_NOT_ENOUGH_MEMORY;
  963. }
  964. }
  965. }
  966. else
  967. {
  968. dwError = ERROR_INVALID_PARAMETER;
  969. }
  970. if (dwError == ERROR_SUCCESS) {
  971. DEBUG_PRINT(HANDLE,
  972. INFO,
  973. ("Url: %s\n",
  974. _CacheUrlName
  975. ));
  976. }
  977. return dwError;
  978. }
  979. DWORD
  980. INTERNET_CONNECT_HANDLE_OBJECT::BeginCacheRetrieval(
  981. LPCACHE_ENTRY_INFO *lplpCacheEntryInfo
  982. )
  983. {
  984. DEBUG_ENTER((DBG_CACHE,
  985. Dword,
  986. "INTERNET_CONNECT_HANDLE_OBJECT::BeginCacheRetrieval",
  987. "{%q} %#x",
  988. _CacheUrlName,
  989. lplpCacheEntryInfo
  990. ));
  991. DWORD Error = ERROR_NOT_SUPPORTED;
  992. DWORD dwBufferSize = 0;
  993. int i;
  994. INET_ASSERT( _CacheReadInProgress == FALSE );
  995. INET_ASSERT( _CacheWriteInProgress == FALSE );
  996. //INET_ASSERT( _CacheFileName == NULL );
  997. INET_ASSERT( _CacheFileHandle == INVALID_HANDLE_VALUE );
  998. INET_ASSERT( _hCacheStream == NULL);
  999. *lplpCacheEntryInfo = NULL;
  1000. if (!_CacheUrlName) {
  1001. DEBUG_PRINT(CACHE,
  1002. ERROR,
  1003. ("Cache: No UrlName\n"
  1004. ));
  1005. DEBUG_LEAVE(ERROR_INVALID_PARAMETER);
  1006. return (ERROR_INVALID_PARAMETER);
  1007. }
  1008. dwBufferSize = sizeof(CACHE_ENTRY_INFO) + DEFAULT_VARIABLE_CACHE_INFO_SIZE;
  1009. for (i=0; i<2; ++i) {
  1010. if (*lplpCacheEntryInfo != NULL) {
  1011. FREE_MEMORY(*lplpCacheEntryInfo);
  1012. }
  1013. *lplpCacheEntryInfo = (LPCACHE_ENTRY_INFO)ALLOCATE_MEMORY(
  1014. LPTR
  1015. , dwBufferSize);
  1016. if (*lplpCacheEntryInfo) {
  1017. _hCacheStream = RetrieveUrlCacheEntryStream( _CacheUrlName,
  1018. *lplpCacheEntryInfo,
  1019. &dwBufferSize,
  1020. FALSE, // Not Random, sequential
  1021. 0);
  1022. if (_hCacheStream == NULL) {
  1023. //
  1024. // second time around the buffer must be sufficient
  1025. //
  1026. INET_ASSERT(!((i == 1) && (Error == ERROR_INSUFFICIENT_BUFFER)));
  1027. Error = GetLastError();
  1028. if ((i == 1) || (Error != ERROR_INSUFFICIENT_BUFFER)) {
  1029. goto Cleanup;
  1030. }
  1031. } else {
  1032. break; // success
  1033. }
  1034. }
  1035. }
  1036. Error = RecordCacheRetrieval (*lplpCacheEntryInfo);
  1037. Cleanup:
  1038. if( Error != ERROR_SUCCESS ) {
  1039. if (*lplpCacheEntryInfo) {
  1040. FREE_MEMORY(*lplpCacheEntryInfo);
  1041. *lplpCacheEntryInfo = NULL;
  1042. }
  1043. FreeCacheFileName();
  1044. }
  1045. DEBUG_LEAVE(Error);
  1046. return( Error );
  1047. }
  1048. DWORD INTERNET_CONNECT_HANDLE_OBJECT::RecordCacheRetrieval
  1049. (LPCACHE_ENTRY_INFO lpCacheEntryInfo)
  1050. {
  1051. //
  1052. // save cache file name.
  1053. //
  1054. FreeCacheFileName();
  1055. INET_ASSERT(!_CacheFileName);
  1056. _CacheFileName = NewString((lpCacheEntryInfo)->lpszLocalFileName);
  1057. if (!_CacheFileName) {
  1058. return ERROR_NOT_ENOUGH_MEMORY;
  1059. }
  1060. _dwStreamRefCount = 0;
  1061. _dwCurrentStreamPosition = 0;
  1062. //
  1063. // we have this much data immediately available to the application
  1064. //
  1065. SetAvailableDataLength((lpCacheEntryInfo)->dwSizeLow);
  1066. //
  1067. // and we automatically have the end-of-file indication
  1068. //
  1069. SetEndOfFile();
  1070. _CacheReadInProgress = TRUE;
  1071. return ERROR_SUCCESS;
  1072. }
  1073. DWORD
  1074. INTERNET_CONNECT_HANDLE_OBJECT::ReadCache(
  1075. LPBYTE lpbBuffer,
  1076. DWORD dwBufferLen,
  1077. LPDWORD lpdwBytesRead
  1078. )
  1079. {
  1080. DWORD dwError = ERROR_NOT_SUPPORTED;
  1081. BOOL fOk;
  1082. INET_ASSERT( _CacheReadInProgress == TRUE );
  1083. *lpdwBytesRead = dwBufferLen;
  1084. fOk = ReadUrlCacheEntryStream(
  1085. _hCacheStream,
  1086. _dwCurrentStreamPosition,
  1087. lpbBuffer,
  1088. lpdwBytesRead,
  1089. 0);
  1090. if (fOk) {
  1091. _dwCurrentStreamPosition += *lpdwBytesRead;
  1092. }
  1093. if( !fOk ) {
  1094. dwError = GetLastError() ;
  1095. }
  1096. else {
  1097. dwError = ERROR_SUCCESS;
  1098. DEBUG_PRINT(CACHE,
  1099. INFO,
  1100. ("read %d bytes from cache\n",
  1101. *lpdwBytesRead
  1102. ));
  1103. }
  1104. return(dwError);
  1105. }
  1106. DWORD
  1107. INTERNET_CONNECT_HANDLE_OBJECT::EndCacheRetrieval(
  1108. VOID
  1109. )
  1110. {
  1111. DEBUG_ENTER((DBG_CACHE,
  1112. Dword,
  1113. "EndCacheRetrieval",
  1114. "Url=%s, File=%s",
  1115. _CacheUrlName, _CacheFileName
  1116. ));
  1117. DWORD Error = ERROR_SUCCESS;
  1118. INET_ASSERT( _CacheUrlName != NULL );
  1119. INET_ASSERT( _CacheReadInProgress == TRUE );
  1120. INET_ASSERT( _CacheWriteInProgress == FALSE );
  1121. INET_ASSERT(_hCacheStream != NULL);
  1122. if (!_dwStreamRefCount) { // if the caller obtained it using GetCacheStream
  1123. // then it is his responsibility to call
  1124. // UnlockCacheStream
  1125. DEBUG_PRINT(CACHE,
  1126. INFO,
  1127. ("Wininet.EndCacheRetrieval: Calling UnlockUrlCacheEntryStream for %s\n",
  1128. _CacheUrlName
  1129. ));
  1130. if (!UnlockUrlCacheEntryStream(_hCacheStream, 0)) {
  1131. Error = GetLastError();
  1132. }
  1133. }
  1134. if (Error == ERROR_SUCCESS) {
  1135. _CacheReadInProgress = FALSE;
  1136. _hCacheStream = NULL;
  1137. _dwCurrentStreamPosition = 0;
  1138. _dwStreamRefCount = 0;
  1139. }
  1140. DEBUG_LEAVE(Error);
  1141. return( Error );
  1142. }
  1143. DWORD
  1144. INTERNET_CONNECT_HANDLE_OBJECT::LazyUpdate()
  1145. {
  1146. DWORD dwError = ERROR_INTERNET_INTERNAL_ERROR;
  1147. INET_ASSERT(_CacheUrlName);
  1148. dwError = CreateAndQueueBackgroundWorkItem(_CacheUrlName);
  1149. return dwError;
  1150. }
  1151. DWORD
  1152. INTERNET_CONNECT_HANDLE_OBJECT::GetCacheStream(
  1153. LPBYTE lpBuffer,
  1154. DWORD dwLen
  1155. )
  1156. {
  1157. DWORD dwError = ERROR_INVALID_FUNCTION;
  1158. if (_CacheReadInProgress) {
  1159. if (dwLen > sizeof(_hCacheStream)) {
  1160. ++_dwStreamRefCount;
  1161. *(HANDLE *)lpBuffer = _hCacheStream;
  1162. dwError = ERROR_SUCCESS;
  1163. }
  1164. else {
  1165. dwError = ERROR_INSUFFICIENT_BUFFER;
  1166. }
  1167. }
  1168. return (dwError);
  1169. }
  1170. DWORD
  1171. INTERNET_CONNECT_HANDLE_OBJECT::ReleaseCacheStream(
  1172. HANDLE hStream
  1173. )
  1174. {
  1175. DWORD dwError = ERROR_INVALID_FUNCTION;
  1176. if (_CacheReadInProgress) {
  1177. if (_hCacheStream == hStream) {
  1178. --_dwStreamRefCount;
  1179. dwError = ERROR_SUCCESS;
  1180. }
  1181. else {
  1182. dwError = ERROR_INVALID_PARAMETER;
  1183. }
  1184. }
  1185. return (dwError);
  1186. }
  1187. DWORD
  1188. INTERNET_CONNECT_HANDLE_OBJECT::BeginCacheWrite(
  1189. DWORD dwExpectedLength,
  1190. LPCSTR lpszFileExtension,
  1191. LPCSTR lpszFileName
  1192. )
  1193. {
  1194. DEBUG_ENTER((DBG_CACHE,
  1195. Dword,
  1196. "BeginCacheWrite",
  1197. "%d, %q",
  1198. dwExpectedLength,
  1199. lpszFileExtension
  1200. ));
  1201. DWORD Error=ERROR_NOT_SUPPORTED;
  1202. CHAR FileName[MAX_PATH];
  1203. CHAR* pFileName;
  1204. // BUGBUG uncode version needs to be fixed
  1205. INET_ASSERT( _CacheReadInProgress == FALSE );
  1206. INET_ASSERT( _CacheWriteInProgress == FALSE );
  1207. FreeCacheFileName(); // may be left over from Begin/EndCacheRetrieval
  1208. // in case of ftp/gopher dir raw/html mismatch
  1209. INET_ASSERT( _CacheFileHandle == INVALID_HANDLE_VALUE);
  1210. if (!_CacheUrlName) {
  1211. DEBUG_PRINT(CACHE,
  1212. ERROR,
  1213. ("Invalid parameter\n"
  1214. ));
  1215. DEBUG_LEAVE(ERROR_INVALID_PARAMETER);
  1216. return (ERROR_INVALID_PARAMETER);
  1217. }
  1218. // lpszFileName passed in indicates that
  1219. // we want to create a filename from scratch.
  1220. if (!lpszFileName)
  1221. {
  1222. *FileName = '\0';
  1223. pFileName = FileName;
  1224. }
  1225. // Otherwise, attempt to use the filename passed in.
  1226. else
  1227. pFileName = (CHAR*) lpszFileName;
  1228. // Create the cache file.
  1229. Error = UrlCacheCreateFile(
  1230. _CacheUrlName,
  1231. (CHAR*) lpszFileExtension,
  1232. pFileName,
  1233. &_CacheFileHandle,
  1234. IsPerUserItem());
  1235. if (Error != ERROR_SUCCESS)
  1236. {
  1237. DEBUG_PRINT(CACHE,
  1238. ERROR,
  1239. ("Cache: Error %ld createurlcacheentry failed for %s\n",
  1240. Error,
  1241. _CacheUrlName
  1242. ));
  1243. DEBUG_LEAVE(Error);
  1244. return( Error); // BUGBUG refine this error
  1245. } else IF_DEBUG(CACHE) {
  1246. DEBUG_PRINT(CACHE, INFO, ("cache filename = %q\n", pFileName));
  1247. }
  1248. //dprintf("caching %s (%s) in %s\n", _CacheUrlName, _OriginalUrl, FileName);
  1249. //
  1250. // save names.
  1251. //
  1252. INET_ASSERT(!_CacheFileName);
  1253. _CacheFileName = NewString(pFileName);
  1254. if (!_CacheFileName) {
  1255. Error = ERROR_NOT_ENOUGH_MEMORY;
  1256. goto Cleanup;
  1257. }
  1258. Error = ERROR_SUCCESS;
  1259. INET_ASSERT(_CacheFileHandle != INVALID_HANDLE_VALUE);
  1260. _CacheWriteInProgress = TRUE;
  1261. Error = ERROR_SUCCESS;
  1262. Cleanup:
  1263. if( Error != ERROR_SUCCESS ) {
  1264. if( _CacheFileHandle != INVALID_HANDLE_VALUE ) {
  1265. CloseHandle( _CacheFileHandle );
  1266. _CacheFileHandle = INVALID_HANDLE_VALUE;
  1267. }
  1268. FreeCacheFileName();
  1269. //
  1270. // delete file temp file
  1271. //
  1272. BOOL BoolError;
  1273. BoolError = DeleteFile( pFileName );
  1274. INET_ASSERT( BoolError == TRUE );
  1275. }
  1276. DEBUG_LEAVE(Error);
  1277. return( Error );
  1278. }
  1279. DWORD
  1280. INTERNET_CONNECT_HANDLE_OBJECT::WriteCache(
  1281. LPBYTE Buffer,
  1282. DWORD BufferLen
  1283. )
  1284. {
  1285. DWORD dwError = ERROR_NOT_SUPPORTED;
  1286. DWORD dwSize, dwUsed, dwRemain;
  1287. BOOL fWriteToDisk = TRUE;
  1288. DWORD BytesWritten;
  1289. INET_ASSERT( _CacheWriteInProgress == TRUE );
  1290. /*
  1291. DEBUG_PRINT( CACHE, INFO,
  1292. ("Writecache: _virtualCacheFileSize=%d, realfilesize= %d, inputsize=%d\n",
  1293. _VirtualCacheFileSize, _RealCacheFileSize, BufferLen));
  1294. */
  1295. #ifdef LAZY_WRITE
  1296. LPBYTE lpScratch, lpBuffer;
  1297. if (_dwCacheFlags & INTERNET_FLAG_NEED_FILE) {
  1298. lpScratch = GetCacheScratchBuf(&dwSize, &dwUsed);
  1299. if (lpScratch) {
  1300. // don't do default writes to disk
  1301. fWriteToDisk = FALSE;
  1302. lpBuffer = Buffer;
  1303. dwRemain = BufferLen;
  1304. INET_ASSERT(dwSize >= dwUsed);
  1305. while ((dwUsed+dwRemain) >= dwSize) {
  1306. DEBUG_PRINT( CACHE, INFO,
  1307. ("remaining=%d\n",
  1308. dwRemain));
  1309. // Fill the buffer to the brim
  1310. CopyToScratch(lpBuffer, (dwSize-dwUsed));
  1311. lpBuffer += (dwSize-dwUsed);
  1312. dwRemain -= (dwSize-dwUsed);
  1313. // and write it out
  1314. dwError = WriteToDisk(lpScratch, dwSize, &BytesWritten);
  1315. if( dwError != ERROR_SUCCESS ) {
  1316. goto bailout;
  1317. }
  1318. INET_ASSERT( BytesWritten == dwSize );
  1319. //mark the buffer as empty
  1320. ResetScratchUseSize();
  1321. // get it's location and new used size
  1322. lpScratch = GetCacheScratchBuf(NULL, &dwUsed);
  1323. INET_ASSERT(dwUsed == 0);
  1324. }
  1325. // if anything remain after our disk-writing frenzy
  1326. // then keep it in the buffer
  1327. if (dwRemain) {
  1328. CopyToScratch(lpBuffer, dwRemain);
  1329. }
  1330. }
  1331. }
  1332. #endif //LAZY_WRITE
  1333. if (fWriteToDisk){
  1334. // DEBUG_PRINT( CACHE, INFO, ("no lazy write, flushing to disk\n"));
  1335. dwError = WriteToDisk(Buffer, BufferLen, &BytesWritten);
  1336. if( dwError != ERROR_SUCCESS ) {
  1337. goto bailout;
  1338. }
  1339. INET_ASSERT( BytesWritten == BufferLen );
  1340. }
  1341. _VirtualCacheFileSize += BufferLen;
  1342. #ifdef LAZY_WRITE
  1343. INET_ASSERT(_VirtualCacheFileSize == (_RealCacheFileSize+_CacheScratchUsedLen));
  1344. #else
  1345. INET_ASSERT(_VirtualCacheFileSize == (_RealCacheFileSize));
  1346. #endif
  1347. dwError = ERROR_SUCCESS;
  1348. bailout:
  1349. DEBUG_PRINT( CACHE, INFO,
  1350. ("WriteCache: _CacheFileSize=%d, inputsize=%d, dwError=%d\n",
  1351. _VirtualCacheFileSize, BufferLen, dwError));
  1352. return (dwError);
  1353. }
  1354. DWORD
  1355. INTERNET_CONNECT_HANDLE_OBJECT::WriteToDisk(
  1356. LPBYTE Buffer,
  1357. DWORD BufferLen,
  1358. LPDWORD lpdwBytesWritten
  1359. )
  1360. {
  1361. BOOL BoolError;
  1362. BoolError = WriteFile(
  1363. _CacheFileHandle,
  1364. Buffer,
  1365. BufferLen,
  1366. lpdwBytesWritten,
  1367. NULL );
  1368. if( !BoolError ) {
  1369. return( GetLastError() );
  1370. }
  1371. _RealCacheFileSize += *lpdwBytesWritten;
  1372. return (ERROR_SUCCESS);
  1373. }
  1374. DWORD
  1375. INTERNET_CONNECT_HANDLE_OBJECT::EndCacheWrite(
  1376. FILETIME *lpftExpireTime,
  1377. FILETIME *lpftLastModifiedTime,
  1378. FILETIME *lpftPostCheckTime,
  1379. DWORD dwCacheEntryType,
  1380. DWORD dwHeaderLen,
  1381. LPSTR lpHeaderInfo,
  1382. LPSTR lpszFileExtension,
  1383. BOOL fImage
  1384. )
  1385. {
  1386. LPBYTE lpBuff;
  1387. DWORD dwBytesWritten, dwUsed;
  1388. FILETIME ftCreate;
  1389. DEBUG_ENTER((DBG_CACHE,
  1390. Dword,
  1391. "INTERNET_CONNECT_HANDLE_OBJECT::EndCacheWrite",
  1392. "{%q} %#x, %#x,, %#x, %d, %d, %.32q",
  1393. _CacheUrlName,
  1394. lpftExpireTime,
  1395. lpftLastModifiedTime,
  1396. lpftPostCheckTime,
  1397. dwCacheEntryType,
  1398. dwHeaderLen,
  1399. lpHeaderInfo
  1400. ));
  1401. DWORD Error = ERROR_NOT_SUPPORTED;
  1402. INET_ASSERT( _CacheUrlName != NULL );
  1403. INET_ASSERT( _CacheFileName != NULL );
  1404. INET_ASSERT( _CacheReadInProgress == FALSE );
  1405. INET_ASSERT( _CacheWriteInProgress == TRUE );
  1406. INET_ASSERT( _CacheFileHandle != INVALID_HANDLE_VALUE );
  1407. //
  1408. // close the file.
  1409. //
  1410. if( _CacheFileHandle != INVALID_HANDLE_VALUE ) {
  1411. GetFileTime( _CacheFileHandle, &ftCreate, NULL, NULL );
  1412. CloseHandle( _CacheFileHandle );
  1413. _CacheFileHandle = INVALID_HANDLE_VALUE;
  1414. } else {
  1415. DEBUG_PRINT(CACHE,
  1416. ERROR,
  1417. ("_CacheFileHandle = %x\n",
  1418. _CacheFileHandle
  1419. ));
  1420. }
  1421. if( _CacheFileHandleRead != INVALID_HANDLE_VALUE ) {
  1422. CloseHandle( _CacheFileHandleRead );
  1423. _CacheFileHandleRead = INVALID_HANDLE_VALUE;
  1424. }
  1425. //
  1426. // Cache the file.
  1427. //
  1428. if( (_CacheUrlName != NULL) && (_CacheFileName != NULL) ) {
  1429. //
  1430. // if the cache file is successfully made, cache it, otherwise
  1431. // mark it for deletion.
  1432. //
  1433. if( dwCacheEntryType == 0xffffffff ) {
  1434. _fDeleteDataFile = TRUE;
  1435. }
  1436. if (!_fDeleteDataFile)
  1437. {
  1438. if (((GetHandleType() == TypeFtpConnectHandle) ||
  1439. (GetHandleType() == TypeFtpFileHandle) ||
  1440. (GetHandleType() == TypeFtpFileHandleHtml))
  1441. && IsPerUserItem())
  1442. {
  1443. char buff[256];
  1444. DEBUG_PRINT(CACHE,
  1445. INFO,
  1446. ("EndCacheWrite():FTP:PerUserItem = TRUE\n")
  1447. //("EndCacheWrite():PerUserItem = TRUE: <pConnect = 0x%x>.\n",pConnect)
  1448. );
  1449. INET_ASSERT(vdwCurrentUserLen);
  1450. // Store the total length to get copied to the args for AddUrl
  1451. dwHeaderLen = sizeof(vszUserNameHeader) - 1
  1452. + vdwCurrentUserLen
  1453. + sizeof("\r\n");
  1454. if (sizeof(buff) >= dwHeaderLen)
  1455. {
  1456. memcpy(buff, vszUserNameHeader, sizeof(vszUserNameHeader) - 1);
  1457. DWORD dwSize = lstrlen(vszCurrentUser);
  1458. memcpy(&buff[sizeof(vszUserNameHeader) - 1],
  1459. vszCurrentUser,
  1460. dwSize);
  1461. dwSize += sizeof(vszUserNameHeader) - 1;
  1462. memcpy(&buff[dwSize], "\r\n", sizeof("\r\n"));
  1463. // Copy over to lpHeaderInfo which gets copied into the args for AddUrl
  1464. lpHeaderInfo = buff;
  1465. DEBUG_PRINT(CACHE,
  1466. INFO,
  1467. ("EndCacheWrite():FTP: lpHeaderInfo = %q dwHeaderLen = %d\n",
  1468. lpHeaderInfo, dwHeaderLen)
  1469. );
  1470. }
  1471. else
  1472. {
  1473. // if it failed, mark it as expired
  1474. /*
  1475. dwUserNameHeader = 0;
  1476. GetCurrentGmtTime(&_ftExpires);
  1477. *(LONGLONG *)&_ftExpires -= ONE_HOUR_DELTA;
  1478. */ }
  1479. }
  1480. else
  1481. {
  1482. DEBUG_PRINT(CACHE,
  1483. INFO,
  1484. ("EndCacheWrite():FTP:PerUserItem = FALSE\n")
  1485. );
  1486. }
  1487. AddUrlArg Args;
  1488. memset(&Args, 0, sizeof(Args));
  1489. Args.pszUrl = _CacheUrlName;
  1490. Args.pszFilePath = _CacheFileName;
  1491. Args.dwFileSize = _RealCacheFileSize;
  1492. Args.qwExpires = *((LONGLONG*)lpftExpireTime);
  1493. Args.qwLastMod = *((LONGLONG*)lpftLastModifiedTime);
  1494. Args.qwPostCheck = *((LONGLONG*)lpftPostCheckTime);
  1495. Args.ftCreate = ftCreate;
  1496. Args.dwEntryType = dwCacheEntryType;
  1497. Args.pbHeaders = lpHeaderInfo;
  1498. Args.cbHeaders = dwHeaderLen;
  1499. Args.pszFileExt = lpszFileExtension;
  1500. Args.pszRedirect = _OriginalUrl;
  1501. Args.fImage = fImage;
  1502. Args.dwIdentity = IsPerUserItem() ? GlobalIdentity : 0;
  1503. Error = UrlCacheCommitFile(&Args);
  1504. if (Error != ERROR_SUCCESS)
  1505. {
  1506. DEBUG_PRINT(CACHE,
  1507. ERROR,
  1508. ("CommitUrlCacheEntry(%q) failed\n",
  1509. _CacheUrlName
  1510. ));
  1511. _fDeleteDataFile = TRUE;
  1512. if (Error == ERROR_SHARING_VIOLATION) {
  1513. // we got new URL data, but the old one is in use.
  1514. // expire it, so any new user's will go to the net
  1515. ExpireUrl();
  1516. }
  1517. }
  1518. }
  1519. }
  1520. _CacheWriteInProgress = FALSE;
  1521. DEBUG_LEAVE(Error);
  1522. return( Error );
  1523. }
  1524. BOOL
  1525. INTERNET_CONNECT_HANDLE_OBJECT::ExpireDependents(VOID
  1526. )
  1527. {
  1528. char szUrlParent[INTERNET_MAX_URL_LENGTH];
  1529. BOOL fRet = FALSE;
  1530. ExpireUrl();
  1531. if (GetCanonicalizedParentUrl( _CacheUrlName,
  1532. szUrlParent,
  1533. sizeof(szUrlParent))){
  1534. ExpireUrl(szUrlParent);
  1535. fRet = TRUE;
  1536. }
  1537. return(fRet);
  1538. }
  1539. #ifdef LAZY_WRITE
  1540. LPBYTE
  1541. INTERNET_CONNECT_HANDLE_OBJECT::GetCacheScratchBuf(
  1542. LPDWORD Length, LPDWORD lpdwUsed
  1543. )
  1544. /*++
  1545. Routine Description:
  1546. Get existing scratch buffer for use.
  1547. Arguments:
  1548. Length : pointer to a location where the buffer length is returned.
  1549. Return Value:
  1550. return scratch buffer pointer.
  1551. --*/
  1552. {
  1553. //
  1554. // no one else is using this buffer.
  1555. //
  1556. if(( _CacheScratchBuf != NULL )||(Length==NULL)) {
  1557. INET_ASSERT(!((_CacheScratchBuf == NULL)&&(_CacheScratchUsedLen != 0)));
  1558. if (Length) {
  1559. *Length = _CacheScratchBufLen;
  1560. }
  1561. *lpdwUsed = _CacheScratchUsedLen;
  1562. return( _CacheScratchBuf );
  1563. }
  1564. INET_ASSERT( _CacheScratchBufLen == 0 );
  1565. //
  1566. // create a default buffer.
  1567. //
  1568. *lpdwUsed = _CacheScratchUsedLen = 0;
  1569. _CacheScratchBufLen = dwCacheWriteBufferSize; // default size;
  1570. INET_ASSERT(dwCacheWriteBufferSize >= 4096);
  1571. _CacheScratchBuf = (LPBYTE)ALLOCATE_MEMORY(LMEM_FIXED | LMEM_ZEROINIT,
  1572. _CacheScratchBufLen
  1573. );
  1574. if( _CacheScratchBuf == NULL ) {
  1575. //
  1576. // we couldn't make one.
  1577. //
  1578. _CacheScratchBufLen = 0;
  1579. *Length = 0;
  1580. return( NULL );
  1581. }
  1582. *Length = _CacheScratchBufLen;
  1583. return( _CacheScratchBuf );
  1584. }
  1585. #endif // LAZY_WRITE
  1586. BOOL
  1587. GetCanonicalizedParentUrl(
  1588. LPSTR lpszChildUrl,
  1589. LPSTR lpszParentUrlBuff,
  1590. DWORD dwBuffSize)
  1591. {
  1592. char szUrlT[INTERNET_MAX_URL_LENGTH];
  1593. LPSTR lpT;
  1594. BOOL fRet = FALSE;
  1595. DWORD dwT = dwBuffSize;
  1596. if(lstrlen(lpszChildUrl) >= sizeof(szUrlT) / sizeof(szUrlT[0]))
  1597. {
  1598. INET_ASSERT(FALSE);
  1599. return FALSE;
  1600. }
  1601. lstrcpy(szUrlT, lpszChildUrl);
  1602. lpT = szUrlT+lstrlen(szUrlT);
  1603. if ( lpT > szUrlT ) {
  1604. --lpT;
  1605. if (*lpT == '/') {
  1606. --lpT;
  1607. }
  1608. for(; lpT >= szUrlT; --lpT){
  1609. if (*lpT == '/') {
  1610. *(lpT+1) = 0;
  1611. if(InternetCanonicalizeUrl(szUrlT, lpszParentUrlBuff, &dwT, 0)) {
  1612. fRet = TRUE;
  1613. }
  1614. goto done;
  1615. }
  1616. }
  1617. }
  1618. done:
  1619. return (fRet);
  1620. }
  1621. VOID
  1622. INTERNET_CONNECT_HANDLE_OBJECT::AttachLastResponseInfo(
  1623. VOID
  1624. )
  1625. /*++
  1626. Routine Description:
  1627. Called when we are performing an FTP URL operation & we want to display
  1628. the welcome message contained in the last response info as part of the
  1629. generated HTML. We need to keep hold of it in this object in case the
  1630. app calls an API which wipes out the last response info before getting
  1631. the HTML data
  1632. Arguments:
  1633. None.
  1634. Return Value:
  1635. None.
  1636. --*/
  1637. {
  1638. LPSTR buffer = NULL;
  1639. DWORD bufferLength = 0;
  1640. DWORD category;
  1641. BOOL ok = InternetGetLastResponseInfo(&category,
  1642. buffer,
  1643. &bufferLength
  1644. );
  1645. if (!ok && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  1646. buffer = (LPSTR)ResizeBuffer(NULL, bufferLength, FALSE);
  1647. if (buffer != NULL) {
  1648. ok = InternetGetLastResponseInfo(&category,
  1649. buffer,
  1650. &bufferLength
  1651. );
  1652. if (ok) {
  1653. SetLastResponseInfo(buffer, bufferLength);
  1654. } else {
  1655. (void)ResizeBuffer((HLOCAL)buffer, 0, FALSE);
  1656. }
  1657. }
  1658. }
  1659. }
  1660. VOID
  1661. INTERNET_CONNECT_HANDLE_OBJECT::SetOriginServer(
  1662. IN CServerInfo * pServerInfo,
  1663. IN BOOL fForceUpdate /* = FALSE */
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. description-of-function.
  1668. Arguments:
  1669. pServerInfo -
  1670. Return Value:
  1671. None.
  1672. --*/
  1673. {
  1674. DEBUG_ENTER((DBG_OBJECTS,
  1675. None,
  1676. "INTERNET_CONNECT_HANDLE_OBJECT::SetOriginServer",
  1677. "%#x{%q}",
  1678. pServerInfo,
  1679. pServerInfo ? pServerInfo->GetHostName() : ""
  1680. ));
  1681. if (_OriginServer == NULL || fForceUpdate) {
  1682. if (_OriginServer) {
  1683. _OriginServer->Dereference();
  1684. }
  1685. _OriginServer = pServerInfo;
  1686. if (pServerInfo != NULL) {
  1687. pServerInfo->Reference();
  1688. }
  1689. }
  1690. DEBUG_LEAVE(0);
  1691. }
  1692. DWORD
  1693. INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo(
  1694. IN INTERNET_SCHEME tScheme,
  1695. IN BOOL bDoResolution,
  1696. IN OPTIONAL BOOL fNtlm
  1697. )
  1698. /*++
  1699. Routine Description:
  1700. Associates a SERVER_INFO with this INTERNET_CONNECT_HANDLE_OBJECT based on
  1701. the host name for which this object was created and an optional scheme
  1702. type
  1703. Arguments:
  1704. tScheme - scheme type we want SERVER_INFO for
  1705. bDoResolution - TRUE if we are to resolve the host name if creating a new
  1706. SERVER_INFO object
  1707. fNtlm - TRUE if we are tunnelling for NTLM
  1708. Return Value:
  1709. DWORD
  1710. Success - ERROR_SUCCESS
  1711. Failure - ERROR_NOT_ENOUGH_MEMORY
  1712. --*/
  1713. {
  1714. DEBUG_ENTER((DBG_OBJECTS,
  1715. Dword,
  1716. "INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo",
  1717. "%s (%d), %B, %B",
  1718. InternetMapScheme(tScheme),
  1719. tScheme,
  1720. bDoResolution,
  1721. fNtlm
  1722. ));
  1723. //INTERNET_SCHEME proxyScheme = INTERNET_SCHEME_DEFAULT;
  1724. //INTERNET_HANDLE_OBJECT * lpParent = (INTERNET_HANDLE_OBJECT *)GetParent();
  1725. //
  1726. //INET_ASSERT(lpParent != NULL);
  1727. //
  1728. ////
  1729. //// this may be called from an INTERNET_CONNECT_HANDLE_OBJECT within a
  1730. //// derived handle (HTTP_REQUEST_HANDLE_OBJECT), in which case we need to go
  1731. //// one level higher to the INTERNET_HANDLE_OBJECT
  1732. ////
  1733. //
  1734. //if (lpParent->GetHandleType() != TypeInternetHandle) {
  1735. // lpParent = (INTERNET_HANDLE_OBJECT *)lpParent->GetParent();
  1736. //
  1737. // INET_ASSERT(lpParent != NULL);
  1738. // INET_ASSERT(lpParent->GetHandleType() == TypeInternetHandle);
  1739. //
  1740. //}
  1741. if (_ServerInfo != NULL) {
  1742. ::ReleaseServerInfo(_ServerInfo);
  1743. }
  1744. //
  1745. // use the base service type to find the server info
  1746. //
  1747. //dprintf("getting server info for %q (current = %q)\n", hostName, GetHostName());
  1748. DWORD error = ::GetServerInfo(GetHostName(),
  1749. _ServiceType,
  1750. bDoResolution,
  1751. &_ServerInfo
  1752. );
  1753. ////
  1754. //// if _ServerInfo is NULL then we didn't find a SERVER_INFO and couldn't
  1755. //// create one, therefore we must be out of memory
  1756. ////
  1757. //
  1758. //if (_ServerInfo != NULL) {
  1759. // if (proxyScheme == INTERNET_SCHEME_HTTP) {
  1760. // _ServerInfo->SetCernProxy();
  1761. // } else if (proxyScheme == INTERNET_SCHEME_FTP) {
  1762. // _ServerInfo->SetFTPProxy();
  1763. // }
  1764. //
  1765. // INET_ASSERT(error == ERROR_SUCCESS);
  1766. //
  1767. //} else {
  1768. //
  1769. // INET_ASSERT(error != ERROR_SUCCESS);
  1770. //
  1771. //}
  1772. DEBUG_LEAVE(error);
  1773. return error;
  1774. }
  1775. DWORD
  1776. INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo(
  1777. IN LPSTR lpszServerName,
  1778. IN DWORD dwServerNameLength
  1779. )
  1780. /*++
  1781. Routine Description:
  1782. Associates a SERVER_INFO with this INTERNET_CONNECT_HANDLE_OBJECT based on
  1783. the host name in the parameters
  1784. Arguments:
  1785. lpszServerName - name of server
  1786. dwServerNameLength - length of lpszServerName
  1787. Return Value:
  1788. DWORD
  1789. Success - ERROR_SUCCESS
  1790. Failure - ERROR_NOT_ENOUGH_MEMORY
  1791. --*/
  1792. {
  1793. DEBUG_ENTER((DBG_OBJECTS,
  1794. Dword,
  1795. "INTERNET_CONNECT_HANDLE_OBJECT::SetServerInfo",
  1796. "%q, %d",
  1797. lpszServerName,
  1798. dwServerNameLength
  1799. ));
  1800. if (_ServerInfo != NULL) {
  1801. ::ReleaseServerInfo(_ServerInfo);
  1802. }
  1803. //
  1804. // use the base service type to find the server info
  1805. //
  1806. char hostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  1807. int copyLength = (int)min(sizeof(hostName) - 1, dwServerNameLength);
  1808. memcpy(hostName, lpszServerName, copyLength);
  1809. hostName[copyLength] = '\0';
  1810. DWORD error = ::GetServerInfo(hostName,
  1811. _ServiceType,
  1812. FALSE,
  1813. &_ServerInfo
  1814. );
  1815. DEBUG_LEAVE(error);
  1816. return error;
  1817. }
  1818. BOOL INTERNET_CONNECT_HANDLE_OBJECT::GetUserAndPass (BOOL fProxy, LPSTR *pszUser, LPSTR *pszPass)
  1819. {
  1820. // How the credentials (username + password) are retrieved from handles during
  1821. // authentication (see AuthOnRequest)
  1822. //
  1823. // Connect Request
  1824. // Server 4 <- 3
  1825. // Proxy 2 <- 1
  1826. //
  1827. //
  1828. //
  1829. // When credentials are transferred from the handle to the password cache, they
  1830. // are invalidated on the handle for internal calls from wininet so that they
  1831. // are not inadvertently used therafter. The handle credentials are maintained
  1832. // for external apps which expect these values to be available via InternetQueryOption.
  1833. // When GetUserAndPass is called, if a credential is found on the handle its validity is
  1834. // checked for internal calls. If no credential is found or the credential is no longer
  1835. // valid GetUserAndPass is called recursively on the parent connect handle if it exists.
  1836. //
  1837. // When transferring credentials from a handle to the password cache it is IMPORTANT
  1838. // GetUserAndPass is called to invalidate the credentials. The credentials (both username
  1839. // and password) are re-validated as a pair if either of them is reset via SetUserOrPass.
  1840. if (fProxy)
  1841. {
  1842. // If proxy credentials are valid and exist invalidate and return.
  1843. if (_HandleFlags.fProxyUserPassValid
  1844. && _pwcProxyCreds
  1845. && _pwcProxyCreds->lpszUser
  1846. && _pwcProxyCreds->lpszPass)
  1847. {
  1848. *pszUser = _pwcProxyCreds->GetUser();
  1849. *pszPass = _pwcProxyCreds->GetPass();
  1850. _HandleFlags.fProxyUserPassValid = FALSE;
  1851. return TRUE;
  1852. }
  1853. }
  1854. else
  1855. {
  1856. // If server credentials are valid and exist, invalidate and return.
  1857. if (_HandleFlags.fServerUserPassValid
  1858. && _pwcServerCreds
  1859. && _pwcServerCreds->lpszUser
  1860. && _pwcServerCreds->lpszPass)
  1861. {
  1862. *pszUser = _pwcServerCreds->GetUser();
  1863. *pszPass = _pwcServerCreds->GetPass();
  1864. _HandleFlags.fServerUserPassValid = FALSE;
  1865. return TRUE;
  1866. }
  1867. }
  1868. // Either credentials not found or are invalid on this handle.
  1869. // Walk up to any existing connect handle and repeat call.
  1870. if (GetHandleType() == TypeHttpRequestHandle)
  1871. {
  1872. INTERNET_CONNECT_HANDLE_OBJECT * pConnect =
  1873. (INTERNET_CONNECT_HANDLE_OBJECT *) GetParent();
  1874. return pConnect->GetUserAndPass (fProxy, pszUser, pszPass);
  1875. }
  1876. // Connect handle returns FALSE and null values if none/invalid.
  1877. *pszUser = *pszPass = NULL;
  1878. return FALSE;
  1879. }