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.

1545 lines
40 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. thrdinfo.cxx
  5. Abstract:
  6. Functions to manipulate an INTERNET_THREAD_INFO
  7. Contents:
  8. InternetCreateThreadInfo
  9. InternetDestroyThreadInfo
  10. InternetTerminateThreadInfo
  11. InternetGetThreadInfo
  12. InternetSetThreadInfo
  13. InternetIndicateStatusAddress
  14. InternetIndicateStatusString
  15. InternetIndicateStatusNewHandle
  16. InternetIndicateStatus
  17. InternetSetLastError
  18. _InternetSetLastError
  19. InternetLockErrorText
  20. InternetUnlockErrorText
  21. InternetSetObjectHandle
  22. InternetGetObjectHandle
  23. InternetFreeThreadInfo
  24. Author:
  25. Richard L Firth (rfirth) 16-Feb-1995
  26. Environment:
  27. Win32 user-level DLL
  28. Revision History:
  29. 16-Feb-1995 rfirth
  30. Created
  31. --*/
  32. #include <wininetp.h>
  33. #include <perfdiag.hxx>
  34. //
  35. // manifests
  36. //
  37. #define BAD_TLS_INDEX 0xffffffff // according to online win32 SDK documentation
  38. #ifdef SPX_SUPPORT
  39. #define GENERIC_SPX_NAME "SPX Server"
  40. #endif //SPX_SUPPORT
  41. //
  42. // macros
  43. //
  44. #ifdef ENABLE_DEBUG
  45. #define InitializeInternetThreadInfo(lpThreadInfo) \
  46. InitializeListHead(&lpThreadInfo->List); \
  47. lpThreadInfo->Signature = INTERNET_THREAD_INFO_SIGNATURE; \
  48. lpThreadInfo->ThreadId = GetCurrentThreadId();
  49. #else
  50. #define InitializeInternetThreadInfo(threadInfo) \
  51. InitializeListHead(&lpThreadInfo->List); \
  52. lpThreadInfo->ThreadId = GetCurrentThreadId();
  53. #endif // ENABLE_DEBUG
  54. //
  55. // private data
  56. //
  57. PRIVATE DWORD InternetTlsIndex = BAD_TLS_INDEX;
  58. PRIVATE SERIALIZED_LIST ThreadInfoList;
  59. LPINTERNET_THREAD_INFO
  60. InternetCreateThreadInfo(
  61. IN BOOL SetTls
  62. )
  63. /*++
  64. Routine Description:
  65. Creates, initializes an INTERNET_THREAD_INFO. Optionally (allocates and)
  66. sets this thread's Internet TLS
  67. Assumes: 1. The first time this function is called is in the context of the
  68. process attach library call, so we allocate the TLS index once
  69. Arguments:
  70. SetTls - TRUE if we are to set the INTERNET_THREAD_INFO TLS for this thread
  71. Return Value:
  72. LPINTERNET_THREAD_INFO
  73. Success - pointer to allocated INTERNET_THREAD_INFO structure which has
  74. been set as this threads value in its InternetTlsIndex slot
  75. Failure - NULL
  76. --*/
  77. {
  78. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  79. BOOL ok = FALSE;
  80. if (InDllCleanup) {
  81. goto quit;
  82. }
  83. if (InternetTlsIndex == BAD_TLS_INDEX) {
  84. //
  85. // first time through, initialize serialized list
  86. //
  87. InitializeSerializedList(&ThreadInfoList);
  88. //
  89. // we assume that if we are allocating the TLS index, then this is the
  90. // one and only thread in this process that can call into this DLL
  91. // right now - i.e. this thread is loading the DLL
  92. //
  93. InternetTlsIndex = TlsAlloc();
  94. }
  95. if (InternetTlsIndex != BAD_TLS_INDEX) {
  96. lpThreadInfo = NEW(INTERNET_THREAD_INFO);
  97. if (lpThreadInfo != NULL) {
  98. InitializeInternetThreadInfo(lpThreadInfo);
  99. if (SetTls) {
  100. ok = TlsSetValue(InternetTlsIndex, (LPVOID)lpThreadInfo);
  101. if (!ok) {
  102. DEBUG_PUT(("InternetCreateThreadInfo(): TlsSetValue(%d, %#x) returns %d\n",
  103. InternetTlsIndex,
  104. lpThreadInfo,
  105. GetLastError()
  106. ));
  107. DEBUG_BREAK(THRDINFO);
  108. }
  109. } else {
  110. ok = TRUE;
  111. }
  112. } else {
  113. DEBUG_PUT(("InternetCreateThreadInfo(): NEW(INTERNET_THREAD_INFO) returned NULL\n"));
  114. DEBUG_BREAK(THRDINFO);
  115. }
  116. } else {
  117. DEBUG_PUT(("InternetCreateThreadInfo(): TlsAlloc() returns %#x, error %d\n",
  118. BAD_TLS_INDEX,
  119. GetLastError()
  120. ));
  121. DEBUG_BREAK(THRDINFO);
  122. }
  123. if (ok) {
  124. if (!InsertAtHeadOfSerializedList(&ThreadInfoList, &lpThreadInfo->List)) {
  125. DEL(lpThreadInfo);
  126. lpThreadInfo = NULL;
  127. if (InternetTlsIndex != BAD_TLS_INDEX) {
  128. TlsFree(InternetTlsIndex);
  129. InternetTlsIndex = BAD_TLS_INDEX;
  130. }
  131. }
  132. } else {
  133. if (lpThreadInfo != NULL) {
  134. DEL(lpThreadInfo);
  135. lpThreadInfo = NULL;
  136. }
  137. if (InternetTlsIndex != BAD_TLS_INDEX) {
  138. TlsFree(InternetTlsIndex);
  139. InternetTlsIndex = BAD_TLS_INDEX;
  140. }
  141. }
  142. quit:
  143. return lpThreadInfo;
  144. }
  145. VOID
  146. InternetDestroyThreadInfo(
  147. VOID
  148. )
  149. /*++
  150. Routine Description:
  151. Cleans up the INTERNET_THREAD_INFO - deletes any memory it owns and deletes
  152. it
  153. Arguments:
  154. None.
  155. Return Value:
  156. None.
  157. --*/
  158. {
  159. LPINTERNET_THREAD_INFO lpThreadInfo;
  160. IF_DEBUG(NOTHING) {
  161. DEBUG_PUT(("InternetDestroyThreadInfo(): Thread %#x: Deleting INTERNET_THREAD_INFO\n",
  162. GetCurrentThreadId()
  163. ));
  164. }
  165. //
  166. // don't call InternetGetThreadInfo() - we don't need to create the
  167. // INTERNET_THREAD_INFO if it doesn't exist in this case
  168. //
  169. lpThreadInfo = (LPINTERNET_THREAD_INFO)TlsGetValue(InternetTlsIndex);
  170. if (lpThreadInfo != NULL) {
  171. #if INET_DEBUG
  172. //
  173. // there shouldn't be anything in the debug record stack. On Win95, we
  174. // ignore this check if this is the async scheduler (nee worker) thread
  175. // AND there are entries in the debug record stack. The async thread
  176. // gets killed off before it has chance to DEBUG_LEAVE, then comes here,
  177. // causing this assert to be over-active
  178. //
  179. if (IsPlatformWin95() && lpThreadInfo->IsAsyncWorkerThread) {
  180. if (lpThreadInfo->CallDepth != 0) {
  181. DEBUG_PUT(("InternetDestroyThreadInfo(): "
  182. "Thread %#x: "
  183. "%d records in debug stack\n",
  184. lpThreadInfo->CallDepth
  185. ));
  186. }
  187. } else {
  188. INET_ASSERT(lpThreadInfo->Stack == NULL);
  189. }
  190. #endif // INET_DEBUG
  191. InternetFreeThreadInfo(lpThreadInfo);
  192. INET_ASSERT(InternetTlsIndex != BAD_TLS_INDEX);
  193. TlsSetValue(InternetTlsIndex, NULL);
  194. } else {
  195. DEBUG_PUT(("InternetDestroyThreadInfo(): Thread %#x: no INTERNET_THREAD_INFO\n",
  196. GetCurrentThreadId()
  197. ));
  198. }
  199. }
  200. VOID
  201. InternetFreeThreadInfo(
  202. IN LPINTERNET_THREAD_INFO lpThreadInfo
  203. )
  204. /*++
  205. Routine Description:
  206. Removes the INTERNET_THREAD_INFO from the list and frees all allocated
  207. blocks
  208. Arguments:
  209. lpThreadInfo - pointer to INTERNET_THREAD_INFO to remove and free
  210. Return Value:
  211. None.
  212. --*/
  213. {
  214. if (RemoveFromSerializedList(&ThreadInfoList, &lpThreadInfo->List)) {
  215. if (lpThreadInfo->hErrorText != NULL) {
  216. FREE_MEMORY(lpThreadInfo->hErrorText);
  217. }
  218. //if (lpThreadInfo->lpResolverInfo != NULL) {
  219. // if (lpThreadInfo->lpResolverInfo->DnrSocketHandle != NULL) {
  220. // lpThreadInfo->lpResolverInfo->DnrSocketHandle->Dereference();
  221. // }
  222. // DEL(lpThreadInfo->lpResolverInfo);
  223. //}
  224. DEL(lpThreadInfo);
  225. }
  226. }
  227. VOID
  228. InternetTerminateThreadInfo(
  229. VOID
  230. )
  231. /*++
  232. Routine Description:
  233. Destroy all INTERNET_THREAD_INFO structures and terminate the serialized
  234. list. This funciton called at process detach time.
  235. At DLL_PROCESS_DETACH time, there may be other threads in the process for
  236. which we created an INTERNET_THREAD_INFO that aren't going to get the chance
  237. to delete the structure, so we do it here.
  238. Code in this module assumes that it is impossible for a new thread to enter
  239. this DLL while we are terminating in DLL_PROCESS_DETACH
  240. Arguments:
  241. None.
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. //
  247. // get rid of this thread's info structure. No more debug output after this!
  248. //
  249. InternetDestroyThreadInfo();
  250. //
  251. // get rid of the thread info structures left by other threads
  252. //
  253. if (LockSerializedList(&ThreadInfoList))
  254. {
  255. LPINTERNET_THREAD_INFO lpThreadInfo;
  256. while (lpThreadInfo = (LPINTERNET_THREAD_INFO)SlDequeueHead(&ThreadInfoList)) {
  257. //
  258. // already dequeued, no need to call InternetFreeThreadInfo()
  259. //
  260. FREE_MEMORY(lpThreadInfo);
  261. }
  262. UnlockSerializedList(&ThreadInfoList);
  263. }
  264. //
  265. // no more need for list
  266. //
  267. TerminateSerializedList(&ThreadInfoList);
  268. //
  269. // or TLS index
  270. //
  271. TlsFree(InternetTlsIndex);
  272. InternetTlsIndex = BAD_TLS_INDEX;
  273. }
  274. LPINTERNET_THREAD_INFO
  275. InternetGetThreadInfo(
  276. VOID
  277. )
  278. /*++
  279. Routine Description:
  280. Gets the pointer to the INTERNET_THREAD_INFO for this thread and checks
  281. that it still looks good.
  282. If this thread does not have an INTERNET_THREAD_INFO then we create one,
  283. presuming that this is a new thread
  284. Arguments:
  285. None.
  286. Return Value:
  287. LPINTERNET_THREAD_INFO
  288. Success - pointer to INTERNET_THREAD_INFO block
  289. Failure - NULL
  290. --*/
  291. {
  292. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  293. DWORD lastError;
  294. //
  295. // this is pretty bad - TlsGetValue() can destroy the per-thread last error
  296. // variable if it returns NULL (to indicate that NULL was actually set, and
  297. // that NULL does not indicate an error). So we have to read it before it is
  298. // potentially destroyed, and reset it before we quit.
  299. //
  300. // We do this here because typically, other functions will be completely
  301. // unsuspecting of this behaviour, and it is better to fix it once here,
  302. // than in several dozen other places, even though it is slightly
  303. // inefficient
  304. //
  305. lastError = GetLastError();
  306. if (InternetTlsIndex != BAD_TLS_INDEX) {
  307. lpThreadInfo = (LPINTERNET_THREAD_INFO)TlsGetValue(InternetTlsIndex);
  308. }
  309. //
  310. // we may be in the process of creating the INTERNET_THREAD_INFO, in
  311. // which case its okay for this to be NULL. According to online SDK
  312. // documentation, a threads TLS value will be initialized to NULL
  313. //
  314. if (lpThreadInfo == NULL) {
  315. //
  316. // we presume this is a new thread. Create an INTERNET_THREAD_INFO
  317. //
  318. IF_DEBUG(NOTHING) {
  319. DEBUG_PUT(("InternetGetThreadInfo(): Thread %#x: Creating INTERNET_THREAD_INFO\n",
  320. GetCurrentThreadId()
  321. ));
  322. }
  323. lpThreadInfo = InternetCreateThreadInfo(TRUE);
  324. }
  325. if (lpThreadInfo != NULL) {
  326. INET_ASSERT(lpThreadInfo->Signature == INTERNET_THREAD_INFO_SIGNATURE);
  327. INET_ASSERT(lpThreadInfo->ThreadId == GetCurrentThreadId());
  328. } else {
  329. DEBUG_PUT(("InternetGetThreadInfo(): Failed to get/create INTERNET_THREAD_INFO\n"));
  330. }
  331. //
  332. // as above - reset the last error variable in case TlsGetValue() trashed it
  333. //
  334. SetLastError(lastError);
  335. //
  336. // actual success/failure indicated by non-NULL/NULL pointer resp.
  337. //
  338. return lpThreadInfo;
  339. }
  340. VOID
  341. InternetSetThreadInfo(
  342. IN LPINTERNET_THREAD_INFO lpThreadInfo
  343. )
  344. /*++
  345. Routine Description:
  346. Sets lpThreadInfo as the current thread's INTERNET_THREAD_INFO. Used within
  347. fibers
  348. Arguments:
  349. lpThreadInfo - new INTERNET_THREAD_INFO to set
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. if (InternetTlsIndex != BAD_TLS_INDEX) {
  355. if (!TlsSetValue(InternetTlsIndex, (LPVOID)lpThreadInfo)) {
  356. DEBUG_PUT(("InternetSetThreadInfo(): TlsSetValue(%d, %#x) returns %d\n",
  357. InternetTlsIndex,
  358. lpThreadInfo,
  359. GetLastError()
  360. ));
  361. INET_ASSERT(FALSE);
  362. }
  363. } else {
  364. DEBUG_PUT(("InternetSetThreadInfo(): InternetTlsIndex = %d\n",
  365. InternetTlsIndex
  366. ));
  367. INET_ASSERT(FALSE);
  368. }
  369. }
  370. DWORD
  371. InternetIndicateStatusAddress(
  372. IN DWORD dwInternetStatus,
  373. IN LPSOCKADDR lpSockAddr,
  374. IN DWORD dwSockAddrLength
  375. )
  376. /*++
  377. Routine Description:
  378. Make a status callback to the app. The data is a network address that we
  379. need to convert to a string
  380. Arguments:
  381. dwInternetStatus - WINHTTP_CALLBACK_STATUS_ value
  382. lpSockAddr - pointer to full socket address
  383. dwSockAddrLength - length of lpSockAddr in bytes
  384. Return Value:
  385. DWORD
  386. Success - ERROR_SUCCESS
  387. Failure - ERROR_WINHTTP_OPERATION_CANCELLED
  388. The app closed the object handle during the callback
  389. --*/
  390. {
  391. LPSTR lpAddress;
  392. INET_ASSERT(lpSockAddr != NULL);
  393. switch (lpSockAddr->sa_family)
  394. {
  395. case AF_INET:
  396. lpAddress = _I_inet_ntoa(
  397. ((struct sockaddr_in*)lpSockAddr)->sin_addr
  398. );
  399. break;
  400. case AF_IPX:
  401. //
  402. // BUGBUG - this should be a call to WSAAddressToString, but that's not implemented yet
  403. //
  404. #ifdef SPX_SUPPORT
  405. lpAddress = GENERIC_SPX_NAME;
  406. #else
  407. lpAddress = NULL;
  408. #endif //SPX_SUPPORT
  409. break;
  410. default:
  411. lpAddress = NULL;
  412. break;
  413. }
  414. // we don't want a client to mess around with a winsock-internal buffer
  415. return InternetIndicateStatusString(dwInternetStatus, lpAddress, TRUE/*bCopyBuffer*/);
  416. }
  417. DWORD
  418. InternetIndicateStatusString(
  419. IN DWORD dwInternetStatus,
  420. IN LPSTR lpszStatusInfo OPTIONAL,
  421. IN BOOL bCopyBuffer,
  422. IN BOOL bConvertToUnicode
  423. )
  424. /*++
  425. Routine Description:
  426. Make a status callback to the app. The data is a string
  427. Arguments:
  428. dwInternetStatus - WINHTTP_CALLBACK_STATUS_ value
  429. lpszStatusInfo - string status data
  430. Return Value:
  431. DWORD
  432. Success - ERROR_SUCCESS
  433. Failure - ERROR_WINHTTP_OPERATION_CANCELLED
  434. The app closed the object handle during the callback
  435. --*/
  436. {
  437. DEBUG_ENTER((DBG_THRDINFO,
  438. Dword,
  439. "InternetIndicateStatusString",
  440. "%d, %q",
  441. dwInternetStatus,
  442. lpszStatusInfo
  443. ));
  444. DWORD length;
  445. if (ARGUMENT_PRESENT(lpszStatusInfo))
  446. {
  447. length = strlen(lpszStatusInfo) + 1;
  448. }
  449. else
  450. {
  451. length = 0;
  452. }
  453. DWORD error;
  454. error = InternetIndicateStatus(dwInternetStatus, lpszStatusInfo, length, bCopyBuffer, bConvertToUnicode);
  455. DEBUG_LEAVE(error);
  456. return error;
  457. }
  458. DWORD
  459. InternetIndicateStatusNewHandle(
  460. IN LPVOID hInternetMapped
  461. )
  462. /*++
  463. Routine Description:
  464. Indicates to the app a new handle
  465. Arguments:
  466. hInternetMapped - mapped address of new handle being indicated
  467. Return Value:
  468. DWORD
  469. Success - ERROR_SUCCESS
  470. Failure - ERROR_WINHTTP_OPERATION_CANCELLED
  471. The app closed the either the new object handle or the
  472. parent object handle during the callback
  473. --*/
  474. {
  475. DEBUG_ENTER((DBG_THRDINFO,
  476. Dword,
  477. "InternetIndicateStatusNewHandle",
  478. "%#x",
  479. hInternetMapped
  480. ));
  481. HANDLE_OBJECT * hObject = (HANDLE_OBJECT *)hInternetMapped;
  482. //
  483. // reference the new request handle, in case the app closes it in the
  484. // callback. The new handle now has a reference count of 2
  485. //
  486. hObject->Reference();
  487. INET_ASSERT(hObject->ReferenceCount() == 2);
  488. //
  489. // we indicate the pseudo handle to the app
  490. //
  491. HINTERNET hInternet = hObject->GetPseudoHandle();
  492. DWORD error = InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_HANDLE_CREATED,
  493. (LPVOID)&hInternet,
  494. sizeof(hInternet)
  495. );
  496. //
  497. // dereference the new request handle. If this returns TRUE then the new
  498. // handle has been deleted (the app called InternetCloseHandle() against
  499. // it which dereferenced it to 1, and now we've dereferenced it to zero)
  500. //
  501. if (hObject->Dereference())
  502. {
  503. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  504. }
  505. else if (error == ERROR_WINHTTP_OPERATION_CANCELLED)
  506. {
  507. //
  508. // the parent handle was deleted. Kill off the new handle too
  509. //
  510. BOOL ok;
  511. ok = hObject->Dereference();
  512. INET_ASSERT(ok);
  513. }
  514. DEBUG_LEAVE(error);
  515. return error;
  516. }
  517. DWORD
  518. InternetIndicateStatus(
  519. IN DWORD dwStatus,
  520. IN LPVOID lpBuffer,
  521. IN DWORD dwLength,
  522. IN BOOL bCopyBuffer,
  523. IN BOOL bConvertToUnicode
  524. )
  525. /*++
  526. Routine Description:
  527. If the app has registered a callback function for the object that this
  528. thread is operating on, call it with the arguments supplied
  529. Arguments:
  530. dwStatus - WINHTTP_CALLBACK_STATUS_ value
  531. lpBuffer - pointer to variable data buffer
  532. dwLength - length of *lpBuffer in bytes
  533. Return Value:
  534. DWORD
  535. Success - ERROR_SUCCESS
  536. Failure - ERROR_WINHTTP_OPERATION_CANCELLED
  537. The app closed the object handle during the callback
  538. --*/
  539. {
  540. DEBUG_ENTER((DBG_THRDINFO,
  541. Dword,
  542. "InternetIndicateStatus",
  543. "%s, %#x, %d",
  544. InternetMapStatus(dwStatus),
  545. lpBuffer,
  546. dwLength
  547. ));
  548. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  549. DWORD error = ERROR_SUCCESS;
  550. //
  551. // the app can affect callback operation by specifying a zero context value
  552. // meaning no callbacks will be generated for this API
  553. //
  554. if (lpThreadInfo != NULL)
  555. {
  556. INET_ASSERT(lpThreadInfo->hObject != NULL);
  557. INET_ASSERT(lpThreadInfo->hObjectMapped != NULL);
  558. //
  559. // if the context value in the thread info block is 0 then we use the
  560. // context from the handle object
  561. //
  562. DWORD_PTR context;
  563. context = ((INTERNET_HANDLE_BASE *)lpThreadInfo->hObjectMapped)->GetContext();
  564. WINHTTP_STATUS_CALLBACK appCallback;
  565. appCallback = ((INTERNET_HANDLE_BASE *)lpThreadInfo->hObjectMapped)->GetStatusCallback();
  566. IF_DEBUG(THRDINFO)
  567. {
  568. switch (dwStatus)
  569. {
  570. case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
  571. case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
  572. case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
  573. DEBUG_PRINT(THRDINFO,
  574. INFO,
  575. ("%s: dwResult = %#x, dwError = %d [%s]\n",
  576. InternetMapStatus(dwStatus),
  577. ((LPWINHTTP_ASYNC_RESULT)lpBuffer)->dwError,
  578. InternetMapError(((LPWINHTTP_ASYNC_RESULT)lpBuffer)->dwError)
  579. ));
  580. break;
  581. case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
  582. case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
  583. DEBUG_PRINT(THRDINFO,
  584. INFO,
  585. ("%s: Buffer = %p, Number of bytes = %d\n",
  586. InternetMapStatus(dwStatus),
  587. lpBuffer,
  588. dwLength
  589. ));
  590. break;
  591. }
  592. }
  593. if ((appCallback != NULL) &&
  594. (((INTERNET_HANDLE_BASE *)lpThreadInfo->hObjectMapped)->IsNotificationEnabled(dwStatus)) )
  595. {
  596. LPVOID pInfo; //reported thru callback
  597. DWORD infoLength; //reported thru callback
  598. BOOL isAsyncWorkerThread;
  599. BYTE buffer[256];
  600. //
  601. // we make a copy of the info to remove the app's opportunity to
  602. // change it. E.g. if we were about to resolve host name "foo" and
  603. // passed the pointer to our buffer containing "foo", the app could
  604. // change the name to "bar", changing the intended server
  605. //
  606. if (lpBuffer != NULL)
  607. {
  608. if (bConvertToUnicode)
  609. {
  610. INET_ASSERT( ((INTERNET_HANDLE_BASE *)lpThreadInfo->hObjectMapped)->IsUnicodeStatusCallback() );
  611. INET_ASSERT(
  612. (dwStatus == WINHTTP_CALLBACK_STATUS_RESOLVING_NAME) ||
  613. (dwStatus == WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) ||
  614. (dwStatus == WINHTTP_CALLBACK_STATUS_REDIRECT) ||
  615. (dwStatus == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER) ||
  616. (dwStatus == WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER)
  617. );
  618. infoLength = MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpBuffer,
  619. dwLength, NULL, 0);
  620. if (infoLength == 0)
  621. {
  622. pInfo = NULL;
  623. DEBUG_PRINT(THRDINFO,
  624. ERROR,
  625. ("MultiByteToWideChar returned 0 for a %d-length MBCS string\n",
  626. dwLength
  627. ));
  628. }
  629. else if (infoLength <= sizeof(buffer)/sizeof(WCHAR))
  630. {
  631. pInfo = buffer;
  632. }
  633. else
  634. {
  635. pInfo = (LPVOID)ALLOCATE_FIXED_MEMORY(infoLength * sizeof(WCHAR));
  636. }
  637. if (pInfo)
  638. {
  639. infoLength = MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpBuffer,
  640. dwLength, (LPWSTR)pInfo, infoLength);
  641. if (infoLength == 0)
  642. {
  643. //MBtoWC failed
  644. if (pInfo != buffer)
  645. FREE_FIXED_MEMORY(pInfo);
  646. pInfo = NULL;
  647. DEBUG_PRINT(THRDINFO,
  648. ERROR,
  649. ("MultiByteToWideChar returned 0 for a %d-length MBCS string\n",
  650. dwLength
  651. ));
  652. }
  653. } //pInfo
  654. else
  655. {
  656. infoLength = 0;
  657. DEBUG_PRINT(THRDINFO,
  658. ERROR,
  659. ("MultiByteToWideChar() error OR Failed to allocate %d bytes for info\n",
  660. dwLength
  661. ));
  662. } //pInfo == NULL
  663. } //bConvertToUnicode
  664. else if (bCopyBuffer)
  665. {
  666. if (dwLength <= sizeof(buffer))
  667. pInfo = buffer;
  668. else
  669. pInfo = (LPVOID)ALLOCATE_FIXED_MEMORY(dwLength);
  670. if (pInfo)
  671. {
  672. memcpy(pInfo, lpBuffer, dwLength);
  673. infoLength = dwLength;
  674. }
  675. else
  676. {
  677. infoLength = 0;
  678. DEBUG_PRINT(THRDINFO,
  679. ERROR,
  680. ("Failed to allocate %d bytes for info\n",
  681. dwLength
  682. ));
  683. }
  684. } //bCopyBuffer
  685. else
  686. {
  687. pInfo = lpBuffer;
  688. infoLength = dwLength;
  689. INET_ASSERT(dwLength);
  690. } //!bCopyBuffer && !bConvertToUnicode
  691. } //lpBuffer != NULL
  692. else
  693. {
  694. pInfo = NULL;
  695. infoLength = 0;
  696. }
  697. //
  698. // we're about to call into the app. We may be in the context of an
  699. // async worker thread, and if the callback submits an async request
  700. // then we'll execute it synchronously. To avoid this, we will reset
  701. // the async worker thread indicator in the INTERNET_THREAD_INFO and
  702. // restore it when the app returns control to us. This way, if the
  703. // app makes an API request during the callback, on a handle that
  704. // has async I/O semantics, then we will simply queue it, and not
  705. // try to execute it synchronously
  706. //
  707. isAsyncWorkerThread = lpThreadInfo->IsAsyncWorkerThread;
  708. lpThreadInfo->IsAsyncWorkerThread = FALSE;
  709. BOOL bInCallback = lpThreadInfo->InCallback;
  710. lpThreadInfo->InCallback = TRUE;
  711. INET_ASSERT(!IsBadCodePtr((FARPROC)appCallback));
  712. DEBUG_ENTER((DBG_THRDINFO,
  713. None,
  714. "(*callback)",
  715. "%#x, %#x, %s (%d), %#x [%#x], %d",
  716. lpThreadInfo->hObject,
  717. context,
  718. InternetMapStatus(dwStatus),
  719. dwStatus,
  720. pInfo,
  721. ((dwStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED)
  722. || (dwStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING))
  723. ? (DWORD_PTR)*(LPHINTERNET)pInfo
  724. : (((dwStatus == WINHTTP_CALLBACK_STATUS_REQUEST_SENT)
  725. || (dwStatus == WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED)
  726. || (dwStatus == WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE))
  727. ? *(LPDWORD)pInfo
  728. : 0),
  729. infoLength
  730. ));
  731. PERF_LOG(PE_APP_CALLBACK_START,
  732. dwStatus,
  733. lpThreadInfo->ThreadId,
  734. lpThreadInfo->hObject
  735. );
  736. HINTERNET hObject = lpThreadInfo->hObject;
  737. LPVOID hObjectMapped = lpThreadInfo->hObjectMapped;
  738. appCallback(lpThreadInfo->hObject,
  739. context,
  740. dwStatus,
  741. pInfo,
  742. infoLength
  743. );
  744. lpThreadInfo->hObject = hObject;
  745. lpThreadInfo->hObjectMapped = hObjectMapped;
  746. PERF_LOG(PE_APP_CALLBACK_END,
  747. dwStatus,
  748. lpThreadInfo->ThreadId,
  749. lpThreadInfo->hObject
  750. );
  751. DEBUG_LEAVE(0);
  752. lpThreadInfo->InCallback = bInCallback;
  753. lpThreadInfo->IsAsyncWorkerThread = isAsyncWorkerThread;
  754. //
  755. // free the buffer
  756. //
  757. // We should free the memory only if we have done an ALLOCATE_FIXED_MEMORY in this function:
  758. if (pInfo != NULL && pInfo != lpBuffer && pInfo != buffer) {
  759. FREE_FIXED_MEMORY(pInfo);
  760. }
  761. } else {
  762. DEBUG_PRINT(THRDINFO,
  763. ERROR,
  764. ("%#x: callback = %#x, context = %#x\n",
  765. lpThreadInfo->hObject,
  766. appCallback,
  767. context
  768. ));
  769. //
  770. // if we're completing a request then we shouldn't be here - it
  771. // means we lost the context or callback address somewhere along the
  772. // way
  773. //
  774. // don't need the ASSERTS below.
  775. // It could also mean something as benign as the notification not being enabled:
  776. /*
  777. INET_ASSERT(
  778. dwStatus != WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE
  779. && dwStatus != WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE
  780. && dwStatus != WINHTTP_CALLBACK_STATUS_REQUEST_ERROR
  781. && dwStatus != WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE
  782. && dwStatus != WINHTTP_CALLBACK_STATUS_READ_COMPLETE
  783. );
  784. */
  785. #ifdef DEBUG
  786. if (
  787. dwStatus == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE
  788. || dwStatus == WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE
  789. || dwStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR
  790. || dwStatus == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE
  791. || dwStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE
  792. )
  793. {
  794. INET_ASSERT(appCallback != NULL);
  795. /*
  796. These are not valid asserts in winhttp.
  797. Contexts don't control whether callbacks are made or not.
  798. */
  799. //INET_ASSERT(context != NULL);
  800. //INET_ASSERT(_InternetGetContext(lpThreadInfo) != NULL);
  801. }
  802. #endif
  803. }
  804. //
  805. // if the object is now invalid then the app closed the handle in
  806. // the callback, or from an external thread and the entire operation is cancelled
  807. // propagate this error back to calling code.
  808. //
  809. if (((HANDLE_OBJECT *)lpThreadInfo->hObjectMapped)->IsInvalidated())
  810. {
  811. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  812. }
  813. } else {
  814. //
  815. // this is catastrophic if the indication was async request completion
  816. //
  817. DEBUG_PUT(("InternetIndicateStatus(): no INTERNET_THREAD_INFO?\n"));
  818. }
  819. DEBUG_LEAVE(error);
  820. return error;
  821. }
  822. DWORD
  823. InternetSetLastError(
  824. IN DWORD ErrorNumber,
  825. IN LPSTR ErrorText,
  826. IN DWORD ErrorTextLength,
  827. IN DWORD Flags
  828. )
  829. /*++
  830. Routine Description:
  831. Copies the error text to the per-thread error buffer (moveable memory)
  832. Arguments:
  833. ErrorNumber - protocol-specific error code
  834. ErrorText - protocol-specific error text (from server). The buffer is
  835. NOT zero-terminated
  836. ErrorTextLength - number of characters in ErrorText
  837. Flags - Flags that control how this function operates:
  838. SLE_APPEND TRUE if ErrorText is to be appended
  839. to the text already in the buffer
  840. SLE_ZERO_TERMINATE TRUE if ErrorText must have a '\0'
  841. appended to it
  842. Return Value:
  843. DWORD
  844. Success - ERROR_SUCCESS
  845. Failure - Win32 error
  846. --*/
  847. {
  848. DEBUG_ENTER((DBG_THRDINFO,
  849. Dword,
  850. "InternetSetLastError",
  851. "%d, %.80q, %d, %#x",
  852. ErrorNumber,
  853. ErrorText,
  854. ErrorTextLength,
  855. Flags
  856. ));
  857. DWORD error;
  858. LPINTERNET_THREAD_INFO lpThreadInfo;
  859. lpThreadInfo = InternetGetThreadInfo();
  860. if (lpThreadInfo != NULL) {
  861. error = _InternetSetLastError(lpThreadInfo,
  862. ErrorNumber,
  863. ErrorText,
  864. ErrorTextLength,
  865. Flags
  866. );
  867. } else {
  868. DEBUG_PUT(("InternetSetLastError(): no INTERNET_THREAD_INFO\n"));
  869. error = ERROR_WINHTTP_INTERNAL_ERROR;
  870. }
  871. DEBUG_LEAVE(error);
  872. return error;
  873. }
  874. DWORD
  875. _InternetSetLastError(
  876. IN LPINTERNET_THREAD_INFO lpThreadInfo,
  877. IN DWORD ErrorNumber,
  878. IN LPSTR ErrorText,
  879. IN DWORD ErrorTextLength,
  880. IN DWORD Flags
  881. )
  882. /*++
  883. Routine Description:
  884. Sets or resets the last error text in an INTERNET_THREAD_INFO block
  885. Arguments:
  886. lpThreadInfo - pointer to INTERNET_THREAD_INFO
  887. ErrorNumber - protocol-specific error code
  888. ErrorText - protocol-specific error text (from server). The buffer is
  889. NOT zero-terminated
  890. ErrorTextLength - number of characters in ErrorText
  891. Flags - Flags that control how this function operates:
  892. SLE_APPEND TRUE if ErrorText is to be appended
  893. to the text already in the buffer
  894. SLE_ZERO_TERMINATE TRUE if ErrorText must have a '\0'
  895. appended to it
  896. Return Value:
  897. DWORD
  898. Success - ERROR_SUCCESS
  899. Failure - Win32 error
  900. --*/
  901. {
  902. DEBUG_ENTER((DBG_THRDINFO,
  903. Dword,
  904. "_InternetSetLastError",
  905. "%#x, %d, %.80q, %d, %#x",
  906. lpThreadInfo,
  907. ErrorNumber,
  908. ErrorText,
  909. ErrorTextLength,
  910. Flags
  911. ));
  912. DWORD currentLength;
  913. DWORD newTextLength;
  914. DWORD error;
  915. newTextLength = ErrorTextLength;
  916. //
  917. // if we are appending text, then account for the '\0' currently at the end
  918. // of the buffer (if it exists)
  919. //
  920. if (Flags & SLE_APPEND) {
  921. currentLength = lpThreadInfo->ErrorTextLength;
  922. if (currentLength != 0) {
  923. --currentLength;
  924. }
  925. newTextLength += currentLength;
  926. }
  927. if (Flags & SLE_ZERO_TERMINATE) {
  928. ++newTextLength;
  929. }
  930. //
  931. // expect success (and why not?)
  932. //
  933. error = ERROR_SUCCESS;
  934. //
  935. // allocate, grow or shrink the buffer to fit. The buffer is moveable. If
  936. // the buffer is being shrunk to zero size then NULL will be returned as
  937. // the buffer handle from ResizeBuffer()
  938. //
  939. lpThreadInfo->hErrorText = ResizeBuffer(lpThreadInfo->hErrorText,
  940. newTextLength,
  941. FALSE
  942. );
  943. if (lpThreadInfo->hErrorText != NULL) {
  944. LPSTR lpErrorText;
  945. lpErrorText = (LPSTR)LOCK_MEMORY(lpThreadInfo->hErrorText);
  946. INET_ASSERT(lpErrorText != NULL);
  947. if (lpErrorText != NULL) {
  948. if (Flags & SLE_APPEND) {
  949. lpErrorText += currentLength;
  950. }
  951. memcpy(lpErrorText, ErrorText, ErrorTextLength);
  952. if (Flags & SLE_ZERO_TERMINATE) {
  953. lpErrorText[ErrorTextLength++] = '\0';
  954. }
  955. //
  956. // the text should always be zero-terminated. We expect this in
  957. // InternetGetLastResponseInfo()
  958. //
  959. INET_ASSERT(lpErrorText[ErrorTextLength - 1] == '\0');
  960. UNLOCK_MEMORY(lpThreadInfo->hErrorText);
  961. } else {
  962. //
  963. // real error occurred - failed to lock memory?
  964. //
  965. error = GetLastError();
  966. }
  967. } else {
  968. INET_ASSERT(newTextLength == 0);
  969. newTextLength = 0;
  970. }
  971. //
  972. // set the error code and text length
  973. //
  974. lpThreadInfo->ErrorTextLength = newTextLength;
  975. lpThreadInfo->ErrorNumber = ErrorNumber;
  976. DEBUG_LEAVE(error);
  977. return error;
  978. }
  979. LPSTR
  980. InternetLockErrorText(
  981. VOID
  982. )
  983. /*++
  984. Routine Description:
  985. Returns a pointer to the locked per-thread error text buffer
  986. Arguments:
  987. None.
  988. Return Value:
  989. LPSTR
  990. Success - pointer to locked buffer
  991. Failure - NULL
  992. --*/
  993. {
  994. LPINTERNET_THREAD_INFO lpThreadInfo;
  995. lpThreadInfo = InternetGetThreadInfo();
  996. if (lpThreadInfo != NULL) {
  997. HLOCAL lpErrorText;
  998. lpErrorText = lpThreadInfo->hErrorText;
  999. if (lpErrorText != (HLOCAL)NULL) {
  1000. return (LPSTR)LOCK_MEMORY(lpErrorText);
  1001. }
  1002. }
  1003. return NULL;
  1004. }
  1005. //
  1006. //VOID
  1007. //InternetUnlockErrorText(
  1008. // VOID
  1009. // )
  1010. //
  1011. ///*++
  1012. //
  1013. //Routine Description:
  1014. //
  1015. // Unlocks the per-thread error text buffer locked by InternetLockErrorText()
  1016. //
  1017. //Arguments:
  1018. //
  1019. // None.
  1020. //
  1021. //Return Value:
  1022. //
  1023. // None.
  1024. //
  1025. //--*/
  1026. //
  1027. //{
  1028. // LPINTERNET_THREAD_INFO lpThreadInfo;
  1029. //
  1030. // lpThreadInfo = InternetGetThreadInfo();
  1031. //
  1032. // //
  1033. // // assume that if we locked the error text, there must be an
  1034. // // INTERNET_THREAD_INFO when we come to unlock it
  1035. // //
  1036. //
  1037. // INET_ASSERT(lpThreadInfo != NULL);
  1038. //
  1039. // if (lpThreadInfo != NULL) {
  1040. //
  1041. // HLOCAL hErrorText;
  1042. //
  1043. // hErrorText = lpThreadInfo->hErrorText;
  1044. //
  1045. // //
  1046. // // similarly, there must be a handle to the error text buffer
  1047. // //
  1048. //
  1049. // INET_ASSERT(hErrorText != NULL);
  1050. //
  1051. // if (hErrorText != (HLOCAL)NULL) {
  1052. // UNLOCK_MEMORY(hErrorText);
  1053. // }
  1054. // }
  1055. //}
  1056. VOID
  1057. InternetSetObjectHandle(
  1058. IN HINTERNET hInternet,
  1059. IN HINTERNET hInternetMapped
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. Sets the hObject field in the INTERNET_THREAD_INFO structure so we can get
  1064. at the handle contents, even when we're in a function that does not take
  1065. the hInternet as a parameter
  1066. Arguments:
  1067. hInternet - handle of object we may need info from
  1068. hInternetMapped - mapped handle of object we may need info from
  1069. Return Value:
  1070. None.
  1071. --*/
  1072. {
  1073. LPINTERNET_THREAD_INFO lpThreadInfo;
  1074. lpThreadInfo = InternetGetThreadInfo();
  1075. if (lpThreadInfo != NULL) {
  1076. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  1077. }
  1078. }
  1079. HINTERNET
  1080. InternetGetObjectHandle(
  1081. VOID
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. Just returns the hObject value stored in our INTERNET_THREAD_INFO
  1086. Arguments:
  1087. None.
  1088. Return Value:
  1089. HINTERNET
  1090. Success - non-NULL handle value
  1091. Failure - NULL object handle (may not have been set)
  1092. --*/
  1093. {
  1094. LPINTERNET_THREAD_INFO lpThreadInfo;
  1095. HINTERNET hInternet;
  1096. lpThreadInfo = InternetGetThreadInfo();
  1097. if (lpThreadInfo != NULL) {
  1098. hInternet = lpThreadInfo->hObject;
  1099. } else {
  1100. hInternet = NULL;
  1101. }
  1102. return hInternet;
  1103. }
  1104. HINTERNET
  1105. InternetGetMappedObjectHandle(
  1106. VOID
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Just returns the hObjectMapped value stored in our INTERNET_THREAD_INFO
  1111. Arguments:
  1112. None.
  1113. Return Value:
  1114. HINTERNET
  1115. Success - non-NULL handle value
  1116. Failure - NULL object handle (may not have been set)
  1117. --*/
  1118. {
  1119. LPINTERNET_THREAD_INFO lpThreadInfo;
  1120. HINTERNET hInternet;
  1121. lpThreadInfo = InternetGetThreadInfo();
  1122. if (lpThreadInfo != NULL) {
  1123. hInternet = lpThreadInfo->hObjectMapped;
  1124. } else {
  1125. hInternet = NULL;
  1126. }
  1127. return hInternet;
  1128. }