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.

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