PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs

https://gitlab.com/0072016/0072016-corefx-
C# | 622 lines | 528 code | 88 blank | 6 comment | 84 complexity | ebfa8d700796b6d68b11377cdea9dbca MD5 | raw file
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Net;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using Microsoft.Win32.SafeHandles;
  13. using System.Net.Http.WinHttpHandlerUnitTests;
  14. using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
  15. internal static partial class Interop
  16. {
  17. internal static partial class Crypt32
  18. {
  19. public static bool CertFreeCertificateContext(IntPtr certContext)
  20. {
  21. return true;
  22. }
  23. public static bool CertVerifyCertificateChainPolicy(
  24. IntPtr pszPolicyOID,
  25. SafeX509ChainHandle pChainContext,
  26. ref CERT_CHAIN_POLICY_PARA pPolicyPara,
  27. ref CERT_CHAIN_POLICY_STATUS pPolicyStatus)
  28. {
  29. return true;
  30. }
  31. }
  32. internal static partial class mincore
  33. {
  34. public static string GetMessage(IntPtr moduleName, int error)
  35. {
  36. string messageFormat = "Fake error message, error code: {0}";
  37. return string.Format(messageFormat, error);
  38. }
  39. public static IntPtr GetModuleHandle(string moduleName)
  40. {
  41. return IntPtr.Zero;
  42. }
  43. }
  44. internal static partial class WinHttp
  45. {
  46. public static SafeWinHttpHandle WinHttpOpen(
  47. IntPtr userAgent,
  48. uint accessType,
  49. string proxyName,
  50. string proxyBypass,
  51. uint flags)
  52. {
  53. if (TestControl.WinHttpOpen.ErrorWithApiCall)
  54. {
  55. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INVALID_HANDLE;
  56. return new FakeSafeWinHttpHandle(false);
  57. }
  58. if (accessType == Interop.WinHttp.WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY &&
  59. !TestControl.WinHttpAutomaticProxySupport)
  60. {
  61. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INVALID_PARAMETER;
  62. return new FakeSafeWinHttpHandle(false);
  63. }
  64. APICallHistory.ProxyInfo proxyInfo;
  65. proxyInfo.AccessType = accessType;
  66. proxyInfo.Proxy = proxyName;
  67. proxyInfo.ProxyBypass = proxyBypass;
  68. APICallHistory.SessionProxySettings = proxyInfo;
  69. return new FakeSafeWinHttpHandle(true);
  70. }
  71. public static bool WinHttpCloseHandle(IntPtr sessionHandle)
  72. {
  73. Marshal.FreeHGlobal(sessionHandle);
  74. return true;
  75. }
  76. public static SafeWinHttpHandle WinHttpConnect(
  77. SafeWinHttpHandle sessionHandle,
  78. string serverName,
  79. ushort serverPort,
  80. uint reserved)
  81. {
  82. return new FakeSafeWinHttpHandle(true);
  83. }
  84. public static bool WinHttpAddRequestHeaders(
  85. SafeWinHttpHandle requestHandle,
  86. StringBuilder headers,
  87. uint headersLength,
  88. uint modifiers)
  89. {
  90. return true;
  91. }
  92. public static bool WinHttpAddRequestHeaders(
  93. SafeWinHttpHandle requestHandle,
  94. string headers,
  95. uint headersLength,
  96. uint modifiers)
  97. {
  98. return true;
  99. }
  100. public static SafeWinHttpHandle WinHttpOpenRequest(
  101. SafeWinHttpHandle connectHandle,
  102. string verb,
  103. string objectName,
  104. string version,
  105. string referrer,
  106. string acceptTypes,
  107. uint flags)
  108. {
  109. return new FakeSafeWinHttpHandle(true);
  110. }
  111. public static bool WinHttpSendRequest(
  112. SafeWinHttpHandle requestHandle,
  113. StringBuilder headers,
  114. uint headersLength,
  115. IntPtr optional,
  116. uint optionalLength,
  117. uint totalLength,
  118. IntPtr context)
  119. {
  120. Task.Run(() => {
  121. var fakeHandle = (FakeSafeWinHttpHandle)requestHandle;
  122. fakeHandle.Context = context;
  123. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, IntPtr.Zero, 0);
  124. });
  125. return true;
  126. }
  127. public static bool WinHttpReceiveResponse(SafeWinHttpHandle requestHandle, IntPtr reserved)
  128. {
  129. Task.Run(() => {
  130. var fakeHandle = (FakeSafeWinHttpHandle)requestHandle;
  131. bool aborted = !fakeHandle.DelayOperation(TestControl.WinHttpReceiveResponse.Delay);
  132. if (aborted || TestControl.WinHttpReadData.ErrorOnCompletion)
  133. {
  134. Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult;
  135. asyncResult.dwResult = new IntPtr((int)Interop.WinHttp.API_RECEIVE_RESPONSE);
  136. asyncResult.dwError = aborted ? Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED :
  137. Interop.WinHttp.ERROR_WINHTTP_CONNECTION_ERROR;
  138. TestControl.WinHttpReadData.Wait();
  139. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, asyncResult);
  140. }
  141. else
  142. {
  143. TestControl.WinHttpReceiveResponse.Wait();
  144. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, IntPtr.Zero, 0);
  145. }
  146. });
  147. return true;
  148. }
  149. public static bool WinHttpQueryDataAvailable(
  150. SafeWinHttpHandle requestHandle,
  151. IntPtr bytesAvailableShouldBeNullForAsync)
  152. {
  153. if (bytesAvailableShouldBeNullForAsync != IntPtr.Zero)
  154. {
  155. return false;
  156. }
  157. if (TestControl.WinHttpQueryDataAvailable.ErrorWithApiCall)
  158. {
  159. return false;
  160. }
  161. Task.Run(() => {
  162. var fakeHandle = (FakeSafeWinHttpHandle)requestHandle;
  163. bool aborted = !fakeHandle.DelayOperation(TestControl.WinHttpReadData.Delay);
  164. if (aborted || TestControl.WinHttpQueryDataAvailable.ErrorOnCompletion)
  165. {
  166. Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult;
  167. asyncResult.dwResult = new IntPtr((int)Interop.WinHttp.API_QUERY_DATA_AVAILABLE);
  168. asyncResult.dwError = aborted ? Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED :
  169. Interop.WinHttp.ERROR_WINHTTP_CONNECTION_ERROR;
  170. TestControl.WinHttpQueryDataAvailable.Wait();
  171. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, asyncResult);
  172. }
  173. else
  174. {
  175. int bufferSize = Marshal.SizeOf<int>();
  176. IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
  177. Marshal.WriteInt32(buffer, TestServer.DataAvailable);
  178. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, buffer, (uint)bufferSize);
  179. Marshal.FreeHGlobal(buffer);
  180. }
  181. });
  182. return true;
  183. }
  184. public static bool WinHttpReadData(
  185. SafeWinHttpHandle requestHandle,
  186. IntPtr buffer,
  187. uint bufferSize,
  188. IntPtr bytesReadShouldBeNullForAsync)
  189. {
  190. if (bytesReadShouldBeNullForAsync != IntPtr.Zero)
  191. {
  192. return false;
  193. }
  194. if (TestControl.WinHttpReadData.ErrorWithApiCall)
  195. {
  196. return false;
  197. }
  198. uint bytesRead;
  199. TestServer.ReadFromResponseBody(buffer, bufferSize, out bytesRead);
  200. Task.Run(() => {
  201. var fakeHandle = (FakeSafeWinHttpHandle)requestHandle;
  202. bool aborted = !fakeHandle.DelayOperation(TestControl.WinHttpReadData.Delay);
  203. if (aborted || TestControl.WinHttpReadData.ErrorOnCompletion)
  204. {
  205. Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult;
  206. asyncResult.dwResult = new IntPtr((int)Interop.WinHttp.API_READ_DATA);
  207. asyncResult.dwError = aborted ? Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED :
  208. Interop.WinHttp.ERROR_WINHTTP_CONNECTION_ERROR;
  209. TestControl.WinHttpReadData.Wait();
  210. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, asyncResult);
  211. }
  212. else
  213. {
  214. TestControl.WinHttpReadData.Wait();
  215. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytesRead);
  216. }
  217. });
  218. return true;
  219. }
  220. public static bool WinHttpQueryHeaders(
  221. SafeWinHttpHandle requestHandle,
  222. uint infoLevel, string name,
  223. IntPtr buffer,
  224. ref uint bufferLength,
  225. ref uint index)
  226. {
  227. string httpVersion = "HTTP/1.1";
  228. string statusText = "OK";
  229. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE)
  230. {
  231. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND;
  232. return false;
  233. }
  234. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_VERSION)
  235. {
  236. return CopyToBufferOrFailIfInsufficientBufferLength(httpVersion, buffer, ref bufferLength);
  237. }
  238. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT)
  239. {
  240. return CopyToBufferOrFailIfInsufficientBufferLength(statusText, buffer, ref bufferLength);
  241. }
  242. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING)
  243. {
  244. string compression =
  245. TestServer.ResponseHeaders.Contains("Content-Encoding: deflate") ? "deflate" :
  246. TestServer.ResponseHeaders.Contains("Content-Encoding: gzip") ? "gzip" :
  247. null;
  248. if (compression == null)
  249. {
  250. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND;
  251. return false;
  252. }
  253. return CopyToBufferOrFailIfInsufficientBufferLength(compression, buffer, ref bufferLength);
  254. }
  255. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF)
  256. {
  257. return CopyToBufferOrFailIfInsufficientBufferLength(TestServer.ResponseHeaders, buffer, ref bufferLength);
  258. }
  259. return false;
  260. }
  261. private static bool CopyToBufferOrFailIfInsufficientBufferLength(string value, IntPtr buffer, ref uint bufferLength)
  262. {
  263. // The length of the string (plus terminating null char) in bytes.
  264. uint bufferLengthNeeded = ((uint)value.Length + 1) * sizeof(char);
  265. if (buffer == IntPtr.Zero || bufferLength < bufferLengthNeeded)
  266. {
  267. bufferLength = bufferLengthNeeded;
  268. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
  269. return false;
  270. }
  271. // Copy the string to the buffer.
  272. char[] temp = new char[value.Length + 1]; // null terminated.
  273. value.CopyTo(0, temp, 0, value.Length);
  274. Marshal.Copy(temp, 0, buffer, temp.Length);
  275. // The length in bytes, minus the length of the null char at the end.
  276. bufferLength = (uint)value.Length * sizeof(char);
  277. return true;
  278. }
  279. public static bool WinHttpQueryHeaders(
  280. SafeWinHttpHandle requestHandle,
  281. uint infoLevel,
  282. string name,
  283. ref uint number,
  284. ref uint bufferLength,
  285. IntPtr index)
  286. {
  287. infoLevel &= ~Interop.WinHttp.WINHTTP_QUERY_FLAG_NUMBER;
  288. if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE)
  289. {
  290. number = (uint)HttpStatusCode.OK;
  291. return true;
  292. }
  293. return false;
  294. }
  295. public static bool WinHttpQueryOption(
  296. SafeWinHttpHandle handle,
  297. uint option,
  298. StringBuilder buffer,
  299. ref uint bufferSize)
  300. {
  301. string uri = "http://www.contoso.com/";
  302. if (option == Interop.WinHttp.WINHTTP_OPTION_URL)
  303. {
  304. if (buffer == null)
  305. {
  306. bufferSize = ((uint)uri.Length + 1) * 2;
  307. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
  308. return false;
  309. }
  310. buffer.Append(uri);
  311. return true;
  312. }
  313. return false;
  314. }
  315. public static bool WinHttpQueryOption(
  316. SafeWinHttpHandle handle,
  317. uint option,
  318. ref IntPtr buffer,
  319. ref uint bufferSize)
  320. {
  321. return true;
  322. }
  323. public static bool WinHttpQueryOption(
  324. SafeWinHttpHandle handle,
  325. uint option,
  326. IntPtr buffer,
  327. ref uint bufferSize)
  328. {
  329. return true;
  330. }
  331. public static bool WinHttpWriteData(
  332. SafeWinHttpHandle requestHandle,
  333. IntPtr buffer,
  334. uint bufferSize,
  335. IntPtr bytesWrittenShouldBeNullForAsync)
  336. {
  337. if (bytesWrittenShouldBeNullForAsync != IntPtr.Zero)
  338. {
  339. return false;
  340. }
  341. if (TestControl.WinHttpWriteData.ErrorWithApiCall)
  342. {
  343. return false;
  344. }
  345. uint bytesWritten;
  346. TestServer.WriteToRequestBody(buffer, bufferSize);
  347. bytesWritten = bufferSize;
  348. Task.Run(() => {
  349. var fakeHandle = (FakeSafeWinHttpHandle)requestHandle;
  350. bool aborted = !fakeHandle.DelayOperation(TestControl.WinHttpWriteData.Delay);
  351. if (aborted || TestControl.WinHttpWriteData.ErrorOnCompletion)
  352. {
  353. Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult;
  354. asyncResult.dwResult = new IntPtr((int)Interop.WinHttp.API_WRITE_DATA);
  355. asyncResult.dwError = Interop.WinHttp.ERROR_WINHTTP_CONNECTION_ERROR;
  356. TestControl.WinHttpWriteData.Wait();
  357. fakeHandle.InvokeCallback(aborted ? Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED :
  358. Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, asyncResult);
  359. }
  360. else
  361. {
  362. TestControl.WinHttpWriteData.Wait();
  363. fakeHandle.InvokeCallback(Interop.WinHttp.WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, IntPtr.Zero, 0);
  364. }
  365. });
  366. return true;
  367. }
  368. public static bool WinHttpSetOption(
  369. SafeWinHttpHandle handle,
  370. uint option,
  371. ref uint optionData,
  372. uint optionLength = sizeof(uint))
  373. {
  374. if (option == Interop.WinHttp.WINHTTP_OPTION_DECOMPRESSION & !TestControl.WinHttpDecompressionSupport)
  375. {
  376. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION;
  377. return false;
  378. }
  379. if (option == Interop.WinHttp.WINHTTP_OPTION_DISABLE_FEATURE &&
  380. optionData == Interop.WinHttp.WINHTTP_DISABLE_COOKIES)
  381. {
  382. APICallHistory.WinHttpOptionDisableCookies = true;
  383. }
  384. else if (option == Interop.WinHttp.WINHTTP_OPTION_ENABLE_FEATURE &&
  385. optionData == Interop.WinHttp.WINHTTP_ENABLE_SSL_REVOCATION)
  386. {
  387. APICallHistory.WinHttpOptionEnableSslRevocation = true;
  388. }
  389. else if (option == Interop.WinHttp.WINHTTP_OPTION_SECURE_PROTOCOLS)
  390. {
  391. APICallHistory.WinHttpOptionSecureProtocols = optionData;
  392. }
  393. else if (option == Interop.WinHttp.WINHTTP_OPTION_SECURITY_FLAGS)
  394. {
  395. APICallHistory.WinHttpOptionSecurityFlags = optionData;
  396. }
  397. else if (option == Interop.WinHttp.WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS)
  398. {
  399. APICallHistory.WinHttpOptionMaxHttpAutomaticRedirects = optionData;
  400. }
  401. else if (option == Interop.WinHttp.WINHTTP_OPTION_REDIRECT_POLICY)
  402. {
  403. APICallHistory.WinHttpOptionRedirectPolicy = optionData;
  404. }
  405. return true;
  406. }
  407. public static bool WinHttpSetOption(
  408. SafeWinHttpHandle handle,
  409. uint option,
  410. string optionData,
  411. uint optionLength)
  412. {
  413. if (option == Interop.WinHttp.WINHTTP_OPTION_PROXY_USERNAME)
  414. {
  415. APICallHistory.ProxyUsernameWithDomain = optionData;
  416. }
  417. else if (option == Interop.WinHttp.WINHTTP_OPTION_PROXY_PASSWORD)
  418. {
  419. APICallHistory.ProxyPassword = optionData;
  420. }
  421. else if (option == Interop.WinHttp.WINHTTP_OPTION_USERNAME)
  422. {
  423. APICallHistory.ServerUsernameWithDomain = optionData;
  424. }
  425. else if (option == Interop.WinHttp.WINHTTP_OPTION_PASSWORD)
  426. {
  427. APICallHistory.ServerPassword = optionData;
  428. }
  429. return true;
  430. }
  431. public static bool WinHttpSetOption(
  432. SafeWinHttpHandle handle,
  433. uint option,
  434. IntPtr optionData,
  435. uint optionLength)
  436. {
  437. if (option == Interop.WinHttp.WINHTTP_OPTION_PROXY)
  438. {
  439. var proxyInfo = Marshal.PtrToStructure<Interop.WinHttp.WINHTTP_PROXY_INFO>(optionData);
  440. var proxyInfoHistory = new APICallHistory.ProxyInfo();
  441. proxyInfoHistory.AccessType = proxyInfo.AccessType;
  442. proxyInfoHistory.Proxy = Marshal.PtrToStringUni(proxyInfo.Proxy);
  443. proxyInfoHistory.ProxyBypass = Marshal.PtrToStringUni(proxyInfo.ProxyBypass);
  444. APICallHistory.RequestProxySettings = proxyInfoHistory;
  445. }
  446. else if (option == Interop.WinHttp.WINHTTP_OPTION_CLIENT_CERT_CONTEXT)
  447. {
  448. APICallHistory.WinHttpOptionClientCertContext.Add(optionData);
  449. }
  450. return true;
  451. }
  452. public static bool WinHttpSetCredentials(
  453. SafeWinHttpHandle requestHandle,
  454. uint authTargets,
  455. uint authScheme,
  456. string userName,
  457. string password,
  458. IntPtr reserved)
  459. {
  460. return true;
  461. }
  462. public static bool WinHttpQueryAuthSchemes(
  463. SafeWinHttpHandle requestHandle,
  464. out uint supportedSchemes,
  465. out uint firstScheme,
  466. out uint authTarget)
  467. {
  468. supportedSchemes = 0;
  469. firstScheme = 0;
  470. authTarget = 0;
  471. return true;
  472. }
  473. public static bool WinHttpSetTimeouts(
  474. SafeWinHttpHandle handle,
  475. int resolveTimeout,
  476. int connectTimeout,
  477. int sendTimeout,
  478. int receiveTimeout)
  479. {
  480. return true;
  481. }
  482. public static bool WinHttpGetIEProxyConfigForCurrentUser(
  483. out Interop.WinHttp.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig)
  484. {
  485. if (FakeRegistry.WinInetProxySettings.RegistryKeyMissing)
  486. {
  487. proxyConfig.AutoDetect = false;
  488. proxyConfig.AutoConfigUrl = IntPtr.Zero;
  489. proxyConfig.Proxy = IntPtr.Zero;
  490. proxyConfig.ProxyBypass = IntPtr.Zero;
  491. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_FILE_NOT_FOUND;
  492. return false;
  493. }
  494. proxyConfig.AutoDetect = FakeRegistry.WinInetProxySettings.AutoDetect;
  495. proxyConfig.AutoConfigUrl = Marshal.StringToHGlobalUni(FakeRegistry.WinInetProxySettings.AutoConfigUrl);
  496. proxyConfig.Proxy = Marshal.StringToHGlobalUni(FakeRegistry.WinInetProxySettings.Proxy);
  497. proxyConfig.ProxyBypass = Marshal.StringToHGlobalUni(FakeRegistry.WinInetProxySettings.ProxyBypass);
  498. return true;
  499. }
  500. public static bool WinHttpGetProxyForUrl(
  501. SafeWinHttpHandle sessionHandle,
  502. string url,
  503. ref Interop.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions,
  504. out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo)
  505. {
  506. if (TestControl.PACFileNotDetectedOnNetwork)
  507. {
  508. proxyInfo.AccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  509. proxyInfo.Proxy = IntPtr.Zero;
  510. proxyInfo.ProxyBypass = IntPtr.Zero;
  511. TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED;
  512. return false;
  513. }
  514. proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  515. proxyInfo.Proxy = Marshal.StringToHGlobalUni(FakeRegistry.WinInetProxySettings.Proxy);
  516. proxyInfo.ProxyBypass = IntPtr.Zero;
  517. return true;
  518. }
  519. public static IntPtr WinHttpSetStatusCallback(
  520. SafeWinHttpHandle handle,
  521. Interop.WinHttp.WINHTTP_STATUS_CALLBACK callback,
  522. uint notificationFlags,
  523. IntPtr reserved)
  524. {
  525. if (handle == null)
  526. {
  527. throw new ArgumentNullException(nameof(handle));
  528. }
  529. var fakeHandle = (FakeSafeWinHttpHandle)handle;
  530. fakeHandle.Callback = callback;
  531. return IntPtr.Zero;
  532. }
  533. }
  534. }