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.

3589 lines
92 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. WinHttpCloseHandle
  9. WinHttpReadData
  10. WinHttpWriteData
  11. WinHttpQueryDataAvailable
  12. WinHttpCrackUrlA
  13. WinHttpCreateUrlA
  14. InternetCanonicalizeUrlA
  15. InternetCombineUrlA
  16. InternetOpenA
  17. _InternetCloseHandle
  18. _InternetCloseHandleNoContext
  19. InternetConnectA
  20. InternetOpenUrlA
  21. ReadFile_End
  22. InternetQueryOptionA
  23. InternetSetOptionA
  24. InternetGetLastResponseInfoA
  25. (wInternetCloseConnectA)
  26. (CreateDeleteSocket)
  27. Author:
  28. Richard L Firth (rfirth) 02-Mar-1995
  29. Environment:
  30. Win32 user-mode DLL
  31. Revision History:
  32. 02-Mar-1995 rfirth
  33. Created
  34. 07-Mar-1995 madana
  35. --*/
  36. #include <wininetp.h>
  37. #include <perfdiag.hxx>
  38. // because wininet doesnt know IStream
  39. #define NO_SHLWAPI_STREAM
  40. #include <shlwapi.h>
  41. #include <shlwapip.h>
  42. //
  43. // private manifests
  44. //
  45. //
  46. // private prototypes
  47. //
  48. PRIVATE
  49. DWORD
  50. ReadFile_Fsm(
  51. IN CFsm_ReadFile * Fsm
  52. );
  53. PRIVATE
  54. DWORD
  55. ReadFileEx_Fsm(
  56. IN CFsm_ReadFileEx * Fsm
  57. );
  58. PRIVATE
  59. VOID
  60. ReadFile_End(
  61. IN BOOL bDeref,
  62. IN BOOL bSuccess,
  63. IN HINTERNET hFileMapped,
  64. IN DWORD dwBytesRead,
  65. IN LPVOID lpBuffer OPTIONAL,
  66. IN DWORD dwNumberOfBytesToRead,
  67. OUT LPDWORD lpdwNumberOfBytesRead OPTIONAL
  68. );
  69. PRIVATE
  70. DWORD
  71. QueryAvailable_Fsm(
  72. IN CFsm_QueryAvailable * Fsm
  73. );
  74. PRIVATE
  75. DWORD
  76. wInternetCloseConnectA(
  77. IN HINTERNET lpConnectHandle,
  78. IN DWORD ServiceType
  79. );
  80. PRIVATE
  81. BOOL
  82. InternetParseCommon(
  83. IN LPCTSTR lpszBaseUrl,
  84. IN LPCTSTR lpszRelativeUrl,
  85. OUT LPTSTR lpszBuffer,
  86. IN OUT LPDWORD lpdwBufferLength,
  87. IN DWORD dwFlags
  88. );
  89. //
  90. // WinHttpCrackUrlA
  91. //
  92. BOOL winHttpCrackUrlAVerifyStringBuffer( LPSTR szStr, DWORD dwStrSize, DWORD dwFlags)
  93. {
  94. if (szStr == NULL
  95. && dwStrSize != 0
  96. && (dwFlags & (ICU_DECODE | ICU_ESCAPE)))
  97. {
  98. return FALSE;
  99. }
  100. else
  101. return TRUE;
  102. }
  103. DWORD winHttpCrackUrlACopyResultToBuffer( LPSTR szResult, DWORD dwResultLength,
  104. LPSTR* pszBuffer, DWORD* pdwBufferSize,
  105. DWORD dwSchemeType, BOOL fDecode, BOOL fEscape, BOOL* pfCopyFailure)
  106. {
  107. DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
  108. LPSTR szAlloc = NULL;
  109. if (*pszBuffer != NULL
  110. && *pdwBufferSize > dwResultLength+1
  111. && szResult != NULL
  112. && szResult[0] != '\0')
  113. {
  114. memcpy(*pszBuffer, szResult, dwResultLength);
  115. (*pszBuffer)[dwResultLength] = '\0';
  116. if (fDecode)
  117. {
  118. HRESULT hr = UrlUnescapeInPlace((*pszBuffer), 0);
  119. if (FAILED(hr))
  120. {
  121. dwError = HRESULT_CODE(hr);
  122. goto quit;
  123. }
  124. }
  125. if (fEscape)
  126. {
  127. DWORD dwAllocSize = (*pdwBufferSize);
  128. szAlloc = (LPSTR)ALLOCATE_MEMORY(dwAllocSize);
  129. if(szAlloc == NULL)
  130. {
  131. dwError = ERROR_NOT_ENOUGH_MEMORY;
  132. goto quit;
  133. }
  134. dwError = EncodeUrlPath(0, dwSchemeType,
  135. (*pszBuffer), strlen((*pszBuffer)) + 1,
  136. &szAlloc, &dwAllocSize);
  137. // dwAllocSize was the size of the buffer going in,
  138. //but after calling EncodeUrlPath it is now the length (without '\0')
  139. //of the result.
  140. if(dwError != ERROR_SUCCESS)
  141. goto quit;
  142. if(dwAllocSize + 1 <= (*pdwBufferSize))
  143. {
  144. memcpy((*pszBuffer), szAlloc, dwAllocSize+1);
  145. (*pdwBufferSize) = dwAllocSize; // if we had enough space, return length not including '\0'
  146. }
  147. else
  148. {
  149. (*pszBuffer)[0] = '\0';
  150. (*pdwBufferSize) = dwAllocSize+1;
  151. *pfCopyFailure = TRUE; // if we didn't have enough space, ask for enough to include '\0'
  152. }
  153. }
  154. else
  155. {
  156. (*pdwBufferSize) = strlen((*pszBuffer));
  157. }
  158. }
  159. else if (*pszBuffer != NULL)
  160. {
  161. // If there wasn't room for the copy, return an empty string
  162. //with the size parameter returning a sufficient size to store
  163. //the full result.
  164. (*pszBuffer)[0] = '\0';
  165. if (dwResultLength > 0)
  166. {
  167. DWORD dwPossibleExpansion = fEscape ? 3 : 1;
  168. (*pdwBufferSize) = dwResultLength * dwPossibleExpansion + 1;
  169. *pfCopyFailure = TRUE;
  170. }
  171. else
  172. {
  173. *pdwBufferSize = 0;
  174. }
  175. }
  176. else if ((*pdwBufferSize) != 0)
  177. {
  178. // *pswBuffer == NULL && *pdwBufferSize != 0 indicates
  179. //user wants a pointer to the result in the original string. This
  180. //also indicates WinHttpCrackUrlA called CrackUrl on the
  181. //original string.
  182. *pszBuffer = szResult;
  183. *pdwBufferSize = dwResultLength;
  184. }
  185. dwError = ERROR_SUCCESS;
  186. quit:
  187. if (szAlloc != NULL)
  188. DEL_STRING(szAlloc);
  189. return dwError;
  190. }
  191. INTERNETAPI
  192. BOOL
  193. WINAPI
  194. WinHttpCrackUrlA(
  195. IN LPCSTR lpszUrl,
  196. IN DWORD dwUrlLength,
  197. IN DWORD dwFlags,
  198. IN LPURL_COMPONENTSA lpUrlComponents
  199. )
  200. /*++
  201. Routine Description:
  202. Cracks an URL into its constituent parts. Optionally escapes the url-path.
  203. We assume that the user has supplied large enough buffers for the various
  204. URL parts
  205. Arguments:
  206. lpszUrl - pointer to URL to crack
  207. dwUrlLength - 0 if lpszUrl is ASCIIZ string, else length of lpszUrl
  208. dwFlags - flags controlling operation
  209. lpUrlComponents - pointer to URL_COMPONENTS
  210. Return Value:
  211. BOOL
  212. Success - TRUE
  213. Failure - FALSE. Call GetLastError() for more info
  214. --*/
  215. {
  216. DEBUG_ENTER_API((DBG_API,
  217. Bool,
  218. "WinHttpCrackUrlA",
  219. "%q, %#x, %#x, %#x",
  220. lpszUrl,
  221. dwUrlLength,
  222. dwFlags,
  223. lpUrlComponents
  224. ));
  225. DWORD error;
  226. LPSTR lpUrl;
  227. LPSTR urlCopy = NULL;
  228. //
  229. // validate parameters
  230. //
  231. if (!dwUrlLength)
  232. dwUrlLength = lstrlen(lpszUrl);
  233. if (!winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength, dwFlags)
  234. || !winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength, dwFlags)
  235. || !winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszUserName, lpUrlComponents->dwUserNameLength, dwFlags)
  236. || !winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszPassword, lpUrlComponents->dwPasswordLength, dwFlags)
  237. || !winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength, dwFlags)
  238. || !winHttpCrackUrlAVerifyStringBuffer(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength, dwFlags))
  239. {
  240. error = ERROR_INVALID_PARAMETER;
  241. goto quit;
  242. }
  243. //
  244. // Below are variables to be used as out params with CrackUrl()
  245. //
  246. LPSTR schemeName = NULL;
  247. DWORD schemeNameLength = 0;
  248. LPSTR hostName = NULL;
  249. DWORD hostNameLength = 0;
  250. LPSTR userName = NULL;
  251. DWORD userNameLength = 0;
  252. LPSTR password = NULL;
  253. DWORD passwordLength = 0;
  254. LPSTR urlPath = NULL;
  255. DWORD urlPathLength = 0;
  256. LPSTR extraInfo = NULL;
  257. DWORD extraInfoLength = 0;
  258. INTERNET_SCHEME schemeType;
  259. INTERNET_PORT nPort;
  260. BOOL havePort;
  261. //
  262. // If we're escaping or decoding, create a separate work buffer
  263. //because we can't do it in place.
  264. //
  265. if (dwFlags & (ICU_ESCAPE | ICU_DECODE))
  266. {
  267. //
  268. // create a copy of the URL. CrackUrl() will modify this in situ. We
  269. // need to copy the results back to the user's buffer(s)
  270. //
  271. urlCopy = NewString((LPSTR)lpszUrl, dwUrlLength);
  272. if (urlCopy == NULL)
  273. {
  274. error = ERROR_NOT_ENOUGH_MEMORY;
  275. goto quit;
  276. }
  277. lpUrl = urlCopy;
  278. }
  279. else
  280. {
  281. lpUrl = (LPSTR)lpszUrl;
  282. urlCopy = NULL;
  283. }
  284. //
  285. // crack the URL into its constituent parts
  286. //
  287. error = CrackUrl(lpUrl,
  288. dwUrlLength,
  289. FALSE,
  290. &schemeType,
  291. &schemeName,
  292. &schemeNameLength,
  293. &hostName,
  294. &hostNameLength,
  295. FALSE,
  296. &nPort,
  297. &userName,
  298. &userNameLength,
  299. &password,
  300. &passwordLength,
  301. &urlPath,
  302. &urlPathLength,
  303. lpUrlComponents->dwExtraInfoLength ? &extraInfo : NULL,
  304. lpUrlComponents->dwExtraInfoLength ? &extraInfoLength : 0,
  305. &havePort
  306. );
  307. if (error != ERROR_SUCCESS) {
  308. goto quit;
  309. }
  310. //
  311. // Transfer the results from CrackUrl() to lpUrlComponents
  312. //
  313. BOOL fCopyFailure;
  314. fCopyFailure = FALSE;
  315. error = winHttpCrackUrlACopyResultToBuffer(
  316. schemeName, schemeNameLength,
  317. &lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
  318. schemeType, dwFlags & ICU_DECODE, FALSE, &fCopyFailure);
  319. if (error != ERROR_SUCCESS)
  320. goto quit;
  321. error = winHttpCrackUrlACopyResultToBuffer(
  322. hostName, hostNameLength,
  323. &lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
  324. schemeType, dwFlags & ICU_DECODE, FALSE, &fCopyFailure);
  325. if (error != ERROR_SUCCESS)
  326. goto quit;
  327. error = winHttpCrackUrlACopyResultToBuffer(
  328. userName, userNameLength,
  329. &lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
  330. schemeType, dwFlags & ICU_DECODE, FALSE, &fCopyFailure);
  331. if (error != ERROR_SUCCESS)
  332. goto quit;
  333. error = winHttpCrackUrlACopyResultToBuffer(
  334. password, passwordLength,
  335. &lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
  336. schemeType, dwFlags & ICU_DECODE, FALSE, &fCopyFailure);
  337. if (error != ERROR_SUCCESS)
  338. goto quit;
  339. error = winHttpCrackUrlACopyResultToBuffer(
  340. urlPath, urlPathLength,
  341. &lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
  342. schemeType, dwFlags & ICU_DECODE, dwFlags & ICU_ESCAPE, &fCopyFailure);
  343. if (error != ERROR_SUCCESS)
  344. goto quit;
  345. error = winHttpCrackUrlACopyResultToBuffer(
  346. extraInfo, extraInfoLength,
  347. &lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
  348. schemeType, dwFlags & ICU_DECODE, dwFlags & ICU_ESCAPE, &fCopyFailure);
  349. if (error != ERROR_SUCCESS)
  350. goto quit;
  351. //
  352. // we may have failed to copy one or more components because we didn't have
  353. // enough buffer space.
  354. //
  355. if (fCopyFailure)
  356. {
  357. error = ERROR_INSUFFICIENT_BUFFER;
  358. }
  359. //
  360. // copy the scheme type
  361. //
  362. lpUrlComponents->nScheme = schemeType;
  363. //
  364. // convert 0 port (not in URL) to default value for scheme
  365. //
  366. if (nPort == INTERNET_INVALID_PORT_NUMBER && !havePort) {
  367. switch (schemeType) {
  368. case INTERNET_SCHEME_HTTP:
  369. nPort = INTERNET_DEFAULT_HTTP_PORT;
  370. break;
  371. case INTERNET_SCHEME_HTTPS:
  372. nPort = INTERNET_DEFAULT_HTTPS_PORT;
  373. break;
  374. }
  375. }
  376. lpUrlComponents->nPort = nPort;
  377. quit:
  378. if (urlCopy != NULL)
  379. {
  380. DEL_STRING(urlCopy);
  381. }
  382. BOOL success = (error==ERROR_SUCCESS);
  383. if (!success) {
  384. DEBUG_ERROR(API, error);
  385. SetLastError(error);
  386. }
  387. DEBUG_LEAVE_API(success);
  388. return success;
  389. }
  390. INTERNETAPI
  391. BOOL
  392. WINAPI
  393. WinHttpCreateUrlA(
  394. IN LPURL_COMPONENTSA lpUrlComponents,
  395. IN DWORD dwFlags,
  396. OUT LPSTR lpszUrl OPTIONAL,
  397. IN OUT LPDWORD lpdwUrlLength
  398. )
  399. /*++
  400. Routine Description:
  401. Creates an URL from its constituent parts
  402. Arguments:
  403. lpUrlComponents - pointer to URL_COMPONENTS structure containing pointers
  404. and lengths of components of interest
  405. dwFlags - flags controlling function:
  406. ICU_ESCAPE - the components contain characters that
  407. must be escaped in the output URL
  408. lpszUrl - pointer to buffer where output URL will be written
  409. lpdwUrlLength - IN: number of bytes in lpszUrl buffer
  410. OUT: if success, number of characters in lpszUrl, else
  411. number of bytes required for buffer
  412. Return Value:
  413. BOOL
  414. Success - URL written to lpszUrl
  415. Failure - call GetLastError() for more info
  416. --*/
  417. {
  418. DEBUG_ENTER_API((DBG_API,
  419. Bool,
  420. "WinHttpCreateUrlA",
  421. "%#x, %#x, %#x, %#x",
  422. lpUrlComponents,
  423. dwFlags,
  424. lpszUrl,
  425. lpdwUrlLength
  426. ));
  427. #if INET_DEBUG
  428. LPSTR lpszUrlOriginal = lpszUrl;
  429. #endif
  430. DWORD error = ERROR_SUCCESS;
  431. LPSTR encodedUrlPath = NULL;
  432. LPSTR encodedExtraInfo = NULL;
  433. //
  434. // validate parameters
  435. //
  436. if (!ARGUMENT_PRESENT(lpszUrl)) {
  437. *lpdwUrlLength = 0;
  438. }
  439. //
  440. // allocate large buffers from heap
  441. //
  442. encodedUrlPath = (LPSTR)ALLOCATE_MEMORY(INTERNET_MAX_URL_LENGTH + 1);
  443. encodedExtraInfo = (LPSTR)ALLOCATE_MEMORY(INTERNET_MAX_URL_LENGTH + 1);
  444. if ((encodedUrlPath == NULL) || (encodedExtraInfo == NULL)) {
  445. error = ERROR_NOT_ENOUGH_MEMORY;
  446. goto quit;
  447. }
  448. //
  449. // if we get an exception, we return ERROR_INVALID_PARAMETER
  450. //
  451. __try {
  452. //
  453. // get the individual components to copy
  454. //
  455. LPSTR schemeName;
  456. DWORD schemeNameLength;
  457. DWORD schemeFlags;
  458. LPSTR hostName;
  459. DWORD hostNameLength;
  460. BOOL bracketsNeeded;
  461. INTERNET_PORT nPort = 0;
  462. DWORD portLength;
  463. LPSTR userName;
  464. DWORD userNameLength;
  465. LPSTR password;
  466. DWORD passwordLength;
  467. LPSTR urlPath;
  468. DWORD urlPathLength;
  469. DWORD extraLength;
  470. DWORD encodedUrlPathLength;
  471. LPSTR extraInfo = NULL;
  472. DWORD extraInfoLength = 0;
  473. DWORD encodedExtraInfoLength;
  474. LPSTR schemeSep;
  475. DWORD schemeSepLength;
  476. INTERNET_SCHEME schemeType;
  477. INTERNET_PORT defaultPort;
  478. //
  479. // if the scheme name is absent then we use the default
  480. //
  481. schemeName = lpUrlComponents->lpszScheme;
  482. schemeType = lpUrlComponents->nScheme;
  483. if (schemeName == NULL) {
  484. if (schemeType == INTERNET_SCHEME_DEFAULT){
  485. schemeName = DEFAULT_URL_SCHEME_NAME;
  486. schemeNameLength = sizeof(DEFAULT_URL_SCHEME_NAME) - 1;
  487. }
  488. else {
  489. schemeName = MapUrlScheme(schemeType, &schemeNameLength);
  490. }
  491. } else {
  492. schemeNameLength = lpUrlComponents->dwSchemeLength;
  493. if (schemeNameLength == 0) {
  494. schemeNameLength = lstrlen(schemeName);
  495. }
  496. }
  497. if (schemeNameLength == 0)
  498. {
  499. error = ERROR_INVALID_PARAMETER;
  500. goto quit;
  501. }
  502. //
  503. // doesn't have to be a host name
  504. //
  505. hostName = lpUrlComponents->lpszHostName;
  506. portLength = 0;
  507. if (hostName != NULL) {
  508. hostNameLength = lpUrlComponents->dwHostNameLength;
  509. if (hostNameLength == 0) {
  510. hostNameLength = lstrlen(hostName);
  511. }
  512. //
  513. // If a hostname was supplied and it contains at least two colons then
  514. // it will be assumed to be an IPv6 literal address. To comply with RFC 2732
  515. // it will need square brackets around it when we construct the URL string.
  516. //
  517. DWORD colonCount, index;
  518. bracketsNeeded = FALSE;
  519. for (colonCount = 0, index = 0; index < hostNameLength; index++) {
  520. if (hostName[index] == ':') {
  521. colonCount++;
  522. }
  523. if (colonCount > 1) {
  524. bracketsNeeded = TRUE;
  525. break;
  526. }
  527. }
  528. // Don't add square brackets to IPv6 literal if they are already there.
  529. if (bracketsNeeded && (hostName[0] == '[') && (hostName[hostNameLength-1] == ']')) {
  530. bracketsNeeded = FALSE;
  531. }
  532. //
  533. // if the port is default then we don't add it to the URL, else we need to
  534. // copy it as a string
  535. //
  536. // there won't be a port unless there's host.
  537. schemeType = MapUrlSchemeName(schemeName, schemeNameLength ? schemeNameLength : -1);
  538. switch (schemeType) {
  539. case INTERNET_SCHEME_HTTP:
  540. defaultPort = INTERNET_DEFAULT_HTTP_PORT;
  541. break;
  542. case INTERNET_SCHEME_HTTPS:
  543. defaultPort = INTERNET_DEFAULT_HTTPS_PORT;
  544. break;
  545. default:
  546. defaultPort = INTERNET_INVALID_PORT_NUMBER;
  547. break;
  548. }
  549. if (lpUrlComponents->nPort != defaultPort) {
  550. INTERNET_PORT divisor;
  551. nPort = lpUrlComponents->nPort;
  552. if (nPort) {
  553. divisor = 10000;
  554. portLength = 6; // max is 5 characters, plus 1 for ':'
  555. while ((nPort / divisor) == 0) {
  556. --portLength;
  557. divisor /= 10;
  558. }
  559. } else {
  560. portLength = 2; // port is ":0"
  561. }
  562. }
  563. } else {
  564. hostNameLength = 0;
  565. bracketsNeeded = FALSE;
  566. }
  567. //
  568. // doesn't have to be a user name
  569. //
  570. userName = lpUrlComponents->lpszUserName;
  571. if (userName != NULL) {
  572. userNameLength = lpUrlComponents->dwUserNameLength;
  573. if (userNameLength == 0) {
  574. userNameLength = lstrlen(userName);
  575. }
  576. } else {
  577. userNameLength = 0;
  578. }
  579. //
  580. // doesn't have to be a password
  581. //
  582. password = lpUrlComponents->lpszPassword;
  583. if (password != NULL) {
  584. passwordLength = lpUrlComponents->dwPasswordLength;
  585. if (passwordLength == 0) {
  586. passwordLength = lstrlen(password);
  587. }
  588. } else {
  589. passwordLength = 0;
  590. }
  591. //
  592. // but if there's a password without a user name, then its an error
  593. //
  594. if (password && !userName) {
  595. error = ERROR_INVALID_PARAMETER;
  596. } else {
  597. //
  598. // determine the scheme type for possible uses below
  599. //
  600. schemeFlags = 0;
  601. if (strnicmp(schemeName, "http", schemeNameLength) == 0) {
  602. schemeFlags = SCHEME_HTTP;
  603. } else if (strnicmp(schemeName, "ftp", schemeNameLength) == 0) {
  604. schemeFlags = SCHEME_FTP;
  605. } else if (strnicmp(schemeName, "gopher", schemeNameLength) == 0) {
  606. schemeFlags = SCHEME_GOPHER;
  607. }
  608. //
  609. // doesn't have to be an URL-path. Empty string is default
  610. //
  611. urlPath = lpUrlComponents->lpszUrlPath;
  612. if (urlPath != NULL) {
  613. urlPathLength = lpUrlComponents->dwUrlPathLength;
  614. if (urlPathLength == 0) {
  615. urlPathLength = lstrlen(urlPath);
  616. }
  617. if ((*urlPath != '/') && (*urlPath != '\\')) {
  618. extraLength = 1;
  619. } else {
  620. extraLength = 0;
  621. }
  622. //
  623. // if requested, we will encode the URL-path
  624. //
  625. if (dwFlags & ICU_ESCAPE) {
  626. //
  627. // only encode the URL-path if it's a recognized scheme
  628. //
  629. if (schemeFlags != 0) {
  630. encodedUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  631. error = EncodeUrlPath(NO_ENCODE_PATH_SEP,
  632. schemeFlags,
  633. urlPath,
  634. urlPathLength,
  635. &encodedUrlPath,
  636. &encodedUrlPathLength
  637. );
  638. if (error == ERROR_SUCCESS) {
  639. urlPath = encodedUrlPath;
  640. urlPathLength = encodedUrlPathLength;
  641. }
  642. }
  643. }
  644. } else {
  645. urlPathLength = 0;
  646. extraLength = 0;
  647. }
  648. //
  649. // handle extra info if present
  650. //
  651. if (error == ERROR_SUCCESS) {
  652. extraInfo = lpUrlComponents->lpszExtraInfo;
  653. if (extraInfo != NULL) {
  654. extraInfoLength = lpUrlComponents->dwExtraInfoLength;
  655. if (extraInfoLength == 0) {
  656. extraInfoLength = lstrlen(extraInfo);
  657. }
  658. //
  659. // if requested, we will encode the extra info
  660. //
  661. if (dwFlags & ICU_ESCAPE) {
  662. //
  663. // only encode the extra info if it's a recognized scheme
  664. //
  665. if (schemeFlags != 0) {
  666. encodedExtraInfoLength = INTERNET_MAX_URL_LENGTH + 1;
  667. error = EncodeUrlPath(0,
  668. schemeFlags,
  669. extraInfo,
  670. extraInfoLength,
  671. &encodedExtraInfo,
  672. &encodedExtraInfoLength
  673. );
  674. if (error == ERROR_SUCCESS) {
  675. extraInfo = encodedExtraInfo;
  676. extraInfoLength = encodedExtraInfoLength;
  677. }
  678. }
  679. }
  680. } else {
  681. extraInfoLength = 0;
  682. }
  683. }
  684. DWORD requiredSize = 0;
  685. if (error == ERROR_SUCCESS) {
  686. //
  687. // Determine if we have a protocol scheme that requires slashes
  688. //
  689. if (DoesSchemeRequireSlashes(schemeName, schemeNameLength, (hostName != NULL))) {
  690. schemeSep = "://";
  691. schemeSepLength = sizeof("://") - 1;
  692. } else {
  693. schemeSep = ":";
  694. schemeSepLength = sizeof(":") - 1;
  695. }
  696. //
  697. // ensure we have enough buffer space
  698. //
  699. requiredSize = schemeNameLength
  700. + schemeSepLength
  701. + hostNameLength
  702. + (bracketsNeeded ? 2 : 0)
  703. + portLength
  704. + (userName ? userNameLength + 1 : 0) // +1 for '@'
  705. + (password ? passwordLength + 1 : 0) // +1 for ':'
  706. + urlPathLength
  707. + extraLength
  708. + extraInfoLength
  709. + 1 // +1 for '\0'
  710. ;
  711. //
  712. // if there is enough buffer, copy the URL
  713. //
  714. if (*lpdwUrlLength >= requiredSize) {
  715. memcpy((LPVOID)lpszUrl, (LPVOID)schemeName, schemeNameLength);
  716. lpszUrl += schemeNameLength;
  717. memcpy((LPVOID)lpszUrl, (LPVOID)schemeSep, schemeSepLength);
  718. lpszUrl += schemeSepLength;
  719. if (userName) {
  720. memcpy((LPVOID)lpszUrl, (LPVOID)userName, userNameLength);
  721. lpszUrl += userNameLength;
  722. if (password) {
  723. *lpszUrl++ = ':';
  724. memcpy((LPVOID)lpszUrl, (LPVOID)password, passwordLength);
  725. lpszUrl += passwordLength;
  726. }
  727. *lpszUrl++ = '@';
  728. }
  729. if (hostName) {
  730. if (bracketsNeeded)
  731. *lpszUrl++ = '[';
  732. memcpy((LPVOID)lpszUrl, (LPVOID)hostName, hostNameLength);
  733. lpszUrl += hostNameLength;
  734. if (bracketsNeeded)
  735. *lpszUrl++ = ']';
  736. // We won't attach a port unless there's a host to go with it.
  737. if (portLength) {
  738. lpszUrl += wsprintf(lpszUrl, ":%d", nPort & 0xffff);
  739. }
  740. }
  741. if (urlPath) {
  742. //
  743. // Only do extraLength if we've actually copied something
  744. // after the scheme.
  745. //
  746. if (extraLength != 0 && (userName || hostName || portLength)) {
  747. *lpszUrl++ = '/';
  748. } else if (extraLength != 0) {
  749. --requiredSize;
  750. }
  751. memcpy((LPVOID)lpszUrl, (LPVOID)urlPath, urlPathLength);
  752. lpszUrl += urlPathLength;
  753. } else if (extraLength != 0) {
  754. --requiredSize;
  755. }
  756. if (extraInfo) {
  757. memcpy((LPVOID)lpszUrl, (LPVOID)extraInfo, extraInfoLength);
  758. lpszUrl += extraInfoLength;
  759. }
  760. //
  761. // terminate string
  762. //
  763. *lpszUrl = '\0';
  764. //
  765. // -1 for terminating '\0'
  766. //
  767. --requiredSize;
  768. } else {
  769. //
  770. // not enough buffer space - just return the required buffer length
  771. //
  772. error = ERROR_INSUFFICIENT_BUFFER;
  773. }
  774. }
  775. //
  776. // update returned parameters
  777. //
  778. *lpdwUrlLength = requiredSize;
  779. }
  780. } __except(EXCEPTION_EXECUTE_HANDLER) {
  781. error = ERROR_INVALID_PARAMETER;
  782. }
  783. ENDEXCEPT
  784. quit:
  785. //
  786. // clear up the buffers we allocated
  787. //
  788. if (encodedUrlPath != NULL) {
  789. FREE_MEMORY(encodedUrlPath);
  790. }
  791. if (encodedExtraInfo != NULL) {
  792. FREE_MEMORY(encodedExtraInfo);
  793. }
  794. BOOL success = (error==ERROR_SUCCESS);
  795. if (success) {
  796. DEBUG_PRINT_API(API,
  797. INFO,
  798. ("URL = %q\n",
  799. lpszUrlOriginal
  800. ));
  801. } else {
  802. DEBUG_ERROR(API, error);
  803. SetLastError(error);
  804. }
  805. DEBUG_LEAVE_API(success);
  806. return success;
  807. }
  808. //
  809. // ICUHrToWin32Error() is specifically for converting the return codes for
  810. // Url* APIs in shlwapi into win32 errors.
  811. // WARNING: it should not be used for any other purpose.
  812. //
  813. DWORD
  814. ICUHrToWin32Error(HRESULT hr)
  815. {
  816. DWORD err = ERROR_INVALID_PARAMETER;
  817. switch(hr)
  818. {
  819. case E_OUTOFMEMORY:
  820. err = ERROR_NOT_ENOUGH_MEMORY;
  821. break;
  822. case E_POINTER:
  823. err = ERROR_INSUFFICIENT_BUFFER;
  824. break;
  825. case S_OK:
  826. err = ERROR_SUCCESS;
  827. break;
  828. default:
  829. break;
  830. }
  831. return err;
  832. }
  833. INTERNETAPI
  834. BOOL
  835. WINAPI
  836. InternetCanonicalizeUrlA(
  837. IN LPCSTR lpszUrl,
  838. OUT LPSTR lpszBuffer,
  839. IN OUT LPDWORD lpdwBufferLength,
  840. IN DWORD dwFlags
  841. )
  842. /*++
  843. Routine Description:
  844. Combines a relative URL with a base URL to form a new full URL.
  845. Arguments:
  846. lpszUrl - pointer to URL to be canonicalize
  847. lpszBuffer - pointer to buffer where new URL is written
  848. lpdwBufferLength - size of buffer on entry, length of new URL on exit
  849. dwFlags - flags controlling operation
  850. Return Value:
  851. BOOL - TRUE if successful, FALSE if not
  852. --*/
  853. {
  854. DEBUG_ENTER((DBG_API,
  855. Bool,
  856. "InternetCanonicalizeUrlA",
  857. "%q, %#x, %#x [%d], %#x",
  858. lpszUrl,
  859. lpszBuffer,
  860. lpdwBufferLength,
  861. lpdwBufferLength ? *lpdwBufferLength : 0,
  862. dwFlags
  863. ));
  864. HRESULT hr ;
  865. BOOL bRet = TRUE;;
  866. INET_ASSERT(lpszUrl);
  867. INET_ASSERT(lpszBuffer);
  868. INET_ASSERT(lpdwBufferLength && (*lpdwBufferLength > 0));
  869. //
  870. // the flags for the Url* APIs in shlwapi should be the same
  871. // except that NO_ENCODE is on by default. so we need to flip it
  872. //
  873. dwFlags ^= ICU_NO_ENCODE;
  874. // Check for invalid parameters
  875. if (!lpszUrl || !lpszBuffer || !lpdwBufferLength || *lpdwBufferLength == 0 || IsBadWritePtr(lpszBuffer, *lpdwBufferLength*sizeof(CHAR)))
  876. {
  877. hr = E_INVALIDARG;
  878. }
  879. else
  880. {
  881. hr = UrlCanonicalizeA(lpszUrl, lpszBuffer,
  882. lpdwBufferLength, dwFlags | URL_WININET_COMPATIBILITY);
  883. }
  884. if(FAILED(hr))
  885. {
  886. DWORD dw = ICUHrToWin32Error(hr);
  887. bRet = FALSE;
  888. DEBUG_ERROR(API, dw);
  889. SetLastError(dw);
  890. }
  891. DEBUG_LEAVE(bRet);
  892. return bRet;
  893. }
  894. INTERNETAPI
  895. BOOL
  896. WINAPI
  897. InternetCombineUrlA(
  898. IN LPCSTR lpszBaseUrl,
  899. IN LPCSTR lpszRelativeUrl,
  900. OUT LPSTR lpszBuffer,
  901. IN OUT LPDWORD lpdwBufferLength,
  902. IN DWORD dwFlags
  903. )
  904. /*++
  905. Routine Description:
  906. Combines a relative URL with a base URL to form a new full URL.
  907. Arguments:
  908. lpszBaseUrl - pointer to base URL
  909. lpszRelativeUrl - pointer to relative URL
  910. lpszBuffer - pointer to buffer where new URL is written
  911. lpdwBufferLength - size of buffer on entry, length of new URL on exit
  912. dwFlags - flags controlling operation
  913. Return Value:
  914. BOOL - TRUE if successful, FALSE if not
  915. --*/
  916. {
  917. DEBUG_ENTER((DBG_API,
  918. Bool,
  919. "InternetCombineUrlA",
  920. "%q, %q, %#x, %#x [%d], %#x",
  921. lpszBaseUrl,
  922. lpszRelativeUrl,
  923. lpszBuffer,
  924. lpdwBufferLength,
  925. lpdwBufferLength ? *lpdwBufferLength : 0,
  926. dwFlags
  927. ));
  928. HRESULT hr ;
  929. BOOL bRet;
  930. INET_ASSERT(lpszBaseUrl);
  931. INET_ASSERT(lpszRelativeUrl);
  932. INET_ASSERT(lpdwBufferLength);
  933. //
  934. // the flags for the Url* APIs in shlwapi should be the same
  935. // except that NO_ENCODE is on by default. so we need to flip it
  936. //
  937. dwFlags ^= ICU_NO_ENCODE;
  938. // Check for invalid parameters
  939. if (!lpszBaseUrl || !lpszRelativeUrl || !lpdwBufferLength || (lpszBuffer && IsBadWritePtr(lpszBuffer, *lpdwBufferLength*sizeof(CHAR))))
  940. {
  941. hr = E_INVALIDARG;
  942. }
  943. else
  944. {
  945. hr = UrlCombineA(lpszBaseUrl, lpszRelativeUrl, lpszBuffer,
  946. lpdwBufferLength, dwFlags | URL_WININET_COMPATIBILITY);
  947. }
  948. if(FAILED(hr))
  949. {
  950. DWORD dw = ICUHrToWin32Error(hr);
  951. bRet = FALSE;
  952. DEBUG_ERROR(API, dw);
  953. SetLastError(dw);
  954. }
  955. else
  956. bRet = TRUE;
  957. IF_DEBUG_CODE() {
  958. if (bRet) {
  959. DEBUG_PRINT_API(API,
  960. INFO,
  961. ("URL = %q\n",
  962. lpszBuffer
  963. ));
  964. }
  965. }
  966. DEBUG_LEAVE(bRet);
  967. return bRet;
  968. }
  969. INTERNETAPI
  970. HINTERNET
  971. WINAPI
  972. InternetOpenA(
  973. IN LPCSTR lpszAgent,
  974. IN DWORD dwAccessType,
  975. IN LPCSTR lpszProxy OPTIONAL,
  976. IN LPCSTR lpszProxyBypass OPTIONAL,
  977. IN DWORD dwFlags
  978. )
  979. /*++
  980. Routine Description:
  981. Opens a root Internet handle from which all HINTERNET objects are derived
  982. Arguments:
  983. lpszAgent - name of the application making the request (arbitrary
  984. identifying string). Used in "User-Agent" header when
  985. communicating with HTTP servers, if the application does
  986. not add a User-Agent header of its own
  987. dwAccessType - type of access required. Can be
  988. WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
  989. - Gets the configuration from the registry
  990. WINHTTP_ACCESS_TYPE_NO_PROXY
  991. - Requests are made directly to the nominated server
  992. WINHTTP_ACCESS_TYPE_NAMED_PROXY
  993. - Requests are made via the nominated proxy
  994. lpszProxy - if INTERNET_OPEN_TYPE_PROXY, a list of proxy servers to
  995. use
  996. lpszProxyBypass - if INTERNET_OPEN_TYPE_PROXY, a list of servers which we
  997. will communicate with directly
  998. dwFlags - flags to control the operation of this API or potentially
  999. all APIs called on the handle generated by this API.
  1000. Currently supported are:
  1001. WINHTTP_FLAG_ASYNC - Not supported in WinHttpX v6.
  1002. Return Value:
  1003. HINTERNET
  1004. Success - handle of Internet object
  1005. Failure - NULL. For more information, call GetLastError()
  1006. --*/
  1007. {
  1008. PERF_INIT();
  1009. DEBUG_ENTER((DBG_API,
  1010. Handle,
  1011. "InternetOpenA",
  1012. "%q, %s (%d), %q, %q, %#x",
  1013. lpszAgent,
  1014. InternetMapOpenType(dwAccessType),
  1015. dwAccessType,
  1016. lpszProxy,
  1017. lpszProxyBypass,
  1018. dwFlags
  1019. ));
  1020. DWORD error;
  1021. HINTERNET hInternet = NULL;
  1022. if (!GlobalDataInitialized) {
  1023. error = GlobalDataInitialize();
  1024. if (error != ERROR_SUCCESS) {
  1025. goto quit;
  1026. }
  1027. }
  1028. //
  1029. // validate parameters
  1030. //
  1031. if (!( (dwAccessType == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
  1032. || (dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
  1033. || ( (dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
  1034. && (ARGUMENT_PRESENT(lpszProxy))
  1035. && (*lpszProxy != '\0'))))
  1036. {
  1037. error = ERROR_INVALID_PARAMETER;
  1038. goto quit;
  1039. }
  1040. if( 0 != (dwFlags & ~WINHTTP_OPEN_FLAGS_MASK))
  1041. {
  1042. error = ERROR_INVALID_PARAMETER;
  1043. goto quit;
  1044. }
  1045. INTERNET_HANDLE_OBJECT * lpInternet;
  1046. lpInternet = New INTERNET_HANDLE_OBJECT(lpszAgent,
  1047. dwAccessType,
  1048. (LPSTR)lpszProxy,
  1049. (LPSTR)lpszProxyBypass,
  1050. dwFlags
  1051. );
  1052. if (lpInternet == NULL) {
  1053. error = ERROR_NOT_ENOUGH_MEMORY;
  1054. goto quit;
  1055. }
  1056. error = lpInternet->GetStatus();
  1057. if (error == ERROR_SUCCESS) {
  1058. hInternet = (HINTERNET)lpInternet;
  1059. //
  1060. // success - don't return the object address, return the pseudo-handle
  1061. // value we generated
  1062. //
  1063. hInternet = ((HANDLE_OBJECT *)hInternet)->GetPseudoHandle();
  1064. } else {
  1065. //
  1066. // hack fix to stop InternetIndicateStatus (called from the handle
  1067. // object destructor) blowing up if there is no handle object in the
  1068. // thread info block. We can't call back anyway
  1069. //
  1070. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  1071. if (lpThreadInfo) {
  1072. //
  1073. // BUGBUG - incorrect handle value
  1074. //
  1075. _InternetSetObjectHandle(lpThreadInfo, lpInternet, lpInternet);
  1076. }
  1077. //
  1078. // we failed during initialization. Kill the handle using Dereference()
  1079. // (in order to stop the debug version complaining about the reference
  1080. // count not being 0. Invalidate for same reason)
  1081. //
  1082. lpInternet->Invalidate();
  1083. lpInternet->Dereference();
  1084. INET_ASSERT(hInternet == NULL);
  1085. }
  1086. quit:
  1087. if (error != ERROR_SUCCESS) {
  1088. DEBUG_ERROR(API, error);
  1089. SetLastError(error);
  1090. }
  1091. DEBUG_LEAVE(hInternet);
  1092. return hInternet;
  1093. }
  1094. INTERNETAPI
  1095. BOOL
  1096. WINAPI
  1097. WinHttpCloseHandle(
  1098. IN HINTERNET hInternet
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. Closes any open internet handle object
  1103. Arguments:
  1104. hInternet - handle of internet object to close
  1105. Return Value:
  1106. BOOL
  1107. Success - TRUE
  1108. Failure - FALSE. For more information call GetLastError()
  1109. --*/
  1110. {
  1111. DEBUG_ENTER_API((DBG_API,
  1112. Bool,
  1113. "WinHttpCloseHandle",
  1114. "%#x",
  1115. hInternet
  1116. ));
  1117. PERF_ENTER(InternetCloseHandle);
  1118. DWORD error;
  1119. BOOL success = FALSE;
  1120. HINTERNET hInternetMapped = NULL;
  1121. INTERNET_THREAD_INFO LocalThreadInfoOnStack;
  1122. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  1123. if (!GlobalDataInitialized) {
  1124. error = GlobalDataInitialize();
  1125. if (error != ERROR_SUCCESS) {
  1126. goto quit;
  1127. }
  1128. }
  1129. lpThreadInfo = InternetGetThreadInfo();
  1130. // If allocation of the thread info object failed, then
  1131. // use a threadinfo object preallocated on our stack.
  1132. if (!lpThreadInfo)
  1133. {
  1134. lpThreadInfo = InternetCreateThreadInfo(TRUE, &LocalThreadInfoOnStack);
  1135. INET_ASSERT(lpThreadInfo->fStaticAllocation);
  1136. }
  1137. //
  1138. // map the handle. Don't invalidate it (_InternetCloseHandle() does this)
  1139. //
  1140. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, FALSE);
  1141. if (error != ERROR_SUCCESS) {
  1142. if (hInternetMapped == NULL) {
  1143. //
  1144. // the handle never existed or has been completely destroyed
  1145. //
  1146. DEBUG_PRINT(API,
  1147. ERROR,
  1148. ("Handle %#x is invalid\n",
  1149. hInternet
  1150. ));
  1151. //
  1152. // catch invalid handles - may help caller
  1153. //
  1154. DEBUG_BREAK(INVALID_HANDLES);
  1155. } else {
  1156. //
  1157. // this handle is already being closed (it's invalidated). We only
  1158. // need one InternetCloseHandle() operation to invalidate the handle.
  1159. // All other threads will simply dereference the handle, and
  1160. // eventually it will be destroyed
  1161. //
  1162. DereferenceObject((LPVOID)hInternetMapped);
  1163. }
  1164. goto quit;
  1165. }
  1166. //
  1167. // the handle is not invalidated
  1168. //
  1169. HANDLE_OBJECT * pHandle;
  1170. pHandle = (HANDLE_OBJECT *)hInternetMapped;
  1171. DEBUG_PRINT(INET,
  1172. INFO,
  1173. ("handle %#x == %#x == %s\n",
  1174. hInternet,
  1175. hInternetMapped,
  1176. InternetMapHandleType(pHandle->GetHandleType())
  1177. ));
  1178. //
  1179. // clear the handle object last error variables
  1180. //
  1181. InternetClearLastError();
  1182. //
  1183. // decrement session count here rather than in destructor, since
  1184. // the session is ref-counted and there may still be outstanding
  1185. // references from request/connect handles on async fsms.
  1186. //
  1187. if (pHandle->GetHandleType() == TypeInternetHandle)
  1188. {
  1189. InterlockedDecrement(&g_cSessionCount);
  1190. }
  1191. //
  1192. // remove the reference added by MapHandleToAddress(), or the handle won't
  1193. // be destroyed by _InternetCloseHandle()
  1194. //
  1195. DereferenceObject((LPVOID)hInternetMapped);
  1196. //
  1197. // use _InternetCloseHandle() to do the work
  1198. //
  1199. success = _InternetCloseHandle(hInternet);
  1200. quit:
  1201. // SetLastError must be called after PERF_LEAVE !!!
  1202. PERF_LEAVE(InternetCloseHandle);
  1203. //
  1204. // If the local stack threadinfo object is in use,
  1205. // then clear out the pointer from TLS here. So when this thread
  1206. // detaches, the InternetDestroyThreadInfo called
  1207. // from DLLMain(DLL_THREAD_DETACH) will have no effect--it will
  1208. // not find a threadinfo object in TLS on this thread.
  1209. //
  1210. if (lpThreadInfo == &LocalThreadInfoOnStack)
  1211. {
  1212. InternetSetThreadInfo(NULL);
  1213. }
  1214. if (error != ERROR_SUCCESS) {
  1215. DEBUG_ERROR(API, error);
  1216. SetLastError(error);
  1217. }
  1218. DEBUG_LEAVE_API(success);
  1219. return success;
  1220. }
  1221. BOOL
  1222. _InternetCloseHandle(
  1223. IN HINTERNET hInternet
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Same as InternetCloseHandle() except does not clear out the last error text.
  1228. Mainly for FTP
  1229. Arguments:
  1230. hInternet - handle of internet object to close
  1231. Return Value:
  1232. BOOL
  1233. Success - TRUE
  1234. Failure - FALSE. For more information call GetLastError()
  1235. --*/
  1236. {
  1237. DEBUG_ENTER((DBG_INET,
  1238. Bool,
  1239. "_InternetCloseHandle",
  1240. "%#x",
  1241. hInternet
  1242. ));
  1243. DWORD error;
  1244. BOOL success;
  1245. HINTERNET hInternetMapped = NULL;
  1246. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  1247. if (lpThreadInfo == NULL) {
  1248. if (InDllCleanup) {
  1249. error = ERROR_WINHTTP_SHUTDOWN;
  1250. } else {
  1251. INET_ASSERT(FALSE);
  1252. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1253. }
  1254. goto quit;
  1255. }
  1256. //
  1257. // map the handle and invalidate it. This will cause any new requests with
  1258. // the handle as a parameter to fail
  1259. //
  1260. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, TRUE);
  1261. if (error != ERROR_SUCCESS) {
  1262. if (hInternetMapped != NULL) {
  1263. //
  1264. // the handle is already being closed, or is already deleted
  1265. //
  1266. DereferenceObject((LPVOID)hInternetMapped);
  1267. }
  1268. //
  1269. // since this is the only function that can invalidate a handle, if we
  1270. // are here then the handle is just waiting for its refcount to go to
  1271. // zero. We already removed the refcount we added above, so we're in
  1272. // the clear
  1273. //
  1274. goto quit;
  1275. }
  1276. //
  1277. // there may be an active socket operation. We close the socket to abort the
  1278. // operation
  1279. //
  1280. ((INTERNET_HANDLE_BASE *)hInternetMapped)->AbortSocket();
  1281. //
  1282. // we need the parent handle - we will set this as the handle object being
  1283. // processed by this thread. This is required for async worker threads (see
  1284. // below)
  1285. //
  1286. HINTERNET hParent = NULL;
  1287. HINTERNET hParentMapped;
  1288. DWORD_PTR dwParentContext;
  1289. hParentMapped = ((HANDLE_OBJECT *)hInternetMapped)->GetParent();
  1290. if (hParentMapped != NULL) {
  1291. hParent = ((HANDLE_OBJECT *)hParentMapped)->GetPseudoHandle();
  1292. dwParentContext = ((HANDLE_OBJECT *)hParentMapped)->GetContext();
  1293. }
  1294. //
  1295. // set the object handle in the per-thread data structure
  1296. //
  1297. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  1298. //
  1299. // at this point, there should *always* be at least 2 references on the
  1300. // handle - one added when the object was created, and one added by
  1301. // MapHandleToAddress() above. If the object is still alive after the 2
  1302. // dereferences, then it will be destroyed when the current owning thread
  1303. // dereferences it
  1304. //
  1305. (void)DereferenceObject((LPVOID)hInternetMapped);
  1306. error = DereferenceObject((LPVOID)hInternetMapped);
  1307. //
  1308. // now set the object to be the parent. This is necessary for e.g.
  1309. // FtpGetFile() and async requests (where the async worker thread will make
  1310. // an extra callback to deliver the results of the async request)
  1311. //
  1312. if (hParentMapped != NULL) {
  1313. _InternetSetObjectHandle(lpThreadInfo, hParent, hParentMapped);
  1314. }
  1315. //
  1316. // if the handle was still alive after dereferencing it then we will inform
  1317. // the app that the close is pending
  1318. //
  1319. quit:
  1320. success = (error==ERROR_SUCCESS);
  1321. if (!success) {
  1322. SetLastError(error);
  1323. DEBUG_ERROR(INET, error);
  1324. }
  1325. DEBUG_LEAVE(success);
  1326. return success;
  1327. }
  1328. DWORD
  1329. _InternetCloseHandleNoContext(
  1330. IN HINTERNET hInternet
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. Same as _InternetCloseHandle() except does not change the per-thread info
  1335. structure handle/context values
  1336. BUGBUG - This should be handled via a parameter to _InternetCloseHandle(),
  1337. but its close to shipping...
  1338. Arguments:
  1339. hInternet - handle of internet object to close
  1340. Return Value:
  1341. DWORD
  1342. Success - ERROR_SUCCESS
  1343. Failure - ERROR_INVALID_HANDLE
  1344. --*/
  1345. {
  1346. DEBUG_ENTER((DBG_INET,
  1347. Bool,
  1348. "_InternetCloseHandleNoContext",
  1349. "%#x",
  1350. hInternet
  1351. ));
  1352. DWORD error;
  1353. HINTERNET hInternetMapped = NULL;
  1354. //
  1355. // map the handle and invalidate it. This will cause any new requests with
  1356. // the handle as a parameter to fail
  1357. //
  1358. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, TRUE);
  1359. if (error != ERROR_SUCCESS) {
  1360. if (hInternetMapped != NULL) {
  1361. //
  1362. // the handle is already being closed, or is already deleted
  1363. //
  1364. DereferenceObject((LPVOID)hInternetMapped);
  1365. }
  1366. //
  1367. // since this is the only function that can invalidate a handle, if we
  1368. // are here then the handle is just waiting for its refcount to go to
  1369. // zero. We already removed the refcount we added above, so we're in
  1370. // the clear
  1371. //
  1372. goto quit;
  1373. }
  1374. //
  1375. // there may be an active socket operation. We close the socket to abort the
  1376. // operation
  1377. //
  1378. ((INTERNET_HANDLE_BASE *)hInternetMapped)->AbortSocket();
  1379. //
  1380. // at this point, there should *always* be at least 2 references on the
  1381. // handle - one added when the object was created, and one added by
  1382. // MapHandleToAddress() above. If the object is still alive after the 2
  1383. // dereferences, then it will be destroyed when the current owning thread
  1384. // dereferences it
  1385. //
  1386. (void)DereferenceObject((LPVOID)hInternetMapped);
  1387. error = DereferenceObject((LPVOID)hInternetMapped);
  1388. quit:
  1389. DEBUG_LEAVE(error);
  1390. return error;
  1391. }
  1392. INTERNETAPI
  1393. HINTERNET
  1394. WINAPI
  1395. InternetConnectA(
  1396. IN HINTERNET hInternet,
  1397. IN LPCSTR lpszServerName,
  1398. IN INTERNET_PORT nServerPort,
  1399. IN DWORD dwFlags,
  1400. IN DWORD_PTR dwContext
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Opens a connection with a server, logging-on the user in the process.
  1405. Arguments:
  1406. hInternet - Internet handle, returned by InternetOpen()
  1407. lpszServerName - name of server with which to connect
  1408. nServerPort - port at which server listens
  1409. dwFlags - protocol-specific flags. The following are defined:
  1410. - INTERNET_FLAG_KEEP_CONNECTION (HTTP)
  1411. - WINHTTP_FLAG_SECURE (HTTP)
  1412. dwContext - application-supplied value used to identify this
  1413. request in callbacks
  1414. - ignored in WinHttp
  1415. Return Value:
  1416. HINTERNET
  1417. Success - address of a new handle object
  1418. Failure - NULL. Call GetLastError() for more info
  1419. --*/
  1420. {
  1421. DEBUG_ENTER((DBG_API,
  1422. Handle,
  1423. "InternetConnectA",
  1424. "%#x, %q, %d, %#08x, %#x",
  1425. hInternet,
  1426. lpszServerName,
  1427. nServerPort,
  1428. dwFlags,
  1429. dwContext
  1430. ));
  1431. HINTERNET connectHandle = NULL;
  1432. HINTERNET hInternetMapped = NULL;
  1433. LPINTERNET_THREAD_INFO lpThreadInfo;
  1434. INTERNET_CONNECT_HANDLE_OBJECT * pConnect = NULL;
  1435. BOOL isAsync;
  1436. DWORD error = ERROR_SUCCESS;
  1437. UNREFERENCED_PARAMETER(dwContext);
  1438. if (!GlobalDataInitialized) {
  1439. error = ERROR_WINHTTP_NOT_INITIALIZED;
  1440. goto done;
  1441. }
  1442. //
  1443. // get the per-thread info block
  1444. //
  1445. lpThreadInfo = InternetGetThreadInfo();
  1446. if (lpThreadInfo == NULL) {
  1447. INET_ASSERT(FALSE);
  1448. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1449. goto done;
  1450. }
  1451. _InternetIncNestingCount();
  1452. error = MapHandleToAddress(hInternet, (LPVOID *)&hInternetMapped, FALSE);
  1453. if ((error != ERROR_SUCCESS) && (hInternetMapped == NULL)) {
  1454. goto quit;
  1455. }
  1456. //
  1457. // set the info and clear the last error info
  1458. //
  1459. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  1460. _InternetClearLastError(lpThreadInfo);
  1461. //
  1462. // quit now if the handle object is invalidated
  1463. //
  1464. if (error != ERROR_SUCCESS) {
  1465. goto quit;
  1466. }
  1467. //
  1468. // validate the handle & discover sync/async
  1469. //
  1470. error = RIsHandleLocal(hInternetMapped,
  1471. NULL,
  1472. &isAsync,
  1473. TypeInternetHandle
  1474. );
  1475. if (error != ERROR_SUCCESS) {
  1476. goto quit;
  1477. }
  1478. //
  1479. // we allow all valid flags to be passed in
  1480. //
  1481. if ((dwFlags & ~WINHTTP_CONNECT_FLAGS_MASK)
  1482. || (lpszServerName == NULL)
  1483. || (*lpszServerName == '\0'))
  1484. {
  1485. error = ERROR_INVALID_PARAMETER;
  1486. goto quit;
  1487. }
  1488. //
  1489. // app thread or in async worker thread but being called from another
  1490. // async API, such as InternetOpenUrl()
  1491. //
  1492. INET_ASSERT(connectHandle == NULL);
  1493. INET_ASSERT(error == ERROR_SUCCESS);
  1494. error = RMakeInternetConnectObjectHandle(
  1495. hInternetMapped,
  1496. &connectHandle,
  1497. (LPSTR) lpszServerName,
  1498. nServerPort,
  1499. dwFlags
  1500. );
  1501. if (error != ERROR_SUCCESS) {
  1502. goto quit;
  1503. }
  1504. //
  1505. // this new handle will be used in callbacks
  1506. //
  1507. _InternetSetObjectHandle(lpThreadInfo,
  1508. ((HANDLE_OBJECT *)connectHandle)->GetPseudoHandle(),
  1509. connectHandle
  1510. );
  1511. //
  1512. // based on whether we have been asked to perform async I/O AND we are not
  1513. // in an async worker thread context AND the request is to connect with an
  1514. // FTP service (currently only FTP because this request performs network
  1515. // I/O - gopher and HTTP just allocate & fill in memory) AND there is a
  1516. // valid context value, we will queue the async request, or execute the
  1517. // request synchronously
  1518. //
  1519. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)connectHandle;
  1520. INET_ASSERT(error == ERROR_SUCCESS);
  1521. quit:
  1522. _InternetDecNestingCount(1);
  1523. done:
  1524. if (error == ERROR_SUCCESS) {
  1525. //
  1526. // success - return generated pseudo-handle
  1527. //
  1528. BOOL fDeleted = ((HANDLE_OBJECT *)connectHandle)->Dereference(); // release the ref claimed by the InternetConnectA() API
  1529. if (fDeleted)
  1530. {
  1531. connectHandle = NULL;
  1532. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  1533. }
  1534. else
  1535. {
  1536. connectHandle = ((HANDLE_OBJECT *)connectHandle)->GetPseudoHandle();
  1537. }
  1538. }
  1539. if (hInternetMapped != NULL) {
  1540. DereferenceObject((LPVOID)hInternetMapped);
  1541. }
  1542. if (error != ERROR_SUCCESS) {
  1543. DEBUG_ERROR(API, error);
  1544. SetLastError(error);
  1545. }
  1546. DEBUG_LEAVE(connectHandle);
  1547. return connectHandle;
  1548. }
  1549. INTERNETAPI
  1550. HINTERNET
  1551. WINAPI
  1552. InternetOpenUrlA(
  1553. IN HINTERNET hInternet,
  1554. IN LPCSTR lpszUrl,
  1555. IN LPCSTR lpszHeaders OPTIONAL,
  1556. IN DWORD dwHeadersLength,
  1557. IN DWORD dwFlags,
  1558. IN DWORD_PTR dwContext
  1559. )
  1560. {
  1561. // this is dead code
  1562. UNREFERENCED_PARAMETER(hInternet);
  1563. UNREFERENCED_PARAMETER(lpszUrl);
  1564. UNREFERENCED_PARAMETER(lpszHeaders);
  1565. UNREFERENCED_PARAMETER(dwHeadersLength);
  1566. UNREFERENCED_PARAMETER(dwFlags);
  1567. UNREFERENCED_PARAMETER(dwContext);
  1568. return FALSE;
  1569. }
  1570. INTERNETAPI
  1571. BOOL
  1572. WINAPI
  1573. WinHttpReadData(
  1574. IN HINTERNET hFile,
  1575. IN LPVOID lpBuffer,
  1576. IN DWORD dwNumberOfBytesToRead,
  1577. OUT LPDWORD lpdwNumberOfBytesRead
  1578. )
  1579. /*++
  1580. Routine Description:
  1581. This functions reads the next block of data from the file object.
  1582. Arguments:
  1583. hFile - handle returned from Open function
  1584. lpBuffer - pointer to caller's buffer
  1585. dwNumberOfBytesToRead - size of lpBuffer in BYTEs
  1586. lpdwNumberOfBytesRead - returned number of bytes read into lpBuffer
  1587. Return Value:
  1588. BOOL
  1589. Success - TRUE
  1590. Failure - FALSE. Call GetLastError() for more info
  1591. --*/
  1592. {
  1593. DEBUG_ENTER_API((DBG_API,
  1594. Bool,
  1595. "WinHttpReadData",
  1596. "%#x, %#x, %d, %#x",
  1597. hFile,
  1598. lpBuffer,
  1599. dwNumberOfBytesToRead,
  1600. lpdwNumberOfBytesRead
  1601. ));
  1602. LPINTERNET_THREAD_INFO lpThreadInfo;
  1603. DWORD nestingLevel = 0;
  1604. DWORD error;
  1605. BOOL success = FALSE;
  1606. HINTERNET hFileMapped = NULL;
  1607. DWORD bytesRead = 0;
  1608. BOOL bEndRead = TRUE;
  1609. BOOL b2ndDeref = FALSE;
  1610. BOOL isAsync = FALSE;
  1611. if (!GlobalDataInitialized)
  1612. {
  1613. error = ERROR_WINHTTP_NOT_INITIALIZED;
  1614. goto done;
  1615. }
  1616. lpThreadInfo = InternetGetThreadInfo();
  1617. if (lpThreadInfo == NULL)
  1618. {
  1619. INET_ASSERT(FALSE);
  1620. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1621. goto done;
  1622. }
  1623. //INET_ASSERT(lpThreadInfo->Fsm == NULL);
  1624. _InternetIncNestingCount();
  1625. nestingLevel = 1;
  1626. error = MapHandleToAddress(hFile, (LPVOID *)&hFileMapped, FALSE);
  1627. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL))
  1628. {
  1629. goto quit;
  1630. }
  1631. // set the handle, and last-error info in the per-thread data block
  1632. // before we go any further. This allows us to return a status in the async
  1633. // case, even if the handle has been closed
  1634. if (!lpThreadInfo->IsAsyncWorkerThread)
  1635. {
  1636. PERF_LOG(PE_CLIENT_REQUEST_START,
  1637. AR_INTERNET_READ_FILE,
  1638. lpThreadInfo->ThreadId,
  1639. hFile
  1640. );
  1641. }
  1642. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  1643. _InternetClearLastError(lpThreadInfo);
  1644. // if MapHandleToAddress() returned a non-NULL object address, but also an
  1645. // error status, then the handle is being closed - quit
  1646. if (error != ERROR_SUCCESS)
  1647. {
  1648. goto quit;
  1649. }
  1650. error = RIsHandleLocal(hFileMapped, NULL, &isAsync, TypeHttpRequestHandle);
  1651. if (error != ERROR_SUCCESS)
  1652. {
  1653. goto quit;
  1654. }
  1655. // validate parameters
  1656. if (!lpThreadInfo->IsAsyncWorkerThread)
  1657. {
  1658. if (lpdwNumberOfBytesRead)
  1659. {
  1660. error = ProbeAndSetDword(lpdwNumberOfBytesRead, 0);
  1661. if (error != ERROR_SUCCESS)
  1662. {
  1663. goto quit;
  1664. }
  1665. }
  1666. error = ProbeWriteBuffer(lpBuffer, dwNumberOfBytesToRead);
  1667. if (error != ERROR_SUCCESS)
  1668. {
  1669. goto quit;
  1670. }
  1671. // *lpdwNumberOfBytesRead = 0;
  1672. } // end if (!lpThreadInfo->IsAsyncWorkerThread)
  1673. INET_ASSERT(error == ERROR_SUCCESS);
  1674. // just call the underlying API: return whatever it returns, and let it
  1675. // handle setting the last error
  1676. CFsm_ReadFile *pFsm;
  1677. pFsm = New CFsm_ReadFile(lpBuffer,
  1678. dwNumberOfBytesToRead,
  1679. /*lpdwNumberOfBytesRead*/ NULL
  1680. );
  1681. HTTP_REQUEST_HANDLE_OBJECT *pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hFileMapped;
  1682. if (pFsm != NULL)
  1683. {
  1684. if (isAsync)
  1685. {
  1686. pRequest->Reference();
  1687. b2ndDeref = TRUE;
  1688. }
  1689. error = StartFsmChain(pFsm, pRequest, FALSE, isAsync);
  1690. //if error == ERROR_IO_PENDING, DO NOT TOUCH this fsm or any pRequest contents.
  1691. //another async thread could be operating on this fsm.
  1692. }
  1693. else
  1694. {
  1695. error = ERROR_NOT_ENOUGH_MEMORY;
  1696. }
  1697. bEndRead = FALSE;
  1698. if (error == ERROR_SUCCESS)
  1699. {
  1700. bytesRead = pRequest->GetBytesRead();
  1701. success = TRUE;
  1702. goto sync_success;
  1703. }
  1704. else
  1705. {
  1706. success = FALSE;
  1707. }
  1708. quit:
  1709. _InternetDecNestingCount(nestingLevel);
  1710. if (bEndRead)
  1711. {
  1712. //
  1713. // if handleType is not HttpRequest or File then we are making this
  1714. // request in the context of an uninterruptable async worker thread.
  1715. // HTTP and file requests use the normal mechanism. In the case of non-
  1716. // HTTP and file requests, we need to treat the request as if it were
  1717. // sync and deref the handle
  1718. //
  1719. ReadFile_End(!lpThreadInfo->IsAsyncWorkerThread,
  1720. success,
  1721. hFileMapped,
  1722. bytesRead,
  1723. lpBuffer,
  1724. dwNumberOfBytesToRead,
  1725. lpdwNumberOfBytesRead
  1726. );
  1727. }
  1728. if (lpThreadInfo && !lpThreadInfo->IsAsyncWorkerThread)
  1729. {
  1730. PERF_LOG(PE_CLIENT_REQUEST_END,
  1731. AR_INTERNET_READ_FILE,
  1732. bytesRead,
  1733. lpThreadInfo->ThreadId,
  1734. hFile
  1735. );
  1736. }
  1737. done:
  1738. if (b2ndDeref)
  1739. {
  1740. // So that we have a refcount on the object going into the callback.
  1741. INET_ASSERT (isAsync);
  1742. DereferenceObject((LPVOID)hFileMapped);
  1743. }
  1744. // if error is not ERROR_SUCCESS then this function returning the error,
  1745. // otherwise the error has already been set by the API we called,
  1746. // irrespective of the value of success
  1747. if (error != ERROR_SUCCESS)
  1748. {
  1749. if (error == ERROR_IO_PENDING)
  1750. {
  1751. SetLastError(ERROR_SUCCESS);
  1752. success = TRUE;
  1753. }
  1754. else
  1755. {
  1756. DEBUG_ERROR(API, error);
  1757. SetLastError(error);
  1758. success = FALSE;
  1759. }
  1760. }
  1761. DEBUG_LEAVE_API(success);
  1762. return success;
  1763. sync_success:
  1764. if (isAsync)
  1765. {
  1766. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_READ_COMPLETE,
  1767. lpBuffer,
  1768. bytesRead
  1769. );
  1770. }
  1771. if (lpdwNumberOfBytesRead)
  1772. {
  1773. *lpdwNumberOfBytesRead = bytesRead;
  1774. }
  1775. goto quit;
  1776. }
  1777. PRIVATE
  1778. VOID
  1779. ReadFile_End(
  1780. IN BOOL bDeref,
  1781. IN BOOL bSuccess,
  1782. IN HINTERNET hFileMapped,
  1783. IN DWORD dwBytesRead,
  1784. IN LPVOID lpBuffer OPTIONAL,
  1785. IN DWORD dwNumberOfBytesToRead,
  1786. OUT LPDWORD lpdwNumberOfBytesRead OPTIONAL
  1787. )
  1788. /*++
  1789. Routine Description:
  1790. Common end-of-read processing:
  1791. - update bytes read parameter
  1792. - dump data if logging & API data requested
  1793. - dereference handle if not async request
  1794. Arguments:
  1795. bDeref - TRUE if handle should be dereferenced (should be
  1796. FALSE for async request)
  1797. bSuccess - TRUE if Read completed successfully
  1798. hFileMapped - mapped file handle
  1799. dwBytesRead - number of bytes read
  1800. lpBuffer - into this buffer
  1801. dwNumberOfBytesToRead - originally requested bytes to read
  1802. lpdwNumberOfBytesRead - where bytes read is stored
  1803. Return Value:
  1804. None.
  1805. --*/
  1806. {
  1807. UNREFERENCED_PARAMETER(lpBuffer);
  1808. DEBUG_ENTER((DBG_INET,
  1809. None,
  1810. "ReadFile_End",
  1811. "%B, %B, %#x, %d, %#x, %d, %#x",
  1812. bDeref,
  1813. bSuccess,
  1814. hFileMapped,
  1815. dwBytesRead,
  1816. lpBuffer,
  1817. dwNumberOfBytesToRead,
  1818. lpdwNumberOfBytesRead
  1819. ));
  1820. if (bSuccess) {
  1821. //
  1822. // update the amount of immediate data available only if we succeeded
  1823. //
  1824. ((INTERNET_HANDLE_BASE *)hFileMapped)->ReduceAvailableDataLength(dwBytesRead);
  1825. if (lpdwNumberOfBytesRead != NULL) {
  1826. *lpdwNumberOfBytesRead = dwBytesRead;
  1827. DEBUG_PRINT(API,
  1828. INFO,
  1829. ("*lpdwNumberOfBytesRead = %d\n",
  1830. *lpdwNumberOfBytesRead
  1831. ));
  1832. //
  1833. // dump API data only if requested
  1834. //
  1835. IF_DEBUG_CONTROL(DUMP_API_DATA) {
  1836. DEBUG_DUMP_API(API,
  1837. "Received data:\n",
  1838. lpBuffer,
  1839. *lpdwNumberOfBytesRead
  1840. );
  1841. }
  1842. /* Likely redundant:
  1843. TRACE_DUMP_API_IF_REQUEST(API,
  1844. "Received data:\n",
  1845. lpBuffer,
  1846. *lpdwNumberOfBytesRead,
  1847. (HANDLE_OBJECT *)(hFileMapped)
  1848. );
  1849. */
  1850. }
  1851. if (dwBytesRead < dwNumberOfBytesToRead) {
  1852. DEBUG_PRINT(API,
  1853. INFO,
  1854. ("(!) bytes read (%d) < bytes requested (%d)\n",
  1855. dwBytesRead,
  1856. dwNumberOfBytesToRead
  1857. ));
  1858. }
  1859. }
  1860. //
  1861. // if async request, handle will be deref'd after REQUEST_COMPLETE callback
  1862. // is delivered
  1863. //
  1864. if (bDeref && (hFileMapped != NULL)) {
  1865. DereferenceObject((LPVOID)hFileMapped);
  1866. }
  1867. PERF_LOG(PE_CLIENT_REQUEST_END,
  1868. AR_INTERNET_READ_FILE,
  1869. dwBytesRead,
  1870. 0,
  1871. (!bDeref && hFileMapped) ? ((INTERNET_HANDLE_BASE *)hFileMapped)->GetPseudoHandle() : NULL
  1872. );
  1873. DEBUG_LEAVE(0);
  1874. }
  1875. DWORD
  1876. CFsm_ReadFile::RunSM(
  1877. IN CFsm * Fsm
  1878. )
  1879. {
  1880. DEBUG_ENTER((DBG_HTTP,
  1881. Dword,
  1882. "CFsm_ReadFile::RunSM",
  1883. "%#x",
  1884. Fsm
  1885. ));
  1886. DWORD error;
  1887. CFsm_ReadFile * stateMachine = (CFsm_ReadFile *)Fsm;
  1888. switch (Fsm->GetState()) {
  1889. case FSM_STATE_INIT:
  1890. case FSM_STATE_CONTINUE:
  1891. error = ReadFile_Fsm(stateMachine);
  1892. break;
  1893. case FSM_STATE_ERROR:
  1894. error = Fsm->GetError();
  1895. INET_ASSERT (error == ERROR_WINHTTP_OPERATION_CANCELLED);
  1896. Fsm->SetDone();
  1897. break;
  1898. default:
  1899. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1900. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  1901. INET_ASSERT(FALSE);
  1902. break;
  1903. }
  1904. DEBUG_LEAVE(error);
  1905. return error;
  1906. }
  1907. PRIVATE
  1908. DWORD
  1909. ReadFile_Fsm(
  1910. IN CFsm_ReadFile * Fsm
  1911. )
  1912. {
  1913. DEBUG_ENTER((DBG_INET,
  1914. Dword,
  1915. "ReadFile_Fsm",
  1916. "%#x",
  1917. Fsm
  1918. ));
  1919. CFsm_ReadFile & fsm = *Fsm;
  1920. DWORD error = fsm.GetError();
  1921. if ((error == ERROR_SUCCESS) && (fsm.GetState() == FSM_STATE_INIT)) {
  1922. error = HttpReadData(fsm.GetMappedHandle(),
  1923. fsm.m_lpBuffer,
  1924. fsm.m_dwNumberOfBytesToRead,
  1925. &fsm.m_dwBytesRead,
  1926. 0
  1927. );
  1928. if (error == ERROR_IO_PENDING) {
  1929. goto quit;
  1930. }
  1931. // the operation has gone sync, let's store the Bytes read in the request handle, otherwise we will
  1932. // lose it as the fsm will be deleted before returning to the API call.
  1933. HTTP_REQUEST_HANDLE_OBJECT* pRequest =
  1934. (HTTP_REQUEST_HANDLE_OBJECT*) fsm.GetMappedHandle();
  1935. pRequest->SetBytesRead(fsm.m_dwBytesRead);
  1936. }
  1937. ReadFile_End(!fsm.GetThreadInfo()->IsAsyncWorkerThread,
  1938. (error == ERROR_SUCCESS) ? TRUE : FALSE,
  1939. fsm.GetMappedHandle(),
  1940. fsm.m_dwBytesRead,
  1941. fsm.m_lpBuffer,
  1942. fsm.m_dwNumberOfBytesToRead,
  1943. fsm.m_lpdwNumberOfBytesRead
  1944. );
  1945. fsm.SetDone();
  1946. quit:
  1947. DEBUG_LEAVE(error);
  1948. return error;
  1949. }
  1950. DWORD
  1951. CFsm_ReadFileEx::RunSM(
  1952. IN CFsm * Fsm
  1953. )
  1954. {
  1955. DEBUG_ENTER((DBG_HTTP,
  1956. Dword,
  1957. "CFsm_ReadFileEx::RunSM",
  1958. "%#x",
  1959. Fsm
  1960. ));
  1961. DWORD error;
  1962. CFsm_ReadFileEx * stateMachine = (CFsm_ReadFileEx *)Fsm;
  1963. switch (Fsm->GetState()) {
  1964. case FSM_STATE_INIT:
  1965. case FSM_STATE_CONTINUE:
  1966. error = ReadFileEx_Fsm(stateMachine);
  1967. break;
  1968. case FSM_STATE_ERROR:
  1969. error = Fsm->GetError();
  1970. INET_ASSERT (error == ERROR_WINHTTP_OPERATION_CANCELLED);
  1971. Fsm->SetDone();
  1972. break;
  1973. default:
  1974. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1975. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  1976. INET_ASSERT(FALSE);
  1977. break;
  1978. }
  1979. DEBUG_LEAVE(error);
  1980. return error;
  1981. }
  1982. PRIVATE
  1983. DWORD
  1984. ReadFileEx_Fsm(
  1985. IN CFsm_ReadFileEx * Fsm
  1986. )
  1987. {
  1988. DEBUG_ENTER((DBG_INET,
  1989. Dword,
  1990. "ReadFileEx_Fsm",
  1991. "%#x",
  1992. Fsm
  1993. ));
  1994. CFsm_ReadFileEx & fsm = *Fsm;
  1995. DWORD error = fsm.GetError();
  1996. if ((error == ERROR_SUCCESS) && (fsm.GetState() == FSM_STATE_INIT)) {
  1997. fsm.m_dwNumberOfBytesToRead = fsm.m_lpBuffersOut->dwBufferLength;
  1998. error = HttpReadData(fsm.GetMappedHandle(),
  1999. fsm.m_lpBuffersOut->lpvBuffer,
  2000. fsm.m_dwNumberOfBytesToRead,
  2001. &fsm.m_dwBytesRead,
  2002. (fsm.m_dwFlags & IRF_NO_WAIT)
  2003. ? SF_NO_WAIT
  2004. : 0
  2005. );
  2006. if (error == ERROR_IO_PENDING) {
  2007. goto quit;
  2008. }
  2009. }
  2010. //
  2011. // if we are asynchronously completing a no-wait read then we don't update
  2012. // any app parameters - we simply return the indication that we completed.
  2013. // The app will then make another no-wait read to get the data
  2014. //
  2015. BOOL bNoOutput;
  2016. bNoOutput = ((fsm.m_dwFlags & IRF_NO_WAIT)
  2017. && fsm.GetThreadInfo()->IsAsyncWorkerThread)
  2018. ? TRUE
  2019. : FALSE;
  2020. ReadFile_End(!fsm.GetThreadInfo()->IsAsyncWorkerThread,
  2021. (error == ERROR_SUCCESS) ? TRUE : FALSE,
  2022. fsm.GetMappedHandle(),
  2023. bNoOutput ? 0 : fsm.m_dwBytesRead,
  2024. bNoOutput ? NULL : fsm.m_lpBuffersOut->lpvBuffer,
  2025. bNoOutput ? 0 : fsm.m_dwNumberOfBytesToRead,
  2026. bNoOutput ? NULL : &fsm.m_lpBuffersOut->dwBufferLength
  2027. );
  2028. fsm.SetDone();
  2029. quit:
  2030. DEBUG_LEAVE(error);
  2031. return error;
  2032. }
  2033. INTERNETAPI
  2034. BOOL
  2035. WINAPI
  2036. WinHttpWriteData(
  2037. IN HINTERNET hFile,
  2038. IN LPCVOID lpBuffer,
  2039. IN DWORD dwNumberOfBytesToWrite,
  2040. OUT LPDWORD lpdwNumberOfBytesWritten
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. This function write next block of data to the internet file. Currently it
  2045. supports the following protocol data:
  2046. HttpWriteFile
  2047. Arguments:
  2048. hFile - handle that was obtained by OpenFile Call
  2049. lpBuffer - pointer to the data buffer
  2050. dwNumberOfBytesToWrite - number of bytes in the above buffer
  2051. lpdwNumberOfBytesWritten - pointer to a DWORD where the number of bytes
  2052. of data actually written is returned
  2053. Return Value:
  2054. BOOL
  2055. Success - TRUE
  2056. Failure - FALSE. Call GetLastError() for more info
  2057. --*/
  2058. {
  2059. DEBUG_ENTER_API((DBG_API,
  2060. Bool,
  2061. "WinHttpWriteData",
  2062. "%#x, %#x, %d, %#x",
  2063. hFile,
  2064. lpBuffer,
  2065. dwNumberOfBytesToWrite,
  2066. lpdwNumberOfBytesWritten
  2067. ));
  2068. LPINTERNET_THREAD_INFO lpThreadInfo;
  2069. DWORD nestingLevel = 0;
  2070. DWORD error;
  2071. BOOL success = FALSE;
  2072. BOOL fNeedDeref = TRUE;
  2073. HINTERNET hFileMapped = NULL;
  2074. if (!GlobalDataInitialized)
  2075. {
  2076. error = ERROR_WINHTTP_NOT_INITIALIZED;
  2077. goto done;
  2078. }
  2079. lpThreadInfo = InternetGetThreadInfo();
  2080. if (lpThreadInfo == NULL)
  2081. {
  2082. //informational INET_ASSERT(FALSE);
  2083. error = ERROR_WINHTTP_INTERNAL_ERROR;
  2084. goto done;
  2085. }
  2086. _InternetIncNestingCount();
  2087. nestingLevel = 1;
  2088. error = MapHandleToAddress(hFile, (LPVOID *)&hFileMapped, FALSE);
  2089. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL))
  2090. {
  2091. goto quit;
  2092. }
  2093. //
  2094. // set the handle, and last-error info in the per-thread data block
  2095. // before we go any further. This allows us to return a status in the async
  2096. // case, even if the handle has been closed
  2097. //
  2098. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  2099. _InternetClearLastError(lpThreadInfo);
  2100. //
  2101. // if MapHandleToAddress() returned a non-NULL object address, but also an
  2102. // error status, then the handle is being closed - quit
  2103. //
  2104. if (error != ERROR_SUCCESS)
  2105. {
  2106. goto quit;
  2107. }
  2108. // validate handle and its type
  2109. BOOL isAsync;
  2110. error = RIsHandleLocal(hFileMapped, NULL, &isAsync, TypeHttpRequestHandle);
  2111. if (error != ERROR_SUCCESS)
  2112. {
  2113. INET_ASSERT(FALSE);
  2114. goto quit;
  2115. }
  2116. //
  2117. // validate parameters - write length cannot be 0
  2118. //
  2119. if (!lpThreadInfo->IsAsyncWorkerThread)
  2120. {
  2121. if (dwNumberOfBytesToWrite != 0)
  2122. {
  2123. error = ProbeReadBuffer((LPVOID)lpBuffer, dwNumberOfBytesToWrite);
  2124. if (error == ERROR_SUCCESS)
  2125. {
  2126. if (lpdwNumberOfBytesWritten)
  2127. {
  2128. error = ProbeAndSetDword(lpdwNumberOfBytesWritten, 0);
  2129. }
  2130. }
  2131. }
  2132. else
  2133. {
  2134. error = ERROR_INVALID_PARAMETER;
  2135. }
  2136. if (error != ERROR_SUCCESS)
  2137. {
  2138. goto quit;
  2139. }
  2140. }
  2141. // # 62953
  2142. // If the authentication state of the handle is Negotiate,
  2143. // don't submit data to the server but return success.
  2144. // ** Added test for NTLM or Negotiate - Adriaanc.
  2145. //
  2146. HTTP_REQUEST_HANDLE_OBJECT *pRequest;
  2147. pRequest = (HTTP_REQUEST_HANDLE_OBJECT*) hFileMapped;
  2148. DWORD dwBytesWritten = 0;
  2149. if (pRequest->GetAuthState() == AUTHSTATE_NEGOTIATE
  2150. || pRequest->GetProxyTunnelingSuppressWrite())
  2151. {
  2152. dwBytesWritten = dwNumberOfBytesToWrite;
  2153. error = ERROR_SUCCESS;
  2154. success = TRUE;
  2155. goto sync_success;
  2156. }
  2157. INET_ASSERT(error == ERROR_SUCCESS);
  2158. CFsm_HttpWriteData *pFsm = New CFsm_HttpWriteData((LPVOID)lpBuffer,
  2159. dwNumberOfBytesToWrite,
  2160. NULL/*lpdwNumberOfBytesWritten*/,
  2161. 0,
  2162. pRequest
  2163. );
  2164. if (pFsm != NULL)
  2165. {
  2166. HTTP_REQUEST_HANDLE_OBJECT *pRequest2 = (HTTP_REQUEST_HANDLE_OBJECT *)hFileMapped;
  2167. error = StartFsmChain(pFsm, pRequest2, FALSE, isAsync);
  2168. //if error == ERROR_IO_PENDING, DO NOT TOUCH this fsm or any pRequest contents.
  2169. //another async thread could be operating on this fsm/request.
  2170. }
  2171. else
  2172. {
  2173. error = ERROR_NOT_ENOUGH_MEMORY;
  2174. }
  2175. //
  2176. // Don't Derefrence if we're going pending cause the FSM will do
  2177. // it for us.
  2178. //
  2179. if ( error == ERROR_IO_PENDING )
  2180. {
  2181. fNeedDeref = FALSE;
  2182. }
  2183. if (error == ERROR_SUCCESS)
  2184. {
  2185. dwBytesWritten = pRequest->GetBytesWritten();
  2186. success = TRUE;
  2187. goto sync_success;
  2188. }
  2189. else
  2190. {
  2191. success = FALSE;
  2192. }
  2193. quit:
  2194. if (hFileMapped != NULL && fNeedDeref)
  2195. {
  2196. DereferenceObject((LPVOID)hFileMapped);
  2197. }
  2198. _InternetDecNestingCount(nestingLevel);;
  2199. done:
  2200. if (error != ERROR_SUCCESS)
  2201. {
  2202. if (error == ERROR_IO_PENDING)
  2203. {
  2204. SetLastError(ERROR_SUCCESS);
  2205. success = TRUE;
  2206. }
  2207. else
  2208. {
  2209. DEBUG_ERROR(API, error);
  2210. SetLastError(error);
  2211. }
  2212. }
  2213. DEBUG_LEAVE_API(success);
  2214. return success;
  2215. sync_success:
  2216. if (isAsync)
  2217. {
  2218. DWORD dwResult = dwBytesWritten;
  2219. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE,
  2220. &dwResult,
  2221. sizeof (DWORD)
  2222. );
  2223. }
  2224. if (lpdwNumberOfBytesWritten)
  2225. {
  2226. *lpdwNumberOfBytesWritten = dwBytesWritten;
  2227. }
  2228. goto quit;
  2229. }
  2230. INTERNETAPI
  2231. BOOL
  2232. WINAPI
  2233. WinHttpQueryDataAvailable(
  2234. IN HINTERNET hFile,
  2235. OUT LPDWORD lpdwNumberOfBytesAvailable
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. Determines the amount of data currently available to be read on the handle
  2240. Arguments:
  2241. hFile - handle of internet object
  2242. lpdwNumberOfBytesAvailable - pointer to returned bytes available
  2243. Return Value:
  2244. BOOL
  2245. Success - TRUE
  2246. Failure - FALSE. Call GetLastError() for more info
  2247. --*/
  2248. {
  2249. DEBUG_ENTER_API((DBG_API,
  2250. Bool,
  2251. "WinHttpQueryDataAvailable",
  2252. "%#x, %#x, %#x",
  2253. hFile,
  2254. lpdwNumberOfBytesAvailable
  2255. ));
  2256. BOOL success;
  2257. DWORD error;
  2258. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  2259. HINTERNET hFileMapped = NULL;
  2260. BOOL bDeref = TRUE;
  2261. DWORD dwNumBytes = (DWORD)-1;
  2262. if (!GlobalDataInitialized)
  2263. {
  2264. error = ERROR_WINHTTP_NOT_INITIALIZED;
  2265. bDeref = FALSE;
  2266. goto quit;
  2267. }
  2268. //
  2269. // get the per-thread info block
  2270. //
  2271. lpThreadInfo = InternetGetThreadInfo();
  2272. if (lpThreadInfo == NULL)
  2273. {
  2274. //informational INET_ASSERT(FALSE);
  2275. error = ERROR_WINHTTP_INTERNAL_ERROR;
  2276. goto quit;
  2277. }
  2278. //INET_ASSERT(lpThreadInfo->Fsm == NULL);
  2279. PERF_LOG(PE_CLIENT_REQUEST_START,
  2280. AR_INTERNET_QUERY_DATA_AVAILABLE,
  2281. lpThreadInfo->ThreadId,
  2282. hFile
  2283. );
  2284. //
  2285. // validate parameters
  2286. //
  2287. error = MapHandleToAddress(hFile, &hFileMapped, FALSE);
  2288. if ((error != ERROR_SUCCESS) && (hFileMapped == NULL))
  2289. {
  2290. goto quit;
  2291. }
  2292. INET_ASSERT(hFileMapped);
  2293. //
  2294. // set the handle values in the per-thread info block (this API
  2295. // can't return extended error info, so we don't care about it)
  2296. //
  2297. _InternetSetObjectHandle(lpThreadInfo, hFile, hFileMapped);
  2298. //
  2299. // if the handle is invalid, quit now
  2300. //
  2301. if (error != ERROR_SUCCESS)
  2302. {
  2303. goto quit;
  2304. }
  2305. //
  2306. // validate rest of parameters
  2307. //
  2308. if (lpdwNumberOfBytesAvailable)
  2309. {
  2310. error = ProbeAndSetDword(lpdwNumberOfBytesAvailable, 0);
  2311. if (error != ERROR_SUCCESS)
  2312. {
  2313. goto quit;
  2314. }
  2315. }
  2316. BOOL isAsync;
  2317. error = RIsHandleLocal(hFileMapped, NULL, &isAsync, TypeHttpRequestHandle);
  2318. if (error != ERROR_SUCCESS)
  2319. {
  2320. goto quit;
  2321. }
  2322. //
  2323. // since the async worker thread doesn't come back through this API, the
  2324. // following test is sufficient. Note that we only go async if there is
  2325. // no data currently available on the handle
  2326. //
  2327. BOOL dataAvailable;
  2328. dataAvailable = ((INTERNET_HANDLE_BASE *)hFileMapped)->IsDataAvailable();
  2329. BOOL eof;
  2330. eof = ((INTERNET_HANDLE_BASE *)hFileMapped)->IsEndOfFile();
  2331. DWORD available;
  2332. if (dataAvailable || eof)
  2333. {
  2334. available = ((INTERNET_HANDLE_BASE *)hFileMapped)->AvailableDataLength();
  2335. DEBUG_PRINT(API,
  2336. INFO,
  2337. ("%d bytes are immediately available\n",
  2338. available
  2339. ));
  2340. // *lpdwNumberOfBytesAvailable = available;
  2341. success = TRUE;
  2342. goto sync_success;
  2343. }
  2344. INET_ASSERT(hFileMapped);
  2345. //
  2346. // sync path. wInternetQueryDataAvailable will set the last error code
  2347. // if it fails
  2348. //
  2349. CFsm_QueryAvailable *pFsm;
  2350. pFsm = New CFsm_QueryAvailable(NULL/*lpdwNumberOfBytesAvailable*/,
  2351. 0,
  2352. NULL
  2353. );
  2354. HTTP_REQUEST_HANDLE_OBJECT *pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hFileMapped;
  2355. if (pFsm != NULL)
  2356. {
  2357. error = StartFsmChain(pFsm, pRequest, FALSE, isAsync);
  2358. }
  2359. else
  2360. {
  2361. error = ERROR_NOT_ENOUGH_MEMORY;
  2362. }
  2363. if (error == ERROR_SUCCESS)
  2364. {
  2365. available = pRequest->AvailableDataLength();
  2366. success = TRUE;
  2367. goto sync_success;
  2368. }
  2369. else
  2370. {
  2371. if (error == ERROR_IO_PENDING)
  2372. {
  2373. bDeref = FALSE;
  2374. }
  2375. goto quit;
  2376. }
  2377. finish:
  2378. DEBUG_PRINT_API(API,
  2379. INFO,
  2380. ("*lpdwNumberOfBytesAvailable (%#x) = %d\n",
  2381. lpdwNumberOfBytesAvailable,
  2382. dwNumBytes
  2383. ));
  2384. if (bDeref && (hFileMapped != NULL))
  2385. {
  2386. DereferenceObject((LPVOID)hFileMapped);
  2387. }
  2388. if (lpThreadInfo)
  2389. {
  2390. PERF_LOG(PE_CLIENT_REQUEST_END,
  2391. AR_INTERNET_QUERY_DATA_AVAILABLE,
  2392. dwNumBytes,
  2393. lpThreadInfo->ThreadId,
  2394. hFile
  2395. );
  2396. }
  2397. if (error == ERROR_IO_PENDING)
  2398. {
  2399. SetLastError(ERROR_SUCCESS);
  2400. success = TRUE;
  2401. }
  2402. DEBUG_LEAVE_API(success);
  2403. return success;
  2404. quit:
  2405. if (error != ERROR_IO_PENDING)
  2406. {
  2407. DEBUG_ERROR(API, error);
  2408. }
  2409. SetLastError(error);
  2410. success = FALSE;
  2411. goto finish;
  2412. sync_success:
  2413. dwNumBytes = available;
  2414. if (isAsync)
  2415. {
  2416. DWORD dwResult = available;
  2417. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE,
  2418. &dwResult,
  2419. sizeof (DWORD)
  2420. );
  2421. }
  2422. if (lpdwNumberOfBytesAvailable)
  2423. {
  2424. *lpdwNumberOfBytesAvailable = available;
  2425. }
  2426. goto finish;
  2427. }
  2428. DWORD
  2429. CFsm_QueryAvailable::RunSM(
  2430. IN CFsm * Fsm
  2431. )
  2432. {
  2433. DEBUG_ENTER((DBG_HTTP,
  2434. Dword,
  2435. "CFsm_QueryAvailable::RunSM",
  2436. "%#x",
  2437. Fsm
  2438. ));
  2439. DWORD error;
  2440. CFsm_QueryAvailable * stateMachine = (CFsm_QueryAvailable *)Fsm;
  2441. switch (Fsm->GetState()) {
  2442. case FSM_STATE_INIT:
  2443. case FSM_STATE_CONTINUE:
  2444. error = QueryAvailable_Fsm(stateMachine);
  2445. break;
  2446. case FSM_STATE_ERROR:
  2447. error = Fsm->GetError();
  2448. INET_ASSERT (error == ERROR_WINHTTP_OPERATION_CANCELLED);
  2449. Fsm->SetDone();
  2450. break;
  2451. default:
  2452. error = ERROR_WINHTTP_INTERNAL_ERROR;
  2453. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  2454. INET_ASSERT(FALSE);
  2455. break;
  2456. }
  2457. DEBUG_LEAVE(error);
  2458. return error;
  2459. }
  2460. PRIVATE
  2461. DWORD
  2462. QueryAvailable_Fsm(
  2463. IN CFsm_QueryAvailable * Fsm
  2464. )
  2465. {
  2466. DEBUG_ENTER((DBG_INET,
  2467. Dword,
  2468. "QueryAvailable_Fsm",
  2469. "%#x",
  2470. Fsm
  2471. ));
  2472. CFsm_QueryAvailable & fsm = *Fsm;
  2473. DWORD error = fsm.GetError();
  2474. if (error != ERROR_SUCCESS) {
  2475. goto quit;
  2476. }
  2477. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  2478. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)fsm.GetMappedHandle();
  2479. if (fsm.GetState() == FSM_STATE_INIT) {
  2480. error = pRequest->QueryDataAvailable(fsm.m_lpdwNumberOfBytesAvailable);
  2481. }
  2482. if (error == ERROR_SUCCESS) {
  2483. pRequest->SetAvailableDataLength(*fsm.m_lpdwNumberOfBytesAvailable);
  2484. DEBUG_PRINT(INET,
  2485. INFO,
  2486. ("%d bytes available\n",
  2487. *fsm.m_lpdwNumberOfBytesAvailable
  2488. ));
  2489. fsm.SetApiData(*fsm.m_lpdwNumberOfBytesAvailable);
  2490. }
  2491. quit:
  2492. if (error != ERROR_IO_PENDING) {
  2493. fsm.SetDone();
  2494. }
  2495. DEBUG_LEAVE(error);
  2496. return error;
  2497. }
  2498. INTERNETAPI
  2499. BOOL
  2500. WINAPI
  2501. InternetGetLastResponseInfoA(
  2502. OUT LPDWORD lpdwErrorCategory,
  2503. IN LPSTR lpszBuffer OPTIONAL,
  2504. IN OUT LPDWORD lpdwBufferLength
  2505. )
  2506. /*++
  2507. Routine Description:
  2508. This function returns the per-thread last internet error description text
  2509. or server response.
  2510. If this function is successful, *lpdwBufferLength contains the string length
  2511. of lpszBuffer.
  2512. If this function returns a failure indication, *lpdwBufferLength contains
  2513. the number of BYTEs required to hold the response text
  2514. Arguments:
  2515. lpdwErrorCategory - pointer to DWORD location where the error catagory is
  2516. returned
  2517. lpszBuffer - pointer to buffer where the error text is returned
  2518. lpdwBufferLength - IN: length of lpszBuffer
  2519. OUT: number of characters in lpszBuffer if successful
  2520. else size of buffer required to hold response text
  2521. Return Value:
  2522. BOOL
  2523. Success - TRUE
  2524. lpszBuffer contains the error text. The caller must check
  2525. *lpdwBufferLength: if 0 then there was no text to return
  2526. Failure - FALSE
  2527. Call GetLastError() for more information
  2528. --*/
  2529. {
  2530. DEBUG_ENTER((DBG_API,
  2531. Bool,
  2532. "InternetGetLastResponseInfoA",
  2533. "%#x, %#x, %#x [%d]",
  2534. lpdwErrorCategory,
  2535. lpszBuffer,
  2536. lpdwBufferLength,
  2537. lpdwBufferLength ? *lpdwBufferLength : 0
  2538. ));
  2539. DWORD error;
  2540. BOOL success;
  2541. DWORD textLength;
  2542. LPINTERNET_THREAD_INFO lpThreadInfo;
  2543. //
  2544. // validate parameters
  2545. //
  2546. if (IsBadWritePtr(lpdwErrorCategory, sizeof(*lpdwErrorCategory))
  2547. || IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
  2548. || (ARGUMENT_PRESENT(lpszBuffer)
  2549. ? IsBadWritePtr(lpszBuffer, *lpdwBufferLength)
  2550. : FALSE)) {
  2551. error = ERROR_INVALID_PARAMETER;
  2552. goto quit;
  2553. }
  2554. //
  2555. // if the buffer pointer is NULL then its the same as a zero-length buffer
  2556. //
  2557. if (!ARGUMENT_PRESENT(lpszBuffer)) {
  2558. *lpdwBufferLength = 0;
  2559. } else if (*lpdwBufferLength != 0) {
  2560. *lpszBuffer = '\0';
  2561. }
  2562. lpThreadInfo = InternetGetThreadInfo();
  2563. if (lpThreadInfo == NULL) {
  2564. DEBUG_PRINT(INET,
  2565. ERROR,
  2566. ("failed to get INTERNET_THREAD_INFO\n"
  2567. ));
  2568. //informational INET_ASSERT(FALSE);
  2569. error = ERROR_WINHTTP_INTERNAL_ERROR;
  2570. goto quit;
  2571. }
  2572. //
  2573. // there may not be any error text for this thread - either no server
  2574. // error/response has been received, or the error text has been cleared by
  2575. // an intervening API
  2576. //
  2577. if (lpThreadInfo->hErrorText != NULL) {
  2578. //
  2579. // copy as much as we can fit in the user supplied buffer
  2580. //
  2581. textLength = lpThreadInfo->ErrorTextLength;
  2582. if (*lpdwBufferLength && lpszBuffer != NULL) {
  2583. LPBYTE errorText;
  2584. errorText = (LPBYTE)LOCK_MEMORY(lpThreadInfo->hErrorText);
  2585. if (errorText != NULL) {
  2586. textLength = min(textLength, *lpdwBufferLength) - 1;
  2587. memcpy(lpszBuffer, errorText, textLength);
  2588. //
  2589. // the error text should always be zero terminated, so the
  2590. // calling app can treat it as a string
  2591. //
  2592. lpszBuffer[textLength] = '\0';
  2593. UNLOCK_MEMORY(lpThreadInfo->hErrorText);
  2594. if (textLength == lpThreadInfo->ErrorTextLength - 1) {
  2595. error = ERROR_SUCCESS;
  2596. } else {
  2597. //
  2598. // returned length is amount of buffer required
  2599. //
  2600. textLength = lpThreadInfo->ErrorTextLength;
  2601. error = ERROR_INSUFFICIENT_BUFFER;
  2602. }
  2603. } else {
  2604. DEBUG_PRINT(INET,
  2605. ERROR,
  2606. ("failed to lock hErrorText (%#x): %d\n",
  2607. lpThreadInfo->hErrorText,
  2608. GetLastError()
  2609. ));
  2610. error = ERROR_WINHTTP_INTERNAL_ERROR;
  2611. }
  2612. } else {
  2613. //
  2614. // user's buffer is not large enough to hold the info. We'll
  2615. // let them know the required length
  2616. //
  2617. error = ERROR_INSUFFICIENT_BUFFER;
  2618. }
  2619. } else {
  2620. INET_ASSERT(lpThreadInfo->ErrorTextLength == 0);
  2621. textLength = 0;
  2622. error = ERROR_SUCCESS;
  2623. }
  2624. *lpdwErrorCategory = lpThreadInfo->ErrorNumber;
  2625. *lpdwBufferLength = textLength;
  2626. IF_DEBUG(ANY) {
  2627. if ((error == ERROR_SUCCESS)
  2628. || ((textLength != 0) && (lpszBuffer != NULL))) {
  2629. DEBUG_DUMP_API(API,
  2630. "Last Response Info:\n",
  2631. lpszBuffer,
  2632. textLength
  2633. );
  2634. }
  2635. }
  2636. if ((error == ERROR_SUCCESS)
  2637. || ((textLength != 0) && (lpszBuffer != NULL))) {
  2638. TRACE_DUMP_API_IF_REQUEST(API,
  2639. "Last Response Info:\n",
  2640. lpszBuffer,
  2641. textLength,
  2642. (HANDLE_OBJECT *) (lpThreadInfo->hObjectMapped)
  2643. );
  2644. }
  2645. quit:
  2646. success = (error == ERROR_SUCCESS);
  2647. if (!success) {
  2648. DEBUG_ERROR(API, error);
  2649. SetLastError(error);
  2650. }
  2651. DEBUG_LEAVE(success);
  2652. return success;
  2653. }
  2654. BOOL
  2655. internalWinHttpGetDefaultProxyConfigurationA( IN OUT WINHTTP_PROXY_INFOA * pProxyInfo)
  2656. /*++
  2657. Routine Description:
  2658. Reads the settings for WinHTTP's default proxy mode.
  2659. Arguments:
  2660. pProxyInfo - Pointer to structure to receive proxy settings
  2661. Return Value:
  2662. BOOL
  2663. Success - TRUE
  2664. Failure - FALSE. Call GetLastError() for more info
  2665. --*/
  2666. {
  2667. DWORD dwError;
  2668. INTERNET_PROXY_INFO_EX proxyInfoEx;
  2669. memset( &proxyInfoEx, 0, sizeof( proxyInfoEx));
  2670. proxyInfoEx.dwStructSize = sizeof( proxyInfoEx);
  2671. dwError = ReadProxySettings( &proxyInfoEx);
  2672. if( dwError == ERROR_SUCCESS)
  2673. {
  2674. // reset access type result to one of two known..
  2675. pProxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  2676. if( proxyInfoEx.dwFlags == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
  2677. pProxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  2678. pProxyInfo->lpszProxy = (LPSTR)proxyInfoEx.lpszProxy; // allocated by GlobalAlloc()
  2679. pProxyInfo->lpszProxyBypass = (LPSTR)proxyInfoEx.lpszProxyBypass; // allocated by GlobalAlloc()
  2680. }
  2681. if( dwError != ERROR_SUCCESS)
  2682. SetLastError( dwError);
  2683. return dwError == ERROR_SUCCESS ? TRUE : FALSE;
  2684. }
  2685. BOOL
  2686. internalWinHttpSetDefaultProxyConfigurationA( IN WINHTTP_PROXY_INFOA * pProxyInfo)
  2687. /*++
  2688. Routine Description:
  2689. Writes settings for WinHTTP's default proxy mode.
  2690. Arguments:
  2691. pProxyInfo - Pointer to structure describing proxy settings
  2692. Return Value:
  2693. BOOL
  2694. Success - TRUE
  2695. Failure - FALSE. Call GetLastError() for more info
  2696. --*/
  2697. {
  2698. BOOL blReturnValue = FALSE;
  2699. //
  2700. // Parameter validation
  2701. //
  2702. // If AccessType is NO_PROXY, make sure no proxy information is given.
  2703. if( pProxyInfo->dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
  2704. {
  2705. if( pProxyInfo->lpszProxy != NULL
  2706. || pProxyInfo->lpszProxyBypass != NULL)
  2707. {
  2708. SetLastError( ERROR_INVALID_PARAMETER);
  2709. goto done;
  2710. }
  2711. }
  2712. // If AccessType is NAMED_PROXY, make sure a proxy is given. ProxyBypass list is optional.
  2713. else if( pProxyInfo->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
  2714. {
  2715. if( pProxyInfo->lpszProxy == NULL)
  2716. {
  2717. SetLastError( ERROR_INVALID_PARAMETER);
  2718. goto done;
  2719. }
  2720. }
  2721. else
  2722. {
  2723. // AccessType is not NAMED_PROXY or NO_PROXY
  2724. SetLastError( ERROR_INVALID_PARAMETER);
  2725. goto done;
  2726. }
  2727. // verify validity of proxy server list
  2728. if( pProxyInfo->lpszProxy != NULL)
  2729. {
  2730. // verify validity of proxy server list
  2731. PROXY_SERVER_LIST proxyServerList( pProxyInfo->lpszProxy);
  2732. if( ERROR_SUCCESS != proxyServerList.GetError())
  2733. {
  2734. SetLastError( ERROR_INVALID_PARAMETER);
  2735. goto done;
  2736. }
  2737. }
  2738. // verify validity of proxy server bypass list
  2739. if( pProxyInfo->lpszProxyBypass != NULL)
  2740. {
  2741. PROXY_BYPASS_LIST proxyBypassList( pProxyInfo->lpszProxyBypass);
  2742. if( ERROR_SUCCESS != proxyBypassList.GetError())
  2743. {
  2744. SetLastError( ERROR_INVALID_PARAMETER);
  2745. goto done;
  2746. }
  2747. }
  2748. INTERNET_PROXY_INFO_EX proxyInfoEx;
  2749. memset( &proxyInfoEx, 0, sizeof( proxyInfoEx));
  2750. proxyInfoEx.dwStructSize = sizeof( proxyInfoEx);
  2751. proxyInfoEx.dwFlags = pProxyInfo->dwAccessType;
  2752. proxyInfoEx.lpszProxy = pProxyInfo->lpszProxy;
  2753. proxyInfoEx.lpszProxyBypass = pProxyInfo->lpszProxyBypass;
  2754. DWORD dwError;
  2755. dwError = WriteProxySettings( &proxyInfoEx);
  2756. if( ERROR_SUCCESS != dwError)
  2757. {
  2758. SetLastError( dwError);
  2759. goto done;
  2760. }
  2761. blReturnValue = TRUE;
  2762. done:
  2763. return blReturnValue;
  2764. }