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.

6969 lines
195 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. inetapia.cxx
  5. Abstract:
  6. Contains the ANSI and character-mode-independent Internet APIs
  7. Contents:
  8. InternetCrackUrlA
  9. InternetCreateUrlA
  10. InternetCanonicalizeUrlA
  11. InternetCombineUrlA
  12. InternetOpenA
  13. InternetCloseHandle
  14. _InternetCloseHandle
  15. _InternetCloseHandleNoContext
  16. InternetConnectA
  17. InternetOpenUrlA
  18. InternetReadFile
  19. ReadFile_End
  20. InternetReadFileExA
  21. InternetWriteFile
  22. InternetWriteFileExA
  23. InternetSetFilePointer
  24. InternetQueryDataAvailable
  25. InternetFindNextFileA
  26. InternetQueryOptionA
  27. InternetSetOptionA
  28. InternetSetOptionExA
  29. InternetGetLastResponseInfoA
  30. InternetSetStatusCallbackA
  31. //InternetCancelAsyncRequest
  32. (wInternetCloseConnectA)
  33. (GetEmailNameAndPassword)
  34. InternetAttemptConnect
  35. (CreateDeleteSocket)
  36. InternetLockRequestFile
  37. InternetUnlockRequestFile
  38. InternetCheckConnectionA
  39. Author:
  40. Richard L Firth (rfirth) 02-Mar-1995
  41. Environment:
  42. Win32 user-mode DLL
  43. Revision History:
  44. 02-Mar-1995 rfirth
  45. Created
  46. 07-Mar-1995 madana
  47. --*/
  48. #include <wininetp.h>
  49. #include <perfdiag.hxx>
  50. #include "inetapiu.h"
  51. // because wininet doesnt know IStream
  52. #define NO_SHLWAPI_STREAM
  53. #include <shlwapi.h>
  54. #include <shlwapip.h>
  55. #include "autodial.h"
  56. //
  57. // public ..?
  58. //
  59. extern "C" {
  60. INTERNETAPI_(BOOL) InternetGetCertByURLA(
  61. IN LPSTR lpszURL,
  62. IN OUT LPSTR lpszCertText,
  63. OUT DWORD dwcbCertText
  64. );
  65. }
  66. //
  67. // private manifests
  68. //
  69. //
  70. // private prototypes
  71. //
  72. PRIVATE
  73. DWORD
  74. ReadFile_Fsm(
  75. IN CFsm_ReadFile * Fsm
  76. );
  77. PRIVATE
  78. DWORD
  79. ReadFileEx_Fsm(
  80. IN CFsm_ReadFileEx * Fsm
  81. );
  82. PRIVATE
  83. VOID
  84. ReadFile_End(
  85. IN BOOL bDeref,
  86. IN BOOL bSuccess,
  87. IN HINTERNET hFileMapped,
  88. IN DWORD dwBytesRead,
  89. IN LPVOID lpBuffer OPTIONAL,
  90. IN DWORD dwNumberOfBytesToRead,
  91. OUT LPDWORD lpdwNumberOfBytesRead OPTIONAL
  92. );
  93. PRIVATE
  94. DWORD
  95. QueryAvailable_Fsm(
  96. IN CFsm_QueryAvailable * Fsm
  97. );
  98. PRIVATE
  99. DWORD
  100. wInternetCloseConnectA(
  101. IN HINTERNET lpConnectHandle,
  102. IN DWORD ServiceType
  103. );
  104. PRIVATE
  105. DWORD
  106. GetEmailNameAndPassword(
  107. IN OUT LPSTR* lplpszUserName,
  108. IN OUT LPSTR* lplpszPassword,
  109. OUT LPSTR lpszEmailName,
  110. IN DWORD dwEmailNameLength
  111. );
  112. PRIVATE
  113. BOOL
  114. InternetParseCommon(
  115. IN LPCTSTR lpszBaseUrl,
  116. IN LPCTSTR lpszRelativeUrl,
  117. OUT LPTSTR lpszBuffer,
  118. IN OUT LPDWORD lpdwBufferLength,
  119. IN DWORD dwFlags
  120. );
  121. //PRIVATE
  122. //DWORD
  123. //CreateDeleteSocket(
  124. // VOID
  125. // );
  126. BOOL
  127. GetWininetUserName(
  128. VOID
  129. );
  130. //
  131. // functions
  132. //
  133. INTERNETAPI_(BOOL) InternetCrackUrlA(
  134. IN LPCSTR lpszUrl,
  135. IN DWORD dwUrlLength,
  136. IN DWORD dwFlags,
  137. IN LPURL_COMPONENTSA lpUrlComponents
  138. )
  139. /*++
  140. Routine Description:
  141. Cracks an URL into its constituent parts. Optionally escapes the url-path.
  142. We assume that the user has supplied large enough buffers for the various
  143. URL parts
  144. Arguments:
  145. lpszUrl - pointer to URL to crack
  146. dwUrlLength - 0 if lpszUrl is ASCIIZ string, else length of lpszUrl
  147. dwFlags - flags controlling operation
  148. lpUrlComponents - pointer to URL_COMPONENTS
  149. Return Value:
  150. BOOL
  151. Success - TRUE
  152. Failure - FALSE. Call GetLastError() for more info
  153. --*/
  154. {
  155. DEBUG_ENTER_API((DBG_API,
  156. Bool,
  157. "InternetCrackUrlA",
  158. "%q, %#x, %#x, %#x",
  159. lpszUrl,
  160. dwUrlLength,
  161. dwFlags,
  162. lpUrlComponents
  163. ));
  164. DWORD error;
  165. //
  166. // validate parameters
  167. //
  168. if (ARGUMENT_PRESENT(lpszUrl)) {
  169. if (dwUrlLength == 0) {
  170. error = ProbeString((LPSTR)lpszUrl, &dwUrlLength);
  171. } else {
  172. error = ProbeReadBuffer((LPVOID)lpszUrl, dwUrlLength);
  173. }
  174. } else {
  175. error = ERROR_INVALID_PARAMETER;
  176. }
  177. if (error != ERROR_SUCCESS) {
  178. goto quit;
  179. }
  180. if ((lpUrlComponents == NULL)
  181. || (lpUrlComponents->dwStructSize != sizeof(*lpUrlComponents))) {
  182. error = ERROR_INVALID_PARAMETER;
  183. } else {
  184. error = ProbeWriteBuffer((LPVOID)lpUrlComponents,
  185. sizeof(*lpUrlComponents)
  186. );
  187. }
  188. if (error != ERROR_SUCCESS) {
  189. goto quit;
  190. }
  191. //
  192. // we only allow two flags for this API
  193. //
  194. if (dwFlags & ~(ICU_ESCAPE | ICU_DECODE)) {
  195. error = ERROR_INVALID_PARAMETER;
  196. goto quit;
  197. }
  198. if (!GlobalDataInitialized)
  199. {
  200. error = GlobalDataInitialize();
  201. if (error != ERROR_SUCCESS)
  202. {
  203. goto quit;
  204. }
  205. }
  206. //
  207. // get the individual components to return. If they reference a buffer then
  208. // check it for writeability
  209. //
  210. LPSTR lpUrl;
  211. LPSTR urlCopy;
  212. INTERNET_SCHEME schemeType;
  213. LPSTR schemeName;
  214. DWORD schemeNameLength;
  215. LPSTR hostName;
  216. DWORD hostNameLength;
  217. INTERNET_PORT nPort;
  218. LPSTR userName;
  219. DWORD userNameLength;
  220. LPSTR password;
  221. DWORD passwordLength;
  222. LPSTR urlPath;
  223. DWORD urlPathLength;
  224. LPSTR extraInfo;
  225. DWORD extraInfoLength;
  226. BOOL copyComponent;
  227. BOOL havePort;
  228. copyComponent = FALSE;
  229. schemeName = lpUrlComponents->lpszScheme;
  230. schemeNameLength = lpUrlComponents->dwSchemeLength;
  231. if ((schemeName != NULL) && (schemeNameLength != 0)) {
  232. error = ProbeWriteBuffer((LPVOID)schemeName, schemeNameLength);
  233. if (error != ERROR_SUCCESS) {
  234. goto quit;
  235. }
  236. *schemeName = '\0';
  237. copyComponent = TRUE;
  238. }
  239. hostName = lpUrlComponents->lpszHostName;
  240. hostNameLength = lpUrlComponents->dwHostNameLength;
  241. if ((hostName != NULL) && (hostNameLength != 0)) {
  242. error = ProbeWriteBuffer((LPVOID)hostName, hostNameLength);
  243. if (error != ERROR_SUCCESS) {
  244. goto quit;
  245. }
  246. *hostName = '\0';
  247. copyComponent = TRUE;
  248. }
  249. userName = lpUrlComponents->lpszUserName;
  250. userNameLength = lpUrlComponents->dwUserNameLength;
  251. if ((userName != NULL) && (userNameLength != 0)) {
  252. error = ProbeWriteBuffer((LPVOID)userName, userNameLength);
  253. if (error != ERROR_SUCCESS) {
  254. goto quit;
  255. }
  256. *userName = '\0';
  257. copyComponent = TRUE;
  258. }
  259. password = lpUrlComponents->lpszPassword;
  260. passwordLength = lpUrlComponents->dwPasswordLength;
  261. if ((password != NULL) && (passwordLength != 0)) {
  262. error = ProbeWriteBuffer((LPVOID)password, passwordLength);
  263. if (error != ERROR_SUCCESS) {
  264. goto quit;
  265. }
  266. *password = '\0';
  267. copyComponent = TRUE;
  268. }
  269. urlPath = lpUrlComponents->lpszUrlPath;
  270. urlPathLength = lpUrlComponents->dwUrlPathLength;
  271. if ((urlPath != NULL) && (urlPathLength != 0)) {
  272. error = ProbeWriteBuffer((LPVOID)urlPath, urlPathLength);
  273. if (error != ERROR_SUCCESS) {
  274. goto quit;
  275. }
  276. *urlPath = '\0';
  277. copyComponent = TRUE;
  278. }
  279. extraInfo = lpUrlComponents->lpszExtraInfo;
  280. extraInfoLength = lpUrlComponents->dwExtraInfoLength;
  281. if ((extraInfo != NULL) && (extraInfoLength != 0)) {
  282. error = ProbeWriteBuffer((LPVOID)extraInfo, extraInfoLength);
  283. if (error != ERROR_SUCCESS) {
  284. goto quit;
  285. }
  286. *extraInfo = '\0';
  287. copyComponent = TRUE;
  288. }
  289. //
  290. // we can only escape or decode the URL if the caller has provided us with
  291. // buffers to write the escaped strings into
  292. //
  293. if (dwFlags & (ICU_ESCAPE | ICU_DECODE)) {
  294. if (!copyComponent) {
  295. error = ERROR_INVALID_PARAMETER;
  296. goto quit;
  297. }
  298. //
  299. // create a copy of the URL. CrackUrl() will modify this in situ. We
  300. // need to copy the results back to the user's buffer(s)
  301. //
  302. urlCopy = NewString((LPSTR)lpszUrl, dwUrlLength);
  303. if (urlCopy == NULL) {
  304. error = ERROR_NOT_ENOUGH_MEMORY;
  305. goto quit;
  306. }
  307. lpUrl = urlCopy;
  308. } else {
  309. lpUrl = (LPSTR)lpszUrl;
  310. urlCopy = NULL;
  311. }
  312. //
  313. // crack the URL into its constituent parts
  314. //
  315. error = CrackUrl(lpUrl,
  316. dwUrlLength,
  317. (dwFlags & ICU_ESCAPE) ? TRUE : FALSE,
  318. &schemeType,
  319. &schemeName,
  320. &schemeNameLength,
  321. &hostName,
  322. &hostNameLength,
  323. &nPort,
  324. &userName,
  325. &userNameLength,
  326. &password,
  327. &passwordLength,
  328. &urlPath,
  329. &urlPathLength,
  330. extraInfoLength ? &extraInfo : NULL,
  331. extraInfoLength ? &extraInfoLength : 0,
  332. &havePort
  333. );
  334. if (error != ERROR_SUCCESS) {
  335. goto crack_error;
  336. }
  337. BOOL copyFailure;
  338. copyFailure = FALSE;
  339. //
  340. // update the URL_COMPONENTS structure based on the results, and what was
  341. // asked for
  342. //
  343. if (lpUrlComponents->lpszScheme != NULL) {
  344. if (lpUrlComponents->dwSchemeLength > schemeNameLength) {
  345. memcpy((LPVOID)lpUrlComponents->lpszScheme,
  346. (LPVOID)schemeName,
  347. schemeNameLength
  348. );
  349. lpUrlComponents->lpszScheme[schemeNameLength] = '\0';
  350. // Windows Bug 757146
  351. // No longer unescaping the scheme. It's just wrong to do so.
  352. // if (dwFlags & ICU_DECODE) {
  353. // UrlUnescapeInPlace(lpUrlComponents->lpszScheme, 0);
  354. // }
  355. } else {
  356. ++schemeNameLength;
  357. copyFailure = TRUE;
  358. }
  359. lpUrlComponents->dwSchemeLength = schemeNameLength;
  360. } else if (lpUrlComponents->dwSchemeLength != 0) {
  361. lpUrlComponents->lpszScheme = schemeName;
  362. lpUrlComponents->dwSchemeLength = schemeNameLength;
  363. }
  364. if (lpUrlComponents->lpszHostName != NULL) {
  365. if (lpUrlComponents->dwHostNameLength > hostNameLength) {
  366. memcpy((LPVOID)lpUrlComponents->lpszHostName,
  367. (LPVOID)hostName,
  368. hostNameLength
  369. );
  370. lpUrlComponents->lpszHostName[hostNameLength] = '\0';
  371. // Windows Bug 757146
  372. // No longer unescaping the host name if ICU_DECODE set.
  373. // It already has been unescaped once in CrackUrl above.
  374. // if (dwFlags & ICU_DECODE) {
  375. // UrlUnescapeInPlace(lpUrlComponents->lpszHostName, 0);
  376. // }
  377. } else {
  378. ++hostNameLength;
  379. copyFailure = TRUE;
  380. }
  381. lpUrlComponents->dwHostNameLength = hostNameLength;
  382. } else if (lpUrlComponents->dwHostNameLength != 0) {
  383. lpUrlComponents->lpszHostName = hostName;
  384. lpUrlComponents->dwHostNameLength = hostNameLength;
  385. }
  386. if (lpUrlComponents->lpszUserName != NULL) {
  387. if (lpUrlComponents->dwUserNameLength > userNameLength) {
  388. memcpy((LPVOID)lpUrlComponents->lpszUserName,
  389. (LPVOID)userName,
  390. userNameLength
  391. );
  392. lpUrlComponents->lpszUserName[userNameLength] = '\0';
  393. // Windows Bug 757146
  394. // No longer unescaping the user name if ICU_DECODE set.
  395. // It already has been unescaped once in CrackUrl above.
  396. // if (dwFlags & ICU_DECODE) {
  397. // UrlUnescapeInPlace(lpUrlComponents->lpszUserName, 0);
  398. // }
  399. } else {
  400. ++userNameLength;
  401. copyFailure = TRUE;
  402. }
  403. lpUrlComponents->dwUserNameLength = userNameLength;
  404. } else if (lpUrlComponents->dwUserNameLength != 0) {
  405. lpUrlComponents->lpszUserName = userName;
  406. lpUrlComponents->dwUserNameLength = userNameLength;
  407. }
  408. if (lpUrlComponents->lpszPassword != NULL) {
  409. if (lpUrlComponents->dwPasswordLength > passwordLength) {
  410. memcpy((LPVOID)lpUrlComponents->lpszPassword,
  411. (LPVOID)password,
  412. passwordLength
  413. );
  414. lpUrlComponents->lpszPassword[passwordLength] = '\0';
  415. // Windows Bug 757146
  416. // No longer unescaping the password if ICU_DECODE set.
  417. // It already has been unescaped once in CrackUrl above.
  418. // if (dwFlags & ICU_DECODE) {
  419. // UrlUnescapeInPlace(lpUrlComponents->lpszPassword, 0);
  420. // }
  421. } else {
  422. ++passwordLength;
  423. copyFailure = TRUE;
  424. }
  425. lpUrlComponents->dwPasswordLength = passwordLength;
  426. } else if (lpUrlComponents->dwPasswordLength != 0) {
  427. lpUrlComponents->lpszPassword = password;
  428. lpUrlComponents->dwPasswordLength = passwordLength;
  429. }
  430. if (lpUrlComponents->lpszUrlPath != NULL) {
  431. if(schemeType == INTERNET_SCHEME_FILE)
  432. {
  433. //
  434. // for file: urls we return the path component
  435. // as a valid dos path.
  436. //
  437. copyFailure = FAILED(PathCreateFromUrl(lpUrl, lpUrlComponents->lpszUrlPath, &(lpUrlComponents->dwUrlPathLength), 0));
  438. }
  439. else if (lpUrlComponents->dwUrlPathLength > urlPathLength) {
  440. memcpy((LPVOID)lpUrlComponents->lpszUrlPath,
  441. (LPVOID)urlPath,
  442. urlPathLength
  443. );
  444. lpUrlComponents->lpszUrlPath[urlPathLength] = '\0';
  445. // Windows Bug 757146
  446. // Unescape the path if only ICU_DECODE is set.
  447. // ICU_ESCAPE causes the path to be unescaped in
  448. // CrackUrl above.
  449. if ((dwFlags & (ICU_DECODE | ICU_ESCAPE)) == ICU_DECODE) {
  450. UrlUnescapeInPlace(lpUrlComponents->lpszUrlPath, 0);
  451. }
  452. lpUrlComponents->dwUrlPathLength = urlPathLength;
  453. } else {
  454. ++urlPathLength;
  455. copyFailure = TRUE;
  456. lpUrlComponents->dwUrlPathLength = urlPathLength;
  457. }
  458. } else if (lpUrlComponents->dwUrlPathLength != 0) {
  459. lpUrlComponents->lpszUrlPath = urlPath;
  460. lpUrlComponents->dwUrlPathLength = urlPathLength;
  461. }
  462. if (lpUrlComponents->lpszExtraInfo != NULL) {
  463. if (lpUrlComponents->dwExtraInfoLength > extraInfoLength) {
  464. memcpy((LPVOID)lpUrlComponents->lpszExtraInfo,
  465. (LPVOID)extraInfo,
  466. extraInfoLength
  467. );
  468. lpUrlComponents->lpszExtraInfo[extraInfoLength] = '\0';
  469. // Windows Bug 757146
  470. // Unescape the extrainfo if only ICU_DECODE is set.
  471. // ICU_ESCAPE causes the extrainfo to be unescaped in
  472. // CrackUrl above.
  473. if ((dwFlags & (ICU_DECODE | ICU_ESCAPE)) == ICU_DECODE) {
  474. UrlUnescapeInPlace(lpUrlComponents->lpszExtraInfo, 0);
  475. }
  476. } else {
  477. ++extraInfoLength;
  478. copyFailure = TRUE;
  479. }
  480. lpUrlComponents->dwExtraInfoLength = extraInfoLength;
  481. } else if (lpUrlComponents->dwExtraInfoLength != 0) {
  482. lpUrlComponents->lpszExtraInfo = extraInfo;
  483. lpUrlComponents->dwExtraInfoLength = extraInfoLength;
  484. }
  485. //
  486. // we may have failed to copy one or more components because we didn't have
  487. // enough buffer space.
  488. //
  489. // N.B. Don't change error below here. If need be, move this test lower
  490. //
  491. if (copyFailure) {
  492. error = ERROR_INSUFFICIENT_BUFFER;
  493. }
  494. //
  495. // copy the scheme type
  496. //
  497. lpUrlComponents->nScheme = schemeType;
  498. //
  499. // convert 0 port (not in URL) to default value for scheme
  500. //
  501. if (nPort == INTERNET_INVALID_PORT_NUMBER && !havePort) {
  502. switch (schemeType) {
  503. case INTERNET_SCHEME_FTP:
  504. nPort = INTERNET_DEFAULT_FTP_PORT;
  505. break;
  506. case INTERNET_SCHEME_GOPHER:
  507. nPort = INTERNET_DEFAULT_GOPHER_PORT;
  508. break;
  509. case INTERNET_SCHEME_HTTP:
  510. nPort = INTERNET_DEFAULT_HTTP_PORT;
  511. break;
  512. case INTERNET_SCHEME_HTTPS:
  513. nPort = INTERNET_DEFAULT_HTTPS_PORT;
  514. break;
  515. }
  516. }
  517. lpUrlComponents->nPort = nPort;
  518. crack_error:
  519. if (urlCopy != NULL) {
  520. DEL_STRING(urlCopy);
  521. }
  522. quit:
  523. BOOL success = (error==ERROR_SUCCESS);
  524. if (!success) {
  525. DEBUG_ERROR(API, error);
  526. SetLastError(error);
  527. }
  528. DEBUG_LEAVE_API(success);
  529. return success;
  530. }
  531. INTERNETAPI_(BOOL) InternetCreateUrlA(
  532. IN LPURL_COMPONENTSA lpUrlComponents,
  533. IN DWORD dwFlags,
  534. OUT LPSTR lpszUrl OPTIONAL,
  535. IN OUT LPDWORD lpdwUrlLength
  536. )
  537. /*++
  538. Routine Description:
  539. Creates an URL from its constituent parts
  540. Arguments:
  541. lpUrlComponents - pointer to URL_COMPONENTS structure containing pointers
  542. and lengths of components of interest
  543. dwFlags - flags controlling function:
  544. ICU_ESCAPE - the components contain characters that
  545. must be escaped in the output URL
  546. lpszUrl - pointer to buffer where output URL will be written
  547. lpdwUrlLength - IN: number of bytes in lpszUrl buffer
  548. OUT: if success, number of characters in lpszUrl, else
  549. number of bytes required for buffer
  550. Return Value:
  551. BOOL
  552. Success - URL written to lpszUrl
  553. Failure - call GetLastError() for more info
  554. --*/
  555. {
  556. DEBUG_ENTER_API((DBG_API,
  557. Bool,
  558. "InternetCreateUrlA",
  559. "%#x, %#x, %#x, %#x",
  560. lpUrlComponents,
  561. dwFlags,
  562. lpszUrl,
  563. lpdwUrlLength
  564. ));
  565. #if INET_DEBUG
  566. LPSTR lpszUrlOriginal = lpszUrl;
  567. #endif
  568. DWORD error = ERROR_SUCCESS;
  569. LPSTR encodedUserName = NULL;
  570. LPSTR encodedPassword = NULL;
  571. LPSTR encodedHostName = NULL;
  572. LPSTR encodedUrlPath = NULL;
  573. LPSTR encodedExtraInfo = NULL;
  574. //
  575. // validate parameters
  576. //
  577. if ((lpUrlComponents == NULL)
  578. || (lpUrlComponents->dwStructSize != sizeof(*lpUrlComponents))
  579. || (dwFlags & ~(ICU_ESCAPE | ICU_USERNAME | ICU_ESCAPE_AUTHORITY))
  580. || (lpdwUrlLength == NULL)) {
  581. error = ERROR_INVALID_PARAMETER;
  582. goto quit;
  583. }
  584. if (!ARGUMENT_PRESENT(lpszUrl)) {
  585. *lpdwUrlLength = 0;
  586. }
  587. //
  588. // allocate large buffers from heap
  589. //
  590. encodedHostName = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, INTERNET_MAX_HOST_NAME_LENGTH + 1);
  591. encodedUserName = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, INTERNET_MAX_USER_NAME_LENGTH + 1);
  592. encodedPassword = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, INTERNET_MAX_PASSWORD_LENGTH + 1);
  593. encodedUrlPath = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, INTERNET_MAX_URL_LENGTH + 1);
  594. encodedExtraInfo = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, INTERNET_MAX_URL_LENGTH + 1);
  595. if ((encodedHostName == NULL) ||
  596. (encodedUserName == NULL) ||
  597. (encodedPassword == NULL) ||
  598. (encodedUrlPath == NULL) ||
  599. (encodedExtraInfo == NULL)
  600. ) {
  601. error = ERROR_NOT_ENOUGH_MEMORY;
  602. goto quit;
  603. }
  604. //
  605. // if we get an exception, we return ERROR_INVALID_PARAMETER
  606. //
  607. __try {
  608. //
  609. // get the individual components to copy
  610. //
  611. LPSTR schemeName;
  612. DWORD schemeNameLength;
  613. DWORD schemeFlags;
  614. LPSTR hostName;
  615. DWORD hostNameLength;
  616. DWORD encodedHostNameLength;
  617. INTERNET_PORT nPort;
  618. DWORD portLength;
  619. LPSTR userName;
  620. DWORD userNameLength;
  621. DWORD encodedUserNameLength;
  622. LPSTR password;
  623. DWORD passwordLength;
  624. DWORD encodedPasswordLength;
  625. LPSTR urlPath;
  626. DWORD urlPathLength;
  627. DWORD extraLength;
  628. DWORD encodedUrlPathLength;
  629. LPSTR extraInfo;
  630. DWORD extraInfoLength;
  631. DWORD encodedExtraInfoLength;
  632. LPSTR schemeSep;
  633. DWORD schemeSepLength;
  634. INTERNET_SCHEME schemeType;
  635. INTERNET_PORT defaultPort;
  636. //
  637. // if the scheme name is absent then we use the default
  638. //
  639. schemeName = lpUrlComponents->lpszScheme;
  640. schemeType = lpUrlComponents->nScheme;
  641. if (schemeName == NULL) {
  642. if (schemeType == INTERNET_SCHEME_DEFAULT){
  643. schemeName = DEFAULT_URL_SCHEME_NAME;
  644. schemeNameLength = sizeof(DEFAULT_URL_SCHEME_NAME) - 1;
  645. }
  646. else {
  647. schemeName = MapUrlScheme(schemeType, &schemeNameLength);
  648. }
  649. } else {
  650. schemeNameLength = lpUrlComponents->dwSchemeLength;
  651. if (schemeNameLength == 0) {
  652. schemeNameLength = lstrlen(schemeName);
  653. }
  654. }
  655. //
  656. // determine the schemeFlags for possible use in encoding below
  657. //
  658. schemeFlags = 0;
  659. if (strnicmp(schemeName, "http", schemeNameLength) == 0) {
  660. schemeFlags = SCHEME_HTTP;
  661. } else if (strnicmp(schemeName, "ftp", schemeNameLength) == 0) {
  662. schemeFlags = SCHEME_FTP;
  663. } else if (strnicmp(schemeName, "gopher", schemeNameLength) == 0) {
  664. schemeFlags = SCHEME_GOPHER;
  665. }
  666. //
  667. // doesn't have to be a host name
  668. //
  669. hostName = lpUrlComponents->lpszHostName;
  670. portLength = 0;
  671. if (hostName != NULL) {
  672. hostNameLength = lpUrlComponents->dwHostNameLength;
  673. if (hostNameLength == 0) {
  674. hostNameLength = lstrlen(hostName);
  675. }
  676. // Windows Bugs 625684
  677. // encode hostname if ICU_ESCAPE_AUTHORITY is set
  678. if (dwFlags & ICU_ESCAPE_AUTHORITY) {
  679. encodedHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH + 1;
  680. error = EncodeAuthorityComponent(
  681. hostName,
  682. hostNameLength,
  683. encodedHostName,
  684. &encodedHostNameLength
  685. );
  686. if (error == ERROR_SUCCESS) {
  687. hostName = encodedHostName;
  688. hostNameLength = encodedHostNameLength;
  689. }
  690. }
  691. //
  692. // if the port is default then we don't add it to the URL, else we need to
  693. // copy it as a string
  694. //
  695. // there won't be a port unless there's host.
  696. schemeType = MapUrlSchemeName(schemeName, schemeNameLength ? schemeNameLength : -1);
  697. switch (schemeType) {
  698. case INTERNET_SCHEME_FTP:
  699. defaultPort = INTERNET_DEFAULT_FTP_PORT;
  700. break;
  701. case INTERNET_SCHEME_GOPHER:
  702. defaultPort = INTERNET_DEFAULT_GOPHER_PORT;
  703. break;
  704. case INTERNET_SCHEME_HTTP:
  705. defaultPort = INTERNET_DEFAULT_HTTP_PORT;
  706. break;
  707. case INTERNET_SCHEME_HTTPS:
  708. defaultPort = INTERNET_DEFAULT_HTTPS_PORT;
  709. break;
  710. default:
  711. defaultPort = INTERNET_INVALID_PORT_NUMBER;
  712. break;
  713. }
  714. if (lpUrlComponents->nPort != defaultPort) {
  715. INTERNET_PORT divisor;
  716. nPort = lpUrlComponents->nPort;
  717. if (nPort) {
  718. divisor = 10000;
  719. portLength = 6; // max is 5 characters, plus 1 for ':'
  720. while ((nPort / divisor) == 0) {
  721. --portLength;
  722. divisor /= 10;
  723. }
  724. } else {
  725. portLength = 2; // port is ":0"
  726. }
  727. }
  728. } else {
  729. hostNameLength = 0;
  730. }
  731. //
  732. // doesn't have to be a user name
  733. //
  734. if (error == ERROR_SUCCESS) {
  735. userName = lpUrlComponents->lpszUserName;
  736. if (userName != NULL) {
  737. userNameLength = lpUrlComponents->dwUserNameLength;
  738. if (userNameLength == 0) {
  739. userNameLength = lstrlen(userName);
  740. }
  741. // Windows Bugs 625684
  742. // encode hostname if ICU_ESCAPE_AUTHORITY is set
  743. if (dwFlags & ICU_ESCAPE_AUTHORITY) {
  744. encodedUserNameLength = INTERNET_MAX_USER_NAME_LENGTH + 1;
  745. error = EncodeAuthorityComponent(
  746. userName,
  747. userNameLength,
  748. encodedUserName,
  749. &encodedUserNameLength
  750. );
  751. if (error == ERROR_SUCCESS) {
  752. userName = encodedUserName;
  753. userNameLength = encodedUserNameLength;
  754. }
  755. }
  756. } else {
  757. //
  758. // BUGBUG - if ICU_USERNAME then we get the value from the registry
  759. //
  760. userNameLength = 0;
  761. }
  762. }
  763. //
  764. // doesn't have to be a password
  765. //
  766. if (error == ERROR_SUCCESS) {
  767. password = lpUrlComponents->lpszPassword;
  768. if (password != NULL) {
  769. passwordLength = lpUrlComponents->dwPasswordLength;
  770. if (passwordLength == 0) {
  771. passwordLength = lstrlen(password);
  772. }
  773. // Windows Bugs 625684
  774. // encode hostname if ICU_ESCAPE_AUTHORITY is set
  775. if (dwFlags & ICU_ESCAPE_AUTHORITY) {
  776. encodedPasswordLength = INTERNET_MAX_PASSWORD_LENGTH + 1;
  777. error = EncodeAuthorityComponent(
  778. password,
  779. passwordLength,
  780. encodedPassword,
  781. &encodedPasswordLength
  782. );
  783. if (error == ERROR_SUCCESS) {
  784. password = encodedPassword;
  785. passwordLength = encodedPasswordLength;
  786. }
  787. }
  788. } else {
  789. //
  790. // BUGBUG - if ICU_USERNAME then we get the value from the registry
  791. //
  792. passwordLength = 0;
  793. }
  794. }
  795. //
  796. // but if there's a password without a user name, then its an error
  797. //
  798. if (error == ERROR_SUCCESS) {
  799. if (password && !userName) {
  800. error = ERROR_INVALID_PARAMETER;
  801. } else {
  802. //
  803. // doesn't have to be an URL-path. Empty string is default
  804. //
  805. urlPath = lpUrlComponents->lpszUrlPath;
  806. if (urlPath != NULL) {
  807. urlPathLength = lpUrlComponents->dwUrlPathLength;
  808. if (urlPathLength == 0) {
  809. urlPathLength = lstrlen(urlPath);
  810. }
  811. if ((*urlPath != '/') && (*urlPath != '\\')) {
  812. extraLength = 1;
  813. } else {
  814. extraLength = 0;
  815. }
  816. //
  817. // if requested, we will encode the URL-path
  818. //
  819. if (dwFlags & ICU_ESCAPE) {
  820. //
  821. // only encode the URL-path if it's a recognized scheme
  822. //
  823. if (schemeFlags != 0) {
  824. encodedUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  825. error = EncodeUrlPath(NO_ENCODE_PATH_SEP,
  826. schemeFlags,
  827. urlPath,
  828. urlPathLength,
  829. encodedUrlPath,
  830. &encodedUrlPathLength
  831. );
  832. if (error == ERROR_SUCCESS) {
  833. urlPath = encodedUrlPath;
  834. urlPathLength = encodedUrlPathLength;
  835. }
  836. }
  837. }
  838. } else {
  839. urlPathLength = 0;
  840. extraLength = 0;
  841. }
  842. //
  843. // handle extra info if present
  844. //
  845. if (error == ERROR_SUCCESS) {
  846. extraInfo = lpUrlComponents->lpszExtraInfo;
  847. if (extraInfo != NULL) {
  848. extraInfoLength = lpUrlComponents->dwExtraInfoLength;
  849. if (extraInfoLength == 0) {
  850. extraInfoLength = lstrlen(extraInfo);
  851. }
  852. //
  853. // if requested, we will encode the extra info
  854. //
  855. if (dwFlags & ICU_ESCAPE) {
  856. //
  857. // only encode the extra info if it's a recognized scheme
  858. //
  859. if (schemeFlags != 0) {
  860. encodedExtraInfoLength = INTERNET_MAX_URL_LENGTH + 1;
  861. error = EncodeUrlPath(0,
  862. schemeFlags,
  863. extraInfo,
  864. extraInfoLength,
  865. encodedExtraInfo,
  866. &encodedExtraInfoLength
  867. );
  868. if (error == ERROR_SUCCESS) {
  869. extraInfo = encodedExtraInfo;
  870. extraInfoLength = encodedExtraInfoLength;
  871. }
  872. }
  873. }
  874. } else {
  875. extraInfoLength = 0;
  876. }
  877. }
  878. DWORD requiredSize;
  879. if (error == ERROR_SUCCESS) {
  880. //
  881. // Determine if we have a protocol scheme that requires slashes
  882. //
  883. if (DoesSchemeRequireSlashes(schemeName, schemeNameLength, (hostName != NULL))
  884. || ((schemeType == INTERNET_SCHEME_NEWS)
  885. && urlPath
  886. && (strchr(urlPath, '/') || strchr(urlPath, '\\')))) {
  887. schemeSep = "://";
  888. schemeSepLength = sizeof("://") - 1;
  889. } else {
  890. schemeSep = ":";
  891. schemeSepLength = sizeof(":") - 1;
  892. }
  893. //
  894. // ensure we have enough buffer space
  895. //
  896. requiredSize = schemeNameLength
  897. + schemeSepLength
  898. + hostNameLength
  899. + portLength
  900. + (userName ? userNameLength + 1 : 0) // +1 for '@'
  901. + (password ? passwordLength + 1 : 0) // +1 for ':'
  902. + urlPathLength
  903. + extraLength
  904. + extraInfoLength
  905. + 1 // +1 for '\0'
  906. ;
  907. //
  908. // if there is enough buffer, copy the URL
  909. //
  910. if (*lpdwUrlLength >= requiredSize) {
  911. memcpy((LPVOID)lpszUrl, (LPVOID)schemeName, schemeNameLength);
  912. lpszUrl += schemeNameLength;
  913. memcpy((LPVOID)lpszUrl, (LPVOID)schemeSep, schemeSepLength);
  914. lpszUrl += schemeSepLength;
  915. if (userName) {
  916. memcpy((LPVOID)lpszUrl, (LPVOID)userName, userNameLength);
  917. lpszUrl += userNameLength;
  918. if (password) {
  919. *lpszUrl++ = ':';
  920. memcpy((LPVOID)lpszUrl, (LPVOID)password, passwordLength);
  921. lpszUrl += passwordLength;
  922. }
  923. *lpszUrl++ = '@';
  924. }
  925. if (hostName) {
  926. memcpy((LPVOID)lpszUrl, (LPVOID)hostName, hostNameLength);
  927. lpszUrl += hostNameLength;
  928. // We won't attach a port unless there's a host to go with it.
  929. if (portLength) {
  930. lpszUrl += wsprintf(lpszUrl, ":%d", nPort & 0xffff);
  931. }
  932. }
  933. if (urlPath) {
  934. //
  935. // Only do extraLength if we've actually copied something
  936. // after the scheme. Also, don't copy slash if it's
  937. // mailto:
  938. //
  939. if (extraLength != 0 && (userName || hostName || portLength) &&
  940. schemeType != INTERNET_SCHEME_MAILTO) {
  941. *lpszUrl++ = '/';
  942. } else if (extraLength != 0) {
  943. --requiredSize;
  944. }
  945. memcpy((LPVOID)lpszUrl, (LPVOID)urlPath, urlPathLength);
  946. lpszUrl += urlPathLength;
  947. } else if (extraLength != 0) {
  948. --requiredSize;
  949. }
  950. if (extraInfo) {
  951. memcpy((LPVOID)lpszUrl, (LPVOID)extraInfo, extraInfoLength);
  952. lpszUrl += extraInfoLength;
  953. }
  954. //
  955. // terminate string
  956. //
  957. *lpszUrl = '\0';
  958. //
  959. // -1 for terminating '\0'
  960. //
  961. --requiredSize;
  962. } else {
  963. //
  964. // not enough buffer space - just return the required buffer length
  965. //
  966. error = ERROR_INSUFFICIENT_BUFFER;
  967. }
  968. }
  969. //
  970. // update returned parameters
  971. //
  972. *lpdwUrlLength = requiredSize;
  973. }
  974. }
  975. } __except(EXCEPTION_EXECUTE_HANDLER) {
  976. error = ERROR_INVALID_PARAMETER;
  977. }
  978. ENDEXCEPT
  979. quit:
  980. //
  981. // clear up the buffers we allocated
  982. //
  983. if (encodedUserName != NULL) {
  984. FREE_MEMORY(encodedUserName);
  985. }
  986. if (encodedPassword != NULL) {
  987. FREE_MEMORY(encodedPassword);
  988. }
  989. if (encodedHostName != NULL) {
  990. FREE_MEMORY(encodedHostName);
  991. }
  992. if (encodedUrlPath != NULL) {
  993. FREE_MEMORY(encodedUrlPath);
  994. }
  995. if (encodedExtraInfo != NULL) {
  996. FREE_MEMORY(encodedExtraInfo);
  997. }
  998. BOOL success = (error==ERROR_SUCCESS);
  999. if (success) {
  1000. DEBUG_PRINT_API(API,
  1001. INFO,
  1002. ("URL = %q\n",
  1003. lpszUrlOriginal
  1004. ));
  1005. } else {
  1006. DEBUG_ERROR(API, error);
  1007. SetLastError(error);
  1008. }
  1009. DEBUG_LEAVE_API(success);
  1010. return success;
  1011. }
  1012. //
  1013. // ICUHrToWin32Error() is specifically for converting the return codes for
  1014. // Url* APIs in shlwapi into win32 errors.
  1015. // WARNING: it should not be used for any other purpose.
  1016. //
  1017. DWORD
  1018. ICUHrToWin32Error(HRESULT hr)
  1019. {
  1020. DWORD err = ERROR_INVALID_PARAMETER;
  1021. switch(hr)
  1022. {
  1023. case E_OUTOFMEMORY:
  1024. err = ERROR_NOT_ENOUGH_MEMORY;
  1025. break;
  1026. case E_POINTER:
  1027. err = ERROR_INSUFFICIENT_BUFFER;
  1028. break;
  1029. case S_OK:
  1030. err = ERROR_SUCCESS;
  1031. break;
  1032. default:
  1033. break;
  1034. }
  1035. return err;
  1036. }
  1037. INTERNETAPI_(BOOL) InternetCanonicalizeUrlA(
  1038. IN LPCSTR lpszUrl,
  1039. OUT LPSTR lpszBuffer,
  1040. IN OUT LPDWORD lpdwBufferLength,
  1041. IN DWORD dwFlags
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. Combines a relative URL with a base URL to form a new full URL.
  1046. Arguments:
  1047. lpszUrl - pointer to URL to be canonicalize
  1048. lpszBuffer - pointer to buffer where new URL is written
  1049. lpdwBufferLength - size of buffer on entry, length of new URL on exit
  1050. dwFlags - flags controlling operation
  1051. Return Value:
  1052. BOOL - TRUE if successful, FALSE if not
  1053. --*/
  1054. {
  1055. DEBUG_ENTER_API((DBG_API,
  1056. Bool,
  1057. "InternetCanonicalizeUrlA",
  1058. "%q, %#x, %#x [%d], %#x",
  1059. lpszUrl,
  1060. lpszBuffer,
  1061. lpdwBufferLength,
  1062. lpdwBufferLength ? *lpdwBufferLength : 0,
  1063. dwFlags
  1064. ));
  1065. HRESULT hr ;
  1066. BOOL bRet = TRUE;;
  1067. INET_ASSERT(lpszUrl);
  1068. INET_ASSERT(lpszBuffer);
  1069. INET_ASSERT(lpdwBufferLength && (*lpdwBufferLength > 0));
  1070. //
  1071. // the flags for the Url* APIs in shlwapi should be the same
  1072. // except that NO_ENCODE is on by default. so we need to flip it
  1073. //
  1074. dwFlags ^= ICU_NO_ENCODE;
  1075. // Check for invalid parameters
  1076. if (!lpszUrl || !lpszBuffer || !lpdwBufferLength || *lpdwBufferLength == 0 || IsBadWritePtr(lpszBuffer, *lpdwBufferLength*sizeof(CHAR)))
  1077. {
  1078. hr = E_INVALIDARG;
  1079. }
  1080. else
  1081. {
  1082. hr = UrlCanonicalizeA(lpszUrl, lpszBuffer,
  1083. lpdwBufferLength, dwFlags | URL_WININET_COMPATIBILITY);
  1084. }
  1085. if(FAILED(hr))
  1086. {
  1087. DWORD dw = ICUHrToWin32Error(hr);
  1088. bRet = FALSE;
  1089. DEBUG_ERROR(API, dw);
  1090. SetLastError(dw);
  1091. }
  1092. DEBUG_LEAVE_API(bRet);
  1093. return bRet;
  1094. }
  1095. INTERNETAPI_(BOOL) InternetCombineUrlA(
  1096. IN LPCSTR lpszBaseUrl,
  1097. IN LPCSTR lpszRelativeUrl,
  1098. OUT LPSTR lpszBuffer,
  1099. IN OUT LPDWORD lpdwBufferLength,
  1100. IN DWORD dwFlags
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Combines a relative URL with a base URL to form a new full URL.
  1105. Arguments:
  1106. lpszBaseUrl - pointer to base URL
  1107. lpszRelativeUrl - pointer to relative URL
  1108. lpszBuffer - pointer to buffer where new URL is written
  1109. lpdwBufferLength - size of buffer on entry, length of new URL on exit
  1110. dwFlags - flags controlling operation
  1111. Return Value:
  1112. BOOL - TRUE if successful, FALSE if not
  1113. --*/
  1114. {
  1115. DEBUG_ENTER_API((DBG_API,
  1116. Bool,
  1117. "InternetCombineUrlA",
  1118. "%q, %q, %#x, %#x [%d], %#x",
  1119. lpszBaseUrl,
  1120. lpszRelativeUrl,
  1121. lpszBuffer,
  1122. lpdwBufferLength,
  1123. lpdwBufferLength ? *lpdwBufferLength : 0,
  1124. dwFlags
  1125. ));
  1126. HRESULT hr ;
  1127. BOOL bRet;
  1128. INET_ASSERT(lpszBaseUrl);
  1129. INET_ASSERT(lpszRelativeUrl);
  1130. INET_ASSERT(lpdwBufferLength);
  1131. //
  1132. // the flags for the Url* APIs in shlwapi should be the same
  1133. // except that NO_ENCODE is on by default. so we need to flip it
  1134. //
  1135. dwFlags ^= ICU_NO_ENCODE;
  1136. // Check for invalid parameters
  1137. if (!lpszBaseUrl || !lpszRelativeUrl || !lpdwBufferLength || (lpszBuffer && IsBadWritePtr(lpszBuffer, *lpdwBufferLength*sizeof(CHAR))))
  1138. {
  1139. hr = E_INVALIDARG;
  1140. }
  1141. else
  1142. {
  1143. hr = UrlCombineA(lpszBaseUrl, lpszRelativeUrl, lpszBuffer,
  1144. lpdwBufferLength, dwFlags | URL_WININET_COMPATIBILITY);
  1145. }
  1146. if(FAILED(hr))
  1147. {
  1148. DWORD dw = ICUHrToWin32Error(hr);
  1149. bRet = FALSE;
  1150. DEBUG_ERROR(API, dw);
  1151. SetLastError(dw);
  1152. }
  1153. else
  1154. bRet = TRUE;
  1155. IF_DEBUG_CODE() {
  1156. if (bRet) {
  1157. DEBUG_PRINT_API(API,
  1158. INFO,
  1159. ("URL = %q\n",
  1160. lpszBuffer
  1161. ));
  1162. }
  1163. }
  1164. DEBUG_LEAVE_API(bRet);
  1165. return bRet;
  1166. }
  1167. INTERNETAPI_(HINTERNET) InternetOpenA(
  1168. IN LPCSTR lpszAgent,
  1169. IN DWORD dwAccessType,
  1170. IN LPCSTR lpszProxy OPTIONAL,
  1171. IN LPCSTR lpszProxyBypass OPTIONAL,
  1172. IN DWORD dwFlags
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. Opens a root Internet handle from which all HINTERNET objects are derived
  1177. Arguments:
  1178. lpszAgent - name of the application making the request (arbitrary
  1179. identifying string). Used in "User-Agent" header when
  1180. communicating with HTTP servers, if the application does
  1181. not add a User-Agent header of its own
  1182. dwAccessType - type of access required. Can be
  1183. INTERNET_OPEN_TYPE_PRECONFIG
  1184. - Gets the configuration from the registry
  1185. INTERNET_OPEN_TYPE_DIRECT
  1186. - Requests are made directly to the nominated server
  1187. INTERNET_OPEN_TYPE_PROXY
  1188. - Requests are made via the nominated proxy
  1189. INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY
  1190. - Like Pre-Config, but prevents JavaScript, INS
  1191. and other auto-proxy types from being used.
  1192. lpszProxy - if INTERNET_OPEN_TYPE_PROXY, a list of proxy servers to
  1193. use
  1194. lpszProxyBypass - if INTERNET_OPEN_TYPE_PROXY, a list of servers which we
  1195. will communicate with directly
  1196. dwFlags - flags to control the operation of this API or potentially
  1197. all APIs called on the handle generated by this API.
  1198. Currently supported are:
  1199. INTERNET_FLAG_ASYNC
  1200. - if specified then all subsequent API calls made
  1201. against the handle returned from this API, or
  1202. handles descended from the handle returned by
  1203. this API, have the opportunity to complete
  1204. asynchronously, depending on other factors
  1205. relevant at the time the API is called
  1206. Return Value:
  1207. HINTERNET
  1208. Success - handle of Internet object
  1209. Failure - NULL. For more information, call GetLastError()
  1210. --*/
  1211. {
  1212. PERF_INIT();
  1213. DEBUG_ENTER_API((DBG_API,
  1214. Handle,
  1215. "InternetOpenA",
  1216. "%q, %s (%d), %q, %q, %#x",
  1217. lpszAgent,
  1218. InternetMapOpenType(dwAccessType),
  1219. dwAccessType,
  1220. lpszProxy,
  1221. lpszProxyBypass,
  1222. dwFlags
  1223. ));
  1224. DWORD error;
  1225. HINTERNET hInternet = NULL;
  1226. if (!GlobalDataInitialized) {
  1227. error = GlobalDataInitialize();
  1228. if (error != ERROR_SUCCESS) {
  1229. goto quit;
  1230. }
  1231. }
  1232. //
  1233. // we are doing GetUserName here instead of in DLL_PROCESS_ATTACH
  1234. // As every caller of wininet has to do this first, we ensure
  1235. // that the username is initialized when they get to actually doing
  1236. // any real operation
  1237. //
  1238. GetWininetUserName();
  1239. //
  1240. // validate parameters
  1241. //
  1242. if (!
  1243. (
  1244. (dwAccessType == INTERNET_OPEN_TYPE_DIRECT)
  1245. || (dwAccessType == INTERNET_OPEN_TYPE_PROXY)
  1246. || (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
  1247. || (dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
  1248. || (
  1249. (dwAccessType == INTERNET_OPEN_TYPE_PROXY)
  1250. &&
  1251. (
  1252. !ARGUMENT_PRESENT(lpszProxy)
  1253. || (*lpszProxy == '\0')
  1254. )
  1255. )
  1256. || (dwFlags & ~INTERNET_FLAGS_MASK)
  1257. )
  1258. )
  1259. {
  1260. error = ERROR_INVALID_PARAMETER;
  1261. goto quit;
  1262. }
  1263. GlobalHaveInternetOpened = TRUE;
  1264. //
  1265. // Initalize an auto proxy dll if needed,
  1266. // as long as the caller is allowing us free rein to do this
  1267. // by calling us with INTERNET_OPEN_TYPE_PRECONFIG.
  1268. //
  1269. //if ( dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG )
  1270. //{
  1271. // if ( ! InitalizeAutoConfigDllIfNeeded() )
  1272. // {
  1273. // error = GetLastError();
  1274. //
  1275. // INET_ASSERT(error != ERROR_SUCCESS);
  1276. //
  1277. // goto quit;
  1278. // }
  1279. //
  1280. //
  1281. INTERNET_HANDLE_OBJECT * lpInternet;
  1282. lpInternet = new INTERNET_HANDLE_OBJECT(lpszAgent,
  1283. dwAccessType,
  1284. (LPSTR)lpszProxy,
  1285. (LPSTR)lpszProxyBypass,
  1286. dwFlags
  1287. );
  1288. if (lpInternet == NULL) {
  1289. error = ERROR_NOT_ENOUGH_MEMORY;
  1290. goto quit;
  1291. }
  1292. error = lpInternet->GetStatus();
  1293. if (error == ERROR_SUCCESS) {
  1294. hInternet = (HINTERNET)lpInternet;
  1295. //
  1296. // success - don't return the object address, return the pseudo-handle
  1297. // value we generated
  1298. //
  1299. hInternet = ((HANDLE_OBJECT *)hInternet)->GetPseudoHandle();
  1300. //
  1301. // start async support now if required. If we can't start it, we'll get
  1302. // another chance the next time we create an async request
  1303. //
  1304. if (dwFlags & INTERNET_FLAG_ASYNC) {
  1305. InitializeAsyncSupport();
  1306. }
  1307. } else {
  1308. //
  1309. // hack fix to stop InternetIndicateStatus (called from the handle
  1310. // object destructor) blowing up if there is no handle object in the
  1311. // thread info block. We can't call back anyway
  1312. //
  1313. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  1314. if (lpThreadInfo) {
  1315. //
  1316. // BUGBUG - incorrect handle value
  1317. //
  1318. _InternetSetObjectHandle(lpThreadInfo, lpInternet, lpInternet);
  1319. }
  1320. //
  1321. // we failed during initialization. Kill the handle using Dereference()
  1322. // (in order to stop the debug version complaining about the reference
  1323. // count not being 0. Invalidate for same reason)
  1324. //
  1325. lpInternet->Invalidate();
  1326. lpInternet->Dereference();
  1327. INET_ASSERT(hInternet == NULL);
  1328. }
  1329. quit:
  1330. if (error != ERROR_SUCCESS) {
  1331. DEBUG_ERROR(API, error);
  1332. SetLastError(error);
  1333. }
  1334. DEBUG_LEAVE_API(hInternet);
  1335. return hInternet;
  1336. }
  1337. INTERNETAPI_(BOOL) InternetCloseHandle(
  1338. IN HINTERNET hInternet
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. Closes any open internet handle object
  1343. Arguments:
  1344. hInternet - handle of internet object to close
  1345. Return Value:
  1346. BOOL
  1347. Success - TRUE
  1348. Failure - FALSE. For more information call GetLastError()
  1349. --*/
  1350. {
  1351. DEBUG_ENTER_API((DBG_API,
  1352. Bool,
  1353. "InternetCloseHandle",
  1354. "%#x",
  1355. hInternet
  1356. ));
  1357. PERF_ENTER(InternetCloseHandle);
  1358. DWORD error;
  1359. BOOL success = FALSE;
  1360. HINTERNET hInternetMapped = NULL;
  1361. static DWORD ticks = GetTickCountWrap();
  1362. if (!GlobalDataInitialized) {
  1363. error = GlobalDataInitialize();
  1364. if (error != ERROR_SUCCESS) {
  1365. goto quit;
  1366. }
  1367. }
  1368. //
  1369. // map the handle. Don't invalidate it (_InternetCloseHandle() does this)
  1370. //
  1371. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, FALSE);
  1372. if (error != ERROR_SUCCESS) {
  1373. if (hInternetMapped == NULL) {
  1374. //
  1375. // the handle never existed or has been completely destroyed
  1376. //
  1377. DEBUG_PRINT(API,
  1378. ERROR,
  1379. ("Handle %#x is invalid\n",
  1380. hInternet
  1381. ));
  1382. //
  1383. // catch invalid handles - may help caller
  1384. //
  1385. DEBUG_BREAK(INVALID_HANDLES);
  1386. } else {
  1387. //
  1388. // this handle is already being closed (it's invalidated). We only
  1389. // need one InternetCloseHandle() operation to invalidate the handle.
  1390. // All other threads will simply dereference the handle, and
  1391. // eventually it will be destroyed
  1392. //
  1393. DereferenceObject((LPVOID)hInternetMapped);
  1394. }
  1395. goto quit;
  1396. }
  1397. //
  1398. // the handle is not invalidated
  1399. //
  1400. HANDLE_OBJECT * pHandle;
  1401. pHandle = (HANDLE_OBJECT *)hInternetMapped;
  1402. if ( ! ((INTERNET_HANDLE_OBJECT *)hInternetMapped)->IsAsyncHandle() )
  1403. {
  1404. if ((GetTickCountWrap() - ticks) >= 5000)
  1405. {
  1406. PurgeServerInfoList(FALSE);
  1407. InterlockedExchange((LPLONG) &ticks, (LONG) GetTickCountWrap());
  1408. }
  1409. }
  1410. DEBUG_PRINT(INET,
  1411. INFO,
  1412. ("handle %#x == %#x == %s\n",
  1413. hInternet,
  1414. hInternetMapped,
  1415. InternetMapHandleType(pHandle->GetHandleType())
  1416. ));
  1417. //
  1418. // if this is an http request handle, notify all filters.
  1419. //
  1420. if (pHandle->GetHandleType() == TypeHttpRequestHandle) {
  1421. HttpFiltOnTransactionComplete (hInternet);
  1422. }
  1423. //
  1424. // if this is a delete-parent-with-child subtree then find the root node
  1425. //
  1426. while (pHandle->GetDeleteWithChild()) {
  1427. HINTERNET handleObject;
  1428. handleObject = pHandle->GetParent();
  1429. INET_ASSERT(handleObject != NULL);
  1430. //
  1431. // remove the delete-parent-with-child indication, or we'll get stuck
  1432. // in a loop
  1433. //
  1434. pHandle->SetParent(handleObject, FALSE);
  1435. //
  1436. // if the parent handle is an EXISTING_CONNECT connect handle then we
  1437. // just mark it unused & close the current handle
  1438. //
  1439. HINTERNET_HANDLE_TYPE handleType;
  1440. handleType = ((HANDLE_OBJECT *)handleObject)->GetHandleType();
  1441. if ((handleType == TypeFtpConnectHandle)
  1442. || (handleType == TypeGopherConnectHandle)
  1443. || (handleType == TypeHttpConnectHandle)) {
  1444. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  1445. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)handleObject;
  1446. //
  1447. // SetUnused() will only operate on a connect handle object that
  1448. // has been created with INTERNET_FLAG_EXISTING_CONNECT
  1449. //
  1450. if (pConnect->SetUnused()) {
  1451. //
  1452. // only handle type should be FTP connect handle for now
  1453. //
  1454. INET_ASSERT(handleType == TypeFtpConnectHandle);
  1455. DEBUG_PRINT(INET,
  1456. INFO,
  1457. ("caching unused %s connect handle object %#x. RefCount = %d\n",
  1458. (handleType == TypeFtpConnectHandle)
  1459. ? "FTP"
  1460. : (handleType == TypeGopherConnectHandle)
  1461. ? "Gopher"
  1462. : "HTTP",
  1463. ((HANDLE_OBJECT *)handleObject)->GetPseudoHandle(),
  1464. ((HANDLE_OBJECT *)handleObject)->ReferenceCount()
  1465. ));
  1466. break;
  1467. }
  1468. }
  1469. pHandle = (HANDLE_OBJECT *)handleObject;
  1470. hInternet = pHandle->GetPseudoHandle();
  1471. }
  1472. //
  1473. // close all child handles first
  1474. //
  1475. while (pHandle->HaveChildren()) {
  1476. //
  1477. // we'll fall out at the first error we get. It *should* mean that this
  1478. // handle (and its descendents) is already being closed
  1479. //
  1480. if (!InternetCloseHandle(pHandle->NextChild())) {
  1481. break;
  1482. }
  1483. }
  1484. //
  1485. // clear the handle object last error variables
  1486. //
  1487. InternetClearLastError();
  1488. //
  1489. // remove the reference added by MapHandleToAddress(), or the handle won't
  1490. // be destroyed by _InternetCloseHandle()
  1491. //
  1492. DereferenceObject((LPVOID)hInternetMapped);
  1493. //
  1494. // use _InternetCloseHandle() to do the work
  1495. //
  1496. success = _InternetCloseHandle(hInternet);
  1497. quit:
  1498. // SetLastError must be called after PERF_LEAVE !!!
  1499. PERF_LEAVE(InternetCloseHandle);
  1500. if (error != ERROR_SUCCESS) {
  1501. DEBUG_ERROR(API, error);
  1502. SetLastError(error);
  1503. }
  1504. DEBUG_LEAVE_API(success);
  1505. return success;
  1506. }
  1507. BOOL
  1508. _InternetCloseHandle(
  1509. IN HINTERNET hInternet
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Same as InternetCloseHandle() except does not clear out the last error text.
  1514. Mainly for FTP
  1515. Arguments:
  1516. hInternet - handle of internet object to close
  1517. Return Value:
  1518. BOOL
  1519. Success - TRUE
  1520. Failure - FALSE. For more information call GetLastError()
  1521. --*/
  1522. {
  1523. DEBUG_ENTER((DBG_INET,
  1524. Bool,
  1525. "_InternetCloseHandle",
  1526. "%#x",
  1527. hInternet
  1528. ));
  1529. DWORD error;
  1530. BOOL success;
  1531. HINTERNET hInternetMapped = NULL;
  1532. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  1533. if (lpThreadInfo == NULL) {
  1534. if (InDllCleanup) {
  1535. error = ERROR_INTERNET_SHUTDOWN;
  1536. } else {
  1537. INET_ASSERT(FALSE);
  1538. error = ERROR_INTERNET_INTERNAL_ERROR;
  1539. }
  1540. goto quit;
  1541. }
  1542. //
  1543. // map the handle and invalidate it. This will cause any new requests with
  1544. // the handle as a parameter to fail
  1545. //
  1546. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, TRUE);
  1547. if (error != ERROR_SUCCESS) {
  1548. if (hInternetMapped != NULL) {
  1549. //
  1550. // the handle is already being closed, or is already deleted
  1551. //
  1552. DereferenceObject((LPVOID)hInternetMapped);
  1553. }
  1554. //
  1555. // since this is the only function that can invalidate a handle, if we
  1556. // are here then the handle is just waiting for its refcount to go to
  1557. // zero. We already removed the refcount we added above, so we're in
  1558. // the clear
  1559. //
  1560. goto quit;
  1561. }
  1562. //
  1563. // there may be an active socket operation. We close the socket to abort the
  1564. // operation
  1565. //
  1566. ((INTERNET_HANDLE_OBJECT *)hInternetMapped)->AbortSocket();
  1567. //
  1568. // we need the parent handle - we will set this as the handle object being
  1569. // processed by this thread. This is required for async worker threads (see
  1570. // below)
  1571. //
  1572. HINTERNET hParent;
  1573. HINTERNET hParentMapped;
  1574. DWORD_PTR dwParentContext;
  1575. hParentMapped = ((HANDLE_OBJECT *)hInternetMapped)->GetParent();
  1576. if (hParentMapped != NULL) {
  1577. hParent = ((HANDLE_OBJECT *)hParentMapped)->GetPseudoHandle();
  1578. dwParentContext = ((HANDLE_OBJECT *)hParentMapped)->GetContext();
  1579. }
  1580. //
  1581. // set the object handle and context in the per-thread data structure
  1582. //
  1583. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  1584. _InternetSetContext(lpThreadInfo,
  1585. ((INTERNET_HANDLE_OBJECT *)hInternetMapped)->GetContext()
  1586. );
  1587. //
  1588. // at this point, there should *always* be at least 2 references on the
  1589. // handle - one added when the object was created, and one added by
  1590. // MapHandleToAddress() above. If the object is still alive after the 2
  1591. // dereferences, then it will be destroyed when the current owning thread
  1592. // dereferences it
  1593. //
  1594. (void)DereferenceObject((LPVOID)hInternetMapped);
  1595. error = DereferenceObject((LPVOID)hInternetMapped);
  1596. //
  1597. // now set the object to be the parent. This is necessary for e.g.
  1598. // FtpGetFile() and async requests (where the async worker thread will make
  1599. // an extra callback to deliver the results of the async request)
  1600. //
  1601. if (hParentMapped != NULL) {
  1602. _InternetSetObjectHandle(lpThreadInfo, hParent, hParentMapped);
  1603. if (dwParentContext != 0) {
  1604. _InternetSetContext(lpThreadInfo, dwParentContext);
  1605. }
  1606. }
  1607. if (g_bHibernating)
  1608. {
  1609. InterruptSelect();
  1610. }
  1611. //
  1612. // if the handle was still alive after dereferencing it then we will inform
  1613. // the app that the close is pending
  1614. //
  1615. quit:
  1616. //
  1617. // if the handle is still alive then we return success - it is invalidated
  1618. // and will be deleted as soon as possible
  1619. //
  1620. if (error == ERROR_INTERNET_HANDLE_EXISTS) {
  1621. error = ERROR_SUCCESS;
  1622. }
  1623. success = (error==ERROR_SUCCESS);
  1624. if (!success) {
  1625. SetLastError(error);
  1626. DEBUG_ERROR(INET, error);
  1627. }
  1628. DEBUG_LEAVE(success);
  1629. return success;
  1630. }
  1631. DWORD
  1632. _InternetCloseHandleNoContext(
  1633. IN HINTERNET hInternet
  1634. )
  1635. /*++
  1636. Routine Description:
  1637. Same as _InternetCloseHandle() except does not change the per-thread info
  1638. structure handle/context values
  1639. BUGBUG - This should be handled via a parameter to _InternetCloseHandle(),
  1640. but its close to shipping...
  1641. Arguments:
  1642. hInternet - handle of internet object to close
  1643. Return Value:
  1644. DWORD
  1645. Success - ERROR_SUCCESS
  1646. Failure - ERROR_INVALID_HANDLE
  1647. --*/
  1648. {
  1649. DEBUG_ENTER((DBG_INET,
  1650. Bool,
  1651. "_InternetCloseHandleNoContext",
  1652. "%#x",
  1653. hInternet
  1654. ));
  1655. DWORD error;
  1656. HINTERNET hInternetMapped = NULL;
  1657. //
  1658. // map the handle and invalidate it. This will cause any new requests with
  1659. // the handle as a parameter to fail
  1660. //
  1661. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, TRUE);
  1662. if (error != ERROR_SUCCESS) {
  1663. if (hInternetMapped != NULL) {
  1664. //
  1665. // the handle is already being closed, or is already deleted
  1666. //
  1667. DereferenceObject((LPVOID)hInternetMapped);
  1668. }
  1669. //
  1670. // since this is the only function that can invalidate a handle, if we
  1671. // are here then the handle is just waiting for its refcount to go to
  1672. // zero. We already removed the refcount we added above, so we're in
  1673. // the clear
  1674. //
  1675. goto quit;
  1676. }
  1677. //
  1678. // there may be an active socket operation. We close the socket to abort the
  1679. // operation
  1680. //
  1681. ((INTERNET_HANDLE_OBJECT *)hInternetMapped)->AbortSocket();
  1682. //
  1683. // at this point, there should *always* be at least 2 references on the
  1684. // handle - one added when the object was created, and one added by
  1685. // MapHandleToAddress() above. If the object is still alive after the 2
  1686. // dereferences, then it will be destroyed when the current owning thread
  1687. // dereferences it
  1688. //
  1689. (void)DereferenceObject((LPVOID)hInternetMapped);
  1690. error = DereferenceObject((LPVOID)hInternetMapped);
  1691. quit:
  1692. //
  1693. // if the handle is still alive then we return success - it is invalidated
  1694. // and will be deleted as soon as possible
  1695. //
  1696. if (error == ERROR_INTERNET_HANDLE_EXISTS) {
  1697. error = ERROR_SUCCESS;
  1698. }
  1699. DEBUG_LEAVE(error);
  1700. return error;
  1701. }
  1702. INTERNETAPI_(BOOL) InternetGetCertByURLA(
  1703. IN LPSTR lpszURL,
  1704. IN OUT LPSTR lpszCertText,
  1705. OUT DWORD dwcbCertText
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Does a high-level lookup against the Certificate Cache.
  1710. Searches by URL (broken down into hostname) for the Certificate,
  1711. and returns it in a formatted (&localized) string.
  1712. Arguments:
  1713. lpszUrl - pointer to URL to crack
  1714. lpszCertText - Output of formatted certifcate
  1715. dwcbCertText - Size of lpszCertText
  1716. Return Value:
  1717. BOOL
  1718. Success - TRUE
  1719. Failure - FALSE. Call GetLastError() for more info
  1720. --*/
  1721. {
  1722. BOOL fSuccess = FALSE;
  1723. /* LPSTR lpszHostName;
  1724. DWORD dwcbHostName;
  1725. INTERNET_CERTIFICATE_INFO cInfo;
  1726. CHAR chBackup;
  1727. DWORD error = ERROR_SUCCESS;
  1728. ZeroMemory(&cInfo, sizeof(INTERNET_CERTIFICATE_INFO));
  1729. error = CrackUrl(lpszURL,
  1730. lstrlen(lpszURL),
  1731. FALSE,
  1732. NULL, // Scheme Type
  1733. NULL, // Scheme Name
  1734. NULL, // Scheme Length
  1735. &lpszHostName, // Host Name
  1736. &dwcbHostName, // Host Length
  1737. NULL, // Internet Port
  1738. NULL, // UserName
  1739. NULL, // UserName Length
  1740. NULL, // Password
  1741. NULL, // Password Lenth
  1742. NULL, // Path
  1743. NULL, // Path Length
  1744. NULL, // Extra Info
  1745. NULL, // Extra Info Length
  1746. NULL
  1747. );
  1748. if ( error != ERROR_SUCCESS)
  1749. goto quit;
  1750. chBackup = lpszHostName[dwcbHostName];
  1751. lpszHostName[dwcbHostName] = '\0';
  1752. fSuccess = GlobalCertCache.GetCert(
  1753. lpszHostName,
  1754. &cInfo
  1755. );
  1756. lpszHostName[dwcbHostName] = chBackup;
  1757. if ( ! fSuccess )
  1758. {
  1759. error = ERROR_INTERNET_INVALID_OPERATION;
  1760. goto quit;
  1761. }
  1762. LPSTR szResult;
  1763. szResult = FormatCertInfo(&cInfo);
  1764. if ( ! szResult )
  1765. {
  1766. error = ERROR_NOT_ENOUGH_MEMORY;
  1767. goto quit;
  1768. }
  1769. DWORD dwcbResult;
  1770. dwcbResult = lstrlen(szResult);
  1771. if ( dwcbCertText < (dwcbResult+1) )
  1772. {
  1773. error = ERROR_INSUFFICIENT_BUFFER;
  1774. goto quit;
  1775. }
  1776. memcpy(
  1777. lpszCertText,
  1778. szResult,
  1779. (dwcbResult + 1) * sizeof(TCHAR));
  1780. quit:
  1781. if (NULL != szResult) {
  1782. FREE_MEMORY(szResult);
  1783. }
  1784. if (NULL != cInfo.lpszSubjectInfo) {
  1785. FREE_MEMORY(cInfo.lpszSubjectInfo);
  1786. }
  1787. if (NULL != cInfo.lpszIssuerInfo) {
  1788. FREE_MEMORY(cInfo.lpszIssuerInfo);
  1789. }
  1790. if (NULL != cInfo.lpszSignatureAlgName) {
  1791. FREE_MEMORY(cInfo.lpszSignatureAlgName);
  1792. }
  1793. if (NULL != cInfo.lpszEncryptionAlgName) {
  1794. FREE_MEMORY(cInfo.lpszEncryptionAlgName);
  1795. }
  1796. if (NULL != cInfo.lpszProtocolName) {
  1797. FREE_MEMORY(cInfo.lpszProtocolName);
  1798. }
  1799. fSuccess = TRUE;
  1800. if ( error != ERROR_SUCCESS )
  1801. {
  1802. fSuccess = FALSE;
  1803. SetLastError(error);
  1804. }*/
  1805. return fSuccess;
  1806. }
  1807. INTERNETAPI_(BOOL) InternetShowSecurityInfoByURLA(
  1808. IN LPSTR lpszURL,
  1809. IN HWND hwndRootWindow
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. Does a high-level lookup against the Certificate Cache.
  1814. Searches by URL (broken down into hostname) for the Certificate,
  1815. and returns it in a formatted (&localized) string.
  1816. Arguments:
  1817. lpszUrl - pointer to URL to crack
  1818. lpszCertText - Output of formatted certifcate
  1819. dwcbCertText - Size of lpszCertText
  1820. Return Value:
  1821. BOOL
  1822. Success - TRUE
  1823. Failure - FALSE. Call GetLastError() for more info
  1824. --*/
  1825. {
  1826. DEBUG_ENTER_API((DBG_INET,
  1827. Bool,
  1828. "InternetShowSecurityInfoA",
  1829. "%q %#x",
  1830. lpszURL,
  1831. hwndRootWindow
  1832. ));
  1833. LPSTR lpszHostName;
  1834. DWORD dwcbHostName;
  1835. INTERNET_SECURITY_INFO cInfo;
  1836. CHAR chBackup;
  1837. DWORD dwFlags;
  1838. DWORD error = ERROR_SUCCESS;
  1839. WCHAR szTitle[MAX_PATH];
  1840. WCHAR szMessage[MAX_PATH];
  1841. INTERNET_SCHEME ustSchemeType;
  1842. BOOL fResult = FALSE;
  1843. if (!GlobalDataInitialized) {
  1844. if (GlobalDataInitialize() != ERROR_SUCCESS) {
  1845. goto Cleanup;
  1846. }
  1847. }
  1848. ZeroMemory(&cInfo, sizeof(INTERNET_SECURITY_INFO));
  1849. error = CrackUrl(lpszURL,
  1850. lstrlen(lpszURL),
  1851. FALSE,
  1852. &ustSchemeType,
  1853. NULL, // Scheme Name
  1854. NULL, // Scheme Length
  1855. &lpszHostName, // Host Name
  1856. &dwcbHostName, // Host Length
  1857. NULL, // Internet Port
  1858. NULL, // UserName
  1859. NULL, // UserName Length
  1860. NULL, // Password
  1861. NULL, // Password Lenth
  1862. NULL, // Path
  1863. NULL, // Path Length
  1864. NULL, // Extra Info
  1865. NULL, // Extra Info Length
  1866. NULL
  1867. );
  1868. if ( error != ERROR_SUCCESS)
  1869. {
  1870. goto Cleanup;
  1871. }
  1872. if ( ustSchemeType != INTERNET_SCHEME_HTTPS )
  1873. {
  1874. goto Cleanup;
  1875. }
  1876. if ( lpszHostName == NULL || dwcbHostName == 0 )
  1877. {
  1878. fResult = TRUE;
  1879. goto done;
  1880. }
  1881. chBackup = lpszHostName[dwcbHostName];
  1882. lpszHostName[dwcbHostName] = '\0';
  1883. SECURITY_CACHE_LIST_ENTRY *pEntry;
  1884. pEntry = GlobalCertCache.Find(lpszHostName);
  1885. lpszHostName[dwcbHostName] = chBackup;
  1886. if(pEntry)
  1887. {
  1888. pEntry->CopyOut(cInfo);
  1889. pEntry->Release();
  1890. ShowSecurityInfo(hwndRootWindow,
  1891. &cInfo);
  1892. CertFreeCertificateContext(cInfo.pCertificate);
  1893. fResult = TRUE;
  1894. goto done;
  1895. }
  1896. Cleanup:
  1897. // No certificate info, display messagebox.
  1898. LoadStringWrapW(
  1899. GlobalDllHandle,
  1900. IDS_NOCERT_TITLE,
  1901. szTitle,
  1902. sizeof(szTitle) / sizeof(szTitle[0]));
  1903. LoadStringWrapW(
  1904. GlobalDllHandle,
  1905. IDS_NOCERT,
  1906. szMessage,
  1907. sizeof(szMessage) / sizeof(szMessage[0]));
  1908. MessageBoxWrapW(hwndRootWindow,
  1909. szMessage,
  1910. szTitle,
  1911. MB_ICONINFORMATION | MB_OK);
  1912. done:
  1913. DEBUG_LEAVE_API(fResult);
  1914. return fResult;
  1915. }
  1916. INTERNETAPI_(HINTERNET) InternetConnectA(
  1917. IN HINTERNET hInternet,
  1918. IN LPCSTR lpszServerName,
  1919. IN INTERNET_PORT nServerPort,
  1920. IN LPCSTR lpszUserName OPTIONAL,
  1921. IN LPCSTR lpszPassword OPTIONAL,
  1922. IN DWORD dwService,
  1923. IN DWORD dwFlags,
  1924. IN DWORD_PTR dwContext
  1925. )
  1926. /*++
  1927. Routine Description:
  1928. Opens a connection with a server, logging-on the user in the process.
  1929. Arguments:
  1930. hInternet - Internet handle, returned by InternetOpen()
  1931. lpszServerName - name of server with which to connect
  1932. nServerPort - port at which server listens
  1933. lpszUserName - name of current user
  1934. lpszPassword - password of current user
  1935. dwService - service required. Controls type of handle generated.
  1936. May be one of:
  1937. - INTERNET_SERVICE_FTP
  1938. - INTERNET_SERVICE_GOPHER
  1939. - INTERNET_SERVICE_HTTP
  1940. dwFlags - protocol-specific flags. The following are defined:
  1941. - INTERNET_FLAG_PASSIVE (FTP)
  1942. - INTERNET_FLAG_KEEP_CONNECTION (HTTP)
  1943. - INTERNET_FLAG_SECURE (HTTP)
  1944. dwContext - application-supplied value used to identify this
  1945. request in callbacks
  1946. Return Value:
  1947. HINTERNET
  1948. Success - address of a new handle object
  1949. Failure - NULL. Call GetLastError() for more info
  1950. --*/
  1951. {
  1952. DEBUG_ENTER_API((DBG_API,
  1953. Handle,
  1954. "InternetConnectA",
  1955. "%#x, %q, %d, %q, %q, %s (%d), %#08x, %#x",
  1956. hInternet,
  1957. lpszServerName,
  1958. nServerPort,
  1959. lpszUserName,
  1960. lpszPassword,
  1961. InternetMapService(dwService),
  1962. dwService,
  1963. dwFlags,
  1964. dwContext
  1965. ));
  1966. char emailName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  1967. char proxyBuf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  1968. HINTERNET connectHandle = NULL;
  1969. HINTERNET hInternetMapped = NULL;
  1970. HINTERNET hObject;
  1971. HINTERNET hObjectMapped = NULL;
  1972. LPINTERNET_THREAD_INFO lpThreadInfo;
  1973. BOOL fUseProxy = FALSE;
  1974. LPSTR serverName = NULL;
  1975. LPSTR userName = (LPSTR)lpszUserName;
  1976. LPSTR password = (LPSTR)lpszPassword;
  1977. LPSTR realServerName = (LPSTR)lpszServerName;
  1978. LPSTR realUserName = (LPSTR)lpszUserName;
  1979. BOOL existingConnection = FALSE;
  1980. BOOL viaProxy = FALSE;
  1981. INTERNET_CONNECT_HANDLE_OBJECT * pConnect = NULL;
  1982. //CServerInfo * lpServerInfo;
  1983. BOOL bProtocolLevel = !(dwFlags & INTERNET_FLAG_OFFLINE);
  1984. BOOL bIsWorker = FALSE;
  1985. BOOL bNonNestedAsync = FALSE;
  1986. BOOL isLocal;
  1987. BOOL isAsync;
  1988. BOOL bFTPSetPerUserItem = FALSE;
  1989. DWORD error = ERROR_SUCCESS;
  1990. if (!GlobalDataInitialized) {
  1991. error = ERROR_INTERNET_NOT_INITIALIZED;
  1992. goto done;
  1993. }
  1994. //
  1995. // get the per-thread info block
  1996. //
  1997. lpThreadInfo = InternetGetThreadInfo();
  1998. if (lpThreadInfo == NULL) {
  1999. INET_ASSERT(FALSE);
  2000. error = ERROR_INTERNET_INTERNAL_ERROR;
  2001. goto done;
  2002. }
  2003. _InternetIncNestingCount();
  2004. bIsWorker = lpThreadInfo->IsAsyncWorkerThread;
  2005. bNonNestedAsync = bIsWorker && (lpThreadInfo->NestedRequests == 1);
  2006. //
  2007. // handle any global proxy settings changes first
  2008. //
  2009. if (InternetSettingsChanged()) {
  2010. ChangeGlobalSettings();
  2011. }
  2012. //
  2013. // handle/refcount munging:
  2014. //
  2015. // sync:
  2016. // map hInternet on input (+1 ref)
  2017. // generate connect handle (1 ref)
  2018. // if failure && !connect handle
  2019. // close connect handle (0 refs: delete)
  2020. // if success
  2021. // deref hInternet (-1 ref)
  2022. // else if going async
  2023. // ref connect handle (2 refs)
  2024. //
  2025. // async:
  2026. // hInternet is mapped connect handle (2 refs)
  2027. // get real hInternet from connect handle parent (2 refs (e.g.))
  2028. // deref connect handle (1 ref)
  2029. // if failure
  2030. // close connect handle (0 refs: delete)
  2031. // deref open handle (-1 ref)
  2032. //
  2033. // N.B. the final deref of the *indicated* handle on async callback will
  2034. // happen in the async code
  2035. //
  2036. if (bNonNestedAsync) {
  2037. connectHandle = hInternet;
  2038. hInternetMapped = ((HANDLE_OBJECT *)connectHandle)->GetParent();
  2039. hInternet = ((HANDLE_OBJECT *)hInternetMapped)->GetPseudoHandle();
  2040. } else {
  2041. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, FALSE);
  2042. if ((error != ERROR_SUCCESS) && (hInternetMapped == NULL)) {
  2043. goto quit;
  2044. }
  2045. //
  2046. // set the info context and clear the last error info
  2047. //
  2048. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  2049. _InternetClearLastError(lpThreadInfo);
  2050. _InternetSetContext(lpThreadInfo, dwContext);
  2051. //
  2052. // quit now if the handle object is invalidated
  2053. //
  2054. if (error != ERROR_SUCCESS) {
  2055. goto quit;
  2056. }
  2057. //
  2058. // validate the handle & discover local/remote & sync/async
  2059. //
  2060. error = RIsHandleLocal(hInternetMapped,
  2061. &isLocal,
  2062. &isAsync,
  2063. TypeInternetHandle
  2064. );
  2065. if (error != ERROR_SUCCESS) {
  2066. goto quit;
  2067. }
  2068. //
  2069. // we allow all valid flags to be passed in
  2070. //
  2071. if ((dwFlags & ~INTERNET_FLAGS_MASK)
  2072. || (lpszServerName == NULL)
  2073. || (*lpszServerName == '\0')) {
  2074. error = ERROR_INVALID_PARAMETER;
  2075. goto quit;
  2076. }
  2077. }
  2078. INTERNET_SCHEME schemeType;
  2079. switch (dwService) {
  2080. case INTERNET_SERVICE_FTP:
  2081. schemeType = INTERNET_SCHEME_FTP;
  2082. break;
  2083. case INTERNET_SERVICE_HTTP:
  2084. schemeType = (dwFlags & INTERNET_FLAG_SECURE)
  2085. ? INTERNET_SCHEME_HTTPS
  2086. : INTERNET_SCHEME_HTTP;
  2087. break;
  2088. case INTERNET_SERVICE_GOPHER: // disable gopher by default
  2089. if (GlobalEnableGopher) {
  2090. schemeType = INTERNET_SCHEME_GOPHER;
  2091. break;
  2092. }
  2093. default:
  2094. error = ERROR_INVALID_PARAMETER;
  2095. goto quit;
  2096. }
  2097. //
  2098. // validate arguments if we're not in the async thread context, in which
  2099. // case we did this when the original request was made
  2100. //
  2101. if (bNonNestedAsync) {
  2102. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)connectHandle;
  2103. goto sync_path;
  2104. }
  2105. //
  2106. // app thread or in async worker thread but being called from another
  2107. // async API, such as InternetOpenUrl()
  2108. //
  2109. //
  2110. // special case: if the server name is the NULL pointer or empty string, and
  2111. // the port is 0 AND we have a proxy configured for this protocol then the
  2112. // app is asking to connect directly to the proxy (the proxy server itself
  2113. // had better be in the bypass list!)
  2114. //
  2115. // BUGBUG - not sure if this is really where we want to do this
  2116. //
  2117. INTERNET_HANDLE_OBJECT * lpInternet;
  2118. lpInternet = (INTERNET_HANDLE_OBJECT * )hInternetMapped;
  2119. //
  2120. // if the port value is 0 convert it to the default port for the
  2121. // protocol
  2122. //
  2123. if (nServerPort == INTERNET_INVALID_PORT_NUMBER) {
  2124. switch (dwService) {
  2125. case INTERNET_SERVICE_FTP:
  2126. nServerPort = INTERNET_DEFAULT_FTP_PORT;
  2127. break;
  2128. case INTERNET_SERVICE_GOPHER:
  2129. nServerPort = INTERNET_DEFAULT_GOPHER_PORT;
  2130. break;
  2131. case INTERNET_SERVICE_HTTP:
  2132. if (dwFlags & INTERNET_FLAG_SECURE) {
  2133. nServerPort = INTERNET_DEFAULT_HTTPS_PORT;
  2134. } else {
  2135. nServerPort = INTERNET_DEFAULT_HTTP_PORT;
  2136. }
  2137. break;
  2138. }
  2139. }
  2140. //
  2141. // if we have been given a net (i.e. IP) address, try to convert it to the
  2142. // corresponding host name
  2143. //
  2144. //if (IsNetAddress((LPSTR)lpszServerName)) {
  2145. //lpszServerName = (LPCSTR)MapNetAddressToName((LPSTR)lpszServerName);
  2146. realServerName = (LPSTR)lpszServerName;
  2147. //}
  2148. //
  2149. // we need to get the username and password for the current user before we
  2150. // make the connection proper. The reason for this is that if we leave it
  2151. // to the server, it will end up with a username of "SYSTEM" for all
  2152. // anonymous FTP connects
  2153. //
  2154. if (dwService == INTERNET_SERVICE_FTP) {
  2155. //
  2156. // Make sure we have the correct Proxy-Network Settings, at this point.
  2157. //
  2158. InternetAutodialIfNotLocalHost(NULL, (LPSTR) lpszServerName);
  2159. //
  2160. // check the user name & password. If NULLs were supplied, use the values
  2161. // from the registry
  2162. //
  2163. //
  2164. // Do we need to set this item as per user? If a username was supplied (
  2165. // either cracked from the URL or set on the handle, userName will be
  2166. // non-null. Currently, this is the only criteria for when we set pu.
  2167. //
  2168. // Need to check this BEFORE calling GetEmailNameAndPassword which will
  2169. // plugin "anonymous" if no username provided.
  2170. //
  2171. bFTPSetPerUserItem = userName ? TRUE : FALSE;
  2172. DEBUG_PRINT(FTP,
  2173. INFO,
  2174. ("InternetConnectA:FTP: bFTPSetPerUserItem = %d\n",
  2175. bFTPSetPerUserItem
  2176. ));
  2177. error = GetEmailNameAndPassword(&userName,
  2178. &password,
  2179. emailName,
  2180. sizeof(emailName)
  2181. );
  2182. if (error != ERROR_SUCCESS) {
  2183. goto quit;
  2184. }
  2185. //
  2186. // this is the user name we will use for the object, i.e. either the
  2187. // name supplied, or "anonymous" as mapped above
  2188. //
  2189. realUserName = userName;
  2190. //
  2191. // if this request is going via an FTP proxy, then convert the parameters
  2192. // now. We convert the username to <username>@<servername>, the password
  2193. // remains the same, and the server name & port become the proxy server
  2194. // name and port
  2195. //
  2196. // N.B. We ONLY do this once on the initial (synchronous) path
  2197. //
  2198. AUTO_PROXY_ASYNC_MSG proxyInfoQuery(
  2199. INTERNET_SCHEME_FTP,
  2200. (LPSTR)lpszServerName,
  2201. lstrlen((LPSTR)lpszServerName)
  2202. );
  2203. AUTO_PROXY_ASYNC_MSG *pProxyInfoQuery;
  2204. pProxyInfoQuery = &proxyInfoQuery;
  2205. proxyInfoQuery.SetAvoidAsyncCall(TRUE);
  2206. error = lpInternet->GetProxyInfo(
  2207. &pProxyInfoQuery
  2208. );
  2209. if ( error != ERROR_SUCCESS )
  2210. {
  2211. goto quit;
  2212. }
  2213. if ( proxyInfoQuery.IsUseProxy() )
  2214. {
  2215. if (proxyInfoQuery.GetProxyScheme() == INTERNET_SCHEME_FTP)
  2216. {
  2217. int ulen = lstrlen(userName);
  2218. int slen = lstrlen(lpszServerName);
  2219. INET_ASSERT((ulen + slen) < (sizeof(proxyBuf) - 1));
  2220. if ((ulen + slen) < (sizeof(proxyBuf) - 1))
  2221. {
  2222. memcpy(proxyBuf, userName, ulen);
  2223. proxyBuf[ulen++] = '@';
  2224. memcpy(&proxyBuf[ulen], lpszServerName, slen + 1);
  2225. //
  2226. // keep a pointer to the real user name for when we
  2227. // create the object
  2228. //
  2229. realUserName = userName;
  2230. userName = proxyBuf;
  2231. //
  2232. // create a copy of the proxy name. We have to do
  2233. // this in case the current proxy list is replaced
  2234. // while we are using this string
  2235. //
  2236. //
  2237. // N.B. we can't be here if we determined that the
  2238. // proxy server was the destination (i.e. we mapped2
  2239. // the empty server name above)
  2240. //
  2241. INET_ASSERT(serverName == NULL);
  2242. serverName = NewString((LPCSTR)proxyInfoQuery._lpszProxyHostName);
  2243. if ( serverName == NULL )
  2244. {
  2245. error = ERROR_NOT_ENOUGH_MEMORY;
  2246. goto quit;
  2247. }
  2248. //
  2249. // keep a pointer to the real (origin) server name
  2250. // for when we create the object
  2251. //
  2252. realServerName = (LPSTR)lpszServerName;
  2253. lpszServerName = serverName;
  2254. //
  2255. // BUGBUG - what if proxyPort != nServerPort? Where
  2256. // should the port go (user@server:port?)
  2257. //
  2258. nServerPort = proxyInfoQuery._nProxyHostPort;
  2259. //
  2260. // this request will go via proxy
  2261. //
  2262. viaProxy = TRUE;
  2263. }
  2264. else
  2265. {
  2266. //
  2267. // blew internal limit
  2268. //
  2269. error = ERROR_INTERNET_INTERNAL_ERROR;
  2270. goto quit;
  2271. }
  2272. }
  2273. }
  2274. }
  2275. else
  2276. {
  2277. if (userName != NULL) {
  2278. if (IsBadStringPtr(userName, INTERNET_MAX_USER_NAME_LENGTH)) {
  2279. error = ERROR_INVALID_PARAMETER;
  2280. goto quit;
  2281. } else if (*userName == '\0') {
  2282. userName = NULL;
  2283. }
  2284. }
  2285. if (password != NULL) {
  2286. if (IsBadStringPtr(password, INTERNET_MAX_PASSWORD_LENGTH)) {
  2287. error = ERROR_INVALID_PASSWORD;
  2288. goto quit;
  2289. } else if (*password == '\0') {
  2290. password = NULL;
  2291. }
  2292. }
  2293. }
  2294. //
  2295. // find the handle object if EXISTING_CONNECT AND we are creating protocol-
  2296. // level connections, else create it
  2297. //
  2298. INET_ASSERT(connectHandle == NULL);
  2299. INET_ASSERT(error == ERROR_SUCCESS);
  2300. if ((dwFlags & INTERNET_FLAG_EXISTING_CONNECT) && bProtocolLevel) {
  2301. connectHandle = FindExistingConnectObject(hInternet,
  2302. realServerName,
  2303. nServerPort,
  2304. realUserName,
  2305. password,
  2306. dwService,
  2307. dwFlags,
  2308. dwContext
  2309. );
  2310. }
  2311. if (connectHandle != NULL) {
  2312. existingConnection = TRUE;
  2313. } else {
  2314. //
  2315. // turn off INTERNET_FLAG_EXISTING_CONNECT if we are creating a cache
  2316. // handle - we don't want the handle to hang around after we delete
  2317. // the request handle (i.e. be set unused by InternetCloseHandle()).
  2318. // N.B. We don't need this flag after this operation, so its safe to
  2319. // remove it from dwFlags
  2320. //
  2321. if (!bProtocolLevel) {
  2322. dwFlags &= ~INTERNET_FLAG_EXISTING_CONNECT;
  2323. }
  2324. error = RMakeInternetConnectObjectHandle(
  2325. hInternetMapped,
  2326. &connectHandle,
  2327. (CONNECT_CLOSE_HANDLE_FUNC)wInternetCloseConnectA,
  2328. realServerName, // origin server, not proxy
  2329. nServerPort,
  2330. realUserName, // just user name, not user@server
  2331. password,
  2332. dwService,
  2333. dwFlags,
  2334. dwContext
  2335. );
  2336. if (error != ERROR_SUCCESS) {
  2337. goto quit;
  2338. }
  2339. }
  2340. //
  2341. // this new handle will be used in callbacks
  2342. //
  2343. _InternetSetObjectHandle(lpThreadInfo,
  2344. ((HANDLE_OBJECT *)connectHandle)->GetPseudoHandle(),
  2345. connectHandle
  2346. );
  2347. //
  2348. // based on whether we have been asked to perform async I/O AND we are not
  2349. // in an async worker thread context AND the request is to connect with an
  2350. // FTP service (currently only FTP because this request performs network
  2351. // I/O - gopher and HTTP just allocate & fill in memory) AND there is a
  2352. // valid context value, we will queue the async request, or execute the
  2353. // request synchronously
  2354. //
  2355. //
  2356. // BUGBUG - GetFlags()
  2357. //
  2358. if ((lpInternet->GetInternetOpenFlags() | dwFlags) & INTERNET_FLAG_OFFLINE) {
  2359. error = ERROR_SUCCESS;
  2360. goto quit;
  2361. }
  2362. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)connectHandle;
  2363. //lpServerInfo = pConnect->GetServerInfo();
  2364. DEBUG_PRINT(FTP,
  2365. INFO,
  2366. ("bIsWorker = %d isAsync = %d dwContext %s INC dwService %s ISF bProtocolLevel = %d\n",
  2367. bIsWorker,
  2368. isAsync,
  2369. (dwContext == INTERNET_NO_CALLBACK) ? "==":"!=",
  2370. (dwService == INTERNET_SERVICE_FTP) ? "==":"!=",
  2371. bProtocolLevel));
  2372. if (!bIsWorker
  2373. && isAsync
  2374. && (dwContext != INTERNET_NO_CALLBACK)
  2375. && ((dwService == INTERNET_SERVICE_FTP) ? bProtocolLevel : FALSE)) {
  2376. // If we determined item should be set pu, do so now
  2377. pConnect->SetPerUserItem(bFTPSetPerUserItem);
  2378. DEBUG_PRINT(FTP,
  2379. INFO,
  2380. ("InternetConnectA:Async Path: SetPerUserItem to %\r\n\
  2381. <pConnect = 0x%x> <connectHandle = 0x%x>\r\n",
  2382. pConnect->IsPerUserItem(), pConnect, connectHandle));
  2383. CFsm_FtpConnect * pFsm;
  2384. pFsm = new CFsm_FtpConnect(lpszServerName,
  2385. userName,
  2386. password,
  2387. nServerPort,
  2388. dwService,
  2389. dwFlags,
  2390. dwContext
  2391. );
  2392. if (pFsm != NULL &&
  2393. pFsm->GetError() == ERROR_SUCCESS)
  2394. {
  2395. BOOL bDerefConnect = TRUE;
  2396. error = pConnect->Reference();
  2397. if (error == ERROR_ACCESS_DENIED)
  2398. {
  2399. bDerefConnect = FALSE;
  2400. }
  2401. else if (error == ERROR_SUCCESS)
  2402. {
  2403. error = pFsm->QueueWorkItem();
  2404. if (error == ERROR_IO_PENDING) {
  2405. hInternetMapped = NULL;
  2406. bDerefConnect = FALSE;
  2407. }
  2408. }
  2409. if (bDerefConnect) {
  2410. pConnect->Dereference();
  2411. }
  2412. }
  2413. else
  2414. {
  2415. error = ERROR_NOT_ENOUGH_MEMORY;
  2416. if ( pFsm )
  2417. {
  2418. error = pFsm->GetError();
  2419. delete pFsm;
  2420. pFsm = NULL;
  2421. }
  2422. }
  2423. //
  2424. // if we're here then ERROR_SUCCESS cannot have been returned from
  2425. // the above calls
  2426. //
  2427. INET_ASSERT(error != ERROR_SUCCESS);
  2428. DEBUG_PRINT(FTP,
  2429. INFO,
  2430. ("processing request asynchronously: error = %d\n",
  2431. error
  2432. ));
  2433. goto quit;
  2434. }
  2435. sync_path:
  2436. if (bProtocolLevel && !existingConnection) {
  2437. //
  2438. // generate the protocol-level connect 'object' if required (for FTP).
  2439. // This simply creates a memory object
  2440. //
  2441. HINTERNET protocolConnectHandle = NULL;
  2442. INET_ASSERT(error == ERROR_SUCCESS);
  2443. if (dwService == INTERNET_SERVICE_FTP) {
  2444. error = wFtpConnect(lpszServerName,
  2445. nServerPort,
  2446. userName,
  2447. password,
  2448. dwService,
  2449. dwFlags,
  2450. &protocolConnectHandle
  2451. );
  2452. if (error != ERROR_SUCCESS) {
  2453. goto quit;
  2454. }
  2455. }
  2456. //
  2457. // associate the protocol-level handle and INTERNET_CONNECT_HANDLE_OBJECT
  2458. //
  2459. pConnect->SetConnectHandle(protocolConnectHandle);
  2460. // If we determined item should be set pu, do so now
  2461. pConnect->SetPerUserItem(bFTPSetPerUserItem);
  2462. DEBUG_PRINT(FTP,
  2463. INFO,
  2464. ("InternetConnectA:Sync Path:SetPerUserItem to %d\r\n\
  2465. <pConnect = 0x%x> <protocolConnectHandle = 0x%x> <connectHandle = 0x%x>\r\n",
  2466. pConnect->IsPerUserItem(), pConnect, protocolConnectHandle, connectHandle));
  2467. // for all connect types, get the server info and resolve the server
  2468. // name. If we can't resolve the name then we fail this request
  2469. //
  2470. //lpServerInfo = pConnect->GetServerInfo();
  2471. //if ((lpServerInfo != NULL) && !lpServerInfo->IsNameResolved()) {
  2472. // error = pConnect->SetServerInfo(schemeType, FALSE, FALSE);
  2473. // if (error != ERROR_SUCCESS) {
  2474. // goto quit;
  2475. // }
  2476. //}
  2477. //
  2478. // if we succeeded in creating the connect object and this is an FTP
  2479. // request then we will now attempt to connect to the server proper.
  2480. //
  2481. // We don't need to do this for gopher and HTTP because (currently) they
  2482. // don't make server connections until we perform some other action,
  2483. // like find file, e.g.
  2484. //
  2485. if (dwService == INTERNET_SERVICE_FTP) {
  2486. error = wFtpMakeConnection(protocolConnectHandle,
  2487. userName,
  2488. password
  2489. );
  2490. }
  2491. }
  2492. quit:
  2493. _InternetDecNestingCount(1);
  2494. //
  2495. // free the buffer we used to hold the proxy name if we had to map the
  2496. // empty string to a proxy name
  2497. //
  2498. if (serverName != NULL) {
  2499. DEL_STRING(serverName);
  2500. }
  2501. done:
  2502. if (error == ERROR_SUCCESS) {
  2503. //
  2504. // set the via proxy flag
  2505. //
  2506. ((INTERNET_CONNECT_HANDLE_OBJECT *)connectHandle)->SetViaProxy(viaProxy);
  2507. //
  2508. // success - return generated pseudo-handle
  2509. //
  2510. connectHandle = ((HANDLE_OBJECT *)connectHandle)->GetPseudoHandle();
  2511. //
  2512. // created a handle. If we are generating protocol-level connections
  2513. // then flush the existing connection cache
  2514. //
  2515. if (bProtocolLevel) {
  2516. FlushExistingConnectObjects(hInternet);
  2517. }
  2518. } else {
  2519. if (bNonNestedAsync
  2520. && (/*((HANDLE_OBJECT *)connectHandle)->Dereference()
  2521. ||*/ ((HANDLE_OBJECT *)connectHandle)->IsInvalidated())) {
  2522. error = ERROR_INTERNET_OPERATION_CANCELLED;
  2523. }
  2524. //
  2525. // if we are not pending an async request but we created a handle object
  2526. // then close it
  2527. //
  2528. if ((error != ERROR_IO_PENDING) && (connectHandle != NULL)) {
  2529. //
  2530. // use _InternetCloseHandle() to close the handle: it doesn't clear
  2531. // out the last error text, so that an app can find out what the
  2532. // server sent us in the event of an FTP login failure
  2533. //
  2534. if (bNonNestedAsync) {
  2535. //
  2536. // this handle deref'd at async completion
  2537. //
  2538. hInternetMapped = NULL;
  2539. }
  2540. else
  2541. {
  2542. _InternetCloseHandle(((HANDLE_OBJECT *)connectHandle)->GetPseudoHandle());
  2543. }
  2544. }
  2545. connectHandle = NULL;
  2546. }
  2547. if (hInternetMapped != NULL) {
  2548. DereferenceObject((LPVOID)hInternetMapped);
  2549. }
  2550. if (error != ERROR_SUCCESS) {
  2551. DEBUG_ERROR(API, error);
  2552. SetLastError(error);
  2553. }
  2554. DEBUG_LEAVE_API(connectHandle);
  2555. return connectHandle;
  2556. }
  2557. INTERNETAPI_(HINTERNET) InternetOpenUrlA(
  2558. IN HINTERNET hInternet,
  2559. IN LPCSTR lpszUrl,
  2560. IN LPCSTR lpszHeaders OPTIONAL,
  2561. IN DWORD dwHeadersLength,
  2562. IN DWORD dwFlags,
  2563. IN DWORD_PTR dwContext
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. Opens an URL. This consists of creating a handle to the type of item
  2568. identified by the URL - directory or file
  2569. Arguments:
  2570. hInternet - root Internet handle
  2571. lpszUrl - pointer to the URL to use to open the item
  2572. lpszHeaders - headers to send to HTTP server. May be NULL
  2573. dwHeadersLength - length of lpszHeaders. May be -1 if the app wants us to
  2574. perform the strlen()
  2575. dwFlags - open flags (cache/nocache, etc.)
  2576. dwContext - app-supplied context value for call-backs
  2577. Return Value:
  2578. HINTERNET
  2579. Success - open handle to item described by URL
  2580. Failure - NULL. Use GetLastError() to get more information about why the
  2581. call failed. There may be error text returned from the server
  2582. (in the case of a gopher or FTP URL)
  2583. --*/
  2584. {
  2585. DEBUG_ENTER_API((DBG_API,
  2586. Handle,
  2587. "InternetOpenUrlA",
  2588. "%#x, %q, %.80q, %d, %#08x, %#x",
  2589. hInternet,
  2590. lpszUrl,
  2591. lpszHeaders,
  2592. dwHeadersLength,
  2593. dwFlags,
  2594. dwContext
  2595. ));
  2596. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  2597. DWORD error;
  2598. DWORD nestingLevel = 0;
  2599. HINTERNET hInternetMapped = NULL;
  2600. HINTERNET hUrlMapped = NULL;
  2601. HINTERNET hUrl = NULL;
  2602. PROXY_STATE * pProxyState = NULL;
  2603. BOOL bDeref = TRUE;
  2604. if (!GlobalDataInitialized) {
  2605. error = ERROR_INTERNET_NOT_INITIALIZED;
  2606. goto quit;
  2607. }
  2608. //
  2609. // get the thread info block
  2610. //
  2611. lpThreadInfo = InternetGetThreadInfo();
  2612. if (lpThreadInfo == NULL) {
  2613. INET_ASSERT(FALSE);
  2614. error = ERROR_INTERNET_INTERNAL_ERROR;
  2615. goto quit;
  2616. }
  2617. _InternetIncNestingCount();
  2618. nestingLevel = 1;
  2619. //
  2620. // map the handle
  2621. //
  2622. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, FALSE);
  2623. if ((error != ERROR_SUCCESS) && (hInternetMapped == NULL)) {
  2624. goto quit;
  2625. }
  2626. //
  2627. // set the info context and clear the last error info
  2628. //
  2629. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  2630. _InternetClearLastError(lpThreadInfo);
  2631. _InternetSetContext(lpThreadInfo, dwContext);
  2632. //
  2633. // quit now if the handle object is invalidated
  2634. //
  2635. if (error != ERROR_SUCCESS) {
  2636. goto quit;
  2637. }
  2638. //
  2639. // validate the handle & discover async/sync & local/remote
  2640. //
  2641. BOOL isLocal;
  2642. BOOL isAsync;
  2643. error = RIsHandleLocal(hInternetMapped,
  2644. &isLocal,
  2645. &isAsync,
  2646. TypeInternetHandle
  2647. );
  2648. if (error != ERROR_SUCCESS) {
  2649. goto quit;
  2650. }
  2651. //
  2652. // validate parameters if we're not in the async worker thread context
  2653. //
  2654. if (!lpThreadInfo->IsAsyncWorkerThread) {
  2655. //
  2656. // ensure we have good values for the headers pointer and length
  2657. //
  2658. INET_ASSERT(error == ERROR_SUCCESS);
  2659. if (ARGUMENT_PRESENT(lpszHeaders) && (dwHeadersLength == -1)) {
  2660. __try {
  2661. dwHeadersLength = lstrlen(lpszHeaders);
  2662. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2663. error = ERROR_INVALID_PARAMETER;
  2664. }
  2665. ENDEXCEPT
  2666. if (error != ERROR_SUCCESS) {
  2667. goto quit;
  2668. }
  2669. } else if (!ARGUMENT_PRESENT(lpszHeaders) || (dwHeadersLength == 0)) {
  2670. lpszHeaders = NULL;
  2671. dwHeadersLength = 0;
  2672. }
  2673. if (!ARGUMENT_PRESENT(lpszUrl)
  2674. || (*lpszUrl == '\0')
  2675. // || !IsValidUrl(lpszUrl)
  2676. || (dwFlags & ~INTERNET_FLAGS_MASK)) {
  2677. error = ERROR_INVALID_PARAMETER;
  2678. goto quit;
  2679. }
  2680. }
  2681. //
  2682. // determine if this is a http request or FTP request - either http URL, or via http proxy.
  2683. // or via another protocol.
  2684. // For any Async request, we must go async in order to determine proxy information
  2685. //
  2686. bDeref = FALSE;
  2687. hUrl = hInternet;
  2688. if (isAsync
  2689. && !lpThreadInfo->IsAsyncWorkerThread
  2690. && (dwContext != INTERNET_NO_CALLBACK))
  2691. {
  2692. CFsm_ParseUrlForHttp *pFsm;
  2693. pFsm = new CFsm_ParseUrlForHttp(&hUrl,
  2694. (INTERNET_HANDLE_OBJECT *)hInternetMapped,
  2695. lpszUrl,
  2696. lpszHeaders,
  2697. dwHeadersLength,
  2698. dwFlags,
  2699. dwContext
  2700. );
  2701. if (pFsm != NULL) {
  2702. // IE6 BUG #27905
  2703. // check if ctor of CFsm_ParseUrlForHttp encountered an error
  2704. error = pFsm->GetError();
  2705. if (error == ERROR_SUCCESS) {
  2706. // first call will not be on this API's thread context
  2707. pFsm->ClearOnApiCall();
  2708. error = pFsm->QueueWorkItem();
  2709. } else {
  2710. delete pFsm;
  2711. }
  2712. } else {
  2713. error = ERROR_NOT_ENOUGH_MEMORY;
  2714. }
  2715. } else {
  2716. bDeref = TRUE;
  2717. CFsm_ParseUrlForHttp *pFsm;
  2718. pFsm = new CFsm_ParseUrlForHttp(&hUrl,
  2719. (INTERNET_HANDLE_OBJECT *)hInternetMapped,
  2720. lpszUrl,
  2721. lpszHeaders,
  2722. dwHeadersLength,
  2723. dwFlags,
  2724. dwContext
  2725. );
  2726. if (pFsm != NULL) {
  2727. // IE6 BUG #27905
  2728. // check if ctor of CFsm_ParseUrlForHttp encountered an error
  2729. error = pFsm->GetError();
  2730. if (error == ERROR_SUCCESS) {
  2731. error = DoFsm(pFsm);
  2732. } else {
  2733. delete pFsm;
  2734. }
  2735. } else {
  2736. error = ERROR_NOT_ENOUGH_MEMORY;
  2737. }
  2738. }
  2739. if ( error == ERROR_IO_PENDING )
  2740. {
  2741. bDeref = FALSE;
  2742. }
  2743. quit:
  2744. if (bDeref && hInternetMapped != NULL) {
  2745. DereferenceObject((LPVOID)hInternetMapped);
  2746. }
  2747. if ( lpThreadInfo != NULL ) {
  2748. _InternetDecNestingCount(nestingLevel);
  2749. }
  2750. if (error != ERROR_SUCCESS) {
  2751. DEBUG_ERROR(API, error);
  2752. SetLastError(error);
  2753. hUrl = NULL;
  2754. }
  2755. DEBUG_LEAVE_API(hUrl);
  2756. return hUrl;
  2757. }
  2758. INTERNETAPI_(BOOL) InternetReadFile(
  2759. IN HINTERNET hFile,
  2760. IN LPVOID lpBuffer,
  2761. IN DWORD dwNumberOfBytesToRead,
  2762. OUT LPDWORD lpdwNumberOfBytesRead
  2763. )
  2764. /*++
  2765. Routine Description:
  2766. This functions reads the next block of data from the file object. The
  2767. following handle/data types are supported:
  2768. TypeGopherFileHandle - raw gopher file data
  2769. TypeGopherFileHandleHtml - HTML-encapsulated gopher file data
  2770. TypeGopherFindHandleHtml - HTML-encapsulated gopher directory data
  2771. TypeFtpFileHandle - raw FTP file data
  2772. TypeFtpFileHandleHtml - HTML-encapsulated FTP file data
  2773. TypeFtpFindHandleHtml - HTML-encapsulated FTP directory data
  2774. Arguments:
  2775. hFile - handle returned from Open function
  2776. lpBuffer - pointer to caller's buffer
  2777. dwNumberOfBytesToRead - size of lpBuffer in BYTEs
  2778. lpdwNumberOfBytesRead - returned number of bytes read into lpBuffer
  2779. Return Value:
  2780. BOOL
  2781. Success - TRUE
  2782. Failure - FALSE. Call GetLastError() for more info
  2783. --*/
  2784. {
  2785. DEBUG_ENTER_API((DBG_API,
  2786. Bool,
  2787. "InternetReadFile",
  2788. "%#x, %#x, %d, %#x",
  2789. hFile,
  2790. lpBuffer,
  2791. dwNumberOfBytesToRead,
  2792. lpdwNumberOfBytesRead
  2793. ));
  2794. LPINTERNET_THREAD_INFO lpThreadInfo;
  2795. DWORD nestingLevel = 0;
  2796. DWORD error;
  2797. BOOL success = FALSE;
  2798. HINTERNET hFileMapped = NULL;
  2799. DWORD bytesRead = 0;
  2800. BOOL bEndRead = TRUE;
  2801. HINTERNET_HANDLE_TYPE handleType = TypeWildHandle;
  2802. if (!GlobalDataInitialized) {
  2803. error = ERROR_INTERNET_NOT_INITIALIZED;
  2804. goto done;
  2805. }
  2806. //
  2807. // we need the thread info block
  2808. //
  2809. lpThreadInfo = InternetGetThreadInfo();
  2810. if (lpThreadInfo == NULL) {
  2811. INET_ASSERT(FALSE);
  2812. error = ERROR_INTERNET_INTERNAL_ERROR;
  2813. goto done;
  2814. }
  2815. //INET_ASSERT(lpThreadInfo->Fsm == NULL);
  2816. _InternetIncNestingCount();
  2817. nestingLevel = 1;
  2818. //
  2819. // map the handle
  2820. //
  2821. error = MapHandleToAddress(hFile, (LPVOID *)&hFileMapped, FALSE);
  2822. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
  2823. goto quit;
  2824. }
  2825. //
  2826. // set the context, handle, and last-error info in the per-thread data block
  2827. // before we go any further. This allows us to return a status in the async
  2828. // case, even if the handle has been closed
  2829. //
  2830. DWORD_PTR context;
  2831. RGetContext(hFileMapped, &context);
  2832. if (!lpThreadInfo->IsAsyncWorkerThread) {
  2833. PERF_LOG(PE_CLIENT_REQUEST_START,
  2834. AR_INTERNET_READ_FILE,
  2835. lpThreadInfo->ThreadId,
  2836. hFile
  2837. );
  2838. }
  2839. _InternetSetContext(lpThreadInfo, context);
  2840. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  2841. _InternetClearLastError(lpThreadInfo);
  2842. //
  2843. // if MapHandleToAddress() returned a non-NULL object address, but also an
  2844. // error status, then the handle is being closed - quit
  2845. //
  2846. if (error != ERROR_SUCCESS) {
  2847. goto quit;
  2848. }
  2849. //
  2850. // validate handle and retrieve its type
  2851. //
  2852. error = RGetHandleType(hFileMapped, &handleType);
  2853. if (error != ERROR_SUCCESS) {
  2854. goto quit;
  2855. }
  2856. BOOL isLocal;
  2857. BOOL isAsync;
  2858. error = RIsHandleLocal(hFileMapped, &isLocal, &isAsync, handleType);
  2859. if (error != ERROR_SUCCESS) {
  2860. //
  2861. // we should not get an error - we already believe the handle object
  2862. // is valid and of the type just retrieved!
  2863. //
  2864. INET_ASSERT(FALSE);
  2865. goto quit;
  2866. }
  2867. //
  2868. // ensure correct handle type
  2869. //
  2870. if ((handleType != TypeHttpRequestHandle)
  2871. && (handleType != TypeFtpFileHandle)
  2872. && (handleType != TypeGopherFileHandle)
  2873. && (handleType != TypeFtpFindHandleHtml)
  2874. && (handleType != TypeGopherFindHandleHtml)
  2875. && (handleType != TypeFtpFileHandleHtml)
  2876. && (handleType != TypeGopherFileHandleHtml)
  2877. && (handleType != TypeFileRequestHandle)) {
  2878. error = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
  2879. goto quit;
  2880. }
  2881. //
  2882. // validate parameters
  2883. //
  2884. if (!lpThreadInfo->IsAsyncWorkerThread) {
  2885. error = ProbeAndSetDword(lpdwNumberOfBytesRead, 0);
  2886. if (error != ERROR_SUCCESS) {
  2887. goto quit;
  2888. }
  2889. error = ProbeWriteBuffer(lpBuffer, dwNumberOfBytesToRead);
  2890. if (error != ERROR_SUCCESS) {
  2891. goto quit;
  2892. }
  2893. *lpdwNumberOfBytesRead = 0;
  2894. if (((handleType == TypeFtpFindHandleHtml) ||
  2895. (handleType == TypeGopherFindHandleHtml)) &&
  2896. ((INTERNET_CONNECT_HANDLE_OBJECT *)hFileMapped)->
  2897. IsCacheReadInProgress())
  2898. {
  2899. error = ((INTERNET_CONNECT_HANDLE_OBJECT *)hFileMapped)->
  2900. ReadCache((LPBYTE)lpBuffer,
  2901. dwNumberOfBytesToRead,
  2902. &bytesRead);
  2903. success = (error == ERROR_SUCCESS);
  2904. goto quit;
  2905. }
  2906. if (handleType == TypeHttpRequestHandle) {
  2907. HTTP_REQUEST_HANDLE_OBJECT *lpRequest =
  2908. (HTTP_REQUEST_HANDLE_OBJECT *) hFileMapped;
  2909. // See if request can be fulfilled from file system.
  2910. if (lpRequest->AttemptReadFromFile
  2911. (lpBuffer, dwNumberOfBytesToRead, &bytesRead)) {
  2912. success = TRUE;
  2913. goto quit;
  2914. }
  2915. } // end if (handleType == TypeHttpRequestHandle)
  2916. else
  2917. {
  2918. //
  2919. // trap a zero-length buffer before we go to the trouble of going async.
  2920. // Maintain compatibility with base ReadFile(), although this is
  2921. // POTENTIALLY A BUG. ReadFile() is *supposed* to return TRUE and number
  2922. // of bytes read equal to zero to indicate end-of-file, but it will also
  2923. // return TRUE and zero if a read of zero bytes is requested. According
  2924. // to MarkL, that's the way it is. Good enough for me...
  2925. //
  2926. // For http, AttemptToReadFromFile traps zero-length reads
  2927. if (dwNumberOfBytesToRead == 0) {
  2928. //
  2929. // *lpdwNumberOfBytesRead and error should have been correctly set
  2930. // during parameter validation
  2931. //
  2932. INET_ASSERT(*lpdwNumberOfBytesRead == 0);
  2933. INET_ASSERT(error == ERROR_SUCCESS);
  2934. success = TRUE;
  2935. goto quit;
  2936. }
  2937. } // end else (handleType != TypeHttpRequestHandle)
  2938. } // end if (!lpThreadInfo->IsAsyncWorkerThread)
  2939. //
  2940. // the request will only be made asynchronously if more data is requested
  2941. // than is immediately available AND we haven't reached end of file
  2942. //
  2943. DWORD available;
  2944. available = ((INTERNET_HANDLE_OBJECT *)hFileMapped)->AvailableDataLength();
  2945. BOOL eof;
  2946. eof = ((INTERNET_HANDLE_OBJECT *)hFileMapped)->IsEndOfFile();
  2947. if (!lpThreadInfo->IsAsyncWorkerThread
  2948. && isAsync
  2949. && (context != INTERNET_NO_CALLBACK)
  2950. && (dwNumberOfBytesToRead > available)
  2951. && !eof
  2952. && (handleType != TypeHttpRequestHandle)
  2953. && (handleType != TypeFileRequestHandle)) {
  2954. // MakeAsyncRequest
  2955. CFsm_InternetReadFile * pFsm;
  2956. pFsm = new CFsm_InternetReadFile(hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead);
  2957. if (pFsm != NULL) {
  2958. error = pFsm->QueueWorkItem();
  2959. if ( error == ERROR_IO_PENDING ) {
  2960. bEndRead = FALSE;
  2961. }
  2962. } else {
  2963. error = ERROR_NOT_ENOUGH_MEMORY;
  2964. }
  2965. //
  2966. // if we're here then ERROR_SUCCESS cannot have been returned from
  2967. // the above calls
  2968. //
  2969. INET_ASSERT(error != ERROR_SUCCESS);
  2970. DEBUG_PRINT(FTP,
  2971. INFO,
  2972. ("processing request asynchronously: error = %d\n",
  2973. error
  2974. ));
  2975. goto quit;
  2976. //
  2977. // we're going synchronous - set the error so we do the right thing when
  2978. // we exit
  2979. //
  2980. error = ERROR_SUCCESS;
  2981. } else if ((available >= dwNumberOfBytesToRead) || eof) {
  2982. DEBUG_PRINT(API,
  2983. INFO,
  2984. ("immediate read: %d requested, %d available. EOF = %B\n",
  2985. dwNumberOfBytesToRead,
  2986. available,
  2987. eof
  2988. ));
  2989. }
  2990. INET_ASSERT(error == ERROR_SUCCESS);
  2991. //
  2992. // just call the underlying API: return whatever it returns, and let it
  2993. // handle setting the last error
  2994. //
  2995. switch (handleType) {
  2996. case TypeFtpFileHandle:
  2997. success = FtpReadFile(hFileMapped,
  2998. lpBuffer,
  2999. dwNumberOfBytesToRead,
  3000. &bytesRead
  3001. );
  3002. break;
  3003. case TypeGopherFileHandle:
  3004. success = GopherReadFile(hFileMapped,
  3005. lpBuffer,
  3006. dwNumberOfBytesToRead,
  3007. &bytesRead
  3008. );
  3009. break;
  3010. case TypeFtpFindHandleHtml:
  3011. case TypeGopherFindHandleHtml:
  3012. //
  3013. // HTML handle types - convert underlying data to HTML document
  3014. //
  3015. success = ReadHtmlUrlData(hFileMapped,
  3016. lpBuffer,
  3017. dwNumberOfBytesToRead,
  3018. &bytesRead
  3019. );
  3020. if (((INTERNET_CONNECT_HANDLE_OBJECT *)hFileMapped)->IsCacheWriteInProgress())
  3021. {
  3022. DWORD errorCache;
  3023. if (success) {
  3024. if (bytesRead) {
  3025. errorCache = ((INTERNET_CONNECT_HANDLE_OBJECT *)hFileMapped)->
  3026. WriteCache(
  3027. (LPBYTE)lpBuffer,
  3028. bytesRead
  3029. );
  3030. }
  3031. else {
  3032. errorCache = ERROR_NO_MORE_FILES;
  3033. }
  3034. }
  3035. else {
  3036. errorCache = GetLastError();
  3037. }
  3038. // if the thing failed because the caller passed in
  3039. // insufficient buffer for internetreadfile
  3040. // then we should do nothing
  3041. if ((errorCache != ERROR_SUCCESS)&&
  3042. (errorCache != ERROR_INSUFFICIENT_BUFFER)) {
  3043. if (handleType == TypeFtpFindHandleHtml) {
  3044. // we save extension in the index file
  3045. // this is used to differentiate between html directory
  3046. // entry from the non-html one for the same url
  3047. InbLocalEndCacheWrite( hFileMapped,
  3048. "htm", // save extension in index file
  3049. (errorCache == ERROR_NO_MORE_FILES)
  3050. );
  3051. }
  3052. else {
  3053. InbGopherLocalEndCacheWrite( hFileMapped,
  3054. "htm",
  3055. (errorCache == ERROR_NO_MORE_FILES)
  3056. );
  3057. }
  3058. }
  3059. }
  3060. break;
  3061. case TypeFtpFileHandleHtml:
  3062. case TypeGopherFileHandleHtml:
  3063. //
  3064. // HTML handle types - convert underlying data to HTML document
  3065. //
  3066. success = ReadHtmlUrlData(hFileMapped,
  3067. lpBuffer,
  3068. dwNumberOfBytesToRead,
  3069. &bytesRead
  3070. );
  3071. break;
  3072. case TypeHttpRequestHandle:
  3073. {
  3074. //HTTP_REQUEST_HANDLE_OBJECT * lpRequest;
  3075. //
  3076. //lpRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hFileMapped;
  3077. //
  3078. //error = lpRequest->QuickSyncRead(
  3079. // lpBuffer,
  3080. // dwNumberOfBytesToRead,
  3081. // lpdwNumberOfBytesRead,
  3082. // 0
  3083. // );
  3084. //
  3085. //if ( error == ERROR_IO_PENDING )
  3086. //{
  3087. error = DoFsm(new CFsm_ReadFile(lpBuffer,
  3088. dwNumberOfBytesToRead,
  3089. lpdwNumberOfBytesRead
  3090. ));
  3091. //}
  3092. success = (error == ERROR_SUCCESS) ? TRUE : FALSE;
  3093. bEndRead = FALSE;
  3094. break;
  3095. }
  3096. case TypeFileRequestHandle:
  3097. success = ReadFile(
  3098. ((INTERNET_FILE_HANDLE_OBJECT *) hFileMapped)->GetFileHandle(),
  3099. lpBuffer,
  3100. dwNumberOfBytesToRead,
  3101. &bytesRead,
  3102. NULL // overlapped I/O
  3103. );
  3104. if (!success)
  3105. {
  3106. error = GetLastError();
  3107. }
  3108. else
  3109. {
  3110. error = ERROR_SUCCESS;
  3111. }
  3112. break;
  3113. case TypeFtpFindHandle:
  3114. case TypeGopherFindHandle:
  3115. //
  3116. // you cannot receive RAW directory data using this API. You have
  3117. // to call InternetFindNextFile()
  3118. //
  3119. default:
  3120. //
  3121. // the handle is a valid handle (or else RGetHandleType() would
  3122. // have returned ERROR_INVALID_HANDLE), but this operation is
  3123. // inconsistent with the handle type. Return a more prosaic error
  3124. // code
  3125. //
  3126. error = ERROR_INTERNET_INVALID_OPERATION;
  3127. break;
  3128. }
  3129. quit:
  3130. _InternetDecNestingCount(nestingLevel);;
  3131. if (bEndRead) {
  3132. //
  3133. // if handleType is not HttpRequest or File then we are making this
  3134. // request in the context of an uninterruptable async worker thread.
  3135. // HTTP and file requests use the normal mechanism. In the case of non-
  3136. // HTTP and file requests, we need to treat the request as if it were
  3137. // sync and deref the handle
  3138. //
  3139. ReadFile_End(!lpThreadInfo->IsAsyncWorkerThread
  3140. || !((handleType == TypeHttpRequestHandle)
  3141. || (handleType == TypeFileRequestHandle)),
  3142. success,
  3143. hFileMapped,
  3144. bytesRead,
  3145. lpBuffer,
  3146. dwNumberOfBytesToRead,
  3147. lpdwNumberOfBytesRead
  3148. );
  3149. }
  3150. if (lpThreadInfo && !lpThreadInfo->IsAsyncWorkerThread) {
  3151. PERF_LOG(PE_CLIENT_REQUEST_END,
  3152. AR_INTERNET_READ_FILE,
  3153. bytesRead,
  3154. lpThreadInfo->ThreadId,
  3155. hFile
  3156. );
  3157. }
  3158. done:
  3159. //
  3160. // if error is not ERROR_SUCCESS then this function returning the error,
  3161. // otherwise the error has already been set by the API we called,
  3162. // irrespective of the value of success
  3163. //
  3164. if (error != ERROR_SUCCESS) {
  3165. DEBUG_ERROR(API, error);
  3166. SetLastError(error);
  3167. success = FALSE;
  3168. }
  3169. DEBUG_LEAVE_API(success);
  3170. return success;
  3171. }
  3172. PRIVATE
  3173. VOID
  3174. ReadFile_End(
  3175. IN BOOL bDeref,
  3176. IN BOOL bSuccess,
  3177. IN HINTERNET hFileMapped,
  3178. IN DWORD dwBytesRead,
  3179. IN LPVOID lpBuffer OPTIONAL,
  3180. IN DWORD dwNumberOfBytesToRead,
  3181. OUT LPDWORD lpdwNumberOfBytesRead OPTIONAL
  3182. )
  3183. /*++
  3184. Routine Description:
  3185. Common end-of-read processing:
  3186. - update bytes read parameter
  3187. - dump data if logging & API data requested
  3188. - dereference handle if not async request
  3189. Arguments:
  3190. bDeref - TRUE if handle should be dereferenced (should be
  3191. FALSE for async request)
  3192. bSuccess - TRUE if Read completed successfully
  3193. hFileMapped - mapped file handle
  3194. dwBytesRead - number of bytes read
  3195. lpBuffer - into this buffer
  3196. dwNumberOfBytesToRead - originally requested bytes to read
  3197. lpdwNumberOfBytesRead - where bytes read is stored
  3198. Return Value:
  3199. None.
  3200. --*/
  3201. {
  3202. DEBUG_ENTER((DBG_INET,
  3203. None,
  3204. "ReadFile_End",
  3205. "%B, %B, %#x, %d, %#x, %d, %#x",
  3206. bDeref,
  3207. bSuccess,
  3208. hFileMapped,
  3209. dwBytesRead,
  3210. lpBuffer,
  3211. dwNumberOfBytesToRead,
  3212. lpdwNumberOfBytesRead
  3213. ));
  3214. if (bSuccess) {
  3215. //
  3216. // update the amount of immediate data available only if we succeeded
  3217. //
  3218. ((INTERNET_HANDLE_OBJECT *)hFileMapped)->ReduceAvailableDataLength(dwBytesRead);
  3219. if (lpdwNumberOfBytesRead != NULL) {
  3220. *lpdwNumberOfBytesRead = dwBytesRead;
  3221. DEBUG_PRINT(API,
  3222. INFO,
  3223. ("*lpdwNumberOfBytesRead = %d\n",
  3224. *lpdwNumberOfBytesRead
  3225. ));
  3226. //
  3227. // dump API data only if requested
  3228. //
  3229. IF_DEBUG_CONTROL(DUMP_API_DATA) {
  3230. DEBUG_DUMP_API(API,
  3231. "Received data:\n",
  3232. lpBuffer,
  3233. *lpdwNumberOfBytesRead
  3234. );
  3235. }
  3236. }
  3237. if (dwBytesRead < dwNumberOfBytesToRead) {
  3238. DEBUG_PRINT(API,
  3239. INFO,
  3240. ("(!) bytes read (%d) < bytes requested (%d)\n",
  3241. dwBytesRead,
  3242. dwNumberOfBytesToRead
  3243. ));
  3244. }
  3245. }
  3246. //
  3247. // if async request, handle will be deref'd after REQUEST_COMPLETE callback
  3248. // is delivered
  3249. //
  3250. if (bDeref && (hFileMapped != NULL)) {
  3251. DereferenceObject((LPVOID)hFileMapped);
  3252. }
  3253. PERF_LOG(PE_CLIENT_REQUEST_END,
  3254. AR_INTERNET_READ_FILE,
  3255. dwBytesRead,
  3256. 0,
  3257. (!bDeref && hFileMapped) ? ((INTERNET_HANDLE_OBJECT *)hFileMapped)->GetPseudoHandle() : NULL
  3258. );
  3259. DEBUG_LEAVE(0);
  3260. }
  3261. DWORD
  3262. CFsm_ReadFile::RunSM(
  3263. IN CFsm * Fsm
  3264. )
  3265. {
  3266. DEBUG_ENTER((DBG_HTTP,
  3267. Dword,
  3268. "CFsm_ReadFile::RunSM",
  3269. "%#x",
  3270. Fsm
  3271. ));
  3272. DWORD error;
  3273. CFsm_ReadFile * stateMachine = (CFsm_ReadFile *)Fsm;
  3274. switch (Fsm->GetState()) {
  3275. case FSM_STATE_INIT:
  3276. case FSM_STATE_CONTINUE:
  3277. error = ReadFile_Fsm(stateMachine);
  3278. break;
  3279. default:
  3280. error = ERROR_INTERNET_INTERNAL_ERROR;
  3281. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  3282. INET_ASSERT(FALSE);
  3283. break;
  3284. }
  3285. DEBUG_LEAVE(error);
  3286. return error;
  3287. }
  3288. PRIVATE
  3289. DWORD
  3290. ReadFile_Fsm(
  3291. IN CFsm_ReadFile * Fsm
  3292. )
  3293. {
  3294. DEBUG_ENTER((DBG_INET,
  3295. Dword,
  3296. "ReadFile_Fsm",
  3297. "%#x",
  3298. Fsm
  3299. ));
  3300. CFsm_ReadFile & fsm = *Fsm;
  3301. DWORD error = fsm.GetError();
  3302. if ((error == ERROR_SUCCESS) && (fsm.GetState() == FSM_STATE_INIT)) {
  3303. error = HttpReadData(fsm.GetMappedHandle(),
  3304. fsm.m_lpBuffer,
  3305. fsm.m_dwNumberOfBytesToRead,
  3306. &fsm.m_dwBytesRead,
  3307. 0
  3308. );
  3309. if (error == ERROR_IO_PENDING) {
  3310. goto quit;
  3311. }
  3312. }
  3313. ReadFile_End(!fsm.GetThreadInfo()->IsAsyncWorkerThread,
  3314. (error == ERROR_SUCCESS) ? TRUE : FALSE,
  3315. fsm.GetMappedHandle(),
  3316. fsm.m_dwBytesRead,
  3317. fsm.m_lpBuffer,
  3318. fsm.m_dwNumberOfBytesToRead,
  3319. fsm.m_lpdwNumberOfBytesRead
  3320. );
  3321. fsm.SetDone();
  3322. quit:
  3323. DEBUG_LEAVE(error);
  3324. return error;
  3325. }
  3326. INTERNETAPI_(BOOL) InternetReadFileExA(
  3327. IN HINTERNET hFile,
  3328. OUT LPINTERNET_BUFFERSA lpBuffersOut,
  3329. IN DWORD dwFlags,
  3330. IN DWORD_PTR dwContext
  3331. )
  3332. {
  3333. DEBUG_ENTER_API((DBG_API,
  3334. Bool,
  3335. "InternetReadFileExA",
  3336. "%#x, %#x [%#x, %d], %#x, %#x",
  3337. hFile,
  3338. lpBuffersOut,
  3339. (lpBuffersOut ? lpBuffersOut->lpvBuffer : NULL),
  3340. (lpBuffersOut ? lpBuffersOut->dwBufferLength : 0),
  3341. dwFlags,
  3342. dwContext
  3343. ));
  3344. LPINTERNET_THREAD_INFO lpThreadInfo;
  3345. DWORD nestingLevel = 0;
  3346. DWORD error;
  3347. HINTERNET hFileMapped = NULL;
  3348. DWORD bytesRead = 0;
  3349. LPVOID lpBuffer = NULL;
  3350. DWORD dwNumberOfBytesToRead;
  3351. BOOL bEndRead = TRUE;
  3352. BOOL success = TRUE;
  3353. if (!GlobalDataInitialized) {
  3354. error = ERROR_INTERNET_NOT_INITIALIZED;
  3355. goto done;
  3356. }
  3357. //
  3358. // we need the thread info block
  3359. //
  3360. lpThreadInfo = InternetGetThreadInfo();
  3361. if (lpThreadInfo == NULL) {
  3362. INET_ASSERT(FALSE);
  3363. error = ERROR_INTERNET_INTERNAL_ERROR;
  3364. goto done;
  3365. }
  3366. _InternetIncNestingCount();
  3367. nestingLevel = 1;
  3368. //
  3369. // map the handle
  3370. //
  3371. error = MapHandleToAddress(hFile, (LPVOID *)&hFileMapped, FALSE);
  3372. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
  3373. goto done;
  3374. }
  3375. //
  3376. // set the context, handle, and last-error info in the per-thread data block
  3377. // before we go any further. This allows us to return a status in the async
  3378. // case, even if the handle has been closed
  3379. //
  3380. DWORD_PTR context;
  3381. RGetContext(hFileMapped, &context);
  3382. if (!lpThreadInfo->IsAsyncWorkerThread) {
  3383. PERF_LOG(PE_CLIENT_REQUEST_START,
  3384. AR_INTERNET_READ_FILE,
  3385. lpThreadInfo->ThreadId,
  3386. hFile
  3387. );
  3388. }
  3389. _InternetSetContext(lpThreadInfo, context);
  3390. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  3391. _InternetClearLastError(lpThreadInfo);
  3392. //
  3393. // if MapHandleToAddress() returned a non-NULL object address, but also an
  3394. // error status, then the handle is being closed - quit
  3395. //
  3396. if (error != ERROR_SUCCESS) {
  3397. goto done;
  3398. }
  3399. //
  3400. // validate handle and retrieve its type
  3401. //
  3402. HINTERNET_HANDLE_TYPE handleType;
  3403. error = RGetHandleType(hFileMapped, &handleType);
  3404. if (error != ERROR_SUCCESS) {
  3405. goto done;
  3406. }
  3407. BOOL isLocal;
  3408. BOOL isAsync;
  3409. error = RIsHandleLocal(hFileMapped, &isLocal, &isAsync, handleType);
  3410. if (error != ERROR_SUCCESS) {
  3411. //
  3412. // we should not get an error - we already believe the handle object
  3413. // is valid and of the type just retrieved!
  3414. //
  3415. INET_ASSERT(FALSE);
  3416. goto done;
  3417. }
  3418. //
  3419. // only accepting HTTP handles currently
  3420. //
  3421. if (handleType != TypeHttpRequestHandle) {
  3422. error = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
  3423. goto done;
  3424. }
  3425. HTTP_REQUEST_HANDLE_OBJECT * lpRequest;
  3426. lpRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hFileMapped;
  3427. //
  3428. // validate params
  3429. //
  3430. if (lpBuffersOut->dwStructSize != sizeof(INTERNET_BUFFERS)) {
  3431. error = ERROR_INVALID_PARAMETER;
  3432. goto quit;
  3433. }
  3434. lpBuffer = lpBuffersOut->lpvBuffer;
  3435. dwNumberOfBytesToRead = lpBuffersOut->dwBufferLength;
  3436. INET_ASSERT(dwNumberOfBytesToRead > 0);
  3437. //
  3438. // See if request can be fulfilled from file system.
  3439. //
  3440. if (lpRequest->AttemptReadFromFile(lpBuffer,
  3441. dwNumberOfBytesToRead,
  3442. &bytesRead)) {
  3443. error = ERROR_SUCCESS;
  3444. goto quit;
  3445. }
  3446. //
  3447. // trap a zero-length buffer before we go to the trouble of going async.
  3448. // Maintain compatibility with base ReadFile(), although this is
  3449. // POTENTIALLY A BUG. ReadFile() is *supposed* to return TRUE and number
  3450. // of bytes read equal to zero to indicate end-of-file, but it will also
  3451. // return TRUE and zero if a read of zero bytes is requested. According
  3452. // to MarkL, that's the way it is. Good enough for me...
  3453. //
  3454. // For http, AttemptToReadFromFile traps zero-length reads
  3455. if (dwNumberOfBytesToRead == 0) {
  3456. //
  3457. // *lpdwNumberOfBytesRead and error should have been correctly set
  3458. // during parameter validation
  3459. //
  3460. INET_ASSERT(error == ERROR_SUCCESS);
  3461. goto quit;
  3462. }
  3463. //error = lpRequest->QuickSyncRead(
  3464. // lpBuffer,
  3465. // dwNumberOfBytesToRead,
  3466. // &bytesRead,
  3467. // SF_NO_WAIT
  3468. // );
  3469. //
  3470. //if ( error == ERROR_IO_PENDING )
  3471. //{
  3472. error = DoFsm(new CFsm_ReadFileEx(lpBuffersOut,
  3473. dwFlags,
  3474. dwContext
  3475. ));
  3476. //}
  3477. if (error == ERROR_SUCCESS) {
  3478. bytesRead = lpBuffersOut->dwBufferLength;
  3479. }
  3480. bEndRead = FALSE;
  3481. quit:
  3482. _InternetDecNestingCount(nestingLevel);;
  3483. if (bEndRead) {
  3484. ReadFile_End(TRUE,
  3485. (error == ERROR_SUCCESS),
  3486. hFileMapped,
  3487. bytesRead,
  3488. lpBuffersOut->lpvBuffer,
  3489. dwNumberOfBytesToRead,
  3490. &lpBuffersOut->dwBufferLength
  3491. );
  3492. }
  3493. done:
  3494. if (error != ERROR_SUCCESS) {
  3495. DEBUG_ERROR(API, error);
  3496. SetLastError(error);
  3497. success = FALSE;
  3498. }
  3499. DEBUG_LEAVE_API(success);
  3500. return success;
  3501. }
  3502. DWORD
  3503. CFsm_ReadFileEx::RunSM(
  3504. IN CFsm * Fsm
  3505. )
  3506. {
  3507. DEBUG_ENTER((DBG_HTTP,
  3508. Dword,
  3509. "CFsm_ReadFileEx::RunSM",
  3510. "%#x",
  3511. Fsm
  3512. ));
  3513. DWORD error;
  3514. CFsm_ReadFileEx * stateMachine = (CFsm_ReadFileEx *)Fsm;
  3515. switch (Fsm->GetState()) {
  3516. case FSM_STATE_INIT:
  3517. case FSM_STATE_CONTINUE:
  3518. error = ReadFileEx_Fsm(stateMachine);
  3519. break;
  3520. default:
  3521. error = ERROR_INTERNET_INTERNAL_ERROR;
  3522. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  3523. INET_ASSERT(FALSE);
  3524. break;
  3525. }
  3526. DEBUG_LEAVE(error);
  3527. return error;
  3528. }
  3529. PRIVATE
  3530. DWORD
  3531. ReadFileEx_Fsm(
  3532. IN CFsm_ReadFileEx * Fsm
  3533. )
  3534. {
  3535. DEBUG_ENTER((DBG_INET,
  3536. Dword,
  3537. "ReadFileEx_Fsm",
  3538. "%#x",
  3539. Fsm
  3540. ));
  3541. CFsm_ReadFileEx & fsm = *Fsm;
  3542. DWORD error = fsm.GetError();
  3543. if ((error == ERROR_SUCCESS) && (fsm.GetState() == FSM_STATE_INIT)) {
  3544. fsm.m_dwNumberOfBytesToRead = fsm.m_lpBuffersOut->dwBufferLength;
  3545. error = HttpReadData(fsm.GetMappedHandle(),
  3546. fsm.m_lpBuffersOut->lpvBuffer,
  3547. fsm.m_dwNumberOfBytesToRead,
  3548. &fsm.m_dwBytesRead,
  3549. (fsm.m_dwFlags & IRF_NO_WAIT)
  3550. ? SF_NO_WAIT
  3551. : 0
  3552. );
  3553. if (error == ERROR_IO_PENDING) {
  3554. goto quit;
  3555. }
  3556. }
  3557. //
  3558. // if we are asynchronously completing a no-wait read then we don't update
  3559. // any app parameters - we simply return the indication that we completed.
  3560. // The app will then make another no-wait read to get the data
  3561. //
  3562. BOOL bNoOutput;
  3563. bNoOutput = ((fsm.m_dwFlags & IRF_NO_WAIT)
  3564. && fsm.GetThreadInfo()->IsAsyncWorkerThread)
  3565. ? TRUE
  3566. : FALSE;
  3567. ReadFile_End(!fsm.GetThreadInfo()->IsAsyncWorkerThread,
  3568. (error == ERROR_SUCCESS) ? TRUE : FALSE,
  3569. fsm.GetMappedHandle(),
  3570. bNoOutput ? 0 : fsm.m_dwBytesRead,
  3571. bNoOutput ? NULL : fsm.m_lpBuffersOut->lpvBuffer,
  3572. bNoOutput ? 0 : fsm.m_dwNumberOfBytesToRead,
  3573. bNoOutput ? NULL : &fsm.m_lpBuffersOut->dwBufferLength
  3574. );
  3575. fsm.SetDone();
  3576. quit:
  3577. DEBUG_LEAVE(error);
  3578. return error;
  3579. }
  3580. INTERNETAPI_(BOOL) InternetWriteFile(
  3581. IN HINTERNET hFile,
  3582. IN LPCVOID lpBuffer,
  3583. IN DWORD dwNumberOfBytesToWrite,
  3584. OUT LPDWORD lpdwNumberOfBytesWritten
  3585. )
  3586. /*++
  3587. Routine Description:
  3588. This function write next block of data to the internet file. Currently it
  3589. supports the following protocol data:
  3590. FtpWriteFile
  3591. HttpWriteFile
  3592. FileWriteFile
  3593. Arguments:
  3594. hFile - handle that was obtained by OpenFile Call
  3595. lpBuffer - pointer to the data buffer
  3596. dwNumberOfBytesToWrite - number of bytes in the above buffer
  3597. lpdwNumberOfBytesWritten - pointer to a DWORD where the number of bytes
  3598. of data actually written is returned
  3599. Return Value:
  3600. BOOL
  3601. Success - TRUE
  3602. Failure - FALSE. Call GetLastError() for more info
  3603. --*/
  3604. {
  3605. DEBUG_ENTER_API((DBG_API,
  3606. Bool,
  3607. "InternetWriteFile",
  3608. "%#x, %#x, %d, %#x",
  3609. hFile,
  3610. lpBuffer,
  3611. dwNumberOfBytesToWrite,
  3612. lpdwNumberOfBytesWritten
  3613. ));
  3614. LPINTERNET_THREAD_INFO lpThreadInfo;
  3615. DWORD nestingLevel = 0;
  3616. DWORD error;
  3617. BOOL success = FALSE;
  3618. BOOL fNeedDeref = TRUE;
  3619. HINTERNET hFileMapped = NULL;
  3620. if (!GlobalDataInitialized) {
  3621. error = ERROR_INTERNET_NOT_INITIALIZED;
  3622. goto done;
  3623. }
  3624. //
  3625. // get the per-thread info block
  3626. //
  3627. lpThreadInfo = InternetGetThreadInfo();
  3628. if (lpThreadInfo == NULL) {
  3629. INET_ASSERT(FALSE);
  3630. error = ERROR_INTERNET_INTERNAL_ERROR;
  3631. goto done;
  3632. }
  3633. _InternetIncNestingCount();
  3634. nestingLevel = 1;
  3635. //
  3636. // map the handle
  3637. //
  3638. error = MapHandleToAddress(hFile, (LPVOID *)&hFileMapped, FALSE);
  3639. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
  3640. goto quit;
  3641. }
  3642. //
  3643. // set the context, handle, and last-error info in the per-thread data block
  3644. // before we go any further. This allows us to return a status in the async
  3645. // case, even if the handle has been closed
  3646. //
  3647. DWORD_PTR context;
  3648. RGetContext(hFileMapped, &context);
  3649. _InternetSetContext(lpThreadInfo, context);
  3650. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  3651. _InternetClearLastError(lpThreadInfo);
  3652. //
  3653. // if MapHandleToAddress() returned a non-NULL object address, but also an
  3654. // error status, then the handle is being closed - quit
  3655. //
  3656. if (error != ERROR_SUCCESS) {
  3657. goto quit;
  3658. }
  3659. //
  3660. // validate handle and retrieve its type
  3661. //
  3662. HINTERNET_HANDLE_TYPE handleType;
  3663. error = RGetHandleType(hFileMapped, &handleType);
  3664. if (error != ERROR_SUCCESS) {
  3665. goto quit;
  3666. }
  3667. BOOL isLocal;
  3668. BOOL isAsync;
  3669. error = RIsHandleLocal(hFileMapped, &isLocal, &isAsync, handleType);
  3670. if (error != ERROR_SUCCESS) {
  3671. //
  3672. // we should not get an error - we already believe the handle object
  3673. // is valid and of the type just retrieved!
  3674. //
  3675. INET_ASSERT(FALSE);
  3676. goto quit;
  3677. }
  3678. //
  3679. // validate parameters - write length cannot be 0
  3680. //
  3681. if (!lpThreadInfo->IsAsyncWorkerThread) {
  3682. if (dwNumberOfBytesToWrite != 0) {
  3683. error = ProbeReadBuffer((LPVOID)lpBuffer, dwNumberOfBytesToWrite);
  3684. if (error == ERROR_SUCCESS) {
  3685. error = ProbeAndSetDword(lpdwNumberOfBytesWritten, 0);
  3686. }
  3687. } else {
  3688. error = ERROR_INVALID_PARAMETER;
  3689. }
  3690. if (error != ERROR_SUCCESS) {
  3691. goto quit;
  3692. }
  3693. }
  3694. // # 62953
  3695. // If the authentication state of the handle is Negotiate,
  3696. // don't submit data to the server but return success.
  3697. // ** Added test for NTLM or Negotiate - Adriaanc.
  3698. if (handleType == TypeHttpRequestHandle)
  3699. {
  3700. HTTP_REQUEST_HANDLE_OBJECT *pRequest;
  3701. pRequest = (HTTP_REQUEST_HANDLE_OBJECT*) hFileMapped;
  3702. if (pRequest->GetAuthState() == AUTHSTATE_NEGOTIATE
  3703. && !((PLUG_CTX*) (pRequest->GetAuthCtx()))->_fNTLMProxyAuth
  3704. && !(pRequest->GetAuthCtx()->GetSchemeType() == AUTHCTX::SCHEME_DPA))
  3705. {
  3706. *lpdwNumberOfBytesWritten = dwNumberOfBytesToWrite;
  3707. error = ERROR_SUCCESS;
  3708. success = TRUE;
  3709. goto quit;
  3710. }
  3711. }
  3712. //
  3713. // we have to do some work. If the file object handle was created with
  3714. // async I/O capability then we will queue an async request, otherwise
  3715. // we will process the request synchronously
  3716. //
  3717. if (isAsync
  3718. && !lpThreadInfo->IsAsyncWorkerThread
  3719. && (handleType != TypeHttpRequestHandle)
  3720. && (handleType != TypeFileRequestHandle)) {
  3721. // MakeAsyncRequest
  3722. CFsm_InternetWriteFile * pFsm;
  3723. pFsm = new CFsm_InternetWriteFile(hFile, lpBuffer, dwNumberOfBytesToWrite, lpdwNumberOfBytesWritten);
  3724. if (pFsm != NULL) {
  3725. error = pFsm->QueueWorkItem();
  3726. if ( error == ERROR_IO_PENDING ) {
  3727. fNeedDeref = FALSE;
  3728. }
  3729. } else {
  3730. error = ERROR_NOT_ENOUGH_MEMORY;
  3731. }
  3732. //
  3733. // if we're here then ERROR_SUCCESS cannot have been returned from
  3734. // the above calls
  3735. //
  3736. INET_ASSERT(error != ERROR_SUCCESS);
  3737. DEBUG_PRINT(FTP,
  3738. INFO,
  3739. ("processing request asynchronously: error = %d\n",
  3740. error
  3741. ));
  3742. goto quit;
  3743. //
  3744. // we're going synchronous. Change error to ERROR_SUCCESS so that we do
  3745. // the right thing at quit
  3746. //
  3747. error = ERROR_SUCCESS;
  3748. }
  3749. INET_ASSERT(error == ERROR_SUCCESS);
  3750. switch (handleType) {
  3751. case TypeFtpFileHandle:
  3752. success = FtpWriteFile(hFileMapped,
  3753. (LPVOID)lpBuffer,
  3754. dwNumberOfBytesToWrite,
  3755. lpdwNumberOfBytesWritten
  3756. );
  3757. break;
  3758. case TypeHttpRequestHandle:
  3759. error = HttpWriteData(hFileMapped,
  3760. (LPVOID)lpBuffer,
  3761. dwNumberOfBytesToWrite,
  3762. lpdwNumberOfBytesWritten,
  3763. 0
  3764. );
  3765. //
  3766. // Don't Derefrence if we're going pending cause the FSM will do
  3767. // it for us.
  3768. //
  3769. if ( error == ERROR_IO_PENDING )
  3770. {
  3771. fNeedDeref = FALSE;
  3772. }
  3773. success = (error == ERROR_SUCCESS) ? TRUE : FALSE;
  3774. //bEndRead = FALSE;
  3775. break;
  3776. case TypeFileRequestHandle:
  3777. success = WriteFile(((INTERNET_FILE_HANDLE_OBJECT *) hFileMapped)->GetFileHandle(),
  3778. (LPVOID)lpBuffer,
  3779. dwNumberOfBytesToWrite,
  3780. lpdwNumberOfBytesWritten,
  3781. NULL // overlapped I/O
  3782. );
  3783. if ( !success )
  3784. {
  3785. error = GetLastError();
  3786. }
  3787. else
  3788. {
  3789. error = ERROR_SUCCESS;
  3790. }
  3791. break;
  3792. default:
  3793. error = ERROR_INVALID_HANDLE;
  3794. break;
  3795. }
  3796. quit:
  3797. if (hFileMapped != NULL && fNeedDeref) {
  3798. DereferenceObject((LPVOID)hFileMapped);
  3799. }
  3800. _InternetDecNestingCount(nestingLevel);;
  3801. done:
  3802. if (error != ERROR_SUCCESS) {
  3803. DEBUG_ERROR(API, error);
  3804. SetLastError(error);
  3805. }
  3806. DEBUG_LEAVE_API(success);
  3807. return success;
  3808. }
  3809. INTERNETAPI_(BOOL) InternetWriteFileExA(
  3810. IN HINTERNET hFile,
  3811. IN LPINTERNET_BUFFERSA lpBuffersIn,
  3812. IN DWORD dwFlags,
  3813. IN DWORD_PTR dwContext
  3814. )
  3815. {
  3816. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3817. return FALSE;
  3818. }
  3819. INTERNETAPI_(DWORD) InternetSetFilePointer(
  3820. IN HINTERNET hFile,
  3821. IN LONG lDistanceToMove,
  3822. IN PVOID pReserved,
  3823. IN DWORD dwMoveMethod,
  3824. IN DWORD_PTR dwContext
  3825. )
  3826. /*++
  3827. Routine Description:
  3828. Sets a file position for InternetReadFile. It is a synchronous call,
  3829. however subsequent calls to InternetReadFile may block or return
  3830. pending if the data is not available from the cache and the server
  3831. does not support random access.
  3832. Arguments:
  3833. hFile
  3834. A valid handle returned from a previous call to InternetOpenUrl
  3835. or a handle returned from HttpOpenRequest for a GET or HEAD method
  3836. and passed to HttpSendRequest. The handle must have been created
  3837. without INTERNET_FLAG_DONT_CACHE.
  3838. lDistanceToMove
  3839. Specifies the number of bytes to move the file pointer. A positive
  3840. value moves the pointer forward in the file and a negative value
  3841. moves it backward.
  3842. pReserved
  3843. Reserved, pass NULL.
  3844. dwMoveMethod
  3845. Specifies the starting point for the file pointer move. This
  3846. parameter can be one of the following values:
  3847. Value Meaning
  3848. FILE_BEGIN The starting point is zero or the beginning of the file.
  3849. If FILE_BEGIN is specified, DistanceToMove is interpreted
  3850. as an unsigned location for the new file pointer.
  3851. FILE_CURRENT The current value of the file pointer is the starting point.
  3852. FILE_END The current end-of-file position is the starting point.
  3853. This method will fail if the content length is unknown.
  3854. Return Value:
  3855. -1 on failure, else the current file position.
  3856. --*/
  3857. {
  3858. DEBUG_ENTER_API((DBG_API,
  3859. Int,
  3860. "InternetSetFilePointer",
  3861. "%#x, %#x, %#x, %#x %#x",
  3862. hFile,
  3863. lDistanceToMove,
  3864. pReserved,
  3865. dwMoveMethod,
  3866. dwContext
  3867. ));
  3868. DWORD dwNewPosition = (DWORD) -1L;
  3869. DWORD error;
  3870. HINTERNET hFileMapped = NULL;
  3871. if (!GlobalDataInitialized) {
  3872. error = ERROR_INTERNET_NOT_INITIALIZED;
  3873. goto done;
  3874. }
  3875. // Validate parameters...
  3876. error = MapHandleToAddress(hFile, &hFileMapped, FALSE);
  3877. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
  3878. goto quit;
  3879. }
  3880. HINTERNET_HANDLE_TYPE handleType;
  3881. error = RGetHandleType(hFileMapped, &handleType);
  3882. if (error != ERROR_SUCCESS) {
  3883. goto quit;
  3884. }
  3885. switch (handleType) {
  3886. // case TypeFtpFileHandle:
  3887. // case TypeGopherFileHandle:
  3888. case TypeHttpRequestHandle:
  3889. break;
  3890. default:
  3891. error = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
  3892. goto quit;
  3893. }
  3894. HTTP_REQUEST_HANDLE_OBJECT *lpRequest;
  3895. lpRequest = (HTTP_REQUEST_HANDLE_OBJECT *) hFileMapped;
  3896. dwNewPosition = lpRequest->SetStreamPointer (lDistanceToMove, dwMoveMethod);
  3897. quit:
  3898. if (hFileMapped != NULL) {
  3899. DereferenceObject((LPVOID)hFileMapped);
  3900. }
  3901. done:
  3902. DEBUG_LEAVE_API(dwNewPosition);
  3903. return dwNewPosition;
  3904. }
  3905. INTERNETAPI_(BOOL) InternetQueryDataAvailable(
  3906. IN HINTERNET hFile,
  3907. OUT LPDWORD lpdwNumberOfBytesAvailable,
  3908. IN DWORD dwFlags,
  3909. IN DWORD_PTR dwContext
  3910. )
  3911. /*++
  3912. Routine Description:
  3913. Determines the amount of data currently available to be read on the handle
  3914. Arguments:
  3915. hFile - handle of internet object
  3916. lpdwNumberOfBytesAvailable - pointer to returned bytes available
  3917. dwFlags - flags controlling operation - FUTURE
  3918. dwContext - used to differentiate multiple requests - FUTURE
  3919. Return Value:
  3920. BOOL
  3921. Success - TRUE
  3922. Failure - FALSE. Call GetLastError() for more info
  3923. --*/
  3924. {
  3925. DEBUG_ENTER_API((DBG_API,
  3926. Bool,
  3927. "InternetQueryDataAvailable",
  3928. "%#x, %#x, %#x, %#x",
  3929. hFile,
  3930. lpdwNumberOfBytesAvailable,
  3931. dwFlags,
  3932. dwContext
  3933. ));
  3934. BOOL success;
  3935. DWORD error;
  3936. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  3937. HINTERNET hFileMapped = NULL;
  3938. BOOL bDeref = TRUE;
  3939. if (!GlobalDataInitialized) {
  3940. error = ERROR_INTERNET_NOT_INITIALIZED;
  3941. bDeref = FALSE;
  3942. goto quit;
  3943. }
  3944. INET_ASSERT(hFile);
  3945. //
  3946. // get the per-thread info block
  3947. //
  3948. lpThreadInfo = InternetGetThreadInfo();
  3949. if (lpThreadInfo == NULL) {
  3950. INET_ASSERT(FALSE);
  3951. error = ERROR_INTERNET_INTERNAL_ERROR;
  3952. goto quit;
  3953. }
  3954. //INET_ASSERT(lpThreadInfo->Fsm == NULL);
  3955. PERF_LOG(PE_CLIENT_REQUEST_START,
  3956. AR_INTERNET_QUERY_DATA_AVAILABLE,
  3957. lpThreadInfo->ThreadId,
  3958. hFile
  3959. );
  3960. //
  3961. // validate parameters
  3962. //
  3963. error = MapHandleToAddress(hFile, &hFileMapped, FALSE);
  3964. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
  3965. goto quit;
  3966. }
  3967. INET_ASSERT(hFileMapped);
  3968. //
  3969. // set the context and handle values in the per-thread info block (this API
  3970. // can't return extended error info, so we don't care about it)
  3971. //
  3972. _InternetSetContext(lpThreadInfo,
  3973. ((INTERNET_HANDLE_OBJECT *)hFileMapped)->GetContext()
  3974. );
  3975. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  3976. //
  3977. // if the handle is invalid, quit now
  3978. //
  3979. if (error != ERROR_SUCCESS) {
  3980. goto quit;
  3981. }
  3982. //
  3983. // validate rest of parameters
  3984. //
  3985. error = ProbeAndSetDword(lpdwNumberOfBytesAvailable, 0);
  3986. if (error != ERROR_SUCCESS) {
  3987. goto quit;
  3988. }
  3989. //
  3990. // get the handle type
  3991. //
  3992. HINTERNET_HANDLE_TYPE handleType;
  3993. handleType = ((HANDLE_OBJECT *)hFileMapped)->GetHandleType();
  3994. //
  3995. // find out if we're sync or async
  3996. //
  3997. BOOL isLocal;
  3998. BOOL isAsync;
  3999. error = RIsHandleLocal(hFileMapped, &isLocal, &isAsync, TypeWildHandle);
  4000. if (error != ERROR_SUCCESS) {
  4001. goto quit;
  4002. }
  4003. // WinSE 4998. If there's no context on the handle, force the request to be synchronous.
  4004. //
  4005. if (isAsync && lpThreadInfo->Context == INTERNET_NO_CALLBACK)
  4006. {
  4007. DEBUG_PRINT(API,
  4008. ERROR,
  4009. ("Zero context: Call is Synchronous\n"
  4010. ));
  4011. isAsync = FALSE;
  4012. }
  4013. //
  4014. // since the async worker thread doesn't come back through this API, the
  4015. // following test is sufficient. Note that we only go async if there is
  4016. // no data currently available on the handle
  4017. //
  4018. BOOL dataAvailable;
  4019. dataAvailable = ((INTERNET_HANDLE_OBJECT *)hFileMapped)->IsDataAvailable();
  4020. BOOL eof;
  4021. eof = ((INTERNET_HANDLE_OBJECT *)hFileMapped)->IsEndOfFile();
  4022. if ((handleType != TypeHttpRequestHandle)
  4023. && isAsync
  4024. && !dataAvailable
  4025. && !eof) {
  4026. INET_ASSERT(hFileMapped);
  4027. // MakeAsyncRequest
  4028. CFsm_InternetQueryDataAvailable * pFsm;
  4029. pFsm = new CFsm_InternetQueryDataAvailable(hFileMapped, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
  4030. if (pFsm != NULL) {
  4031. error = pFsm->QueueWorkItem();
  4032. if (error == ERROR_IO_PENDING) {
  4033. bDeref = FALSE;
  4034. }
  4035. } else {
  4036. error = ERROR_NOT_ENOUGH_MEMORY;
  4037. }
  4038. //
  4039. // if we're here then ERROR_SUCCESS cannot have been returned from
  4040. // the above calls
  4041. //
  4042. INET_ASSERT(error != ERROR_SUCCESS);
  4043. DEBUG_PRINT(FTP,
  4044. INFO,
  4045. ("processing request asynchronously: error = %d\n",
  4046. error
  4047. ));
  4048. goto quit;
  4049. //
  4050. // we will continue along the synchronous path, in which case we
  4051. // need to set error back to ERROR_SUCCESS so that our exit
  4052. // processing (at quit) does the right thing
  4053. //
  4054. error = ERROR_SUCCESS;
  4055. } else if (dataAvailable || eof) {
  4056. DWORD available;
  4057. available = ((INTERNET_HANDLE_OBJECT *)hFileMapped)->AvailableDataLength();
  4058. //
  4059. // we have immediate data; if the handle type is FTP or gopher find and
  4060. // the data is coming from cache, then we only want to indicate that a
  4061. // single (fixed-length) find structure is available
  4062. //
  4063. switch (((HANDLE_OBJECT *)hFileMapped)->GetHandleType()) {
  4064. case TypeFtpFindHandle:
  4065. available = min(available, sizeof(WIN32_FIND_DATA));
  4066. break;
  4067. case TypeGopherFindHandle:
  4068. available = min(available, sizeof(GOPHER_FIND_DATA));
  4069. break;
  4070. }
  4071. DEBUG_PRINT(API,
  4072. INFO,
  4073. ("%d bytes are immediately available\n",
  4074. available
  4075. ));
  4076. *lpdwNumberOfBytesAvailable = available;
  4077. success = TRUE;
  4078. goto finish;
  4079. }
  4080. INET_ASSERT(hFileMapped);
  4081. //
  4082. // sync path. wInternetQueryDataAvailable will set the last error code
  4083. // if it fails
  4084. //
  4085. if (handleType == TypeHttpRequestHandle) {
  4086. error = DoFsm(new CFsm_QueryAvailable(lpdwNumberOfBytesAvailable,
  4087. dwFlags,
  4088. dwContext
  4089. ));
  4090. if (error == ERROR_SUCCESS) {
  4091. success = TRUE;
  4092. } else {
  4093. if (error == ERROR_IO_PENDING) {
  4094. bDeref = FALSE;
  4095. }
  4096. goto quit;
  4097. }
  4098. } else {
  4099. success = wInternetQueryDataAvailable(hFileMapped,
  4100. lpdwNumberOfBytesAvailable,
  4101. dwFlags,
  4102. dwContext
  4103. );
  4104. }
  4105. finish:
  4106. DEBUG_PRINT_API(API,
  4107. INFO,
  4108. ("*lpdwNumberOfBytesAvailable (%#x) = %d\n",
  4109. lpdwNumberOfBytesAvailable,
  4110. *lpdwNumberOfBytesAvailable
  4111. ));
  4112. if (bDeref && (hFileMapped != NULL)) {
  4113. DereferenceObject((LPVOID)hFileMapped);
  4114. }
  4115. if (lpThreadInfo) {
  4116. PERF_LOG(PE_CLIENT_REQUEST_END,
  4117. AR_INTERNET_QUERY_DATA_AVAILABLE,
  4118. *lpdwNumberOfBytesAvailable,
  4119. lpThreadInfo->ThreadId,
  4120. hFile
  4121. );
  4122. }
  4123. DEBUG_LEAVE_API(success);
  4124. return success;
  4125. //
  4126. // we only come here if we are returning an error before calling
  4127. // wInternetQueryDataAvailable
  4128. //
  4129. INET_ASSERT(error != ERROR_SUCCESS);
  4130. quit:
  4131. DEBUG_ERROR(API, error);
  4132. SetLastError(error);
  4133. success = FALSE;
  4134. goto finish;
  4135. }
  4136. DWORD
  4137. CFsm_QueryAvailable::RunSM(
  4138. IN CFsm * Fsm
  4139. )
  4140. {
  4141. DEBUG_ENTER((DBG_HTTP,
  4142. Dword,
  4143. "CFsm_QueryAvailable::RunSM",
  4144. "%#x",
  4145. Fsm
  4146. ));
  4147. DWORD error;
  4148. CFsm_QueryAvailable * stateMachine = (CFsm_QueryAvailable *)Fsm;
  4149. switch (Fsm->GetState()) {
  4150. case FSM_STATE_INIT:
  4151. case FSM_STATE_CONTINUE:
  4152. error = QueryAvailable_Fsm(stateMachine);
  4153. break;
  4154. default:
  4155. error = ERROR_INTERNET_INTERNAL_ERROR;
  4156. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  4157. INET_ASSERT(FALSE);
  4158. break;
  4159. }
  4160. DEBUG_LEAVE(error);
  4161. return error;
  4162. }
  4163. PRIVATE
  4164. DWORD
  4165. QueryAvailable_Fsm(
  4166. IN CFsm_QueryAvailable * Fsm
  4167. )
  4168. {
  4169. DEBUG_ENTER((DBG_INET,
  4170. Dword,
  4171. "QueryAvailable_Fsm",
  4172. "%#x",
  4173. Fsm
  4174. ));
  4175. CFsm_QueryAvailable & fsm = *Fsm;
  4176. DWORD error = fsm.GetError();
  4177. if (error != ERROR_SUCCESS) {
  4178. goto quit;
  4179. }
  4180. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  4181. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)fsm.GetMappedHandle();
  4182. if (fsm.GetState() == FSM_STATE_INIT) {
  4183. error = pRequest->QueryDataAvailable(fsm.m_lpdwNumberOfBytesAvailable);
  4184. }
  4185. if (error == ERROR_SUCCESS) {
  4186. pRequest->SetAvailableDataLength(*fsm.m_lpdwNumberOfBytesAvailable);
  4187. DEBUG_PRINT(INET,
  4188. INFO,
  4189. ("%d bytes available\n",
  4190. *fsm.m_lpdwNumberOfBytesAvailable
  4191. ));
  4192. fsm.SetApiData(*fsm.m_lpdwNumberOfBytesAvailable);
  4193. }
  4194. quit:
  4195. if (error != ERROR_IO_PENDING) {
  4196. fsm.SetDone();
  4197. }
  4198. DEBUG_LEAVE(error);
  4199. return error;
  4200. }
  4201. INTERNETAPI_(BOOL) InternetFindNextFileA(
  4202. IN HINTERNET hFind,
  4203. OUT LPVOID lpBuffer
  4204. )
  4205. /*++
  4206. Routine Description:
  4207. Returns the next directory entry in the listing identified by the handle
  4208. Arguments:
  4209. hFind - find handle, as returned by e.g. FtpFindFirstFile()
  4210. lpBuffer - pointer to buffer where next directory entry information will
  4211. be written. Contents of buffer may be different depending on
  4212. type of directory request, and protocol used (FTP/gopher/etc.)
  4213. Return Value:
  4214. BOOL
  4215. Success - TRUE
  4216. Failure - FALSE. Call GetLastError() for more info
  4217. --*/
  4218. {
  4219. DEBUG_ENTER_API((DBG_API,
  4220. Bool,
  4221. "InternetFindNextFileA",
  4222. "%#x, %#x",
  4223. hFind,
  4224. lpBuffer
  4225. ));
  4226. LPINTERNET_THREAD_INFO lpThreadInfo;
  4227. DWORD nestingLevel = 0;
  4228. DWORD error;
  4229. BOOL success = FALSE;
  4230. BOOL fDeref = TRUE;
  4231. HINTERNET hFindMapped = NULL;
  4232. if (!GlobalDataInitialized) {
  4233. error = ERROR_INTERNET_NOT_INITIALIZED;
  4234. goto done;
  4235. }
  4236. //
  4237. // we need the per-thread info block on all paths
  4238. //
  4239. lpThreadInfo = InternetGetThreadInfo();
  4240. if (lpThreadInfo == NULL) {
  4241. INET_ASSERT(FALSE);
  4242. error = ERROR_INTERNET_INTERNAL_ERROR;
  4243. goto done;
  4244. }
  4245. _InternetIncNestingCount();
  4246. nestingLevel = 1;
  4247. //
  4248. // map the handle
  4249. //
  4250. error = MapHandleToAddress(hFind, (LPVOID *)&hFindMapped, FALSE);
  4251. if ((error != ERROR_SUCCESS) && (hFindMapped == NULL)) {
  4252. goto quit;
  4253. }
  4254. //
  4255. // set the context, handle, and last-error info in the per-thread data block
  4256. // before we go any further. This allows us to return a status in the async
  4257. // case, even if the handle has been closed
  4258. //
  4259. DWORD_PTR context;
  4260. RGetContext(hFindMapped, &context);
  4261. _InternetSetContext(lpThreadInfo, context);
  4262. _InternetSetObjectHandle(lpThreadInfo, hFind, hFindMapped);
  4263. _InternetClearLastError(lpThreadInfo);
  4264. //
  4265. // if MapHandleToAddress() returned a non-NULL object address, but also an
  4266. // error status, then the handle is being closed - quit
  4267. //
  4268. if (error != ERROR_SUCCESS) {
  4269. goto quit;
  4270. }
  4271. //
  4272. // retrieve handle type, and validate in the process
  4273. //
  4274. HINTERNET_HANDLE_TYPE handleType;
  4275. error = RGetHandleType(hFindMapped, &handleType);
  4276. if (error != ERROR_SUCCESS) {
  4277. goto quit;
  4278. }
  4279. //
  4280. // get async/sync and local/remote
  4281. //
  4282. BOOL isLocal;
  4283. BOOL isAsync;
  4284. error = RIsHandleLocal(hFindMapped, &isLocal, &isAsync, handleType);
  4285. if (error != ERROR_SUCCESS) {
  4286. //
  4287. // this should never happen - we just successfully called
  4288. // RGetHandleType(), so RIsHandleLocal() should have worked too
  4289. //
  4290. DEBUG_PRINT(INET,
  4291. ERROR,
  4292. ("RIsHandleLocal() returns %d\n",
  4293. error
  4294. ));
  4295. INET_ASSERT(FALSE);
  4296. goto quit;
  4297. }
  4298. //
  4299. // make sure the handle type is valid for this request. We only support
  4300. // FTP find handle and gopher find handle (both raw data)
  4301. //
  4302. if (!((handleType == TypeFtpFindHandle)
  4303. || (handleType == TypeGopherFindHandle))) {
  4304. error = ERROR_INTERNET_INVALID_OPERATION;
  4305. goto quit;
  4306. }
  4307. //
  4308. // if we're not in an async worker thread context then probe the buffer. If
  4309. // we are in the async worker thread context, then we've already validated
  4310. // the buffer. If is has since become invalid, then the app will fail
  4311. //
  4312. if (!lpThreadInfo->IsAsyncWorkerThread) {
  4313. error = ProbeWriteBuffer(lpBuffer,
  4314. (handleType == TypeFtpFindHandle)
  4315. ? sizeof(WIN32_FIND_DATA)
  4316. : sizeof(GOPHER_FIND_DATA)
  4317. );
  4318. if (error != ERROR_SUCCESS) {
  4319. goto quit;
  4320. }
  4321. //
  4322. // if this is an async request and we are not an async worker thread
  4323. // then queue the request
  4324. //
  4325. if (isAsync) {
  4326. // MakeAsyncRequest
  4327. CFsm_InternetFindNextFile * pFsm;
  4328. pFsm = new CFsm_InternetFindNextFile(hFind, lpBuffer);
  4329. if (pFsm != NULL) {
  4330. error = pFsm->QueueWorkItem();
  4331. if ( error == ERROR_IO_PENDING ) {
  4332. fDeref = FALSE;
  4333. }
  4334. } else {
  4335. error = ERROR_NOT_ENOUGH_MEMORY;
  4336. }
  4337. //
  4338. // if we're here then ERROR_SUCCESS cannot have been returned from
  4339. // the above calls
  4340. //
  4341. INET_ASSERT(error != ERROR_SUCCESS);
  4342. DEBUG_PRINT(FTP,
  4343. INFO,
  4344. ("processing request asynchronously: error = %d\n",
  4345. error
  4346. ));
  4347. goto quit;
  4348. //
  4349. // we will continue along the synchronous path, in which case we
  4350. // need to set error back to ERROR_SUCCESS so that our exit
  4351. // processing (at quit) does the right thing
  4352. //
  4353. error = ERROR_SUCCESS;
  4354. }
  4355. }
  4356. //
  4357. // dispatch to the underlying API. Return what the API returns, and let
  4358. // the API SetLastError()
  4359. //
  4360. // N.B. We have already checked the handle type above, and we know at
  4361. // this stage that we have a correct handle type
  4362. //
  4363. INET_ASSERT(error == ERROR_SUCCESS);
  4364. switch (handleType) {
  4365. case TypeFtpFindHandle:
  4366. success = FtpFindNextFileA(hFindMapped,
  4367. (LPWIN32_FIND_DATA)lpBuffer
  4368. );
  4369. break;
  4370. case TypeGopherFindHandle:
  4371. success = GopherFindNextA(hFindMapped,
  4372. (LPGOPHER_FIND_DATA)lpBuffer
  4373. );
  4374. break;
  4375. }
  4376. quit:
  4377. if (hFindMapped != NULL && fDeref) {
  4378. DereferenceObject((LPVOID)hFindMapped);
  4379. }
  4380. _InternetDecNestingCount(nestingLevel);;
  4381. done:
  4382. //
  4383. // if error is not ERROR_SUCCESS then this function returning the error,
  4384. // otherwise the error has already been set by the API we called,
  4385. // irrespective of the value of success
  4386. //
  4387. if (error != ERROR_SUCCESS) {
  4388. DEBUG_ERROR(API, error);
  4389. SetLastError(error);
  4390. }
  4391. DEBUG_LEAVE_API(success);
  4392. return success;
  4393. }
  4394. INTERNETAPI_(BOOL) InternetGetLastResponseInfoA(
  4395. OUT LPDWORD lpdwErrorCategory,
  4396. IN LPSTR lpszBuffer OPTIONAL,
  4397. IN OUT LPDWORD lpdwBufferLength
  4398. )
  4399. /*++
  4400. Routine Description:
  4401. This function returns the per-thread last internet error description text
  4402. or server response.
  4403. If this function is successful, *lpdwBufferLength contains the string length
  4404. of lpszBuffer.
  4405. If this function returns a failure indication, *lpdwBufferLength contains
  4406. the number of BYTEs required to hold the response text
  4407. Arguments:
  4408. lpdwErrorCategory - pointer to DWORD location where the error catagory is
  4409. returned
  4410. lpszBuffer - pointer to buffer where the error text is returned
  4411. lpdwBufferLength - IN: length of lpszBuffer
  4412. OUT: number of characters in lpszBuffer if successful
  4413. else size of buffer required to hold response text
  4414. Return Value:
  4415. BOOL
  4416. Success - TRUE
  4417. lpszBuffer contains the error text. The caller must check
  4418. *lpdwBufferLength: if 0 then there was no text to return
  4419. Failure - FALSE
  4420. Call GetLastError() for more information
  4421. --*/
  4422. {
  4423. DEBUG_ENTER_API((DBG_API,
  4424. Bool,
  4425. "InternetGetLastResponseInfoA",
  4426. "%#x, %#x, %#x [%d]",
  4427. lpdwErrorCategory,
  4428. lpszBuffer,
  4429. lpdwBufferLength,
  4430. lpdwBufferLength ? *lpdwBufferLength : 0
  4431. ));
  4432. DWORD error;
  4433. BOOL success;
  4434. DWORD textLength;
  4435. LPINTERNET_THREAD_INFO lpThreadInfo;
  4436. //
  4437. // validate parameters
  4438. //
  4439. if (IsBadWritePtr(lpdwErrorCategory, sizeof(*lpdwErrorCategory))
  4440. || IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
  4441. || (ARGUMENT_PRESENT(lpszBuffer)
  4442. ? IsBadWritePtr(lpszBuffer, *lpdwBufferLength)
  4443. : FALSE)) {
  4444. error = ERROR_INVALID_PARAMETER;
  4445. goto quit;
  4446. }
  4447. //
  4448. // if the buffer pointer is NULL then its the same as a zero-length buffer
  4449. //
  4450. if (!ARGUMENT_PRESENT(lpszBuffer)) {
  4451. *lpdwBufferLength = 0;
  4452. } else if (*lpdwBufferLength != 0) {
  4453. *lpszBuffer = '\0';
  4454. }
  4455. lpThreadInfo = InternetGetThreadInfo();
  4456. if (lpThreadInfo == NULL) {
  4457. DEBUG_PRINT(INET,
  4458. ERROR,
  4459. ("failed to get INTERNET_THREAD_INFO\n"
  4460. ));
  4461. INET_ASSERT(FALSE);
  4462. error = ERROR_INTERNET_INTERNAL_ERROR;
  4463. goto quit;
  4464. }
  4465. //
  4466. // there may not be any error text for this thread - either no server
  4467. // error/response has been received, or the error text has been cleared by
  4468. // an intervening API
  4469. //
  4470. if (lpThreadInfo->hErrorText != NULL) {
  4471. //
  4472. // copy as much as we can fit in the user supplied buffer
  4473. //
  4474. textLength = lpThreadInfo->ErrorTextLength;
  4475. if (*lpdwBufferLength) {
  4476. LPBYTE errorText;
  4477. errorText = (LPBYTE)LOCK_MEMORY(lpThreadInfo->hErrorText);
  4478. if (errorText != NULL) {
  4479. textLength = min(textLength, *lpdwBufferLength) - 1;
  4480. memcpy(lpszBuffer, errorText, textLength);
  4481. //
  4482. // the error text should always be zero terminated, so the
  4483. // calling app can treat it as a string
  4484. //
  4485. lpszBuffer[textLength] = '\0';
  4486. UNLOCK_MEMORY(lpThreadInfo->hErrorText);
  4487. if (textLength == lpThreadInfo->ErrorTextLength - 1) {
  4488. error = ERROR_SUCCESS;
  4489. } else {
  4490. //
  4491. // returned length is amount of buffer required
  4492. //
  4493. textLength = lpThreadInfo->ErrorTextLength;
  4494. error = ERROR_INSUFFICIENT_BUFFER;
  4495. }
  4496. } else {
  4497. DEBUG_PRINT(INET,
  4498. ERROR,
  4499. ("failed to lock hErrorText (%#x): %d\n",
  4500. lpThreadInfo->hErrorText,
  4501. GetLastError()
  4502. ));
  4503. error = ERROR_INTERNET_INTERNAL_ERROR;
  4504. }
  4505. } else {
  4506. //
  4507. // user's buffer is not large enough to hold the info. We'll
  4508. // let them know the required length
  4509. //
  4510. error = ERROR_INSUFFICIENT_BUFFER;
  4511. }
  4512. } else {
  4513. INET_ASSERT(lpThreadInfo->ErrorTextLength == 0);
  4514. textLength = 0;
  4515. error = ERROR_SUCCESS;
  4516. }
  4517. *lpdwErrorCategory = lpThreadInfo->ErrorNumber;
  4518. *lpdwBufferLength = textLength;
  4519. IF_DEBUG(ANY) {
  4520. if ((error == ERROR_SUCCESS)
  4521. || ((textLength != 0) && (lpszBuffer != NULL))) {
  4522. DEBUG_DUMP_API(API,
  4523. "Last Response Info:\n",
  4524. lpszBuffer,
  4525. textLength
  4526. );
  4527. }
  4528. }
  4529. quit:
  4530. success = (error == ERROR_SUCCESS);
  4531. if (!success) {
  4532. DEBUG_ERROR(API, error);
  4533. SetLastError(error);
  4534. }
  4535. DEBUG_LEAVE_API(success);
  4536. return success;
  4537. }
  4538. INTERNETAPI_(INTERNET_STATUS_CALLBACK) InternetSetStatusCallbackCore(
  4539. IN HINTERNET hInternet,
  4540. IN INTERNET_STATUS_CALLBACK lpfnInternetCallback,
  4541. IN BOOL fType
  4542. )
  4543. /*++
  4544. Routine Description:
  4545. Sets the status callback function for the DLL or the handle object
  4546. Arguments:
  4547. hInternet - handle of the object for which we wish to set the
  4548. status callback
  4549. lpfnInternetCallback - pointer to caller-supplied status function
  4550. Return Value:
  4551. FARPROC
  4552. Success - previous status callback function address
  4553. Failure - INTERNET_INVALID_STATUS_CALLBACK. Call GetLastErrorInfo() for
  4554. more information:
  4555. ERROR_INVALID_PARAMETER
  4556. The callback function is invalid
  4557. ERROR_INTERNET_INCORRECT_HANDLE_TYPE
  4558. Cannot set the callback on the supplied handle (probably
  4559. a NULL handle - per-process callbacks no longer
  4560. supported)
  4561. --*/
  4562. {
  4563. DWORD dwErr = ERROR_SUCCESS;
  4564. INTERNET_STATUS_CALLBACK previousCallback = INTERNET_INVALID_STATUS_CALLBACK;
  4565. HINTERNET hObjectMapped = NULL;
  4566. if (!GlobalDataInitialized) {
  4567. dwErr = GlobalDataInitialize();
  4568. if (dwErr != ERROR_SUCCESS) {
  4569. goto cleanup;
  4570. }
  4571. }
  4572. if ((lpfnInternetCallback != NULL) && IsBadCodePtr((FARPROC)lpfnInternetCallback))
  4573. {
  4574. dwErr = ERROR_INVALID_PARAMETER;
  4575. goto cleanup;
  4576. }
  4577. if (!hInternet)
  4578. {
  4579. dwErr = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
  4580. goto cleanup;
  4581. }
  4582. //
  4583. // map the handle
  4584. //
  4585. dwErr = MapHandleToAddress(hInternet, (LPVOID *)&hObjectMapped, FALSE);
  4586. if (dwErr == ERROR_SUCCESS)
  4587. {
  4588. //
  4589. // swap the new and previous handle object status callbacks, ONLY
  4590. // if there are no pending requests on this handle
  4591. //
  4592. previousCallback = lpfnInternetCallback;
  4593. dwErr = RExchangeStatusCallback(hObjectMapped, &previousCallback, fType);
  4594. }
  4595. if (hObjectMapped != NULL) {
  4596. DereferenceObject((LPVOID)hObjectMapped);
  4597. }
  4598. cleanup:
  4599. if (dwErr!=ERROR_SUCCESS)
  4600. {
  4601. SetLastError(dwErr);
  4602. DEBUG_ERROR(API, dwErr);
  4603. }
  4604. return previousCallback;
  4605. }
  4606. INTERNETAPI_(INTERNET_STATUS_CALLBACK) InternetSetStatusCallbackA(
  4607. IN HINTERNET hInternet,
  4608. IN INTERNET_STATUS_CALLBACK lpfnInternetCallback
  4609. )
  4610. /*++
  4611. Routine Description:
  4612. Sets the status callback function for the DLL or the handle object
  4613. Arguments:
  4614. hInternet - handle of the object for which we wish to set the
  4615. status callback
  4616. lpfnInternetCallback - pointer to caller-supplied status function
  4617. Return Value:
  4618. FARPROC
  4619. Success - previous status callback function address
  4620. Failure - INTERNET_INVALID_STATUS_CALLBACK. Call GetLastErrorInfo() for
  4621. more information:
  4622. ERROR_INVALID_PARAMETER
  4623. The callback function is invalid
  4624. ERROR_INTERNET_INCORRECT_HANDLE_TYPE
  4625. Cannot set the callback on the supplied handle (probably
  4626. a NULL handle - per-process callbacks no longer
  4627. supported)
  4628. --*/
  4629. {
  4630. DEBUG_ENTER_API((DBG_INET,
  4631. Pointer,
  4632. "InternetSetStatusCallbackA",
  4633. "%#x, %#x",
  4634. hInternet,
  4635. lpfnInternetCallback
  4636. ));
  4637. INTERNET_STATUS_CALLBACK previousCallback = InternetSetStatusCallbackCore(
  4638. hInternet,
  4639. lpfnInternetCallback,
  4640. FALSE
  4641. );
  4642. DEBUG_LEAVE_API(previousCallback);
  4643. return previousCallback;
  4644. }
  4645. //
  4646. //INTERNETAPI_(BOOL) InternetCancelAsyncRequest(
  4647. // IN DWORD dwAsyncId
  4648. // )
  4649. //
  4650. ///*++
  4651. //
  4652. //Routine Description:
  4653. //
  4654. // Cancels an outstanding async request
  4655. //
  4656. //Arguments:
  4657. //
  4658. // dwAsyncId - identifier of the async I/O request
  4659. //
  4660. //Return Value:
  4661. //
  4662. // BOOL
  4663. // Success - TRUE
  4664. // Request was cancelled
  4665. //
  4666. // Failure - FALSE
  4667. // Call GetLastError() for more information
  4668. //
  4669. //--*/
  4670. //
  4671. //{
  4672. // DEBUG_ENTER((DBG_INET,
  4673. // Bool,
  4674. // "InternetCancelAsyncRequest",
  4675. // "%d",
  4676. // dwAsyncId
  4677. // ));
  4678. //
  4679. // DWORD error;
  4680. // BOOL success;
  4681. //
  4682. // error = CancelAsyncRequest(dwAsyncId);
  4683. // if (error != ERROR_SUCCESS) {
  4684. //
  4685. // DEBUG_ERROR(INET, error);
  4686. //
  4687. // SetLastError(error);
  4688. // success = FALSE;
  4689. // } else {
  4690. // success = TRUE;
  4691. // }
  4692. //
  4693. // DEBUG_LEAVE(success);
  4694. //
  4695. // return success;
  4696. //}
  4697. //
  4698. // private functions
  4699. //
  4700. PRIVATE
  4701. DWORD
  4702. wInternetCloseConnectA(
  4703. IN HINTERNET hConnect,
  4704. IN DWORD dwService
  4705. )
  4706. /*++
  4707. Routine Description:
  4708. The obverse of InternetConnect(). Closes the handle created in
  4709. InternetConnect()
  4710. Arguments:
  4711. hConnect - protocol handle created in InternetConnect()
  4712. dwService - service required. Controls type of handle generated.
  4713. May be one of:
  4714. - INTERNET_SERVICE_FTP
  4715. - INTERNET_SERVICE_GOPHER
  4716. - INTERNET_SERVICE_HTTP
  4717. Return Value:
  4718. Success - ERROR_SUCCESS
  4719. Failure - ERROR_INVALID_PARAMETER
  4720. Incorrect dwService parameter (*never* expect this)
  4721. Windows error
  4722. Wininet error
  4723. WSA error
  4724. Error from protocol-specific disconnect function
  4725. --*/
  4726. {
  4727. DEBUG_ENTER((DBG_INET,
  4728. Dword,
  4729. "wInternetCloseConnectA",
  4730. "%#x, %d",
  4731. hConnect,
  4732. dwService
  4733. ));
  4734. DWORD error;
  4735. switch (dwService) {
  4736. case INTERNET_SERVICE_FTP :
  4737. error = wFtpDisconnect(hConnect, CF_EXPEDITED_CLOSE);
  4738. break;
  4739. case INTERNET_SERVICE_GOPHER :
  4740. //error = wGopherDisconnect(hConnect);
  4741. error = ERROR_SUCCESS;
  4742. break;
  4743. case INTERNET_SERVICE_HTTP:
  4744. //error = wHttpConnectClose((LPHINTERNET)hConnect);
  4745. error = ERROR_SUCCESS;
  4746. break;
  4747. default:
  4748. error = ERROR_INVALID_PARAMETER;
  4749. break;
  4750. }
  4751. DEBUG_LEAVE(error);
  4752. return error;
  4753. }
  4754. PRIVATE
  4755. DWORD
  4756. GetEmailNameAndPassword(
  4757. IN OUT LPSTR* lplpszUserName,
  4758. IN OUT LPSTR* lplpszPassword,
  4759. OUT LPSTR EmailName,
  4760. IN DWORD EmailNameLength
  4761. )
  4762. /*++
  4763. Routine Description:
  4764. Gets the login name and password for the FTP server (but can be used for any
  4765. other protocol)
  4766. Arguments:
  4767. lplpszUserName - IN: pointer to pointer to user name
  4768. OUT: pointer to pointer to user name; may be modified
  4769. lplpszPassword - IN: pointer to pointer to password
  4770. OUT: pointer to pointer to password; may be modified
  4771. EmailName - pointer to buffer in which to store password if
  4772. "anonymous" returned for login name
  4773. EmailNameLength - length of EmailName
  4774. Return Value:
  4775. DWORD
  4776. Success - ERROR_SUCCESS
  4777. Failure - ERROR_INVALID_PARAMETER
  4778. --*/
  4779. {
  4780. DWORD error;
  4781. LPSTR lpszUserName;
  4782. LPSTR lpszPassword;
  4783. lpszUserName = *lplpszUserName;
  4784. lpszPassword = *lplpszPassword;
  4785. //
  4786. // validate username and password arguments. Valid combinations are:
  4787. // (N.B. NULL means NULL pointer or NUL string)
  4788. //
  4789. // lpszUsername lpszPassword Result
  4790. //
  4791. // NULL NULL "anonymous", "emailname@domain"
  4792. // !NULL NULL lpszUserName, NULL
  4793. // NULL !NULL ERROR
  4794. // !NULL !NULL lpszUserName, lpszPassword
  4795. //
  4796. error = ERROR_SUCCESS;
  4797. if (lpszUserName != NULL) {
  4798. if (IsBadStringPtr(lpszUserName, INTERNET_MAX_USER_NAME_LENGTH)) {
  4799. error = ERROR_INVALID_PARAMETER;
  4800. } else if (*lpszUserName == '\0') {
  4801. lpszUserName = NULL;
  4802. }
  4803. }
  4804. if (error == ERROR_SUCCESS) {
  4805. if (lpszPassword != NULL) {
  4806. if (IsBadStringPtr(lpszPassword, INTERNET_MAX_PASSWORD_LENGTH)) {
  4807. error = ERROR_INVALID_PASSWORD;
  4808. } else if (*lpszPassword == '\0') {
  4809. lpszPassword = NULL;
  4810. }
  4811. }
  4812. }
  4813. if (error == ERROR_SUCCESS) {
  4814. if (lpszPassword == NULL) {
  4815. if (lpszUserName == NULL) {
  4816. DWORD length;
  4817. //
  4818. // both name and password are null pointers. We will convert to
  4819. // "anonymous", "EmailName@DomainName"
  4820. //
  4821. //
  4822. // because we don't require a client to be running TCP/IP, we
  4823. // may be unable to get a domain name. Hence we now require the
  4824. // EmailName entry in the registry to contain the entire
  4825. // EmailName@DomainName string, including the '@'. If this is
  4826. // not available, then we will just return an error
  4827. //
  4828. lpszUserName = "anonymous";
  4829. length = EmailNameLength;
  4830. error = GetMyEmailName(EmailName, &EmailNameLength);
  4831. if (error == ERROR_SUCCESS) {
  4832. lpszPassword = EmailName;
  4833. }
  4834. } else {
  4835. lpszPassword = "";
  4836. }
  4837. } else if (lpszUserName == NULL) {
  4838. error = ERROR_INVALID_PARAMETER;
  4839. }
  4840. }
  4841. *lplpszUserName = lpszUserName;
  4842. *lplpszPassword = lpszPassword;
  4843. return error;
  4844. }
  4845. INTERNETAPI_(DWORD) InternetAttemptConnect(
  4846. IN DWORD dwReserved
  4847. )
  4848. /*++
  4849. Routine Description:
  4850. This routine attempts to make a loopback socket
  4851. Clients call this to either invoke the dialdialog or to see whether
  4852. they are connected to the net (??).
  4853. 4/29/97 (darrenmi) This function now calls InternetAutodial to see if a
  4854. connection needs to be made.
  4855. This function
  4856. Arguments:
  4857. dwReserved - ?
  4858. Return Value:
  4859. DWORD
  4860. Windows error code, or sockets error code
  4861. --*/
  4862. {
  4863. DEBUG_ENTER_API((DBG_API,
  4864. Dword,
  4865. "InternetAttemptConnect",
  4866. "%d",
  4867. dwReserved
  4868. ));
  4869. DWORD error = ERROR_SUCCESS;
  4870. if (!GlobalDataInitialized) {
  4871. error = GlobalDataInitialize();
  4872. if (error != ERROR_SUCCESS) {
  4873. goto quit;
  4874. }
  4875. }
  4876. if(!InternetAutodial(0, 0)) {
  4877. error = ERROR_GEN_FAILURE;
  4878. }
  4879. quit:
  4880. DEBUG_LEAVE_API(error);
  4881. return error;
  4882. }
  4883. INTERNETAPI_(BOOL) InternetLockRequestFile(
  4884. IN HINTERNET hInternet,
  4885. OUT HANDLE *lphLockReqHandle
  4886. )
  4887. /*++
  4888. Routine Description:
  4889. This routine allows the caller to place a lock on the file that he is
  4890. using by doing a CreateFile. This ensures that if this file is associated
  4891. with this url, and another download on this url tries to commit another
  4892. file, then this file won't vanish because the cache does a safe delete
  4893. when updating or deleting the cache entry.
  4894. The caller can then call the InternetUnlockRequestFile to give wininet
  4895. the permission to delete this file if not committed to the cache.
  4896. Arguments:
  4897. hInternet request object which is doing the download
  4898. lphLocReqHandle place to return LockRequestHandle
  4899. Return Value:
  4900. TRUE - Success
  4901. FALSE - failure, GetLastError returns the error code
  4902. --*/
  4903. {
  4904. DEBUG_ENTER_API((DBG_API,
  4905. Bool,
  4906. "InternetLockRequest",
  4907. "%#x, %#x",
  4908. hInternet,
  4909. lphLockReqHandle
  4910. ));
  4911. DWORD error, dwSize, dwUrlLenPlus1, dwFileLenPlus1;
  4912. HINTERNET_HANDLE_TYPE handleType;
  4913. HINTERNET hObjectMapped = NULL;
  4914. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  4915. LPLOCK_REQUEST_INFO lpLockReqInfo = NULL;
  4916. LPSTR lpSource;
  4917. BOOL locked = FALSE;
  4918. if (!GlobalDataInitialized) {
  4919. error = GlobalDataInitialize();
  4920. if (error != ERROR_SUCCESS) {
  4921. goto Cleanup;
  4922. }
  4923. }
  4924. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternet, FALSE);
  4925. if (error == ERROR_SUCCESS) {
  4926. hObjectMapped = hInternet;
  4927. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)hInternet;
  4928. error = RGetHandleType(hInternet, &handleType);
  4929. }
  4930. if (error != ERROR_SUCCESS) {
  4931. goto Cleanup;
  4932. }
  4933. if ((handleType == TypeGenericHandle)||
  4934. (handleType == TypeInternetHandle)||
  4935. (handleType == TypeFtpConnectHandle)||
  4936. (handleType == TypeGopherConnectHandle)||
  4937. (handleType == TypeHttpConnectHandle) ||
  4938. (handleType == TypeFileRequestHandle)) {
  4939. error = ERROR_INVALID_HANDLE;
  4940. goto Cleanup;
  4941. }
  4942. EnterCriticalSection(&LockRequestFileCritSec);
  4943. locked = TRUE;
  4944. //
  4945. // If a lock handle was already created, simply increment the refcount.
  4946. //
  4947. if(lpLockReqInfo = (LPLOCK_REQUEST_INFO)(pConnect->GetLockRequestHandle())) {
  4948. lpLockReqInfo->dwCount++;
  4949. *lphLockReqHandle = (HANDLE)lpLockReqInfo;
  4950. error = ERROR_SUCCESS;
  4951. goto Cleanup;
  4952. }
  4953. //
  4954. // Record the URL and associated filename in the lock handle.
  4955. //
  4956. lpSource = pConnect->GetDataFileName();
  4957. if (!lpSource) {
  4958. error = ERROR_FILE_NOT_FOUND;
  4959. goto Cleanup;
  4960. }
  4961. dwSize = sizeof(LOCK_REQUEST_INFO)
  4962. +(dwUrlLenPlus1 = lstrlen(pConnect->GetCacheKey())+1)
  4963. +(dwFileLenPlus1 = lstrlen(lpSource)+1)+3; // atmost 3 bytes slop
  4964. lpLockReqInfo = (LPLOCK_REQUEST_INFO)ALLOCATE_MEMORY(LPTR, dwSize);
  4965. if (!lpLockReqInfo) {
  4966. error = ERROR_NOT_ENOUGH_MEMORY;
  4967. goto Cleanup;
  4968. }
  4969. lpLockReqInfo->dwSignature = LOCK_REQUEST_SIGNATURE;
  4970. lpLockReqInfo->dwSize = dwSize;
  4971. lpLockReqInfo->fNoCacheLookup = FALSE;
  4972. memcpy(lpLockReqInfo->rgBuff, pConnect->GetCacheKey(), dwUrlLenPlus1);
  4973. lpLockReqInfo->UrlName = lpLockReqInfo->rgBuff;
  4974. // align filename to DWORD
  4975. lpLockReqInfo->FileName = &(lpLockReqInfo->rgBuff[((dwUrlLenPlus1+sizeof(DWORD)) & ~(3))]);
  4976. memcpy(lpLockReqInfo->FileName, lpSource, dwFileLenPlus1);
  4977. DEBUG_PRINT(INET,
  4978. INFO,
  4979. ("Url==%s, File== %s\n",
  4980. lpLockReqInfo->UrlName,
  4981. lpLockReqInfo->FileName
  4982. ));
  4983. //
  4984. // Open the file so it will not be deleted upon cache entry delete/update.
  4985. //
  4986. lpLockReqInfo->hFile = CreateFile (
  4987. lpSource,
  4988. GENERIC_READ,
  4989. FILE_SHARE_READ|FILE_SHARE_WRITE,
  4990. NULL,
  4991. OPEN_EXISTING,
  4992. FILE_ATTRIBUTE_NORMAL,
  4993. NULL );
  4994. if (lpLockReqInfo->hFile == INVALID_HANDLE_VALUE) {
  4995. error = GetLastError();
  4996. goto Cleanup;
  4997. }
  4998. //
  4999. // Set refcount to 2, one for connect handle and the other for lock handle.
  5000. // Whichever one is closed last will perform cleanup.
  5001. //
  5002. lpLockReqInfo->dwCount = 2;
  5003. *lphLockReqHandle = (HANDLE)lpLockReqInfo;
  5004. pConnect->SetLockRequestHandle((HANDLE)lpLockReqInfo);
  5005. // Check to see if this file corresponds to an installed cache
  5006. // entry. If so, set fNoDelete so unlocking cannot delete the file.
  5007. // Note - because installed cache entries are generally not downloaded
  5008. // by wininet this is ok to do - it is only necessary to check if there
  5009. // is a cache entry in the request object and if it is an installed type.
  5010. if (handleType == TypeHttpRequestHandle)
  5011. {
  5012. LPCACHE_ENTRY_INFO pcei;
  5013. pcei = ((HTTP_REQUEST_HANDLE_OBJECT*) pConnect)->GetCacheEntryInfo();
  5014. if (pcei)
  5015. {
  5016. if (pcei->CacheEntryType & INSTALLED_CACHE_ENTRY)
  5017. lpLockReqInfo->fNoDelete = TRUE;
  5018. }
  5019. }
  5020. error = ERROR_SUCCESS;
  5021. Cleanup:
  5022. BOOL fRet = (error==ERROR_SUCCESS);
  5023. if (!fRet) {
  5024. if (lpLockReqInfo) {
  5025. FREE_MEMORY(lpLockReqInfo);
  5026. }
  5027. DEBUG_ERROR(API, error);
  5028. SetLastError(error);
  5029. }
  5030. else {
  5031. DEBUG_PRINT(INET,
  5032. INFO,
  5033. ("Url==%s, File== %s RefCount=%d, Handle = %#x\n",
  5034. lpLockReqInfo->UrlName,
  5035. lpLockReqInfo->FileName,
  5036. lpLockReqInfo->dwCount,
  5037. *lphLockReqHandle
  5038. ));
  5039. }
  5040. if (locked) {
  5041. LeaveCriticalSection(&LockRequestFileCritSec);
  5042. }
  5043. if (hObjectMapped) {
  5044. DereferenceObject((LPVOID)hObjectMapped);
  5045. }
  5046. DEBUG_LEAVE_API(fRet);
  5047. return fRet;
  5048. }
  5049. INTERNETAPI_(BOOL) InternetUnlockRequestFile(
  5050. IN HANDLE hLockHandle
  5051. )
  5052. /*++
  5053. Routine Description:
  5054. This routine allows the caller to unlock a request file that was locked
  5055. using the InternetLockRequestFile routine. This allows the file
  5056. to be deleted after the request object is long gone.
  5057. Arguments:
  5058. hLockHandle Lock Request Handle that was returned in InternetLockRequestFile
  5059. Return Value:
  5060. TRUE - Success
  5061. FALSE - failure, GetLastError returns the error code
  5062. --*/
  5063. {
  5064. DEBUG_ENTER_API((DBG_API,
  5065. Bool,
  5066. "InternetUnlockRequest",
  5067. "%#x",
  5068. hLockHandle
  5069. ));
  5070. DWORD error, dwUrlLen, dwFileNameLen;
  5071. LPLOCK_REQUEST_INFO lpLockReqInfo;
  5072. if (!GlobalDataInitialized) {
  5073. error = GlobalDataInitialize();
  5074. if (error != ERROR_SUCCESS) {
  5075. goto quit;
  5076. }
  5077. }
  5078. EnterCriticalSection(&LockRequestFileCritSec);
  5079. lpLockReqInfo = (LPLOCK_REQUEST_INFO)hLockHandle;
  5080. __try {
  5081. if (lpLockReqInfo->dwSignature == LOCK_REQUEST_SIGNATURE) {
  5082. DEBUG_PRINT(INET,
  5083. INFO,
  5084. ("Url==%s, File== %s, refcount=%d\n",
  5085. lpLockReqInfo->UrlName,
  5086. lpLockReqInfo->FileName,
  5087. lpLockReqInfo->dwCount
  5088. ));
  5089. if (--lpLockReqInfo->dwCount == 0) {
  5090. if (!CloseHandle(lpLockReqInfo->hFile)) {
  5091. DEBUG_PRINT(INET,
  5092. ERROR,
  5093. ("Error=%d while Closing OpenHandle for file=%s for url=%s\n",
  5094. GetLastError(),
  5095. lpLockReqInfo->FileName,
  5096. lpLockReqInfo->UrlName
  5097. ));
  5098. }
  5099. if (!lpLockReqInfo->fNoDelete) {
  5100. //
  5101. // Validate URL and filename.
  5102. //
  5103. dwUrlLen = lstrlen(lpLockReqInfo->UrlName);
  5104. dwFileNameLen = lstrlen(lpLockReqInfo->FileName);
  5105. //
  5106. // Check if there is a cache entry for the URL.
  5107. //
  5108. DWORD dwSize;
  5109. LPINTERNET_CACHE_ENTRY_INFO pCEI;
  5110. char buf[sizeof(INTERNET_CACHE_ENTRY_INFO)+MAX_PATH+1];
  5111. pCEI = (LPINTERNET_CACHE_ENTRY_INFO)buf;
  5112. dwSize = sizeof(buf);
  5113. if (lpLockReqInfo->fNoCacheLookup) {
  5114. error = ERROR_FILE_NOT_FOUND;
  5115. } else {
  5116. // Grab info and
  5117. // Check if the filename actually matches.
  5118. error = GetUrlCacheEntryInfoEx(lpLockReqInfo->UrlName,
  5119. pCEI,
  5120. &dwSize,
  5121. NULL,
  5122. NULL,
  5123. NULL,
  5124. INTERNET_CACHE_FLAG_ADD_FILENAME_ONLY) ?
  5125. (lstrcmpi(lpLockReqInfo->FileName, pCEI->lpszLocalFileName) ?
  5126. ERROR_FILE_NOT_FOUND
  5127. : ERROR_SUCCESS)
  5128. : GetLastError();
  5129. } // end else if (!lpLockReqInfo->fNoCacheLookup)
  5130. if (error != ERROR_SUCCESS) {
  5131. //
  5132. // The file was not committed to cache, so attempt to delete it.
  5133. //
  5134. DEBUG_PRINT(INET, INFO,("deleting %q\n",lpLockReqInfo->FileName));
  5135. if (!DeleteFile(lpLockReqInfo->FileName)) {
  5136. DEBUG_PRINT(INET,
  5137. ERROR,
  5138. ("Error=%d while deleting file=%s for url=%s\n",
  5139. GetLastError(),
  5140. lpLockReqInfo->FileName,
  5141. lpLockReqInfo->UrlName
  5142. ));
  5143. if (lpLockReqInfo->fNoCacheLookup) {
  5144. switch (GetLastError()) {
  5145. case ERROR_SHARING_VIOLATION:
  5146. case ERROR_ACCESS_DENIED:
  5147. UrlCacheAddLeakFile (lpLockReqInfo->FileName);
  5148. }
  5149. }
  5150. } // end if (!DeleteFile(...))
  5151. }
  5152. } // end if (!lpLockReqInfo->fNoDelete)
  5153. FREE_MEMORY(lpLockReqInfo);
  5154. error = ERROR_SUCCESS;
  5155. } else {
  5156. DEBUG_PRINT(INET,
  5157. INFO,
  5158. ("Quitting after decrementing refcount, new refcount=%d\n",
  5159. lpLockReqInfo->dwCount
  5160. ));
  5161. error = ERROR_SUCCESS;
  5162. }
  5163. } else {
  5164. error = ERROR_INVALID_PARAMETER;
  5165. }
  5166. } __except(EXCEPTION_EXECUTE_HANDLER) {
  5167. error = ERROR_INVALID_PARAMETER;
  5168. }
  5169. ENDEXCEPT
  5170. LeaveCriticalSection(&LockRequestFileCritSec);
  5171. quit:
  5172. BOOL fRet = (error==ERROR_SUCCESS);
  5173. if (fRet) {
  5174. DEBUG_ERROR(API, error);
  5175. SetLastError(error);
  5176. }
  5177. DEBUG_LEAVE_API(fRet);
  5178. return fRet;
  5179. }
  5180. INTERNETAPI_(BOOL) InternetCheckConnectionA(
  5181. IN LPCSTR lpszUrl,
  5182. IN DWORD dwFlags,
  5183. IN DWORD dwReserved
  5184. )
  5185. /*++
  5186. Routine Description:
  5187. This routine tells the caller whether he can establish a connection to the
  5188. network. If no URL is specified and dwFlags are set to NULL then wininet
  5189. a) checks whether it has an outstanding socket connection and if so
  5190. then the API returns TRUE.
  5191. b) If there are no outstanding socket connections then a check
  5192. is made in the wininet serverdatabase for servers which were
  5193. connected to in the recent past. If one is found then the API returns TRUE.
  5194. If neither a) or b) succeeds the API returns FALSE.
  5195. Arguments:
  5196. lpszUrl this parameter is an indication to the API to attempt
  5197. a specific host. The use of this parameter is based on the
  5198. flags set in the dwFlags parameter
  5199. dwFlags a bitwise OR of the following flags
  5200. INTERNET_FLAG_ICC_FORCE_CONNECTION - force a connection
  5201. A sockets connection is attempted in the following order
  5202. 1) If lpszUrl is non-NULL then a host value is extracted
  5203. fromt it used that to ping the specific host
  5204. 2) If the lpszUrl parameter is NULL then if there is an
  5205. entry in the wininet's internal server database for
  5206. the nearest server, it is used to do the pinging
  5207. If neither of these are available then ERROR_NOT_CONNECTED is
  5208. returned in GetLastError()
  5209. dwReserved reserved
  5210. Return Value:
  5211. TRUE - Success
  5212. FALSE - failure, GetLastError returns the error code
  5213. --*/
  5214. {
  5215. DEBUG_ENTER_API((DBG_API,
  5216. Bool,
  5217. "InternetCheckConnectionA",
  5218. "%s %x",
  5219. lpszUrl,
  5220. dwFlags
  5221. ));
  5222. DWORD dwError = ERROR_SUCCESS;
  5223. LPSTR lpszHostName;
  5224. DWORD dwHostNameLen;
  5225. INTERNET_PORT ServerPort = INTERNET_DEFAULT_HTTP_PORT;
  5226. INTERNET_SCHEME ustScheme = INTERNET_SCHEME_HTTP;
  5227. ICSocket *pSocket = NULL;
  5228. char buff[INTERNET_MAX_HOST_NAME_LENGTH+1];
  5229. LPINTERNET_THREAD_INFO lpThreadInfo;
  5230. HINTERNET hInternet = NULL, hConnect = NULL, hConnectMapped = NULL;
  5231. CServerInfo * lpServerInfo = NULL;
  5232. if (!GlobalDataInitialized) {
  5233. dwError = GlobalDataInitialize();
  5234. if (dwError != ERROR_SUCCESS) {
  5235. goto Cleanup;
  5236. }
  5237. }
  5238. // if the main sockets database thinks we are
  5239. // unconditionally offline, then let us give that to the user
  5240. //if(vSocketsDatabase.IsOffline())
  5241. //{
  5242. //
  5243. // dwError = ERROR_NOT_CONNECTED;
  5244. //}
  5245. //else
  5246. {
  5247. // We are not explicitly in offline mode
  5248. lpServerInfo = FindNearestServer();
  5249. if (dwFlags & FLAG_ICC_FORCE_CONNECTION) {
  5250. buff[0] = 0;
  5251. if (lpszUrl) {
  5252. if (((dwError = CrackUrl(
  5253. (LPSTR)lpszUrl, // url
  5254. lstrlen(lpszUrl), // url length
  5255. FALSE, // escape the URL ?
  5256. &ustScheme, // scheme type
  5257. NULL, // scheme name
  5258. NULL, // scheme length
  5259. &lpszHostName, // hostname pointer
  5260. &dwHostNameLen, // hostname length
  5261. &ServerPort, // port
  5262. NULL, // UserName
  5263. NULL, // UserName Length
  5264. NULL, // Password
  5265. NULL, // Password Length
  5266. NULL, // Path
  5267. NULL, // Path Length
  5268. NULL, // Extra
  5269. NULL, // Extra Length
  5270. NULL // have port?
  5271. )) == ERROR_SUCCESS)&&
  5272. (dwHostNameLen<=INTERNET_MAX_HOST_NAME_LENGTH))
  5273. {
  5274. memcpy(buff, lpszHostName, dwHostNameLen);
  5275. buff[dwHostNameLen] = 0;
  5276. // make sure we have a valid scheme
  5277. if(INTERNET_SCHEME_UNKNOWN == ustScheme)
  5278. {
  5279. ustScheme = INTERNET_SCHEME_HTTP;
  5280. }
  5281. // make sure we have a valid port
  5282. if(0 == ServerPort)
  5283. {
  5284. switch(ustScheme)
  5285. {
  5286. case INTERNET_SCHEME_FTP:
  5287. ServerPort = INTERNET_DEFAULT_FTP_PORT;
  5288. break;
  5289. case INTERNET_SCHEME_HTTPS:
  5290. ServerPort = INTERNET_DEFAULT_HTTPS_PORT;
  5291. break;
  5292. default:
  5293. ServerPort = INTERNET_DEFAULT_HTTP_PORT;
  5294. break;
  5295. }
  5296. }
  5297. // for our purposes, HTTPS == HTTP
  5298. if(INTERNET_SCHEME_HTTPS == ustScheme)
  5299. {
  5300. ustScheme = INTERNET_SCHEME_HTTP;
  5301. }
  5302. // we need the serverinfo struct for this server, not
  5303. // the nearest one that we already found
  5304. if(lpServerInfo)
  5305. {
  5306. lpServerInfo->Dereference();
  5307. }
  5308. lpServerInfo = FindServerInfo(buff);
  5309. if(!lpServerInfo)
  5310. {
  5311. // new CServerInfo has ref count 1 already
  5312. // we need to raise it so another thread won't go ahead and destroy this.
  5313. LockSerializedList(&GlobalServerInfoList);
  5314. lpServerInfo = new CServerInfo(buff, &dwError, INTERNET_SERVICE_HTTP, 0);
  5315. if(NULL == lpServerInfo)
  5316. {
  5317. dwError = ERROR_NOT_ENOUGH_MEMORY;
  5318. goto Cleanup;
  5319. }
  5320. else if (dwError != ERROR_SUCCESS)
  5321. {
  5322. delete lpServerInfo;
  5323. lpServerInfo = NULL;
  5324. }
  5325. else
  5326. {
  5327. lpServerInfo->Reference();
  5328. }
  5329. UnlockSerializedList(&GlobalServerInfoList);
  5330. }
  5331. }
  5332. }
  5333. else {
  5334. if (lpServerInfo) {
  5335. buff[sizeof(buff)-1] = 0;
  5336. strncpy(buff, lpServerInfo->GetHostName(), sizeof(buff)-1);
  5337. }
  5338. else
  5339. {
  5340. // FORCE but no server to try - set error
  5341. dwError = ERROR_INTERNET_INVALID_OPERATION;
  5342. goto Cleanup;
  5343. }
  5344. }
  5345. if (buff[0] && lpServerInfo) {
  5346. // we have a host name, ping it.
  5347. // This threadinfo/InternetOpen stuff is being done
  5348. // because the ICSocket class is intertwined with
  5349. // an internet handle, so we are just getting round that
  5350. // difficulty. Ideally, ICSocket should have been a
  5351. // standalone sockets class
  5352. lpThreadInfo = InternetGetThreadInfo();
  5353. if (lpThreadInfo == NULL) {
  5354. INET_ASSERT(FALSE);
  5355. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  5356. goto Cleanup;
  5357. }
  5358. hInternet = InternetOpen("Internal",
  5359. 0,
  5360. NULL,
  5361. NULL,
  5362. 0
  5363. );
  5364. if (!hInternet) {
  5365. dwError = GetLastError();
  5366. goto Cleanup;
  5367. }
  5368. hConnect = InternetConnect(hInternet,
  5369. buff,
  5370. ServerPort,
  5371. NULL,
  5372. NULL,
  5373. ustScheme,
  5374. 0,
  5375. 0);
  5376. if (!hConnect) {
  5377. dwError = GetLastError();
  5378. goto Cleanup;
  5379. }
  5380. dwError = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
  5381. if (dwError != ERROR_SUCCESS) {
  5382. goto Cleanup;
  5383. }
  5384. _InternetSetObjectHandle(lpThreadInfo, hConnect, hConnectMapped);
  5385. // Ping the server
  5386. if (pSocket = new ICSocket()) {
  5387. pSocket->SetPort(ServerPort);
  5388. dwError = pSocket->SocketConnect(
  5389. GetTimeoutValue(INTERNET_OPTION_CONNECT_TIMEOUT),
  5390. GetTimeoutValue(INTERNET_OPTION_CONNECT_RETRIES),
  5391. 0,
  5392. lpServerInfo
  5393. );
  5394. if (dwError == ERROR_SUCCESS) {
  5395. pSocket->Disconnect();
  5396. }
  5397. }
  5398. else {
  5399. dwError = ERROR_NOT_ENOUGH_MEMORY;
  5400. }
  5401. }
  5402. }
  5403. else{
  5404. // caller doesn't ask us to force a connection
  5405. // do the best we can and tell him
  5406. dwError = (/*vSocketsDatabase.GetSocketCount() ||*/ lpServerInfo)?
  5407. ERROR_SUCCESS:
  5408. ERROR_NOT_CONNECTED;
  5409. }
  5410. }
  5411. Cleanup:
  5412. if (lpServerInfo)
  5413. {
  5414. lpServerInfo->Dereference();
  5415. }
  5416. if (pSocket) {
  5417. pSocket->Dereference();
  5418. }
  5419. if (hConnectMapped) {
  5420. DereferenceObject((LPVOID)hConnectMapped);
  5421. }
  5422. if (hConnect) {
  5423. InternetCloseHandle(hConnect);
  5424. }
  5425. if (hInternet) {
  5426. InternetCloseHandle(hInternet);
  5427. }
  5428. BOOL fRet = (dwError==ERROR_SUCCESS);
  5429. if (FALSE == fRet) {
  5430. SetLastError(dwError);
  5431. DEBUG_ERROR(API, dwError);
  5432. }
  5433. DEBUG_LEAVE_API(fRet);
  5434. return (fRet);
  5435. }