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.

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