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.

7097 lines
177 KiB

  1. /*
  2. * HttpRequest.cxx
  3. *
  4. * WinHttp.WinHttpRequest COM component
  5. *
  6. * Copyright (C) 2000 Microsoft Corporation. All rights reserved. *
  7. *
  8. * Much of this code was stolen from our Xml-Http friends over in
  9. * inetcore\xml\http\xmlhttp.cxx. Thanks very much!
  10. *
  11. */
  12. #include <wininetp.h>
  13. #include "httprequest.hxx"
  14. #include <olectl.h>
  15. #include "EnumConns.hxx" //IEnumConnections implementator
  16. #include "EnumCP.hxx" //IEnumConnectionPoints implementator
  17. #include "multilang.hxx"
  18. /////////////////////////////////////////////////////////////////////////////
  19. // private function prototypes
  20. static void PreWideCharToUtf8(WCHAR * buffer, UINT cch, UINT * cb, bool * bSimpleConversion);
  21. static void WideCharToUtf8(WCHAR * buffer, UINT cch, BYTE * bytebuffer, bool bSimpleConversion);
  22. static HRESULT BSTRToUTF8(char ** psz, DWORD * pcbUTF8, BSTR bstr, bool * pbSetUtf8Charset);
  23. static HRESULT AsciiToBSTR(BSTR * pbstr, char * sz, int cch);
  24. static HRESULT GetBSTRFromVariant(VARIANT varVariant, BSTR * pBstr);
  25. static BOOL GetBoolFromVariant(VARIANT varVariant, BOOL fDefault);
  26. static DWORD GetDwordFromVariant(VARIANT varVariant, DWORD dwDefault);
  27. static long GetLongFromVariant(VARIANT varVariant, long lDefault);
  28. static HRESULT CreateVector(VARIANT * pVar, const BYTE * pData, DWORD cElems);
  29. static HRESULT ReadFromStream(char ** ppData, ULONG * pcbData, IStream * pStm);
  30. static void MessageLoop();
  31. static DWORD UpdateTimeout(DWORD dwTimeout, DWORD dwStartTime);
  32. static HRESULT FillExcepInfo(HRESULT hr, EXCEPINFO * pExcepInfo);
  33. static BOOL IsValidVariant(VARIANT v);
  34. static HRESULT ParseSelectedCert(BSTR bstrSelection,
  35. LPBOOL pfLocalMachine,
  36. BSTR *pbstrStore,
  37. BSTR *pbstrSubject);
  38. static BOOL GetContentLengthIfResponseNotChunked(HINTERNET hHttpRequest,
  39. DWORD * pdwContentLength);
  40. static HRESULT SecureFailureFromStatus(DWORD dwFlags);
  41. static BOOL s_fWndClassRegistered;
  42. // Change the name of the window class for each new version of WinHTTP
  43. static const char * s_szWinHttpEventMarshallerWndClass = "_WinHttpEventMarshaller51";
  44. static CMimeInfoCache* g_pMimeInfoCache = NULL;
  45. BOOL IsValidHeaderName(LPCWSTR lpszHeaderName);
  46. #define SafeRelease(p) \
  47. { \
  48. if (p) \
  49. (p)->Release();\
  50. (p) = NULL;\
  51. }
  52. #ifndef HWND_MESSAGE
  53. #define HWND_MESSAGE ((HWND)-3)
  54. #endif
  55. #define SIZEOF_BUFFER (8192)
  56. inline BOOL IsValidBstr(BSTR bstr)
  57. {
  58. return (bstr == NULL) || (!IsBadStringPtrW(bstr, (UINT_PTR)-1));
  59. }
  60. #ifndef WINHTTP_STATIC_LIBRARY
  61. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void ** ppv)
  62. {
  63. if (rclsid != CLSID_WinHttpRequest)
  64. return CLASS_E_CLASSNOTAVAILABLE;
  65. if (!WinHttpCheckPlatform())
  66. return CLASS_E_CLASSNOTAVAILABLE;
  67. if (riid != IID_IClassFactory || ppv == NULL)
  68. return E_INVALIDARG;
  69. CClassFactory * pCF = New CClassFactory();
  70. if (pCF)
  71. {
  72. *ppv = static_cast<IClassFactory *>(pCF);
  73. pCF->AddRef();
  74. return NOERROR;
  75. }
  76. else
  77. {
  78. *ppv = NULL;
  79. return E_OUTOFMEMORY;
  80. }
  81. }
  82. CClassFactory::CClassFactory()
  83. {
  84. _cRefs = 0;
  85. InterlockedIncrement(&g_cSessionCount);
  86. }
  87. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void ** ppvObject)
  88. {
  89. if (ppvObject == NULL)
  90. return E_INVALIDARG;
  91. if (riid == IID_IClassFactory || riid == IID_IUnknown)
  92. {
  93. *ppvObject = static_cast<IClassFactory *>(this);
  94. AddRef();
  95. return NOERROR;
  96. }
  97. else
  98. return E_NOINTERFACE;
  99. }
  100. ULONG STDMETHODCALLTYPE CClassFactory::AddRef()
  101. {
  102. return ++_cRefs;
  103. }
  104. ULONG STDMETHODCALLTYPE CClassFactory::Release()
  105. {
  106. if (--_cRefs == 0)
  107. {
  108. delete this;
  109. InterlockedDecrement(&g_cSessionCount);
  110. return 0;
  111. }
  112. return _cRefs;
  113. }
  114. STDMETHODIMP
  115. CClassFactory::CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject)
  116. {
  117. if (pUnkOuter != NULL)
  118. return CLASS_E_NOAGGREGATION;
  119. if (ppvObject == NULL)
  120. return E_INVALIDARG;
  121. if( !DelayLoad(&g_moduleOle32)
  122. || !DelayLoad(&g_moduleOleAut32))
  123. {
  124. return E_UNEXPECTED;
  125. }
  126. return CreateHttpRequest(riid, ppvObject);
  127. }
  128. STDMETHODIMP
  129. CClassFactory::LockServer(BOOL fLock)
  130. {
  131. if (fLock)
  132. InterlockedIncrement(&g_cSessionCount);
  133. else
  134. InterlockedDecrement(&g_cSessionCount);
  135. return NOERROR;
  136. }
  137. STDAPI DllCanUnloadNow()
  138. {
  139. return ((g_cSessionCount == 0) && (g_pAsyncCount == NULL || g_pAsyncCount->GetRef() == 0)) ? S_OK : S_FALSE;
  140. }
  141. #else
  142. STDAPI WinHttpCreateHttpRequestComponent(REFIID riid, void ** ppvObject)
  143. {
  144. return CreateHttpRequest(riid, ppvObject);
  145. }
  146. #endif //WINHTTP_STATIC_LIBRARY
  147. STDMETHODIMP
  148. CreateHttpRequest(REFIID riid, void ** ppvObject)
  149. {
  150. CHttpRequest * pHttpRequest = New CHttpRequest();
  151. HRESULT hr;
  152. if (pHttpRequest)
  153. {
  154. hr = pHttpRequest->QueryInterface(riid, ppvObject);
  155. if (FAILED(hr))
  156. {
  157. delete pHttpRequest;
  158. }
  159. }
  160. else
  161. hr = E_OUTOFMEMORY;
  162. return hr;
  163. }
  164. /*
  165. * CHttpRequest::CHttpRequest constructor
  166. *
  167. */
  168. CHttpRequest::CHttpRequest()
  169. {
  170. InterlockedIncrement(&g_cSessionCount);
  171. Initialize();
  172. }
  173. /*
  174. * CHttpRequest::~CHttpRequest destructor
  175. *
  176. */
  177. CHttpRequest::~CHttpRequest()
  178. {
  179. ReleaseResources();
  180. InterlockedDecrement(&g_cSessionCount);
  181. }
  182. #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
  183. const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
  184. MIDL_DEFINE_GUID(IID, IID_IWinHttpRequest_TechBeta,0x06f29373,0x5c5a,0x4b54,0xb0,0x25,0x6e,0xf1,0xbf,0x8a,0xbf,0x0e);
  185. MIDL_DEFINE_GUID(IID, IID_IWinHttpRequestEvents_TechBeta,0xcff7bd4c,0x6689,0x4bbe,0x91,0xc2,0x0f,0x55,0x9e,0x8b,0x88,0xa7);
  186. HRESULT STDMETHODCALLTYPE
  187. CHttpRequest::QueryInterface(REFIID riid, void ** ppv)
  188. {
  189. HRESULT hr = NOERROR;
  190. if (ppv == NULL)
  191. {
  192. hr = E_INVALIDARG;
  193. }
  194. else if (riid == IID_IWinHttpRequest ||
  195. riid == IID_IDispatch ||
  196. riid == IID_IWinHttpRequest_TechBeta ||
  197. riid == IID_IUnknown)
  198. {
  199. *ppv = static_cast<IWinHttpRequest *>(this);
  200. AddRef();
  201. }
  202. else if (riid == IID_IConnectionPointContainer)
  203. {
  204. *ppv = static_cast<IConnectionPointContainer *>(this);
  205. AddRef();
  206. }
  207. else if (riid == IID_ISupportErrorInfo)
  208. {
  209. *ppv = static_cast<ISupportErrorInfo *>(this);
  210. AddRef();
  211. }
  212. else if (riid == IID_IProvideClassInfo)
  213. {
  214. *ppv = static_cast<IProvideClassInfo *>(static_cast<IProvideClassInfo2 *>(this));
  215. AddRef();
  216. }
  217. else if (riid == IID_IProvideClassInfo2)
  218. {
  219. *ppv = static_cast<IProvideClassInfo2 *>(this);
  220. AddRef();
  221. }
  222. else
  223. hr = E_NOINTERFACE;
  224. return hr;
  225. }
  226. ULONG STDMETHODCALLTYPE
  227. CHttpRequest::AddRef()
  228. {
  229. if (GetCurrentThreadId() == _dwMainThreadId)
  230. ++_cRefsOnMainThread;
  231. return InterlockedIncrement(&_cRefs);
  232. }
  233. ULONG STDMETHODCALLTYPE
  234. CHttpRequest::Release()
  235. {
  236. if (GetCurrentThreadId() == _dwMainThreadId)
  237. {
  238. if ((--_cRefsOnMainThread == 0) && _fAsync)
  239. {
  240. // Clean up the Event Marshaller. This must be done
  241. // on the main thread.
  242. _CP.ShutdownEventSinksMarshaller();
  243. // If the worker thread is still running, abort it
  244. // and wait for it to run down.
  245. Abort();
  246. }
  247. }
  248. DWORD cRefs = InterlockedDecrement(&_cRefs);
  249. if (cRefs == 0)
  250. {
  251. delete this;
  252. return 0;
  253. }
  254. else
  255. return cRefs;
  256. }
  257. HRESULT
  258. CHttpRequest::GetHttpRequestTypeInfo(REFGUID guid, ITypeInfo ** ppTypeInfo)
  259. {
  260. HRESULT hr = NOERROR;
  261. ITypeLib * pTypeLib;
  262. char szPath[MAX_PATH+1];
  263. OLECHAR wszPath[MAX_PATH+1];
  264. GetModuleFileName(GlobalDllHandle, szPath, sizeof(szPath)-1); // leave room for null char
  265. szPath[sizeof(szPath)-1] = '\0'; // guarantee null-termination
  266. MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
  267. hr = DL(LoadTypeLib)(wszPath, &pTypeLib);
  268. if (SUCCEEDED(hr))
  269. {
  270. hr = pTypeLib->GetTypeInfoOfGuid(guid, ppTypeInfo);
  271. pTypeLib->Release();
  272. }
  273. return hr;
  274. }
  275. STDMETHODIMP
  276. CHttpRequest::GetTypeInfoCount(UINT * pctinfo)
  277. {
  278. if (!pctinfo)
  279. return E_INVALIDARG;
  280. *pctinfo = 1;
  281. return NOERROR;
  282. }
  283. STDMETHODIMP
  284. CHttpRequest::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo)
  285. {
  286. if (!ppTInfo)
  287. return E_INVALIDARG;
  288. *ppTInfo = NULL;
  289. if (iTInfo != 0)
  290. return DISP_E_BADINDEX;
  291. if (!_pTypeInfo)
  292. {
  293. HRESULT hr = GetHttpRequestTypeInfo(IID_IWinHttpRequest, &_pTypeInfo);
  294. if (FAILED(hr))
  295. return hr;
  296. }
  297. *ppTInfo = _pTypeInfo;
  298. _pTypeInfo->AddRef();
  299. return NOERROR;
  300. }
  301. struct IDMAPPING
  302. {
  303. const OLECHAR * wszMemberName;
  304. DISPID dispId;
  305. };
  306. static const IDMAPPING IdMapping[] =
  307. {
  308. { L"Open", DISPID_HTTPREQUEST_OPEN },
  309. { L"SetRequestHeader", DISPID_HTTPREQUEST_SETREQUESTHEADER },
  310. { L"Send", DISPID_HTTPREQUEST_SEND },
  311. { L"Status", DISPID_HTTPREQUEST_STATUS },
  312. { L"WaitForResponse", DISPID_HTTPREQUEST_WAITFORRESPONSE },
  313. { L"GetResponseHeader", DISPID_HTTPREQUEST_GETRESPONSEHEADER },
  314. { L"ResponseBody", DISPID_HTTPREQUEST_RESPONSEBODY },
  315. { L"ResponseText", DISPID_HTTPREQUEST_RESPONSETEXT },
  316. { L"ResponseStream", DISPID_HTTPREQUEST_RESPONSESTREAM },
  317. { L"StatusText", DISPID_HTTPREQUEST_STATUSTEXT },
  318. { L"SetAutoLogonPolicy", DISPID_HTTPREQUEST_SETAUTOLOGONPOLICY },
  319. { L"SetClientCertificate", DISPID_HTTPREQUEST_SETCLIENTCERTIFICATE },
  320. { L"SetCredentials", DISPID_HTTPREQUEST_SETCREDENTIALS },
  321. { L"SetProxy", DISPID_HTTPREQUEST_SETPROXY },
  322. { L"GetAllResponseHeaders", DISPID_HTTPREQUEST_GETALLRESPONSEHEADERS },
  323. { L"Abort", DISPID_HTTPREQUEST_ABORT },
  324. { L"SetTimeouts", DISPID_HTTPREQUEST_SETTIMEOUTS },
  325. { L"Option", DISPID_HTTPREQUEST_OPTION }
  326. };
  327. STDMETHODIMP
  328. CHttpRequest::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames,
  329. UINT cNames,
  330. LCID ,
  331. DISPID * rgDispId)
  332. {
  333. if (riid != IID_NULL)
  334. return E_INVALIDARG;
  335. HRESULT hr = NOERROR;
  336. if (cNames > 0)
  337. {
  338. hr = DISP_E_UNKNOWNNAME;
  339. for (int i = 0; i < (sizeof(IdMapping)/sizeof(IdMapping[0])); i++)
  340. {
  341. if (StrCmpIW(rgszNames[0], IdMapping[i].wszMemberName) == 0)
  342. {
  343. hr = NOERROR;
  344. rgDispId[0] = IdMapping[i].dispId;
  345. break;
  346. }
  347. }
  348. }
  349. return hr;
  350. }
  351. // _DispGetParamSafe
  352. //
  353. // A wrapper around the OLE Automation DispGetParam API that protects
  354. // the call with a __try/__except block. Needed for casting to BSTR,
  355. // as bogus BSTR pointers can cause an AV in VariantChangeType (which
  356. // DispGetParam calls).
  357. //
  358. static HRESULT _DispGetParamSafe
  359. (
  360. DISPPARAMS * pDispParams,
  361. DISPID dispid,
  362. VARTYPE vt,
  363. VARIANT * pvarResult,
  364. unsigned int * puArgErr
  365. )
  366. {
  367. HRESULT hr;
  368. __try
  369. {
  370. hr = DL(DispGetParam)(pDispParams, dispid, vt, pvarResult, puArgErr);
  371. }
  372. __except (EXCEPTION_EXECUTE_HANDLER)
  373. {
  374. hr = E_INVALIDARG;
  375. }
  376. return hr;
  377. }
  378. // _DispGetOptionalParam
  379. //
  380. // Helper routine to fetch optional parameters. If DL(DispGetParam) returns
  381. // DISP_E_PARAMNOTFOUND, the error is converted to NOERROR.
  382. //
  383. static inline HRESULT _DispGetOptionalParam
  384. (
  385. DISPPARAMS * pDispParams,
  386. DISPID dispid,
  387. VARTYPE vt,
  388. VARIANT * pvarResult,
  389. unsigned int * puArgErr
  390. )
  391. {
  392. HRESULT hr = _DispGetParamSafe(pDispParams, dispid, vt, pvarResult, puArgErr);
  393. return (hr == DISP_E_PARAMNOTFOUND) ? NOERROR : hr;
  394. }
  395. STDMETHODIMP
  396. CHttpRequest::Invoke(DISPID dispIdMember, REFIID riid,
  397. LCID,
  398. WORD wFlags,
  399. DISPPARAMS * pDispParams,
  400. VARIANT * pVarResult,
  401. EXCEPINFO * pExcepInfo,
  402. UINT * puArgErr)
  403. {
  404. HRESULT hr = NOERROR;
  405. unsigned int uArgErr;
  406. if (wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT))
  407. return E_INVALIDARG;
  408. if (riid != IID_NULL)
  409. return DISP_E_UNKNOWNINTERFACE;
  410. if (IsBadReadPtr(pDispParams, sizeof(DISPPARAMS)))
  411. return E_INVALIDARG;
  412. if (!puArgErr)
  413. {
  414. puArgErr = &uArgErr;
  415. }
  416. else if (IsBadWritePtr(puArgErr, sizeof(UINT)))
  417. {
  418. return E_INVALIDARG;
  419. }
  420. if (pVarResult)
  421. {
  422. if (IsBadWritePtr(pVarResult, sizeof(VARIANT)))
  423. return E_INVALIDARG;
  424. DL(VariantInit)(pVarResult);
  425. }
  426. switch (dispIdMember)
  427. {
  428. case DISPID_HTTPREQUEST_ABORT:
  429. {
  430. hr = Abort();
  431. break;
  432. }
  433. case DISPID_HTTPREQUEST_SETPROXY:
  434. {
  435. VARIANT varProxySetting;
  436. VARIANT varProxyServer;
  437. VARIANT varBypassList;
  438. DL(VariantInit)(&varProxySetting);
  439. DL(VariantInit)(&varProxyServer);
  440. DL(VariantInit)(&varBypassList);
  441. hr = DL(DispGetParam)(pDispParams, 0, VT_I4, &varProxySetting, puArgErr);
  442. if (SUCCEEDED(hr))
  443. {
  444. hr = _DispGetOptionalParam(pDispParams, 1, VT_BSTR, &varProxyServer, puArgErr);
  445. }
  446. if (SUCCEEDED(hr))
  447. {
  448. hr = _DispGetOptionalParam(pDispParams, 2, VT_BSTR, &varBypassList, puArgErr);
  449. }
  450. if (SUCCEEDED(hr))
  451. {
  452. hr = SetProxy(V_I4(&varProxySetting), varProxyServer, varBypassList);
  453. }
  454. DL(VariantClear)(&varProxySetting);
  455. DL(VariantClear)(&varProxyServer);
  456. DL(VariantClear)(&varBypassList);
  457. break;
  458. }
  459. case DISPID_HTTPREQUEST_SETCREDENTIALS:
  460. {
  461. VARIANT varUserName;
  462. VARIANT varPassword;
  463. VARIANT varAuthTarget;
  464. DL(VariantInit)(&varUserName);
  465. DL(VariantInit)(&varPassword);
  466. DL(VariantInit)(&varAuthTarget);
  467. hr = _DispGetParamSafe(pDispParams, 0, VT_BSTR, &varUserName, puArgErr);
  468. if (SUCCEEDED(hr))
  469. {
  470. hr = _DispGetParamSafe(pDispParams, 1, VT_BSTR, &varPassword, puArgErr);
  471. }
  472. if (SUCCEEDED(hr))
  473. {
  474. hr = DL(DispGetParam)(pDispParams, 2, VT_I4, &varAuthTarget, puArgErr);
  475. }
  476. if (SUCCEEDED(hr))
  477. {
  478. hr = SetCredentials(V_BSTR(&varUserName), V_BSTR(&varPassword),
  479. V_I4(&varAuthTarget));
  480. }
  481. DL(VariantClear)(&varUserName);
  482. DL(VariantClear)(&varPassword);
  483. DL(VariantClear)(&varAuthTarget);
  484. break;
  485. }
  486. case DISPID_HTTPREQUEST_OPEN:
  487. {
  488. VARIANT varMethod;
  489. VARIANT varUrl;
  490. VARIANT varAsync;
  491. DL(VariantInit)(&varMethod);
  492. DL(VariantInit)(&varUrl);
  493. DL(VariantInit)(&varAsync);
  494. hr = _DispGetParamSafe(pDispParams, 0, VT_BSTR, &varMethod, puArgErr);
  495. if (SUCCEEDED(hr))
  496. {
  497. hr = _DispGetParamSafe(pDispParams, 1, VT_BSTR, &varUrl, puArgErr);
  498. }
  499. if (SUCCEEDED(hr))
  500. {
  501. hr = _DispGetOptionalParam(pDispParams, 2, VT_BOOL, &varAsync, puArgErr);
  502. }
  503. if (SUCCEEDED(hr))
  504. {
  505. hr = Open(V_BSTR(&varMethod), V_BSTR(&varUrl), varAsync);
  506. }
  507. DL(VariantClear)(&varMethod);
  508. DL(VariantClear)(&varUrl);
  509. DL(VariantClear)(&varAsync);
  510. break;
  511. }
  512. case DISPID_HTTPREQUEST_SETREQUESTHEADER:
  513. {
  514. VARIANT varHeader;
  515. VARIANT varValue;
  516. DL(VariantInit)(&varHeader);
  517. DL(VariantInit)(&varValue);
  518. hr = _DispGetParamSafe(pDispParams, 0, VT_BSTR, &varHeader, puArgErr);
  519. if (SUCCEEDED(hr))
  520. {
  521. hr = _DispGetParamSafe(pDispParams, 1, VT_BSTR, &varValue, puArgErr);
  522. }
  523. if (SUCCEEDED(hr))
  524. {
  525. hr = SetRequestHeader(V_BSTR(&varHeader), V_BSTR(&varValue));
  526. }
  527. DL(VariantClear)(&varHeader);
  528. DL(VariantClear)(&varValue);
  529. break;
  530. }
  531. case DISPID_HTTPREQUEST_GETRESPONSEHEADER:
  532. {
  533. VARIANT varHeader;
  534. DL(VariantInit)(&varHeader);
  535. hr = _DispGetParamSafe(pDispParams, 0, VT_BSTR, &varHeader, puArgErr);
  536. if (SUCCEEDED(hr))
  537. {
  538. BSTR bstrValue = NULL;
  539. hr = GetResponseHeader(V_BSTR(&varHeader), &bstrValue);
  540. if (SUCCEEDED(hr) && pVarResult)
  541. {
  542. V_VT(pVarResult) = VT_BSTR;
  543. V_BSTR(pVarResult) = bstrValue;
  544. }
  545. else
  546. DL(SysFreeString)(bstrValue);
  547. }
  548. DL(VariantClear)(&varHeader);
  549. break;
  550. }
  551. case DISPID_HTTPREQUEST_GETALLRESPONSEHEADERS:
  552. {
  553. BSTR bstrResponseHeaders = NULL;
  554. hr = GetAllResponseHeaders(&bstrResponseHeaders);
  555. if (SUCCEEDED(hr) && pVarResult)
  556. {
  557. V_VT(pVarResult) = VT_BSTR;
  558. V_BSTR(pVarResult) = bstrResponseHeaders;
  559. }
  560. else
  561. DL(SysFreeString)(bstrResponseHeaders);
  562. break;
  563. }
  564. case DISPID_HTTPREQUEST_SEND:
  565. {
  566. if (pDispParams->cArgs <= 1)
  567. {
  568. VARIANT varEmptyBody;
  569. DL(VariantInit)(&varEmptyBody);
  570. hr = Send((pDispParams->cArgs == 0) ? varEmptyBody : pDispParams->rgvarg[0]);
  571. }
  572. else
  573. {
  574. hr = DISP_E_BADPARAMCOUNT;
  575. }
  576. break;
  577. }
  578. case DISPID_HTTPREQUEST_STATUS:
  579. {
  580. long Status;
  581. hr = get_Status(&Status);
  582. if (SUCCEEDED(hr) && pVarResult)
  583. {
  584. V_VT(pVarResult) = VT_I4;
  585. V_I4(pVarResult) = Status;
  586. }
  587. break;
  588. }
  589. case DISPID_HTTPREQUEST_STATUSTEXT:
  590. {
  591. BSTR bstrStatus = NULL;
  592. hr = get_StatusText(&bstrStatus);
  593. if (SUCCEEDED(hr) && pVarResult)
  594. {
  595. V_VT(pVarResult) = VT_BSTR;
  596. V_BSTR(pVarResult) = bstrStatus;
  597. }
  598. else
  599. DL(SysFreeString)(bstrStatus);
  600. break;
  601. }
  602. case DISPID_HTTPREQUEST_RESPONSETEXT:
  603. {
  604. BSTR bstrResponse = NULL;
  605. hr = get_ResponseText(&bstrResponse);
  606. if (SUCCEEDED(hr) && pVarResult)
  607. {
  608. V_VT(pVarResult) = VT_BSTR;
  609. V_BSTR(pVarResult) = bstrResponse;
  610. }
  611. else
  612. DL(SysFreeString)(bstrResponse);
  613. break;
  614. }
  615. case DISPID_HTTPREQUEST_RESPONSEBODY:
  616. {
  617. if (pVarResult)
  618. {
  619. hr = get_ResponseBody(pVarResult);
  620. }
  621. break;
  622. }
  623. case DISPID_HTTPREQUEST_RESPONSESTREAM:
  624. {
  625. if (pVarResult)
  626. {
  627. hr = get_ResponseStream(pVarResult);
  628. }
  629. break;
  630. }
  631. case DISPID_HTTPREQUEST_OPTION:
  632. {
  633. VARIANT varOption;
  634. WinHttpRequestOption Option;
  635. DL(VariantInit)(&varOption);
  636. hr = DL(DispGetParam)(pDispParams, 0, VT_I4, &varOption, puArgErr);
  637. if (FAILED(hr))
  638. break;
  639. Option = static_cast<WinHttpRequestOption>(V_I4(&varOption));
  640. if (wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET))
  641. {
  642. if (pVarResult)
  643. {
  644. hr = get_Option(Option, pVarResult);
  645. }
  646. }
  647. else if (wFlags & DISPATCH_PROPERTYPUT)
  648. {
  649. hr = put_Option(Option, pDispParams->rgvarg[0]);
  650. }
  651. DL(VariantClear)(&varOption);
  652. break;
  653. }
  654. case DISPID_HTTPREQUEST_WAITFORRESPONSE:
  655. {
  656. VARIANT varTimeout;
  657. VARIANT_BOOL boolSucceeded = FALSE;
  658. DL(VariantInit)(&varTimeout);
  659. hr = _DispGetOptionalParam(pDispParams, 0, VT_I4, &varTimeout, puArgErr);
  660. if (SUCCEEDED(hr))
  661. {
  662. hr = WaitForResponse(varTimeout, &boolSucceeded);
  663. }
  664. if (pVarResult)
  665. {
  666. V_VT(pVarResult) = VT_BOOL;
  667. V_BOOL(pVarResult) = boolSucceeded;
  668. }
  669. DL(VariantClear)(&varTimeout);
  670. break;
  671. }
  672. case DISPID_HTTPREQUEST_SETTIMEOUTS:
  673. {
  674. VARIANT varResolveTimeout;
  675. VARIANT varConnectTimeout;
  676. VARIANT varSendTimeout;
  677. VARIANT varReceiveTimeout;
  678. DL(VariantInit)(&varResolveTimeout);
  679. DL(VariantInit)(&varConnectTimeout);
  680. DL(VariantInit)(&varSendTimeout);
  681. DL(VariantInit)(&varReceiveTimeout);
  682. hr = DL(DispGetParam)(pDispParams, 0, VT_I4, &varResolveTimeout, puArgErr);
  683. if (SUCCEEDED(hr))
  684. {
  685. hr = DL(DispGetParam)(pDispParams, 1, VT_I4, &varConnectTimeout, puArgErr);
  686. }
  687. if (SUCCEEDED(hr))
  688. {
  689. hr = DL(DispGetParam)(pDispParams, 2, VT_I4, &varSendTimeout, puArgErr);
  690. }
  691. if (SUCCEEDED(hr))
  692. {
  693. hr = DL(DispGetParam)(pDispParams, 3, VT_I4, &varReceiveTimeout, puArgErr);
  694. }
  695. if (SUCCEEDED(hr))
  696. {
  697. hr = SetTimeouts(V_I4(&varResolveTimeout), V_I4(&varConnectTimeout),
  698. V_I4(&varSendTimeout),
  699. V_I4(&varReceiveTimeout));
  700. }
  701. DL(VariantClear)(&varResolveTimeout);
  702. DL(VariantClear)(&varConnectTimeout);
  703. DL(VariantClear)(&varSendTimeout);
  704. DL(VariantClear)(&varReceiveTimeout);
  705. break;
  706. }
  707. case DISPID_HTTPREQUEST_SETCLIENTCERTIFICATE:
  708. {
  709. VARIANT varClientCertificate;
  710. DL(VariantInit)(&varClientCertificate);
  711. hr = _DispGetParamSafe(pDispParams, 0, VT_BSTR, &varClientCertificate, puArgErr);
  712. if (SUCCEEDED(hr))
  713. {
  714. hr = SetClientCertificate(V_BSTR(&varClientCertificate));
  715. }
  716. DL(VariantClear)(&varClientCertificate);
  717. break;
  718. }
  719. case DISPID_HTTPREQUEST_SETAUTOLOGONPOLICY:
  720. {
  721. VARIANT varAutoLogonPolicy;
  722. DL(VariantInit)(&varAutoLogonPolicy);
  723. hr = DL(DispGetParam)(pDispParams, 0, VT_I4, &varAutoLogonPolicy, puArgErr);
  724. if (SUCCEEDED(hr))
  725. {
  726. WinHttpRequestAutoLogonPolicy AutoLogonPolicy;
  727. AutoLogonPolicy = static_cast<WinHttpRequestAutoLogonPolicy>(V_I4(&varAutoLogonPolicy));
  728. hr = SetAutoLogonPolicy(AutoLogonPolicy);
  729. }
  730. DL(VariantClear)(&varAutoLogonPolicy);
  731. break;
  732. }
  733. default:
  734. hr = DISP_E_MEMBERNOTFOUND;
  735. break;
  736. }
  737. if (FAILED(hr) && (pExcepInfo != NULL))
  738. {
  739. hr = FillExcepInfo(hr, pExcepInfo);
  740. }
  741. return hr;
  742. }
  743. static
  744. HRESULT
  745. FillExcepInfo(HRESULT hr, EXCEPINFO * pExcepInfo)
  746. {
  747. // Don't create excepinfo for these errors to mimic oleaut behavior.
  748. if( hr == DISP_E_BADPARAMCOUNT ||
  749. hr == DISP_E_NONAMEDARGS ||
  750. hr == DISP_E_MEMBERNOTFOUND ||
  751. hr == E_INVALIDARG)
  752. {
  753. return hr;
  754. }
  755. // clear out exception info
  756. IErrorInfo * pei = NULL;
  757. pExcepInfo->wCode = 0;
  758. pExcepInfo->scode = hr;
  759. // if error info exists, use it
  760. DL(GetErrorInfo)(0, &pei);
  761. if (pei)
  762. {
  763. // give back to OLE
  764. DL(SetErrorInfo)(0, pei);
  765. pei->GetHelpContext(&pExcepInfo->dwHelpContext);
  766. pei->GetSource(&pExcepInfo->bstrSource);
  767. pei->GetDescription(&pExcepInfo->bstrDescription);
  768. pei->GetHelpFile(&pExcepInfo->bstrHelpFile);
  769. // give complete ownership to OLEAUT
  770. pei->Release();
  771. hr = DISP_E_EXCEPTION;
  772. }
  773. return hr;
  774. }
  775. STDMETHODIMP
  776. CHttpRequest::InterfaceSupportsErrorInfo(REFIID riid)
  777. {
  778. return (riid == IID_IWinHttpRequest) ? S_OK : S_FALSE;
  779. }
  780. STDMETHODIMP
  781. CHttpRequest::GetClassInfo(ITypeInfo ** ppTI)
  782. {
  783. if (!ppTI)
  784. return E_POINTER;
  785. *ppTI = NULL;
  786. return GetHttpRequestTypeInfo(CLSID_WinHttpRequest, ppTI);
  787. }
  788. STDMETHODIMP
  789. CHttpRequest::GetGUID(DWORD dwGuidKind, GUID * pGUID)
  790. {
  791. if (!pGUID)
  792. return E_POINTER;
  793. if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID)
  794. {
  795. *pGUID = IID_IWinHttpRequestEvents;
  796. }
  797. else
  798. return E_INVALIDARG;
  799. return NOERROR;
  800. }
  801. STDMETHODIMP
  802. CHttpRequest::EnumConnectionPoints(IEnumConnectionPoints ** ppEnum)
  803. {
  804. if (!ppEnum)
  805. return E_POINTER;
  806. *ppEnum = static_cast<IEnumConnectionPoints*>(
  807. new CEnumConnectionPoints(static_cast<IConnectionPoint*>(&_CP))
  808. );
  809. return (*ppEnum) ? S_OK : E_OUTOFMEMORY;
  810. }
  811. STDMETHODIMP
  812. CHttpRequest::FindConnectionPoint(REFIID riid, IConnectionPoint ** ppCP)
  813. {
  814. if (!ppCP)
  815. return E_POINTER;
  816. if (riid == IID_IWinHttpRequestEvents)
  817. {
  818. return _CP.QueryInterface(IID_IConnectionPoint, (void **)ppCP);
  819. }
  820. else if (riid == IID_IWinHttpRequestEvents_TechBeta)
  821. {
  822. _CP.DisableOnError();
  823. return _CP.QueryInterface(IID_IConnectionPoint, (void **)ppCP);
  824. }
  825. else
  826. return CONNECT_E_NOCONNECTION;
  827. }
  828. STDMETHODIMP
  829. CHttpRequest::CHttpRequestEventsCP::QueryInterface(REFIID riid, void ** ppvObject)
  830. {
  831. if (!ppvObject)
  832. return E_INVALIDARG;
  833. if (riid == IID_IUnknown || riid == IID_IConnectionPoint)
  834. {
  835. *ppvObject = static_cast<IUnknown *>(static_cast<IConnectionPoint *>(this));
  836. AddRef();
  837. return NOERROR;
  838. }
  839. return E_NOINTERFACE;
  840. }
  841. ULONG STDMETHODCALLTYPE
  842. CHttpRequest::CHttpRequestEventsCP::AddRef()
  843. {
  844. return Px()->AddRef();
  845. }
  846. ULONG STDMETHODCALLTYPE
  847. CHttpRequest::CHttpRequestEventsCP::Release()
  848. {
  849. return Px()->Release();
  850. }
  851. STDMETHODIMP
  852. CHttpRequest::CHttpRequestEventsCP::GetConnectionInterface(IID * pIID)
  853. {
  854. if (!pIID)
  855. return E_POINTER;
  856. *pIID = IID_IWinHttpRequestEvents;
  857. return NOERROR;
  858. }
  859. STDMETHODIMP
  860. CHttpRequest::CHttpRequestEventsCP::GetConnectionPointContainer
  861. (
  862. IConnectionPointContainer ** ppCPC
  863. )
  864. {
  865. if (!ppCPC)
  866. return E_POINTER;
  867. return Px()->QueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
  868. }
  869. STDMETHODIMP
  870. CHttpRequest::CHttpRequestEventsCP::Advise(IUnknown * pUnk, DWORD * pdwCookie)
  871. {
  872. if (!pUnk || !pdwCookie)
  873. {
  874. return E_POINTER;
  875. }
  876. IWinHttpRequestEvents * pIWinHttpRequestEvents;
  877. HRESULT hr;
  878. hr = pUnk->QueryInterface(IID_IWinHttpRequestEvents, (void **)&pIWinHttpRequestEvents);
  879. // RENO 39279: if the QI for IWinHttpRequestEvents fails, try the older
  880. // IID from the Tech Beta.
  881. if (FAILED(hr))
  882. {
  883. hr = pUnk->QueryInterface(IID_IWinHttpRequestEvents_TechBeta, (void **)&pIWinHttpRequestEvents);
  884. if (SUCCEEDED(hr))
  885. {
  886. // The OnError event should have already been disabled in
  887. // CHttpRequest::FindConnectionPoint(), but it doesn't
  888. // hurt to be paranoid.
  889. DisableOnError();
  890. }
  891. }
  892. if (SUCCEEDED(hr))
  893. {
  894. *pdwCookie = _SinkArray.Add(static_cast<IUnknown *>(pIWinHttpRequestEvents));
  895. if (*pdwCookie)
  896. {
  897. _cConnections++;
  898. hr = NOERROR;
  899. }
  900. else
  901. {
  902. hr = E_OUTOFMEMORY;
  903. }
  904. }
  905. else
  906. hr = CONNECT_E_CANNOTCONNECT;
  907. return hr;
  908. }
  909. STDMETHODIMP
  910. CHttpRequest::CHttpRequestEventsCP::Unadvise(DWORD dwCookie)
  911. {
  912. IUnknown * pSink = _SinkArray.GetUnknown(dwCookie);
  913. if (pSink)
  914. {
  915. _SinkArray.Remove(dwCookie);
  916. pSink->Release();
  917. --_cConnections;
  918. }
  919. return NOERROR;
  920. }
  921. STDMETHODIMP
  922. CHttpRequest::CHttpRequestEventsCP::EnumConnections(IEnumConnections ** ppEnum)
  923. {
  924. if (!ppEnum)
  925. return E_POINTER;
  926. *ppEnum = NULL;
  927. DWORD_PTR size = _SinkArray.end() - _SinkArray.begin();
  928. CONNECTDATA* pCD = NULL;
  929. if (size != 0)
  930. {
  931. //allocate data on stack, we usually expect just 1 or few connections,
  932. //so it's ok to allocate such ammount of data on stack
  933. __try
  934. {
  935. pCD = (CONNECTDATA*)_alloca(size * sizeof(CONNECTDATA[1]));
  936. }
  937. __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  938. {
  939. return E_OUTOFMEMORY;
  940. }
  941. }
  942. IUnknown** ppUnk = _SinkArray.begin();
  943. for (DWORD i = 0; i < size; ++i)
  944. {
  945. pCD[i].pUnk = ppUnk[i];
  946. pCD[i].dwCookie = i + 1;
  947. }
  948. CEnumConnections* pE = new CEnumConnections();
  949. if (pE)
  950. {
  951. HRESULT hr = pE->Init(pCD, (DWORD)size);
  952. if ( SUCCEEDED(hr) )
  953. *ppEnum = static_cast<IEnumConnections*>(pE);
  954. else
  955. delete pE;
  956. return hr;
  957. }
  958. else
  959. return E_OUTOFMEMORY;
  960. }
  961. void
  962. CHttpRequest::CHttpRequestEventsCP::FireOnResponseStart(long Status, BSTR ContentType)
  963. {
  964. if (_cConnections > 0 && !Px()->_bAborted)
  965. {
  966. GetSink()->OnResponseStart(Status, ContentType);
  967. }
  968. }
  969. void
  970. CHttpRequest::CHttpRequestEventsCP::FireOnResponseDataAvailable
  971. (
  972. const BYTE * rgbData,
  973. DWORD cbData
  974. )
  975. {
  976. if (_cConnections > 0 && !Px()->_bAborted)
  977. {
  978. VARIANT varData;
  979. HRESULT hr;
  980. DL(VariantInit)(&varData);
  981. hr = CreateVector(&varData, rgbData, cbData);
  982. if (SUCCEEDED(hr))
  983. {
  984. GetSink()->OnResponseDataAvailable(&V_ARRAY(&varData));
  985. }
  986. DL(VariantClear)(&varData);
  987. }
  988. }
  989. void
  990. CHttpRequest::CHttpRequestEventsCP::FireOnResponseFinished()
  991. {
  992. if (_cConnections > 0 && !Px()->_bAborted)
  993. {
  994. GetSink()->OnResponseFinished();
  995. }
  996. }
  997. void
  998. CHttpRequest::CHttpRequestEventsCP::FireOnError(HRESULT hr)
  999. {
  1000. if ((_cConnections > 0) && (!Px()->_bAborted) && (!_bOnErrorDisabled))
  1001. {
  1002. IErrorInfo * pErrorInfo = CreateErrorObject(hr);
  1003. BSTR bstrErrorDescription = NULL;
  1004. if (pErrorInfo)
  1005. {
  1006. pErrorInfo->GetDescription(&bstrErrorDescription);
  1007. pErrorInfo->Release();
  1008. }
  1009. GetSink()->OnError((long) hr, bstrErrorDescription);
  1010. DL(SysFreeString)(bstrErrorDescription);
  1011. }
  1012. }
  1013. HRESULT
  1014. CHttpRequest::CHttpRequestEventsCP::CreateEventSinksMarshaller()
  1015. {
  1016. HRESULT hr = NOERROR;
  1017. if (_cConnections > 0)
  1018. {
  1019. SafeRelease(_pSinkMarshaller);
  1020. hr = CWinHttpRequestEventsMarshaller::Create(&_SinkArray, &_pSinkMarshaller);
  1021. }
  1022. return hr;
  1023. }
  1024. void
  1025. CHttpRequest::CHttpRequestEventsCP::ShutdownEventSinksMarshaller()
  1026. {
  1027. if (_pSinkMarshaller)
  1028. _pSinkMarshaller->Shutdown();
  1029. }
  1030. void
  1031. CHttpRequest::CHttpRequestEventsCP::ReleaseEventSinksMarshaller()
  1032. {
  1033. SafeRelease(_pSinkMarshaller);
  1034. }
  1035. void
  1036. CHttpRequest::CHttpRequestEventsCP::FreezeEvents()
  1037. {
  1038. if (_pSinkMarshaller)
  1039. _pSinkMarshaller->FreezeEvents();
  1040. }
  1041. void
  1042. CHttpRequest::CHttpRequestEventsCP::UnfreezeEvents()
  1043. {
  1044. if (_pSinkMarshaller)
  1045. _pSinkMarshaller->UnfreezeEvents();
  1046. }
  1047. CHttpRequest::CHttpRequestEventsCP::~CHttpRequestEventsCP()
  1048. {
  1049. // If any connections are still alive, unadvise them.
  1050. if (_cConnections > 0)
  1051. {
  1052. _SinkArray.ReleaseAll();
  1053. _cConnections = 0;
  1054. }
  1055. }
  1056. /*
  1057. * CHttpRequest::Initialize
  1058. *
  1059. * Purpose:
  1060. * Zero all data members
  1061. *
  1062. */
  1063. void
  1064. CHttpRequest::Initialize()
  1065. {
  1066. _cRefs = 0;
  1067. _pTypeInfo = NULL;
  1068. _bstrUserAgent = NULL;
  1069. _dwProxySetting = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
  1070. _bstrProxyServer = NULL;
  1071. _bstrBypassList = NULL;
  1072. _eState = CHttpRequest::CREATED;
  1073. _fAsync = FALSE;
  1074. #if !defined(TRUE_ASYNC)
  1075. _hWorkerThread = NULL;
  1076. #endif//!TRUE_ASYNC
  1077. _cRefsOnMainThread = 0;
  1078. _dwMainThreadId = GetCurrentThreadId();
  1079. _hrAsyncResult = NOERROR;
  1080. _bAborted = false;
  1081. _bSetTimeouts = false;
  1082. _bSetUtf8Charset = false;
  1083. _hInet = NULL;
  1084. _hConnection = NULL;
  1085. _hHTTP = NULL;
  1086. _ResolveTimeout = 0;
  1087. _ConnectTimeout = 0;
  1088. _SendTimeout = 0;
  1089. _ReceiveTimeout = 0;
  1090. _cbRequestBody = 0;
  1091. _szRequestBuffer = NULL;
  1092. _dwCodePage = CP_UTF8;
  1093. _dwEscapeFlag = WINHTTP_FLAG_ESCAPE_DISABLE_QUERY;
  1094. _cbResponseBody = 0;
  1095. _pResponseStream = NULL;
  1096. _hAbortedConnectObject = NULL;
  1097. _hAbortedRequestObject = NULL;
  1098. _bstrCertSubject = NULL;
  1099. _bstrCertStore = NULL;
  1100. _fCertLocalMachine = FALSE;
  1101. _fCheckForRevocation = FALSE;
  1102. _dwSslIgnoreFlags = 0;
  1103. _dwSecureProtocols = DEFAULT_SECURE_PROTOCOLS;
  1104. _hrSecureFailure = HRESULT_FROM_WIN32(ERROR_WINHTTP_SECURE_FAILURE);
  1105. _bEnableSslImpersonation = FALSE;
  1106. _bMethodGET = FALSE;
  1107. _bHttp1_1Mode = TRUE;
  1108. #ifdef TRUE_ASYNC
  1109. _hCompleteEvent = NULL;
  1110. _bRetriedWithCert = FALSE;
  1111. _Buffer = NULL;
  1112. #endif
  1113. _dwAutoLogonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_DEFAULT;
  1114. _dwRedirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_DEFAULT;
  1115. _lMaxAutomaticRedirects = GlobalMaxHttpRedirects;
  1116. _lMaxResponseHeaderSize = GlobalMaxHeaderSize;
  1117. _lMaxResponseDrainSize = GlobalMaxDrainSize;
  1118. _dwPassportConfig = (WINHTTP_DISABLE_PASSPORT_AUTH | WINHTTP_DISABLE_PASSPORT_KEYRING);
  1119. }
  1120. /*
  1121. * CHttpRequest::ReleaseResources
  1122. *
  1123. * Purpose:
  1124. * Release all handles, events, and buffers
  1125. *
  1126. */
  1127. void
  1128. CHttpRequest::ReleaseResources()
  1129. {
  1130. SafeRelease(_pTypeInfo);
  1131. #if !defined(TRUE_ASYNC)
  1132. if (_hWorkerThread)
  1133. {
  1134. CloseHandle(_hWorkerThread);
  1135. _hWorkerThread = NULL;
  1136. }
  1137. #endif//!TRUE_ASYNC
  1138. _CP.ReleaseEventSinksMarshaller();
  1139. //
  1140. // Derefence aborted handle objects (if any).
  1141. //
  1142. if (_hAbortedRequestObject != NULL)
  1143. {
  1144. DereferenceObject(_hAbortedRequestObject);
  1145. _hAbortedRequestObject = NULL;
  1146. }
  1147. if (_hAbortedConnectObject != NULL)
  1148. {
  1149. DereferenceObject(_hAbortedConnectObject);
  1150. _hAbortedConnectObject = NULL;
  1151. }
  1152. if (_hHTTP)
  1153. {
  1154. HINTERNET temp = _hHTTP;
  1155. _hHTTP = NULL;
  1156. WinHttpCloseHandle(temp);
  1157. }
  1158. if (_hConnection)
  1159. {
  1160. HINTERNET temp = _hConnection;
  1161. _hConnection = NULL;
  1162. WinHttpCloseHandle(temp);
  1163. }
  1164. if (_hInet)
  1165. {
  1166. HINTERNET temp = _hInet;
  1167. _hInet = NULL;
  1168. WinHttpCloseHandle(temp);
  1169. }
  1170. if (_szRequestBuffer)
  1171. {
  1172. delete [] _szRequestBuffer;
  1173. _szRequestBuffer = NULL;
  1174. }
  1175. SafeRelease(_pResponseStream);
  1176. if (_bstrUserAgent)
  1177. {
  1178. DL(SysFreeString)(_bstrUserAgent);
  1179. _bstrUserAgent = NULL;
  1180. }
  1181. if (_bstrProxyServer)
  1182. {
  1183. DL(SysFreeString)(_bstrProxyServer);
  1184. _bstrProxyServer = NULL;
  1185. }
  1186. if (_bstrBypassList)
  1187. {
  1188. DL(SysFreeString)(_bstrBypassList);
  1189. _bstrBypassList = NULL;
  1190. }
  1191. if (_bstrCertSubject)
  1192. {
  1193. DL(SysFreeString)(_bstrCertSubject);
  1194. _bstrCertSubject = NULL;
  1195. }
  1196. if (_bstrCertStore)
  1197. {
  1198. DL(SysFreeString)(_bstrCertStore);
  1199. _bstrCertStore = NULL;
  1200. }
  1201. #ifdef TRUE_ASYNC
  1202. if (_hCompleteEvent != NULL)
  1203. {
  1204. CloseHandle(_hCompleteEvent);
  1205. _hCompleteEvent = NULL;
  1206. }
  1207. if (_Buffer != NULL)
  1208. {
  1209. delete [] _Buffer;
  1210. }
  1211. #endif
  1212. }
  1213. /*
  1214. * CHttpRequest::Reset
  1215. *
  1216. * Purpose:
  1217. * Release all resources and initialize data members
  1218. *
  1219. */
  1220. void
  1221. CHttpRequest::Reset()
  1222. {
  1223. ReleaseResources();
  1224. Initialize();
  1225. }
  1226. /*
  1227. * CHttpRequest::Recycle
  1228. *
  1229. * Purpose:
  1230. * Recycle object
  1231. *
  1232. */
  1233. void
  1234. CHttpRequest::Recycle()
  1235. {
  1236. DEBUG_ENTER((DBG_HTTP,
  1237. None,
  1238. "IWinHttpRequest::Recycle",
  1239. NULL));
  1240. //
  1241. // Wait for the worker thread to shut down. This shouldn't take long
  1242. // since the Abort will close the Request and Connection handles.
  1243. //
  1244. if (
  1245. #ifdef TRUE_ASYNC
  1246. _hCompleteEvent
  1247. #else
  1248. _hWorkerThread
  1249. #endif//TRUE_ASYNC
  1250. )
  1251. {
  1252. DWORD dwWaitResult;
  1253. for (;;)
  1254. {
  1255. dwWaitResult = MsgWaitForMultipleObjects(1,
  1256. #ifdef TRUE_ASYNC
  1257. &_hCompleteEvent
  1258. #else
  1259. &_hWorkerThread
  1260. #endif//TRUE_ASYNC
  1261. ,
  1262. FALSE,
  1263. INFINITE,
  1264. QS_ALLINPUT);
  1265. if (dwWaitResult == (WAIT_OBJECT_0 + 1))
  1266. {
  1267. // Message waiting in the message queue.
  1268. // Run message pump to clear queue.
  1269. MessageLoop();
  1270. }
  1271. else
  1272. {
  1273. break;
  1274. }
  1275. }
  1276. #ifdef TRUE_ASYNC
  1277. CloseHandle(_hCompleteEvent);
  1278. _hCompleteEvent = NULL;
  1279. #else
  1280. CloseHandle(_hWorkerThread);
  1281. _hWorkerThread = NULL;
  1282. #endif//TRUE_ASYNC
  1283. }
  1284. _hConnection = NULL;
  1285. _hHTTP = NULL;
  1286. //
  1287. // Derefence aborted handle objects (if any).
  1288. //
  1289. if (_hAbortedRequestObject != NULL)
  1290. {
  1291. DereferenceObject(_hAbortedRequestObject);
  1292. _hAbortedRequestObject = NULL;
  1293. }
  1294. if (_hAbortedConnectObject != NULL)
  1295. {
  1296. DereferenceObject(_hAbortedConnectObject);
  1297. _hAbortedConnectObject = NULL;
  1298. }
  1299. //sergekh: we shouldn't reset _fAsync to know the state of _hInet
  1300. //_fAsync = FALSE;
  1301. _hrAsyncResult = NOERROR;
  1302. _bAborted = false;
  1303. // don't reset timeouts, keep any that were set.
  1304. _cbRequestBody = 0;
  1305. _cbResponseBody = 0;
  1306. if (_szRequestBuffer)
  1307. {
  1308. delete [] _szRequestBuffer;
  1309. _szRequestBuffer = NULL;
  1310. }
  1311. SafeRelease(_pResponseStream);
  1312. _CP.ShutdownEventSinksMarshaller();
  1313. _CP.ReleaseEventSinksMarshaller();
  1314. // Allow events to fire; Abort() would have frozen them from firing.
  1315. _CP.UnfreezeEvents();
  1316. SetState(CHttpRequest::CREATED);
  1317. DEBUG_LEAVE(0);
  1318. }
  1319. static BOOL GetContentLengthIfResponseNotChunked(
  1320. HINTERNET hHttpRequest,
  1321. DWORD * pdwContentLength
  1322. )
  1323. {
  1324. char szTransferEncoding[16]; // big enough for "chunked" or "identity"
  1325. DWORD cb;
  1326. BOOL fRetCode;
  1327. cb = sizeof(szTransferEncoding) - 1;
  1328. fRetCode = HttpQueryInfoA(
  1329. hHttpRequest,
  1330. WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING,
  1331. WINHTTP_HEADER_NAME_BY_INDEX,
  1332. szTransferEncoding,
  1333. &cb,
  1334. 0);
  1335. if (!fRetCode || lstrcmpi(szTransferEncoding, "identity") == 0)
  1336. {
  1337. // Determine the content length
  1338. cb = sizeof(DWORD);
  1339. fRetCode = HttpQueryInfoA(
  1340. hHttpRequest,
  1341. WINHTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
  1342. WINHTTP_HEADER_NAME_BY_INDEX,
  1343. pdwContentLength,
  1344. &cb,
  1345. 0);
  1346. }
  1347. else
  1348. {
  1349. fRetCode = FALSE;
  1350. }
  1351. return fRetCode;
  1352. }
  1353. /*
  1354. * CHttpRequest::ReadResponse
  1355. *
  1356. * Purpose:
  1357. * Read the response bits
  1358. *
  1359. * Parameters:
  1360. * None
  1361. *
  1362. * Errors:
  1363. * E_FAIL
  1364. * E_OUTOFMEMORY
  1365. */
  1366. HRESULT
  1367. CHttpRequest::ReadResponse()
  1368. {
  1369. HRESULT hr = NOERROR;
  1370. BOOL fRetCode;
  1371. long lStatus;
  1372. BSTR bstrContentType = NULL;
  1373. DWORD dwContentLength = 0;
  1374. BYTE * Buffer = NULL;
  1375. SetState(CHttpRequest::RECEIVING);
  1376. hr = get_Status(&lStatus);
  1377. if (FAILED(hr))
  1378. goto Error;
  1379. hr = _GetResponseHeader(L"Content-Type", &bstrContentType);
  1380. if (FAILED(hr))
  1381. {
  1382. bstrContentType = DL(SysAllocString)(L"");
  1383. if (bstrContentType == NULL)
  1384. goto ErrorOutOfMemory;
  1385. hr = NOERROR;
  1386. }
  1387. INET_ASSERT((_pResponseStream == NULL) && (_cbResponseBody == 0));
  1388. hr = DL(CreateStreamOnHGlobal)(NULL, TRUE, &_pResponseStream);
  1389. if (SUCCEEDED(hr))
  1390. {
  1391. // Determine the content length
  1392. fRetCode = GetContentLengthIfResponseNotChunked(_hHTTP, &dwContentLength);
  1393. // pre-set response stream size if we have a Content-Length
  1394. if (fRetCode)
  1395. {
  1396. ULARGE_INTEGER size;
  1397. size.LowPart = dwContentLength;
  1398. size.HighPart = 0;
  1399. _pResponseStream->SetSize(size);
  1400. }
  1401. else
  1402. {
  1403. // Content-Length was not specified in the response, but this
  1404. // does not mean Content-Length==0. We will keep reading until
  1405. // either no more data is available. Set dwContentLength to 4GB
  1406. // to trick our read loop into reading until eof is reached.
  1407. dwContentLength = (DWORD)(-1L);
  1408. ULARGE_INTEGER size;
  1409. // Set initial size of the response stream to 8K.
  1410. size.LowPart = SIZEOF_BUFFER;
  1411. size.HighPart = 0;
  1412. _pResponseStream->SetSize(size);
  1413. }
  1414. }
  1415. else
  1416. goto ErrorOutOfMemory;
  1417. //
  1418. // Allocate an 8K buffer to read the response data in chunks.
  1419. //
  1420. Buffer = New BYTE[SIZEOF_BUFFER];
  1421. if (!Buffer)
  1422. {
  1423. goto ErrorOutOfMemory;
  1424. }
  1425. //
  1426. // Fire the initial OnResponseStart event
  1427. //
  1428. _CP.FireOnResponseStart(lStatus, bstrContentType);
  1429. // Skip read loop if Content-Length==0.
  1430. if (dwContentLength == 0)
  1431. {
  1432. goto Finished;
  1433. }
  1434. //
  1435. // Read data until there is no more - we need to buffer the data
  1436. //
  1437. while (!_bAborted)
  1438. {
  1439. DWORD cbAvail = 0;
  1440. DWORD cbRead = 0;
  1441. fRetCode = WinHttpQueryDataAvailable(_hHTTP, &cbAvail);
  1442. if (!fRetCode)
  1443. {
  1444. goto ErrorFail;
  1445. }
  1446. // Read up to 8K (sizeof Buffer) of data.
  1447. cbAvail = min(cbAvail, SIZEOF_BUFFER);
  1448. fRetCode = WinHttpReadData(_hHTTP, Buffer, cbAvail, &cbRead);
  1449. if (!fRetCode)
  1450. {
  1451. goto ErrorFail;
  1452. }
  1453. if (cbRead != 0)
  1454. {
  1455. hr = _pResponseStream->Write(Buffer, cbRead, NULL);
  1456. if (FAILED(hr))
  1457. {
  1458. goto ErrorOutOfMemory;
  1459. }
  1460. _CP.FireOnResponseDataAvailable((const BYTE *)Buffer, cbRead);
  1461. _cbResponseBody += cbRead;
  1462. }
  1463. // If WinHttpReadData indicates there is no more data to read,
  1464. // or we've read as much data as the Content-Length header tells
  1465. // us to expect, then we're finished reading the response.
  1466. if ((cbRead == 0) || (_cbResponseBody >= dwContentLength))
  1467. {
  1468. ULARGE_INTEGER size;
  1469. // set final size on stream
  1470. size.LowPart = _cbResponseBody;
  1471. size.HighPart = 0;
  1472. _pResponseStream->SetSize(size);
  1473. break;
  1474. }
  1475. }
  1476. Finished:
  1477. SetState(CHttpRequest::RESPONSE);
  1478. _CP.FireOnResponseFinished();
  1479. hr = NOERROR;
  1480. Cleanup:
  1481. if (bstrContentType)
  1482. DL(SysFreeString)(bstrContentType);
  1483. if (Buffer)
  1484. delete [] Buffer;
  1485. return hr;
  1486. ErrorOutOfMemory:
  1487. hr = E_OUTOFMEMORY;
  1488. goto Error;
  1489. ErrorFail:
  1490. hr = HRESULT_FROM_WIN32(::GetLastError());
  1491. _CP.FireOnError(hr);
  1492. goto Error;
  1493. Error:
  1494. SafeRelease(_pResponseStream);
  1495. _cbResponseBody = NULL;
  1496. goto Cleanup;
  1497. }
  1498. STDMETHODIMP
  1499. CHttpRequest::SetProxy(HTTPREQUEST_PROXY_SETTING ProxySetting,
  1500. VARIANT varProxyServer,
  1501. VARIANT varBypassList)
  1502. {
  1503. HRESULT hr = NOERROR;
  1504. if (!IsValidVariant(varProxyServer) || !IsValidVariant(varBypassList))
  1505. return E_INVALIDARG;
  1506. DEBUG_ENTER_API((DBG_HTTP,
  1507. Dword,
  1508. "IWinHttpRequest::SetProxy",
  1509. "HTTPREQUEST_PROXY_SETTING: %d, VARIANT, VARIANT",
  1510. ProxySetting
  1511. ));
  1512. if (_bstrProxyServer)
  1513. {
  1514. DL(SysFreeString)(_bstrProxyServer);
  1515. _bstrProxyServer = NULL;
  1516. }
  1517. if (_bstrBypassList)
  1518. {
  1519. DL(SysFreeString)(_bstrBypassList);
  1520. _bstrBypassList = NULL;
  1521. }
  1522. switch (ProxySetting)
  1523. {
  1524. case HTTPREQUEST_PROXYSETTING_PRECONFIG:
  1525. _dwProxySetting = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
  1526. break;
  1527. case HTTPREQUEST_PROXYSETTING_DIRECT:
  1528. _dwProxySetting = WINHTTP_ACCESS_TYPE_NO_PROXY;
  1529. break;
  1530. case HTTPREQUEST_PROXYSETTING_PROXY:
  1531. _dwProxySetting = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  1532. hr = GetBSTRFromVariant(varProxyServer, &_bstrProxyServer);
  1533. if (SUCCEEDED(hr))
  1534. {
  1535. hr = GetBSTRFromVariant(varBypassList, &_bstrBypassList);
  1536. }
  1537. if (FAILED(hr))
  1538. {
  1539. hr = E_INVALIDARG;
  1540. }
  1541. break;
  1542. default:
  1543. hr = E_INVALIDARG;
  1544. break;
  1545. }
  1546. if (SUCCEEDED(hr))
  1547. {
  1548. if (_hHTTP)
  1549. {
  1550. WINHTTP_PROXY_INFOW ProxyInfo;
  1551. memset(&ProxyInfo, 0, sizeof(ProxyInfo));
  1552. ProxyInfo.dwAccessType = _dwProxySetting;
  1553. ProxyInfo.lpszProxy = _bstrProxyServer;
  1554. ProxyInfo.lpszProxyBypass = _bstrBypassList;
  1555. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_PROXY,
  1556. &ProxyInfo,
  1557. sizeof(ProxyInfo)))
  1558. {
  1559. hr = HRESULT_FROM_WIN32(GetLastError());
  1560. }
  1561. if (SUCCEEDED(hr) &&
  1562. !WinHttpSetOption(_hInet, WINHTTP_OPTION_PROXY,
  1563. &ProxyInfo,
  1564. sizeof(ProxyInfo)))
  1565. {
  1566. hr = HRESULT_FROM_WIN32(GetLastError());
  1567. }
  1568. }
  1569. }
  1570. SetErrorInfo(hr);
  1571. DEBUG_LEAVE_API(hr);
  1572. return hr;
  1573. }
  1574. STDMETHODIMP
  1575. CHttpRequest::SetCredentials(
  1576. BSTR bstrUserName,
  1577. BSTR bstrPassword,
  1578. HTTPREQUEST_SETCREDENTIALS_FLAGS Flags)
  1579. {
  1580. HRESULT hr;
  1581. DEBUG_ENTER_API((DBG_HTTP,
  1582. Dword,
  1583. "IWinHttpRequest::SetCredentials",
  1584. "BSTR %Q, BSTR *, Flags: %x",
  1585. _hHTTP? bstrUserName: L"",
  1586. Flags
  1587. ));
  1588. // Must call Open method before SetCredentials.
  1589. if (! _hHTTP)
  1590. {
  1591. goto ErrorCannotCallBeforeOpen;
  1592. }
  1593. if (!IsValidBstr(bstrUserName) || !IsValidBstr(bstrPassword))
  1594. return E_INVALIDARG;
  1595. if (Flags == HTTPREQUEST_SETCREDENTIALS_FOR_SERVER)
  1596. {
  1597. // Set Username and Password.
  1598. if (!WinHttpSetOption(
  1599. _hHTTP,
  1600. WINHTTP_OPTION_USERNAME,
  1601. bstrUserName,
  1602. lstrlenW(bstrUserName)))
  1603. goto ErrorFail;
  1604. if (!WinHttpSetOption(
  1605. _hHTTP,
  1606. WINHTTP_OPTION_PASSWORD,
  1607. bstrPassword,
  1608. lstrlenW(bstrPassword)+1)) // 596411 allow empty/blank password
  1609. goto ErrorFail;
  1610. }
  1611. else if (Flags == HTTPREQUEST_SETCREDENTIALS_FOR_PROXY)
  1612. {
  1613. // Set Username and Password.
  1614. if (!WinHttpSetOption(
  1615. _hHTTP,
  1616. WINHTTP_OPTION_PROXY_USERNAME,
  1617. bstrUserName,
  1618. lstrlenW(bstrUserName)))
  1619. goto ErrorFail;
  1620. if (!WinHttpSetOption(
  1621. _hHTTP,
  1622. WINHTTP_OPTION_PROXY_PASSWORD,
  1623. bstrPassword,
  1624. lstrlenW(bstrPassword)+1)) // 596411 allow empty/blank password
  1625. goto ErrorFail;
  1626. }
  1627. else
  1628. {
  1629. DEBUG_LEAVE_API(E_INVALIDARG);
  1630. return E_INVALIDARG;
  1631. }
  1632. hr = NOERROR;
  1633. Cleanup:
  1634. SetErrorInfo(hr);
  1635. DEBUG_LEAVE_API(hr);
  1636. return hr;
  1637. ErrorCannotCallBeforeOpen:
  1638. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN);
  1639. goto Cleanup;
  1640. ErrorFail:
  1641. hr = HRESULT_FROM_WIN32(::GetLastError());
  1642. goto Cleanup;
  1643. }
  1644. /*
  1645. * CHttpRequest::Open
  1646. *
  1647. * Purpose:
  1648. * Open a logical HTTP connection
  1649. *
  1650. * Parameters:
  1651. * bstrMethod IN HTTP method (GET, PUT, ...)
  1652. * bstrUrl IN Target URL
  1653. *
  1654. * Errors:
  1655. * E_FAIL
  1656. * E_INVALIDARG
  1657. * E_OUTOFMEMORY
  1658. * E_ACCESSDENIED
  1659. * Errors from InternetOpenA and WinHttpCrackUrlA and InternetConnectA
  1660. * and HttpOpenRequestA
  1661. */
  1662. STDMETHODIMP
  1663. CHttpRequest::Open(
  1664. BSTR bstrMethod,
  1665. BSTR bstrUrl,
  1666. VARIANT varAsync)
  1667. {
  1668. HRESULT hr = NOERROR;
  1669. BSTR bstrHostName = NULL;
  1670. BSTR bstrUrlPath = NULL;
  1671. DWORD dwHttpOpenFlags = 0;
  1672. DWORD dw;
  1673. URL_COMPONENTSW url;
  1674. // Validate that we are called from our apartment's thread.
  1675. if (GetCurrentThreadId() != _dwMainThreadId)
  1676. return RPC_E_WRONG_THREAD;
  1677. // Validate parameters
  1678. if (!bstrMethod || !bstrUrl ||
  1679. !IsValidBstr(bstrMethod) ||
  1680. !IsValidBstr(bstrUrl) ||
  1681. !lstrlenW(bstrMethod) || // cannot have empty method
  1682. !lstrlenW(bstrUrl) || // cannot have empty url
  1683. !IsValidVariant(varAsync))
  1684. return E_INVALIDARG;
  1685. BOOL newAsync = GetBoolFromVariant(varAsync, FALSE);
  1686. DEBUG_ENTER_API((DBG_HTTP,
  1687. Dword,
  1688. "IWinHttpRequest::Open",
  1689. "method: %Q, url: %Q, async: %d",
  1690. bstrMethod,
  1691. bstrUrl,
  1692. newAsync
  1693. ));
  1694. // Check for reinitialization
  1695. if (_eState != CHttpRequest::CREATED)
  1696. {
  1697. //
  1698. // Abort any request in progress.
  1699. // This will also recycle the object.
  1700. //
  1701. Abort();
  1702. }
  1703. //
  1704. //check if session has the async state we need
  1705. //
  1706. if (_hInet)
  1707. {
  1708. if ((_fAsync && !newAsync) || (!_fAsync && newAsync)) //XOR
  1709. {
  1710. //state is not the same, close session
  1711. WinHttpCloseHandle(_hInet);
  1712. _hInet = NULL;
  1713. }
  1714. }
  1715. _fAsync = newAsync;
  1716. //
  1717. // Open an Internet Session if one does not already exist.
  1718. //
  1719. if (!_hInet)
  1720. {
  1721. _hInet = WinHttpOpen(
  1722. GetUserAgentString(),
  1723. _dwProxySetting,
  1724. _bstrProxyServer,
  1725. _bstrBypassList,
  1726. #ifdef TRUE_ASYNC
  1727. _fAsync ? WINHTTP_FLAG_ASYNC : 0
  1728. #else
  1729. 0
  1730. #endif//TRUE_ASYNC
  1731. );
  1732. if (!_hInet)
  1733. goto ErrorFail;
  1734. DWORD dwEnableFlags = _bEnableSslImpersonation ? 0 : WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION;
  1735. if (dwEnableFlags)
  1736. {
  1737. WinHttpSetOption(_hInet,
  1738. WINHTTP_OPTION_ENABLE_FEATURE,
  1739. (LPVOID)&dwEnableFlags,
  1740. sizeof(dwEnableFlags));
  1741. }
  1742. }
  1743. //
  1744. // If any timeouts were set previously, apply them.
  1745. //
  1746. if (_bSetTimeouts)
  1747. {
  1748. if (!WinHttpSetTimeouts(_hInet, (int)_ResolveTimeout,
  1749. (int)_ConnectTimeout,
  1750. (int)_SendTimeout,
  1751. (int)_ReceiveTimeout))
  1752. goto ErrorFail;
  1753. }
  1754. //
  1755. // Set the code page on the Session handle; the Connect
  1756. // handle will also inherit this value.
  1757. //
  1758. if (!WinHttpSetOption(_hInet, WINHTTP_OPTION_CODEPAGE,
  1759. &_dwCodePage,
  1760. sizeof(_dwCodePage)))
  1761. goto ErrorFail;
  1762. if (!WinHttpSetOption(_hInet,
  1763. WINHTTP_OPTION_SECURE_PROTOCOLS,
  1764. (LPVOID)&_dwSecureProtocols,
  1765. sizeof(_dwSecureProtocols)))
  1766. goto ErrorFail;
  1767. if (!WinHttpSetOption(_hInet,
  1768. WINHTTP_OPTION_REDIRECT_POLICY,
  1769. (LPVOID)&_dwRedirectPolicy,
  1770. sizeof(DWORD)))
  1771. goto ErrorFail;
  1772. if (!WinHttpSetOption(_hInet,
  1773. WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH,
  1774. (LPVOID)&_dwPassportConfig,
  1775. sizeof(DWORD)))
  1776. goto ErrorFail;
  1777. // Break the URL into the required components
  1778. ZeroMemory(&url, sizeof(URL_COMPONENTSW));
  1779. url.dwStructSize = sizeof(URL_COMPONENTSW);
  1780. url.dwHostNameLength = 1;
  1781. url.dwUrlPathLength = 1;
  1782. url.dwExtraInfoLength = 1;
  1783. if (!WinHttpCrackUrl(bstrUrl, 0, 0, &url))
  1784. goto ErrorFail;
  1785. // Check for non-http schemes
  1786. if (url.nScheme != INTERNET_SCHEME_HTTP && url.nScheme != INTERNET_SCHEME_HTTPS)
  1787. goto ErrorUnsupportedScheme;
  1788. // IE6/Reno Bug #6236: if the client does not specify a resource path,
  1789. // then add the "/".
  1790. if (url.dwUrlPathLength == 0)
  1791. {
  1792. INET_ASSERT(url.dwExtraInfoLength == 0);
  1793. url.lpszUrlPath = L"/";
  1794. url.dwUrlPathLength = 1;
  1795. }
  1796. bstrHostName = DL(SysAllocStringLen)(url.lpszHostName, url.dwHostNameLength);
  1797. bstrUrlPath = DL(SysAllocStringLen)(url.lpszUrlPath, lstrlenW(url.lpszUrlPath));
  1798. if (!bstrHostName || !bstrUrlPath)
  1799. goto ErrorOutOfMemory;
  1800. INET_ASSERT(_hConnection == NULL);
  1801. INET_ASSERT(_hHTTP == NULL);
  1802. _hConnection = WinHttpConnect(
  1803. _hInet,
  1804. bstrHostName,
  1805. url.nPort,
  1806. 0);
  1807. if (!_hConnection)
  1808. goto ErrorFail;
  1809. if (url.nScheme == INTERNET_SCHEME_HTTPS)
  1810. {
  1811. dwHttpOpenFlags |= WINHTTP_FLAG_SECURE;
  1812. }
  1813. //
  1814. // Apply EscapePercentInURL option.
  1815. //
  1816. dwHttpOpenFlags |= _dwEscapeFlag;
  1817. _hHTTP = WinHttpOpenRequest(
  1818. _hConnection,
  1819. bstrMethod,
  1820. bstrUrlPath,
  1821. _bHttp1_1Mode ? L"HTTP/1.1" : L"HTTP/1.0",
  1822. NULL,
  1823. NULL,
  1824. dwHttpOpenFlags);
  1825. if (!_hHTTP)
  1826. goto ErrorFail;
  1827. if ((StrCmpIW(bstrMethod, L"GET") == 0) || (StrCmpIW(bstrMethod, L"HEAD") == 0))
  1828. {
  1829. _bMethodGET = TRUE;
  1830. }
  1831. if (_fCheckForRevocation)
  1832. {
  1833. DWORD dwOptions = WINHTTP_ENABLE_SSL_REVOCATION;
  1834. WinHttpSetOption(_hHTTP,
  1835. WINHTTP_OPTION_ENABLE_FEATURE,
  1836. (LPVOID)&dwOptions,
  1837. sizeof(dwOptions));
  1838. }
  1839. // Set the SSL ignore flags through an undocumented front door
  1840. if (_dwSslIgnoreFlags)
  1841. {
  1842. WinHttpSetOption(_hHTTP,
  1843. WINHTTP_OPTION_SECURITY_FLAGS,
  1844. (LPVOID)&_dwSslIgnoreFlags,
  1845. sizeof(_dwSslIgnoreFlags));
  1846. }
  1847. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_AUTOLOGON_POLICY,
  1848. (void *) &_dwAutoLogonPolicy,
  1849. sizeof(_dwAutoLogonPolicy)))
  1850. goto ErrorFail;
  1851. dw = (DWORD)_lMaxAutomaticRedirects;
  1852. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS,
  1853. (void *) &dw, sizeof(dw)))
  1854. goto ErrorFail;
  1855. dw = (DWORD)_lMaxResponseHeaderSize;
  1856. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE,
  1857. (void *) &dw, sizeof(dw)))
  1858. goto ErrorFail;
  1859. dw = (DWORD)_lMaxResponseDrainSize;
  1860. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE,
  1861. (void *) &dw, sizeof(dw)))
  1862. goto ErrorFail;
  1863. SetState(CHttpRequest::OPENED);
  1864. hr = NOERROR;
  1865. Cleanup:
  1866. if (bstrHostName)
  1867. DL(SysFreeString)(bstrHostName);;
  1868. if (bstrUrlPath)
  1869. DL(SysFreeString)(bstrUrlPath);
  1870. SetErrorInfo(hr);
  1871. DEBUG_LEAVE_API(hr);
  1872. return hr;
  1873. ErrorUnsupportedScheme:
  1874. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_UNRECOGNIZED_SCHEME);
  1875. goto Cleanup;
  1876. ErrorOutOfMemory:
  1877. hr = E_OUTOFMEMORY;
  1878. goto Error;
  1879. ErrorFail:
  1880. if (_hHTTP)
  1881. {
  1882. WinHttpCloseHandle(_hHTTP);
  1883. _hHTTP = NULL;
  1884. }
  1885. if (_hConnection)
  1886. {
  1887. WinHttpCloseHandle(_hConnection);
  1888. _hConnection = NULL;
  1889. }
  1890. hr = HRESULT_FROM_WIN32(GetLastError());
  1891. goto Cleanup;
  1892. Error:
  1893. goto Cleanup;
  1894. }
  1895. /*
  1896. * CHttpRequest::SetRequestHeader
  1897. *
  1898. * Purpose:
  1899. * Set a request header
  1900. *
  1901. * Parameters:
  1902. * bstrHeader IN HTTP request header
  1903. * bstrValue IN Header value
  1904. *
  1905. * Errors:
  1906. * E_FAIL
  1907. * E_INVALIDARG
  1908. * E_UNEXPECTED
  1909. */
  1910. STDMETHODIMP
  1911. CHttpRequest::SetRequestHeader(BSTR bstrHeader, BSTR bstrValue)
  1912. {
  1913. WCHAR * wszHeaderValue = NULL;
  1914. DWORD cchHeaderValue;
  1915. DWORD dwModifiers = HTTP_ADDREQ_FLAG_ADD;
  1916. HRESULT hr = NOERROR;
  1917. // Validate header parameter (null or zero-length value is allowed)
  1918. if (!bstrHeader
  1919. || !IsValidBstr(bstrHeader)
  1920. || (lstrlenW(bstrHeader)==0)
  1921. || !IsValidBstr(bstrValue)
  1922. || !IsValidHeaderName(bstrHeader))
  1923. return E_INVALIDARG;
  1924. DEBUG_ENTER_API((DBG_HTTP,
  1925. Dword,
  1926. "IWinHttpRequest::SetRequestHeader",
  1927. "header: %Q, value: %Q",
  1928. bstrHeader,
  1929. bstrValue
  1930. ));
  1931. // Validate state
  1932. if (_eState < CHttpRequest::OPENED)
  1933. goto ErrorCannotCallBeforeOpen;
  1934. else if (_eState >= CHttpRequest::SENDING)
  1935. goto ErrorCannotCallAfterSend;
  1936. // Ignore attempts to set the Content-Length header; the
  1937. // content length is computed and sent automatically.
  1938. if (StrCmpIW(bstrHeader, L"Content-Length") == 0)
  1939. goto Cleanup;
  1940. if (StrCmpIW(bstrHeader, L"Cookie") == 0)
  1941. dwModifiers |= HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON;
  1942. cchHeaderValue = lstrlenW(bstrHeader) + lstrlenW(bstrValue)
  1943. + 2 /* wcslen(L": ") */
  1944. + 2 /* wcslen(L"\r\n") */;
  1945. wszHeaderValue = New WCHAR [cchHeaderValue + 1];
  1946. if (!wszHeaderValue)
  1947. goto ErrorOutOfMemory;
  1948. wcscpy(wszHeaderValue, bstrHeader);
  1949. wcscat(wszHeaderValue, L": ");
  1950. if (bstrValue)
  1951. wcscat(wszHeaderValue, bstrValue);
  1952. wcscat(wszHeaderValue, L"\r\n");
  1953. // For blank header values, erase the header by setting the
  1954. // REPLACE flag.
  1955. if (lstrlenW(bstrValue) == 0)
  1956. {
  1957. dwModifiers |= HTTP_ADDREQ_FLAG_REPLACE;
  1958. }
  1959. if (! WinHttpAddRequestHeaders(_hHTTP, wszHeaderValue,
  1960. (DWORD)-1L,
  1961. dwModifiers))
  1962. goto ErrorFail;
  1963. hr = NOERROR;
  1964. Cleanup:
  1965. if (wszHeaderValue)
  1966. delete [] wszHeaderValue;
  1967. SetErrorInfo(hr);
  1968. DEBUG_LEAVE_API(hr);
  1969. return hr;
  1970. ErrorOutOfMemory:
  1971. hr = E_OUTOFMEMORY;
  1972. goto Error;
  1973. ErrorCannotCallBeforeOpen:
  1974. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN);
  1975. goto Error;
  1976. ErrorCannotCallAfterSend:
  1977. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND);
  1978. goto Error;
  1979. ErrorFail:
  1980. hr = HRESULT_FROM_WIN32(GetLastError());
  1981. goto Error;
  1982. Error:
  1983. goto Cleanup;
  1984. }
  1985. /*
  1986. * CHttpRequest::SetRequiredRequestHeaders
  1987. *
  1988. * Purpose:
  1989. * Set implicit request headers
  1990. *
  1991. * Parameters:
  1992. * None
  1993. *
  1994. * Errors:
  1995. * E_FAIL
  1996. * E_UNEXPECTED
  1997. * E_OUTOFMEMORY
  1998. * Errors from WinHttpAddRequestHeaders and WinHttpSendRequest
  1999. */
  2000. HRESULT
  2001. CHttpRequest::SetRequiredRequestHeaders()
  2002. {
  2003. HRESULT hr = NOERROR;
  2004. if (!(_bMethodGET && _cbRequestBody == 0))
  2005. {
  2006. char szContentLengthHeader[sizeof("Content-Length") +
  2007. sizeof(": ") +
  2008. 15 + // content-length value
  2009. sizeof("\r\n") + 1];
  2010. lstrcpy(szContentLengthHeader, "Content-Length: ");
  2011. _ltoa(_cbRequestBody,
  2012. szContentLengthHeader + 16, /* "Content-Length: " */
  2013. 10);
  2014. lstrcat(szContentLengthHeader, "\r\n");
  2015. if (! HttpAddRequestHeadersA(_hHTTP, szContentLengthHeader,
  2016. (DWORD)-1L,
  2017. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE))
  2018. {
  2019. hr = E_FAIL;
  2020. }
  2021. }
  2022. // Add an Accept: */* header if no other Accept header
  2023. // has been set. Ignore any return code, since it is
  2024. // not fatal if this fails.
  2025. HttpAddRequestHeadersA(_hHTTP, "Accept: */*",
  2026. (DWORD)-1L,
  2027. HTTP_ADDREQ_FLAG_ADD_IF_NEW);
  2028. if (_bSetUtf8Charset)
  2029. {
  2030. CHAR szContentType[256];
  2031. BOOL fRetCode;
  2032. DWORD cb = sizeof(szContentType) - sizeof("Content-Type: ") - sizeof("; Charset=UTF-8");
  2033. LPSTR pszNewContentType = NULL;
  2034. lstrcpy(szContentType, "Content-Type: ");
  2035. fRetCode = HttpQueryInfoA(_hHTTP,
  2036. HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_CONTENT_TYPE,
  2037. WINHTTP_HEADER_NAME_BY_INDEX,
  2038. szContentType + sizeof("Content-Type: ") - 1,
  2039. &cb,
  2040. 0);
  2041. if (fRetCode)
  2042. {
  2043. if (!StrStrIA(szContentType, "charset"))
  2044. {
  2045. lstrcat(szContentType, "; Charset=UTF-8");
  2046. pszNewContentType = szContentType;
  2047. }
  2048. }
  2049. else if (GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND)
  2050. {
  2051. pszNewContentType = "Content-Type: text/plain; Charset=UTF-8";
  2052. }
  2053. if (pszNewContentType)
  2054. {
  2055. fRetCode = HttpAddRequestHeadersA(_hHTTP, pszNewContentType,
  2056. (DWORD)-1L,
  2057. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
  2058. INET_ASSERT(fRetCode);
  2059. }
  2060. }
  2061. return hr;
  2062. }
  2063. #if !defined(TRUE_ASYNC)
  2064. DWORD WINAPI WinHttpRequestSendAsync(LPVOID lpParameter)
  2065. {
  2066. #ifdef WINHTTP_FOR_MSXML
  2067. //
  2068. // MSXML needs to initialize its thread local storage data.
  2069. // It does not do this during DLL_THREAD_ATTACH, so our
  2070. // worker thread must explicitly call into MSXML to initialize
  2071. // its TLS for this thread.
  2072. //
  2073. InitializeMsxmlTLS();
  2074. #endif
  2075. HRESULT hr;
  2076. DWORD dwExitCode;
  2077. CHttpRequest * pWinHttpRequest = reinterpret_cast<CHttpRequest *>(lpParameter);
  2078. INET_ASSERT(pWinHttpRequest != NULL);
  2079. dwExitCode = pWinHttpRequest->SendAsync();
  2080. pWinHttpRequest->Release();
  2081. // If this worker thread was impersonating, revert to the default
  2082. // process identity.
  2083. RevertToSelf();
  2084. return dwExitCode;
  2085. }
  2086. #endif//!TRUE_ASYNC
  2087. /*
  2088. * CHttpRequest::CreateAsyncWorkerThread
  2089. *
  2090. */
  2091. #if !defined(TRUE_ASYNC)
  2092. HRESULT
  2093. CHttpRequest::CreateAsyncWorkerThread()
  2094. {
  2095. DWORD dwWorkerThreadId;
  2096. HANDLE hThreadToken = NULL;
  2097. HRESULT hr;
  2098. hr = _CP.CreateEventSinksMarshaller();
  2099. if (FAILED(hr))
  2100. return hr;
  2101. hr = NOERROR;
  2102. //
  2103. // If the current thread is impersonating, then grab its access token
  2104. // and revert the current thread (so it is nolonger impersonating).
  2105. // After creating the worker thread, we will make the main thread
  2106. // impersonate again. Apparently you should not call CreateThread
  2107. // while impersonating.
  2108. //
  2109. if (OpenThreadToken(GetCurrentThread(), (TOKEN_IMPERSONATE | TOKEN_READ),
  2110. FALSE,
  2111. &hThreadToken))
  2112. {
  2113. INET_ASSERT(hThreadToken != 0);
  2114. RevertToSelf();
  2115. }
  2116. // Create the worker thread suspended.
  2117. _hWorkerThread = CreateThread(NULL, 0, WinHttpRequestSendAsync,
  2118. (void *)static_cast<CHttpRequest *>(this),
  2119. CREATE_SUSPENDED,
  2120. &dwWorkerThreadId);
  2121. // If CreateThread fails, grab the error code now.
  2122. if (!_hWorkerThread)
  2123. {
  2124. hr = HRESULT_FROM_WIN32(GetLastError());
  2125. }
  2126. //
  2127. // If the main thread was impersonating, then:
  2128. // (1) have the worker thread impersonate the same user, and
  2129. // (2) have the main thread resume impersonating the
  2130. // client too (since we called RevertToSelf above).
  2131. //
  2132. if (hThreadToken)
  2133. {
  2134. if (_hWorkerThread)
  2135. {
  2136. (void)SetThreadToken(&_hWorkerThread, hThreadToken);
  2137. }
  2138. (void)SetThreadToken(NULL, hThreadToken);
  2139. CloseHandle(hThreadToken);
  2140. }
  2141. // If the worker thread was created, start it running.
  2142. if (_hWorkerThread)
  2143. {
  2144. // The worker thread owns a ref count on the component.
  2145. // Don't call AddRef() as it will attribute the ref count
  2146. // to the main thread.
  2147. _cRefs++;
  2148. ResumeThread(_hWorkerThread);
  2149. }
  2150. else
  2151. {
  2152. _CP.ShutdownEventSinksMarshaller();
  2153. _CP.ReleaseEventSinksMarshaller();
  2154. }
  2155. return hr;
  2156. }
  2157. #endif//!TRUE_ASYNC
  2158. /*
  2159. * CHttpRequest::Send
  2160. *
  2161. * Purpose:
  2162. * Send the HTTP request
  2163. *
  2164. * Parameters:
  2165. * varBody IN Request body
  2166. *
  2167. * Errors:
  2168. * E_FAIL
  2169. * E_UNEXPECTED
  2170. * E_OUTOFMEMORY
  2171. * Errors from WinHttpAddRequestHeaders and WinHttpSendRequest
  2172. */
  2173. STDMETHODIMP
  2174. CHttpRequest::Send(VARIANT varBody)
  2175. {
  2176. HRESULT hr = NOERROR;
  2177. BOOL fRetCode = FALSE;
  2178. BOOL fRetryWithClientAuth = TRUE;
  2179. // Validate that we are called from our apartment's thread.
  2180. if (GetCurrentThreadId() != _dwMainThreadId)
  2181. return RPC_E_WRONG_THREAD;
  2182. // Validate parameter
  2183. if (!IsValidVariant(varBody))
  2184. return E_INVALIDARG;
  2185. DEBUG_ENTER2_API((DBG_HTTP,
  2186. Dword,
  2187. "IWinHttpRequest::Send",
  2188. "VARIANT varBody"
  2189. ));
  2190. TRACE_ENTER2_API((DBG_HTTP,
  2191. Dword,
  2192. "IWinHttpRequest::Send",
  2193. _hHTTP,
  2194. "VARIANT varBody"
  2195. ));
  2196. // Validate state
  2197. if (_eState < CHttpRequest::OPENED)
  2198. goto ErrorCannotCallBeforeOpen;
  2199. if (_fAsync)
  2200. {
  2201. if ((_eState > CHttpRequest::OPENED) && (_eState < CHttpRequest::RESPONSE))
  2202. goto ErrorPending;
  2203. }
  2204. // Get the request body
  2205. hr = SetRequestBody(varBody);
  2206. if (FAILED(hr))
  2207. goto Error;
  2208. hr = SetRequiredRequestHeaders();
  2209. if (FAILED(hr))
  2210. goto Error;
  2211. try_again:
  2212. SetState(CHttpRequest::SENDING);
  2213. if (_fAsync)
  2214. {
  2215. #if !defined(TRUE_ASYNC)
  2216. hr = CreateAsyncWorkerThread();
  2217. #else
  2218. hr = StartAsyncSend();
  2219. #endif//!TRUE_ASYNC
  2220. if (FAILED(hr))
  2221. goto Error;
  2222. }
  2223. else
  2224. {
  2225. //register callback
  2226. if (WINHTTP_INVALID_STATUS_CALLBACK ==
  2227. WinHttpSetStatusCallback(_hHTTP,
  2228. SyncCallback,
  2229. WINHTTP_CALLBACK_STATUS_SECURE_FAILURE,
  2230. NULL))
  2231. goto ErrorFail;
  2232. // Send the HTTP request
  2233. fRetCode = WinHttpSendRequest(
  2234. _hHTTP,
  2235. NULL, 0, // No header info here
  2236. _szRequestBuffer,
  2237. _cbRequestBody,
  2238. _cbRequestBody,
  2239. reinterpret_cast<DWORD_PTR>(this));
  2240. if (!fRetCode)
  2241. {
  2242. goto ErrorFail;
  2243. }
  2244. SetState(CHttpRequest::SENT);
  2245. fRetCode = WinHttpReceiveResponse(_hHTTP, NULL);
  2246. if (!fRetCode)
  2247. {
  2248. goto ErrorFail;
  2249. }
  2250. // Read the response data
  2251. hr = ReadResponse();
  2252. if (FAILED(hr))
  2253. goto Error;
  2254. }
  2255. hr = NOERROR;
  2256. Cleanup:
  2257. SetErrorInfo(hr);
  2258. DEBUG_LEAVE_API(hr);
  2259. return hr;
  2260. ErrorCannotCallBeforeOpen:
  2261. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN);
  2262. goto Error;
  2263. ErrorPending:
  2264. hr = E_PENDING;
  2265. goto Error;
  2266. ErrorFail:
  2267. hr = HRESULT_FROM_WIN32(GetLastError());
  2268. if (!_fAsync &&
  2269. hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) &&
  2270. fRetryWithClientAuth)
  2271. {
  2272. fRetryWithClientAuth = FALSE;
  2273. // Try to enumerate the first cert in the reverted user context,
  2274. // select the cert (per object sesssion, not global), and send
  2275. // the request again.
  2276. if (SelectCertificate())
  2277. goto try_again;
  2278. }
  2279. else if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_SECURE_FAILURE))
  2280. {
  2281. INET_ASSERT(FAILED(_hrSecureFailure));
  2282. hr = _hrSecureFailure;
  2283. }
  2284. _CP.FireOnError(hr);
  2285. goto Cleanup;
  2286. Error:
  2287. goto Cleanup;
  2288. }
  2289. /*
  2290. * CHttpRequest::SendAsync
  2291. *
  2292. * Purpose:
  2293. * Send the HTTP request
  2294. *
  2295. * Parameters:
  2296. * varBody IN Request body
  2297. *
  2298. * Errors:
  2299. * E_FAIL
  2300. * E_UNEXPECTED
  2301. * E_OUTOFMEMORY
  2302. * Errors from WinHttpAddRequestHeaders and WinHttpSendRequest
  2303. */
  2304. #if !defined(TRUE_ASYNC)
  2305. DWORD
  2306. CHttpRequest::SendAsync()
  2307. {
  2308. DWORD dwLastError = 0;
  2309. DWORD fRetCode;
  2310. HRESULT hr;
  2311. BOOL fRetryWithClientAuth = TRUE;
  2312. try_again:
  2313. if (_bAborted || !_hHTTP)
  2314. goto ErrorUnexpected;
  2315. // Send the HTTP request
  2316. fRetCode = WinHttpSendRequest(
  2317. _hHTTP,
  2318. NULL, 0, // No header info here
  2319. _szRequestBuffer,
  2320. _cbRequestBody,
  2321. _cbRequestBody,
  2322. 0);
  2323. if (!fRetCode)
  2324. goto ErrorFail;
  2325. SetState(CHttpRequest::SENT);
  2326. fRetCode = WinHttpReceiveResponse(_hHTTP, NULL);
  2327. if (!fRetCode)
  2328. goto ErrorFail;
  2329. if (!_bAborted)
  2330. {
  2331. hr = ReadResponse();
  2332. if (FAILED(hr))
  2333. {
  2334. if (hr == E_OUTOFMEMORY)
  2335. goto ErrorOutOfMemory;
  2336. goto ErrorFail;
  2337. }
  2338. }
  2339. hr = NOERROR;
  2340. Cleanup:
  2341. _hrAsyncResult = hr;
  2342. return dwLastError;
  2343. ErrorUnexpected:
  2344. dwLastError = ERROR_WINHTTP_INTERNAL_ERROR;
  2345. hr = HRESULT_FROM_WIN32(dwLastError);
  2346. goto Cleanup;
  2347. ErrorFail:
  2348. dwLastError = GetLastError();
  2349. if (dwLastError == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED &&
  2350. fRetryWithClientAuth)
  2351. {
  2352. fRetryWithClientAuth = FALSE;
  2353. // Try to enumerate the first cert in the reverted user context,
  2354. // select the cert (per object sesssion, not global), and send
  2355. // the request again.
  2356. if (SelectCertificate())
  2357. {
  2358. SetState(CHttpRequest::SENDING);
  2359. goto try_again;
  2360. }
  2361. }
  2362. hr = HRESULT_FROM_WIN32(dwLastError);
  2363. goto Cleanup;
  2364. ErrorOutOfMemory:
  2365. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2366. hr = E_OUTOFMEMORY;
  2367. goto Cleanup;
  2368. }
  2369. #endif//!TRUE_ASYNC
  2370. STDMETHODIMP
  2371. CHttpRequest::WaitForResponse(VARIANT varTimeout, VARIANT_BOOL * pboolSucceeded)
  2372. {
  2373. HRESULT hr = NOERROR;
  2374. bool bSucceeded= true;
  2375. DWORD dwTimeout;
  2376. // Validate that we are called from our apartment's thread.
  2377. if (GetCurrentThreadId() != _dwMainThreadId)
  2378. return RPC_E_WRONG_THREAD;
  2379. // Validate parameters; null pboolSucceeded pointer is Ok.
  2380. if (!IsValidVariant(varTimeout) ||
  2381. (pboolSucceeded &&
  2382. IsBadWritePtr(pboolSucceeded, sizeof(VARIANT_BOOL))))
  2383. return E_INVALIDARG;
  2384. // Get the timeout value. Disallow numbers
  2385. // less than -1 (which means INFINITE).
  2386. if (GetLongFromVariant(varTimeout, INFINITE) < -1L)
  2387. return E_INVALIDARG;
  2388. dwTimeout = GetDwordFromVariant(varTimeout, INFINITE);
  2389. DEBUG_ENTER_API((DBG_HTTP,
  2390. Dword,
  2391. "IWinHttpRequest::WaitForResponse",
  2392. "Timeout: %d, VARIANT_BOOL* pboolSucceeded: %#x",
  2393. dwTimeout,
  2394. pboolSucceeded
  2395. ));
  2396. // Validate state.
  2397. if (_eState < CHttpRequest::SENDING)
  2398. goto ErrorCannotCallBeforeSend;
  2399. //
  2400. // WaitForResponse is a no-op if we're not in async mode.
  2401. //
  2402. if (_fAsync &&
  2403. #ifdef TRUE_ASYNC
  2404. _hCompleteEvent
  2405. #else
  2406. _hWorkerThread
  2407. #endif
  2408. )
  2409. {
  2410. //
  2411. // Has the worker thread has already finished or event signaled?
  2412. //
  2413. if (WaitForSingleObject(
  2414. #ifdef TRUE_ASYNC
  2415. _hCompleteEvent
  2416. #else
  2417. _hWorkerThread
  2418. #endif
  2419. , 0) == WAIT_TIMEOUT)
  2420. {
  2421. //
  2422. // Convert Timeout from seconds to milliseconds. Any timeout
  2423. // value over 4 million seconds (~46 days) is "rounded up"
  2424. // to INFINITE. :)
  2425. //
  2426. if (dwTimeout > 4000000) // avoid overflow
  2427. {
  2428. dwTimeout = INFINITE;
  2429. }
  2430. else
  2431. {
  2432. // convert to milliseconds
  2433. dwTimeout *= 1000;
  2434. }
  2435. DWORD dwStartTime;
  2436. DWORD dwWaitResult;
  2437. bool bWaitAgain;
  2438. do
  2439. {
  2440. dwStartTime = GetTickCount();
  2441. dwWaitResult = MsgWaitForMultipleObjects(1,
  2442. #ifdef TRUE_ASYNC
  2443. &_hCompleteEvent
  2444. #else
  2445. &_hWorkerThread
  2446. #endif
  2447. ,
  2448. FALSE,
  2449. dwTimeout,
  2450. QS_ALLINPUT);
  2451. bWaitAgain = false;
  2452. switch (dwWaitResult)
  2453. {
  2454. case WAIT_OBJECT_0:
  2455. // Thread exited.
  2456. MessageLoop();
  2457. hr = _hrAsyncResult;
  2458. bSucceeded = SUCCEEDED(hr);
  2459. break;
  2460. case WAIT_OBJECT_0 + 1:
  2461. // Message waiting in the message queue.
  2462. // Run message pump to clear queue.
  2463. MessageLoop();
  2464. //check if object was not aborted
  2465. if (_eState != CHttpRequest::CREATED)
  2466. bWaitAgain = true;
  2467. else
  2468. hr = _hrAsyncResult;
  2469. break;
  2470. case WAIT_TIMEOUT:
  2471. // Timeout.
  2472. bSucceeded = false;
  2473. break;
  2474. case (-1):
  2475. default:
  2476. // Error.
  2477. goto ErrorFail;
  2478. break;
  2479. }
  2480. // If we're going to continue waiting for the worker
  2481. // thread, decrease timeout appropriately.
  2482. if (bWaitAgain)
  2483. {
  2484. dwTimeout = UpdateTimeout(dwTimeout, dwStartTime);
  2485. }
  2486. } while (bWaitAgain);
  2487. }
  2488. else
  2489. {
  2490. // If the worker thread is already done, then pump messages
  2491. // to clear any events that it may have posted.
  2492. MessageLoop();
  2493. hr = _hrAsyncResult;
  2494. bSucceeded = SUCCEEDED(hr);
  2495. }
  2496. }
  2497. //check if object was aborted
  2498. if (_eState == CHttpRequest::CREATED)
  2499. bSucceeded = false;
  2500. Cleanup:
  2501. if (pboolSucceeded)
  2502. {
  2503. *pboolSucceeded = (bSucceeded ? VARIANT_TRUE : VARIANT_FALSE);
  2504. }
  2505. if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_SECURE_FAILURE))
  2506. {
  2507. INET_ASSERT(FAILED(_hrSecureFailure));
  2508. hr = _hrSecureFailure;
  2509. }
  2510. SetErrorInfo(hr);
  2511. DEBUG_PRINT_API(ASYNC, INFO, (bSucceeded ? "Succeeded set to true\n" : "Succeeded set to false\n"))
  2512. DEBUG_LEAVE_API(hr);
  2513. return hr;
  2514. ErrorFail:
  2515. hr = HRESULT_FROM_WIN32(GetLastError());
  2516. goto Error;
  2517. ErrorCannotCallBeforeSend:
  2518. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  2519. goto Error;
  2520. Error:
  2521. bSucceeded = false;
  2522. goto Cleanup;
  2523. }
  2524. STDMETHODIMP
  2525. CHttpRequest::Abort()
  2526. {
  2527. DEBUG_ENTER_API((DBG_HTTP,
  2528. Dword,
  2529. "IWinHttpRequest::Abort",
  2530. NULL
  2531. ));
  2532. // Validate that we are called from our apartment's thread.
  2533. if (GetCurrentThreadId() != _dwMainThreadId)
  2534. return RPC_E_WRONG_THREAD;
  2535. //
  2536. // Abort if not already aborted and not in the CREATED state,
  2537. // (meaning at least the Open method has been called).
  2538. //
  2539. if ((_eState > CHttpRequest::CREATED) && !_bAborted)
  2540. {
  2541. DWORD error;
  2542. _bAborted = true;
  2543. // Tell our connection point manager to abort any
  2544. // events "in flight"--i.e., abort any events that
  2545. // may have already been posted by the worker thread.
  2546. _CP.FreezeEvents();
  2547. if (_hHTTP)
  2548. {
  2549. //
  2550. // Add a ref count on the HTTP Request handle.
  2551. //
  2552. INET_ASSERT(_hAbortedRequestObject == NULL);
  2553. error = MapHandleToAddress(_hHTTP, (LPVOID *)&_hAbortedRequestObject, FALSE);
  2554. INET_ASSERT(error == 0);
  2555. WinHttpCloseHandle(_hHTTP);
  2556. _hHTTP = NULL;
  2557. }
  2558. if (_hConnection)
  2559. {
  2560. //
  2561. // Add a ref count on the Connection handle.
  2562. //
  2563. INET_ASSERT(_hAbortedConnectObject == NULL);
  2564. error = MapHandleToAddress(_hConnection, (LPVOID *)&_hAbortedConnectObject, FALSE);
  2565. INET_ASSERT(error == 0);
  2566. WinHttpCloseHandle(_hConnection);
  2567. _hConnection = NULL;
  2568. }
  2569. // Recycle the object.
  2570. Recycle();
  2571. }
  2572. DEBUG_LEAVE_API(NOERROR);
  2573. return NOERROR;
  2574. }
  2575. STDMETHODIMP
  2576. CHttpRequest::SetTimeouts(long ResolveTimeout, long ConnectTimeout, long SendTimeout, long ReceiveTimeout)
  2577. {
  2578. if ((ResolveTimeout < -1L) || (ConnectTimeout < -1L) ||
  2579. (SendTimeout < -1L) || (ReceiveTimeout < -1L))
  2580. {
  2581. return E_INVALIDARG;
  2582. }
  2583. HRESULT hr = NOERROR;
  2584. _ResolveTimeout = (DWORD) ResolveTimeout;
  2585. _ConnectTimeout = (DWORD) ConnectTimeout;
  2586. _SendTimeout = (DWORD) SendTimeout;
  2587. _ReceiveTimeout = (DWORD) ReceiveTimeout;
  2588. _bSetTimeouts = true;
  2589. if (_hHTTP)
  2590. {
  2591. DWORD fRetCode;
  2592. fRetCode = WinHttpSetTimeouts(_hHTTP, (int)_ResolveTimeout,
  2593. (int)_ConnectTimeout,
  2594. (int)_SendTimeout,
  2595. (int)_ReceiveTimeout);
  2596. if (!fRetCode)
  2597. hr = E_INVALIDARG;
  2598. }
  2599. return hr;
  2600. }
  2601. STDMETHODIMP
  2602. CHttpRequest::SetClientCertificate(BSTR ClientCertificate)
  2603. {
  2604. BOOL fCertLocalMachine = FALSE;
  2605. BSTR bstrCertStore = NULL;
  2606. BSTR bstrCertSubject = NULL;
  2607. HRESULT hr;
  2608. if (!IsValidBstr(ClientCertificate))
  2609. goto ErrorInvalidArg;
  2610. hr = ParseSelectedCert(ClientCertificate,
  2611. &fCertLocalMachine,
  2612. &bstrCertStore,
  2613. &bstrCertSubject
  2614. );
  2615. // Only fill in new selection if parsed successfully.
  2616. if (hr == S_OK)
  2617. {
  2618. _fCertLocalMachine = fCertLocalMachine;
  2619. if (_bstrCertStore)
  2620. DL(SysFreeString)(_bstrCertStore);
  2621. _bstrCertStore = bstrCertStore;
  2622. if (_bstrCertSubject)
  2623. DL(SysFreeString)(_bstrCertSubject);
  2624. _bstrCertSubject = bstrCertSubject;
  2625. }
  2626. if (_hHTTP)
  2627. {
  2628. // We will try again later if this fails now, so
  2629. // don't worry about detecting an error.
  2630. SelectCertificate();
  2631. }
  2632. Exit:
  2633. SetErrorInfo(hr);
  2634. return hr;
  2635. ErrorInvalidArg:
  2636. hr = E_INVALIDARG;
  2637. goto Exit;
  2638. }
  2639. STDMETHODIMP
  2640. CHttpRequest::SetAutoLogonPolicy(WinHttpRequestAutoLogonPolicy AutoLogonPolicy)
  2641. {
  2642. HRESULT hr;
  2643. switch (AutoLogonPolicy)
  2644. {
  2645. case AutoLogonPolicy_Always:
  2646. _dwAutoLogonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
  2647. break;
  2648. case AutoLogonPolicy_OnlyIfBypassProxy:
  2649. _dwAutoLogonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM;
  2650. break;
  2651. case AutoLogonPolicy_Never:
  2652. _dwAutoLogonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
  2653. break;
  2654. default:
  2655. goto ErrorInvalidArg;
  2656. }
  2657. if (_hHTTP)
  2658. {
  2659. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_AUTOLOGON_POLICY,
  2660. (void *) &_dwAutoLogonPolicy,
  2661. sizeof(_dwAutoLogonPolicy)))
  2662. goto ErrorFail;
  2663. }
  2664. hr = NOERROR;
  2665. Exit:
  2666. SetErrorInfo(hr);
  2667. return hr;
  2668. ErrorInvalidArg:
  2669. hr = E_INVALIDARG;
  2670. goto Exit;
  2671. ErrorFail:
  2672. hr = HRESULT_FROM_WIN32(GetLastError());
  2673. goto Exit;
  2674. }
  2675. /*
  2676. * CHttpRequest::SetRequestBody
  2677. *
  2678. * Purpose:
  2679. * Set the request body
  2680. *
  2681. * Parameters:
  2682. * varBody IN Request body
  2683. *
  2684. * Errors:
  2685. * E_FAIL
  2686. * E_OUTOFMEMORY
  2687. * E_UNEXPECTED
  2688. */
  2689. HRESULT
  2690. CHttpRequest::SetRequestBody(VARIANT varBody)
  2691. {
  2692. HRESULT hr = NOERROR;
  2693. VARIANT varTemp;
  2694. SAFEARRAY * psa = NULL;
  2695. VARIANT * pvarBody = NULL;
  2696. // varBody is validated by CHttpRequest::Send().
  2697. DL(VariantInit)(&varTemp);
  2698. // Free a previously set body and its response
  2699. if (_szRequestBuffer)
  2700. {
  2701. delete [] _szRequestBuffer;
  2702. _szRequestBuffer = NULL;
  2703. _cbRequestBody = 0;
  2704. }
  2705. _bSetUtf8Charset = false;
  2706. SafeRelease(_pResponseStream);
  2707. _cbResponseBody = 0;
  2708. if (V_ISBYREF(&varBody))
  2709. {
  2710. pvarBody = varBody.pvarVal;
  2711. }
  2712. else
  2713. {
  2714. pvarBody = &varBody;
  2715. }
  2716. // Check for an empty body
  2717. if (V_VT(pvarBody) == VT_EMPTY ||
  2718. V_VT(pvarBody) == VT_NULL ||
  2719. V_VT(pvarBody) == VT_ERROR)
  2720. goto Cleanup;
  2721. //
  2722. // Extract the body: BSTR or array of UI1
  2723. //
  2724. // We need to explicitly look for the byte array since it will be converted
  2725. // to a BSTR by DL(VariantChangeType).
  2726. if (V_ISARRAY(pvarBody) && (V_VT(pvarBody) & VT_UI1))
  2727. {
  2728. BYTE * pb = NULL;
  2729. long lUBound = 0;
  2730. long lLBound = 0;
  2731. psa = V_ARRAY(pvarBody);
  2732. // We only handle 1 dimensional arrays
  2733. if (DL(SafeArrayGetDim)(psa) != 1)
  2734. goto ErrorFail;
  2735. // Get access to the blob
  2736. hr = DL(SafeArrayAccessData)(psa, (void **)&pb);
  2737. if (FAILED(hr))
  2738. goto Error;
  2739. // Compute the data size from the upper and lower array bounds
  2740. hr = DL(SafeArrayGetLBound)(psa, 1, &lLBound);
  2741. if (FAILED(hr))
  2742. goto Error;
  2743. hr = DL(SafeArrayGetUBound)(psa, 1, &lUBound);
  2744. if (FAILED(hr))
  2745. goto Error;
  2746. _cbRequestBody = lUBound - lLBound + 1;
  2747. if (_cbRequestBody > 0)
  2748. {
  2749. // Copy the data into the request buffer
  2750. _szRequestBuffer = New char [_cbRequestBody];
  2751. if (!_szRequestBuffer)
  2752. {
  2753. _cbRequestBody = 0;
  2754. goto ErrorOutOfMemory;
  2755. }
  2756. ::memcpy(_szRequestBuffer, pb, _cbRequestBody);
  2757. }
  2758. DL(SafeArrayUnaccessData)(psa);
  2759. psa = NULL;
  2760. }
  2761. else
  2762. {
  2763. BSTR bstrBody = NULL;
  2764. bool bFreeString = false;
  2765. //
  2766. // Try a BSTR; avoiding to call GetBSTRFromVariant (which makes
  2767. // a copy) if possible.
  2768. //
  2769. if (V_VT(pvarBody) == VT_BSTR)
  2770. {
  2771. bstrBody = V_BSTR(pvarBody); // direct BSTR string, do not free
  2772. bFreeString = false;
  2773. }
  2774. else
  2775. {
  2776. hr = GetBSTRFromVariant(*pvarBody, &bstrBody);
  2777. if (SUCCEEDED(hr))
  2778. {
  2779. bFreeString = true;
  2780. }
  2781. else if (hr == E_INVALIDARG)
  2782. {
  2783. // GetBSTRFromVariant will return E_INVALIDARG if the
  2784. // call to VariantChangeType AVs. The VARIANT may be
  2785. // valid, but may simply not contain a BSTR, so if
  2786. // some other error is returned (most likely
  2787. // DISP_E_MISMATCH), then continue and see if the
  2788. // VARIANT contains an IStream object.
  2789. goto Error;
  2790. }
  2791. }
  2792. if (bstrBody)
  2793. {
  2794. hr = BSTRToUTF8(&_szRequestBuffer, &_cbRequestBody, bstrBody, &_bSetUtf8Charset);
  2795. if (bFreeString)
  2796. DL(SysFreeString)(bstrBody);
  2797. if (FAILED(hr))
  2798. goto Error;
  2799. }
  2800. else
  2801. {
  2802. // Try a Stream
  2803. if (V_VT(pvarBody) == VT_UNKNOWN || V_VT(pvarBody) == VT_DISPATCH)
  2804. {
  2805. IStream * pStm = NULL;
  2806. __try
  2807. {
  2808. hr = pvarBody->punkVal->QueryInterface(
  2809. IID_IStream,
  2810. (void **)&pStm);
  2811. }
  2812. __except (EXCEPTION_EXECUTE_HANDLER)
  2813. {
  2814. hr = E_INVALIDARG;
  2815. }
  2816. if (FAILED(hr))
  2817. goto Error;
  2818. hr = ReadFromStream(
  2819. &_szRequestBuffer,
  2820. &_cbRequestBody,
  2821. pStm);
  2822. pStm->Release();
  2823. if (FAILED(hr))
  2824. goto Error;
  2825. }
  2826. }
  2827. }
  2828. hr = NOERROR;
  2829. Cleanup:
  2830. DL(VariantClear)(&varTemp);
  2831. if (psa)
  2832. DL(SafeArrayUnaccessData)(psa);
  2833. return hr;
  2834. ErrorOutOfMemory:
  2835. hr = E_OUTOFMEMORY;
  2836. goto Error;
  2837. ErrorFail:
  2838. hr = HRESULT_FROM_WIN32(GetLastError());
  2839. goto Error;
  2840. Error:
  2841. goto Cleanup;
  2842. }
  2843. /*
  2844. * CHttpRequest::GetResponseHeader
  2845. *
  2846. * Purpose:
  2847. * Get a response header
  2848. *
  2849. * Parameters:
  2850. * bstrHeader IN HTTP request header
  2851. * pbstrValue OUT Header value
  2852. *
  2853. * Errors:
  2854. * E_FAIL
  2855. * E_INVALIDARG
  2856. * E_OUTOFMEMORY
  2857. * E_UNEXPECTED
  2858. * Errors from WinHttpQueryHeaders
  2859. */
  2860. STDMETHODIMP
  2861. CHttpRequest::GetResponseHeader(BSTR bstrHeader, BSTR * pbstrValue)
  2862. {
  2863. return _GetResponseHeader(bstrHeader, pbstrValue);
  2864. }
  2865. #ifdef TRUE_ASYNC
  2866. HRESULT
  2867. CHttpRequest::_GetResponseHeader(OLECHAR * wszHeader, BSTR * pbstrValue)
  2868. {
  2869. HRESULT hr;
  2870. // Validate state
  2871. if (_eState < CHttpRequest::SENDING)
  2872. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  2873. else
  2874. hr = _GetResponseHeader2(wszHeader, pbstrValue, _hHTTP);
  2875. SetErrorInfo(hr);
  2876. return hr;
  2877. }
  2878. HRESULT
  2879. CHttpRequest::_GetResponseHeader2(OLECHAR * wszHeader, BSTR * pbstrValue, HINTERNET hInternet)
  2880. {
  2881. HRESULT hr = NOERROR;
  2882. WCHAR * wszHeaderValue = NULL;
  2883. DWORD cb;
  2884. BOOL fRetCode;
  2885. // Validate parameters
  2886. if (IsBadReadPtr(wszHeader, 2) ||
  2887. IsBadWritePtr(pbstrValue, sizeof(BSTR)) ||
  2888. !lstrlenW(wszHeader))
  2889. return E_INVALIDARG;
  2890. *pbstrValue = NULL;
  2891. cb = 64; // arbitrary size in which many header values will fit
  2892. wszHeaderValue = New WCHAR[cb];
  2893. if (!wszHeaderValue)
  2894. goto ErrorOutOfMemory;
  2895. RetryQuery:
  2896. // Determine length of requested header
  2897. fRetCode = WinHttpQueryHeaders(
  2898. hInternet,
  2899. HTTP_QUERY_CUSTOM,
  2900. wszHeader,
  2901. wszHeaderValue,
  2902. &cb,
  2903. 0);
  2904. // Check for ERROR_INSUFFICIENT_BUFFER - reallocate the buffer and retry
  2905. if (!fRetCode)
  2906. {
  2907. switch (GetLastError())
  2908. {
  2909. case ERROR_INSUFFICIENT_BUFFER:
  2910. {
  2911. delete [] wszHeaderValue;
  2912. wszHeaderValue = New WCHAR[cb]; // should this be cb/2?
  2913. if (!wszHeaderValue)
  2914. goto ErrorOutOfMemory;
  2915. goto RetryQuery;
  2916. }
  2917. case ERROR_HTTP_HEADER_NOT_FOUND:
  2918. goto ErrorFail;
  2919. default:
  2920. goto ErrorFail;
  2921. }
  2922. }
  2923. *pbstrValue = DL(SysAllocString)(wszHeaderValue);
  2924. if (!*pbstrValue)
  2925. goto ErrorOutOfMemory;
  2926. hr = NOERROR;
  2927. Cleanup:
  2928. if (wszHeaderValue)
  2929. delete [] wszHeaderValue;
  2930. return hr;
  2931. ErrorOutOfMemory:
  2932. hr = E_OUTOFMEMORY;
  2933. goto Error;
  2934. ErrorFail:
  2935. hr = HRESULT_FROM_WIN32(GetLastError());
  2936. goto Error;
  2937. Error:
  2938. goto Cleanup;
  2939. }
  2940. #else//TRUE_ASYNC
  2941. HRESULT
  2942. CHttpRequest::_GetResponseHeader(OLECHAR * wszHeader, BSTR * pbstrValue)
  2943. {
  2944. HRESULT hr = NOERROR;
  2945. WCHAR * wszHeaderValue = NULL;
  2946. DWORD cb;
  2947. BOOL fRetCode;
  2948. // Validate parameters
  2949. if (IsBadReadPtr(wszHeader, 2) ||
  2950. IsBadWritePtr(pbstrValue, sizeof(BSTR)) ||
  2951. !lstrlenW(wszHeader))
  2952. return E_INVALIDARG;
  2953. // Validate state
  2954. if (_eState < CHttpRequest::SENDING)
  2955. goto ErrorCannotCallBeforeSend;
  2956. *pbstrValue = NULL;
  2957. cb = 64; // arbitrary size in which many header values will fit
  2958. wszHeaderValue = New WCHAR[cb];
  2959. if (!wszHeaderValue)
  2960. goto ErrorOutOfMemory;
  2961. RetryQuery:
  2962. // Determine length of requested header
  2963. fRetCode = WinHttpQueryHeaders(
  2964. _hHTTP,
  2965. HTTP_QUERY_CUSTOM,
  2966. wszHeader,
  2967. wszHeaderValue,
  2968. &cb,
  2969. 0);
  2970. // Check for ERROR_INSUFFICIENT_BUFFER - reallocate the buffer and retry
  2971. if (!fRetCode)
  2972. {
  2973. switch (GetLastError())
  2974. {
  2975. case ERROR_INSUFFICIENT_BUFFER:
  2976. {
  2977. delete [] wszHeaderValue;
  2978. wszHeaderValue = New WCHAR[cb]; // should this be cb/2?
  2979. if (!wszHeaderValue)
  2980. goto ErrorOutOfMemory;
  2981. goto RetryQuery;
  2982. }
  2983. case ERROR_HTTP_HEADER_NOT_FOUND:
  2984. goto ErrorFail;
  2985. default:
  2986. goto ErrorFail;
  2987. }
  2988. }
  2989. *pbstrValue = DL(SysAllocString)(wszHeaderValue);
  2990. if (!*pbstrValue)
  2991. goto ErrorOutOfMemory;
  2992. hr = NOERROR;
  2993. Cleanup:
  2994. if (wszHeaderValue)
  2995. delete [] wszHeaderValue;
  2996. SetErrorInfo(hr);
  2997. return hr;
  2998. ErrorOutOfMemory:
  2999. hr = E_OUTOFMEMORY;
  3000. goto Error;
  3001. ErrorFail:
  3002. hr = HRESULT_FROM_WIN32(GetLastError());
  3003. goto Error;
  3004. ErrorCannotCallBeforeSend:
  3005. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3006. goto Error;
  3007. Error:
  3008. goto Cleanup;
  3009. }
  3010. #endif//TRUE_ASYNC
  3011. /*
  3012. * CHttpRequest::GetAllResponseHeaders
  3013. *
  3014. * Purpose:
  3015. * Return the response headers
  3016. *
  3017. * Parameters:
  3018. * pbstrHeaders IN/OUT CRLF delimited headers
  3019. *
  3020. * Errors:
  3021. * E_FAIL
  3022. * E_INVALIDARG
  3023. * E_OUTOFMEMORY
  3024. * E_UNEXPECTED
  3025. */
  3026. STDMETHODIMP
  3027. CHttpRequest::GetAllResponseHeaders(BSTR * pbstrHeaders)
  3028. {
  3029. HRESULT hr = NOERROR;
  3030. BOOL fRetCode;
  3031. WCHAR * wszAllHeaders = NULL;
  3032. WCHAR * wszFirstHeader = NULL;
  3033. DWORD cb = 0;
  3034. // Validate parameter
  3035. if (IsBadWritePtr(pbstrHeaders, sizeof(BSTR)))
  3036. return E_INVALIDARG;
  3037. // Validate state
  3038. if (_eState < CHttpRequest::SENDING)
  3039. goto ErrorCannotCallBeforeSend;
  3040. *pbstrHeaders = NULL;
  3041. RetryQuery:
  3042. // Determine the length of all headers and then get all the headers
  3043. fRetCode = WinHttpQueryHeaders(
  3044. _hHTTP,
  3045. HTTP_QUERY_RAW_HEADERS_CRLF,
  3046. WINHTTP_HEADER_NAME_BY_INDEX,
  3047. wszAllHeaders,
  3048. &cb,
  3049. 0);
  3050. if (!fRetCode)
  3051. {
  3052. // Allocate a buffer large enough to hold all headers
  3053. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3054. {
  3055. if (wszAllHeaders != NULL)
  3056. {
  3057. delete [] wszAllHeaders;
  3058. wszAllHeaders = NULL;
  3059. }
  3060. wszAllHeaders = New WCHAR[cb];
  3061. if (!wszAllHeaders)
  3062. goto ErrorOutOfMemory;
  3063. goto RetryQuery;
  3064. }
  3065. else
  3066. {
  3067. goto ErrorFail;
  3068. }
  3069. }
  3070. // Bypass status line - jump past first CRLF (0x13, 0x10)
  3071. wszFirstHeader = wcschr(wszAllHeaders, '\n');
  3072. if (*wszFirstHeader == '\n')
  3073. {
  3074. *pbstrHeaders = DL(SysAllocString)(wszFirstHeader + 1);
  3075. if (!*pbstrHeaders)
  3076. goto ErrorOutOfMemory;
  3077. }
  3078. hr = NOERROR;
  3079. Cleanup:
  3080. if (wszAllHeaders)
  3081. delete [] wszAllHeaders;
  3082. SetErrorInfo(hr);
  3083. return hr;
  3084. ErrorOutOfMemory:
  3085. hr = E_OUTOFMEMORY;
  3086. goto Error;
  3087. ErrorFail:
  3088. hr = HRESULT_FROM_WIN32(GetLastError());
  3089. goto Error;
  3090. ErrorCannotCallBeforeSend:
  3091. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3092. goto Error;
  3093. Error:
  3094. if (pbstrHeaders)
  3095. {
  3096. DL(SysFreeString)(*pbstrHeaders);
  3097. *pbstrHeaders = NULL;
  3098. }
  3099. goto Cleanup;
  3100. }
  3101. /*
  3102. * CHttpRequest::get_status
  3103. *
  3104. * Purpose:
  3105. * Get the request status code
  3106. *
  3107. * Parameters:
  3108. * plStatus OUT HTTP request status code
  3109. *
  3110. * Errors:
  3111. * E_FAIL
  3112. * E_INVALIDARG
  3113. * E_UNEXPECTED
  3114. */
  3115. STDMETHODIMP
  3116. CHttpRequest::get_Status(long * plStatus)
  3117. {
  3118. HRESULT hr = NOERROR;
  3119. DWORD cb = sizeof(DWORD);
  3120. BOOL fRetCode;
  3121. DWORD dwStatus;
  3122. // Validate parameter
  3123. if (IsBadWritePtr(plStatus, sizeof(long)))
  3124. return E_INVALIDARG;
  3125. // Validate state
  3126. if (_eState < CHttpRequest::SENDING)
  3127. goto ErrorCannotCallBeforeSend;
  3128. else if (_eState < CHttpRequest::RECEIVING)
  3129. goto ErrorRequestInProgress;
  3130. fRetCode = HttpQueryInfoA(
  3131. _hHTTP,
  3132. HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  3133. WINHTTP_HEADER_NAME_BY_INDEX,
  3134. &dwStatus,
  3135. &cb,
  3136. 0);
  3137. if (!fRetCode)
  3138. goto ErrorFail;
  3139. *plStatus = dwStatus;
  3140. hr = NOERROR;
  3141. Cleanup:
  3142. SetErrorInfo(hr);
  3143. return hr;
  3144. ErrorCannotCallBeforeSend:
  3145. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3146. goto Error;
  3147. ErrorRequestInProgress:
  3148. hr = E_PENDING;
  3149. goto Error;
  3150. ErrorFail:
  3151. hr = HRESULT_FROM_WIN32(GetLastError());
  3152. goto Error;
  3153. Error:
  3154. goto Cleanup;
  3155. }
  3156. /*
  3157. * CHttpRequest::get_StatusText
  3158. *
  3159. * Purpose:
  3160. * Get the request status text
  3161. *
  3162. * Parameters:
  3163. * pbstrStatus OUT HTTP request status text
  3164. *
  3165. * Errors:
  3166. * E_FAIL
  3167. * E_INVALIDARG
  3168. * E_UNEXPECTED
  3169. */
  3170. STDMETHODIMP
  3171. CHttpRequest::get_StatusText(BSTR * pbstrStatus)
  3172. {
  3173. HRESULT hr = NOERROR;
  3174. WCHAR wszStatusText[32];
  3175. WCHAR * pwszStatusText = wszStatusText;
  3176. BOOL fFreeStatusString = FALSE;
  3177. DWORD cb;
  3178. BOOL fRetCode;
  3179. // Validate parameter
  3180. if (IsBadWritePtr(pbstrStatus, sizeof(BSTR)))
  3181. return E_INVALIDARG;
  3182. // Validate state
  3183. // Validate state
  3184. if (_eState < CHttpRequest::SENDING)
  3185. goto ErrorCannotCallBeforeSend;
  3186. else if (_eState < CHttpRequest::RECEIVING)
  3187. goto ErrorRequestInProgress;
  3188. *pbstrStatus = NULL;
  3189. cb = sizeof(wszStatusText) / sizeof(WCHAR);
  3190. RetryQuery:
  3191. fRetCode = WinHttpQueryHeaders(
  3192. _hHTTP,
  3193. HTTP_QUERY_STATUS_TEXT,
  3194. WINHTTP_HEADER_NAME_BY_INDEX,
  3195. pwszStatusText,
  3196. &cb,
  3197. 0);
  3198. if (!fRetCode)
  3199. {
  3200. // Check for ERROR_INSUFFICIENT_BUFFER error
  3201. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3202. {
  3203. // Reallocate the status text buffer
  3204. if (fFreeStatusString)
  3205. delete [] pwszStatusText;
  3206. pwszStatusText = New WCHAR[cb];
  3207. if (!pwszStatusText)
  3208. goto ErrorOutOfMemory;
  3209. fFreeStatusString = TRUE;
  3210. goto RetryQuery;
  3211. }
  3212. else
  3213. {
  3214. goto ErrorFail;
  3215. }
  3216. }
  3217. // Convert the status text to a BSTR
  3218. *pbstrStatus = DL(SysAllocString)(pwszStatusText);
  3219. if (!*pbstrStatus)
  3220. goto ErrorOutOfMemory;
  3221. hr = NOERROR;
  3222. Cleanup:
  3223. if (fFreeStatusString)
  3224. delete [] pwszStatusText;
  3225. SetErrorInfo(hr);
  3226. return hr;
  3227. ErrorOutOfMemory:
  3228. hr = E_OUTOFMEMORY;
  3229. goto Error;
  3230. ErrorCannotCallBeforeSend:
  3231. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3232. goto Error;
  3233. ErrorRequestInProgress:
  3234. hr = E_PENDING;
  3235. goto Error;
  3236. ErrorFail:
  3237. hr = HRESULT_FROM_WIN32(GetLastError());
  3238. goto Cleanup;
  3239. Error:
  3240. goto Cleanup;
  3241. }
  3242. /*
  3243. * CHttpRequest::get_ResponseBody
  3244. *
  3245. * Purpose:
  3246. * Retrieve the response body as a SAFEARRAY of UI1
  3247. *
  3248. * Parameters:
  3249. * pvarBody OUT Response blob
  3250. *
  3251. * Errors:
  3252. * E_INVALIDARG
  3253. * E_UNEXPECTED
  3254. * E_PENDING
  3255. */
  3256. STDMETHODIMP
  3257. CHttpRequest::get_ResponseBody(VARIANT * pvarBody)
  3258. {
  3259. HRESULT hr = NOERROR;
  3260. // Validate parameter
  3261. if (IsBadWritePtr(pvarBody, sizeof(VARIANT)))
  3262. return E_INVALIDARG;
  3263. // Validate state
  3264. if (_eState < CHttpRequest::SENDING)
  3265. goto ErrorCannotCallBeforeSend;
  3266. else if (_eState < CHttpRequest::RESPONSE)
  3267. goto ErrorPending;
  3268. DL(VariantInit)(pvarBody);
  3269. if (_cbResponseBody != 0)
  3270. {
  3271. HGLOBAL hGlobal;
  3272. hr = DL(GetHGlobalFromStream)(_pResponseStream, &hGlobal);
  3273. if (FAILED(hr))
  3274. goto Error;
  3275. const BYTE * pResponseData = (const BYTE *) GlobalLock(hGlobal);
  3276. if (!pResponseData)
  3277. goto ErrorFail;
  3278. hr = CreateVector(pvarBody, pResponseData, _cbResponseBody);
  3279. GlobalUnlock(hGlobal);
  3280. if (FAILED(hr))
  3281. goto Error;
  3282. }
  3283. else
  3284. {
  3285. V_VT(pvarBody) = VT_EMPTY;
  3286. }
  3287. hr = NOERROR;
  3288. Cleanup:
  3289. SetErrorInfo(hr);
  3290. return hr;
  3291. ErrorCannotCallBeforeSend:
  3292. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3293. goto Error;
  3294. ErrorPending:
  3295. hr = E_PENDING;
  3296. goto Error;
  3297. ErrorFail:
  3298. hr = HRESULT_FROM_WIN32(::GetLastError());
  3299. goto Error;
  3300. Error:
  3301. if (pvarBody)
  3302. DL(VariantClear)(pvarBody);
  3303. goto Cleanup;
  3304. }
  3305. /*
  3306. * CHttpRequest::get_ResponseText
  3307. *
  3308. * Purpose:
  3309. * Retrieve the response body as a BSTR
  3310. *
  3311. * Parameters:
  3312. * pbstrBody OUT response as a BSTR
  3313. *
  3314. * Errors:
  3315. * E_INVALIDARG
  3316. * E_OUTOFMEMORY
  3317. * E_UNEXPECTED
  3318. * E_PENDING
  3319. */
  3320. STDMETHODIMP
  3321. CHttpRequest::get_ResponseText(BSTR * pbstrBody)
  3322. {
  3323. HRESULT hr;
  3324. MIMECSETINFO mimeSetInfo;
  3325. IMultiLanguage * pMultiLanguage = NULL;
  3326. IMultiLanguage2 * pMultiLanguage2 = NULL;
  3327. CHAR szContentType[1024];
  3328. DWORD cb;
  3329. BSTR bstrCharset = NULL;
  3330. HGLOBAL hGlobal = NULL;
  3331. char * pResponseData = NULL;
  3332. // Validate parameter
  3333. if (IsBadWritePtr(pbstrBody, sizeof(BSTR)))
  3334. return E_INVALIDARG;
  3335. // Validate state
  3336. if (_eState < CHttpRequest::SENDING)
  3337. goto ErrorCannotCallBeforeSend;
  3338. else if (_eState < CHttpRequest::RESPONSE)
  3339. goto ErrorPending;
  3340. if (!_hHTTP)
  3341. {
  3342. hr = E_UNEXPECTED;
  3343. goto Error;
  3344. }
  3345. if (_cbResponseBody != 0)
  3346. {
  3347. hr = DL(GetHGlobalFromStream)(_pResponseStream, &hGlobal);
  3348. if (FAILED(hr))
  3349. goto Error;
  3350. pResponseData = (char *) GlobalLock(hGlobal);
  3351. if (!pResponseData)
  3352. goto ErrorFail;
  3353. }
  3354. else
  3355. {
  3356. *pbstrBody = NULL;
  3357. }
  3358. // Check if charset is present.
  3359. cb = sizeof(szContentType);
  3360. if (HttpQueryInfoA(_hHTTP,
  3361. WINHTTP_QUERY_CONTENT_TYPE,
  3362. NULL,
  3363. szContentType,
  3364. &cb,
  3365. NULL))
  3366. {
  3367. LPSTR lpszCharset;
  3368. LPSTR lpszCharsetEnd;
  3369. if ((lpszCharset = StrStrIA(szContentType, "charset=")) != NULL)
  3370. {
  3371. LPSTR lpszBeginQuote = NULL;
  3372. LPSTR lpszEndQuote = NULL;
  3373. if ((lpszBeginQuote = StrChrA(lpszCharset, '\"')) != NULL)
  3374. {
  3375. lpszEndQuote = StrChrA(lpszBeginQuote+1, '\"');
  3376. }
  3377. if (lpszEndQuote)
  3378. {
  3379. lpszCharset = lpszBeginQuote + 1;
  3380. lpszCharsetEnd = lpszEndQuote;
  3381. }
  3382. else
  3383. {
  3384. lpszCharset += sizeof("charset=")-1;
  3385. lpszCharsetEnd = StrChrA(lpszCharset, ';');
  3386. }
  3387. // only **STRLEN** to be passed to AsciiToBSTR
  3388. AsciiToBSTR(&bstrCharset, lpszCharset, (int)(lpszCharsetEnd ? (lpszCharsetEnd-lpszCharset) : lstrlen(lpszCharset)));
  3389. }
  3390. }
  3391. if (!bstrCharset)
  3392. {
  3393. // use ISO-8859-1
  3394. mimeSetInfo.uiInternetEncoding = 28591;
  3395. mimeSetInfo.uiCodePage = 1252;
  3396. // note unitialized wszCharset - not cached, not used.
  3397. }
  3398. else
  3399. {
  3400. // obtain codepage corresponding to charset
  3401. if (!g_pMimeInfoCache)
  3402. {
  3403. //create the mimeinfo cache.
  3404. DWORD dwStatus = 0;
  3405. if (!GlobalDataInitCritSec.Lock())
  3406. {
  3407. goto ErrorOutOfMemory;
  3408. }
  3409. if (!g_pMimeInfoCache)
  3410. {
  3411. g_pMimeInfoCache = new CMimeInfoCache(&dwStatus);
  3412. if(!g_pMimeInfoCache
  3413. || dwStatus)
  3414. {
  3415. if (g_pMimeInfoCache)
  3416. delete g_pMimeInfoCache;
  3417. g_pMimeInfoCache = NULL;
  3418. GlobalDataInitCritSec.Unlock();
  3419. goto ErrorOutOfMemory;
  3420. }
  3421. }
  3422. GlobalDataInitCritSec.Unlock();
  3423. }
  3424. //check the cache for info
  3425. if (S_OK != g_pMimeInfoCache->GetCharsetInfo(bstrCharset, &mimeSetInfo))
  3426. {
  3427. // if info not in cache, get from mlang
  3428. hr = DL(CoCreateInstance)(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
  3429. IID_IMultiLanguage, (void**)&pMultiLanguage);
  3430. if (FAILED(hr))
  3431. {
  3432. goto ConvertError;
  3433. }
  3434. INET_ASSERT (pMultiLanguage);
  3435. pMultiLanguage->QueryInterface(IID_IMultiLanguage2, (void **)&pMultiLanguage2);
  3436. pMultiLanguage->Release();
  3437. if (!pMultiLanguage2)
  3438. {
  3439. goto ConvertError;
  3440. }
  3441. if (FAILED((pMultiLanguage2)->GetCharsetInfo(bstrCharset, &mimeSetInfo)))
  3442. {
  3443. //Check for known-exceptions
  3444. if (!StrCmpNIW(bstrCharset, L"ISO8859_1", MAX_MIMECSET_NAME))
  3445. {
  3446. mimeSetInfo.uiInternetEncoding = 28591;
  3447. mimeSetInfo.uiCodePage = 1252;
  3448. StrCpyNW(mimeSetInfo.wszCharset, L"ISO8859_1", lstrlenW(L"ISO8859_1")+1);
  3449. }
  3450. else
  3451. {
  3452. goto ConvertError;
  3453. }
  3454. }
  3455. // add obtained info to cache.
  3456. g_pMimeInfoCache->AddCharsetInfo(&mimeSetInfo);
  3457. }
  3458. }
  3459. // here only if we have mimeSetInfo filled in correctly.
  3460. hr = MultiByteToWideCharInternal(pbstrBody, pResponseData, (int)_cbResponseBody, mimeSetInfo.uiInternetEncoding, &pMultiLanguage2);
  3461. if (hr != S_OK)
  3462. {
  3463. MultiByteToWideCharInternal(pbstrBody, pResponseData, (int)_cbResponseBody, mimeSetInfo.uiCodePage, &pMultiLanguage2);
  3464. }
  3465. Cleanup:
  3466. if (hGlobal)
  3467. GlobalUnlock(hGlobal);
  3468. if (pMultiLanguage2)
  3469. {
  3470. pMultiLanguage2->Release();
  3471. }
  3472. SetErrorInfo(hr);
  3473. return hr;
  3474. ErrorCannotCallBeforeSend:
  3475. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3476. goto Error;
  3477. ErrorPending:
  3478. hr = E_PENDING;
  3479. goto Error;
  3480. ErrorFail:
  3481. hr = HRESULT_FROM_WIN32(::GetLastError());
  3482. goto Error;
  3483. ErrorOutOfMemory:
  3484. hr = E_OUTOFMEMORY;
  3485. goto Error;
  3486. Error:
  3487. goto Cleanup;
  3488. ConvertError:
  3489. hr = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION);
  3490. goto Cleanup;
  3491. }
  3492. STDMETHODIMP
  3493. CHttpRequest::get_ResponseStream(VARIANT * pvarBody)
  3494. {
  3495. HRESULT hr = NOERROR;
  3496. IStream * pStm = NULL;
  3497. // Validate parameter
  3498. if (IsBadWritePtr(pvarBody, sizeof(VARIANT)))
  3499. return E_INVALIDARG;
  3500. // Validate state
  3501. if (_eState < CHttpRequest::SENDING)
  3502. goto ErrorCannotCallBeforeSend;
  3503. else if (_eState < CHttpRequest::RESPONSE)
  3504. goto ErrorPending;
  3505. DL(VariantInit)(pvarBody);
  3506. hr = CreateStreamOnResponse(&pStm);
  3507. if (FAILED(hr))
  3508. goto Error;
  3509. V_VT(pvarBody) = VT_UNKNOWN;
  3510. pvarBody->punkVal = pStm;
  3511. hr = NOERROR;
  3512. Cleanup:
  3513. SetErrorInfo(hr);
  3514. return hr;
  3515. ErrorCannotCallBeforeSend:
  3516. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND);
  3517. goto Error;
  3518. ErrorPending:
  3519. hr = E_PENDING;
  3520. goto Error;
  3521. Error:
  3522. if (pvarBody)
  3523. DL(VariantClear)(pvarBody);
  3524. goto Cleanup;
  3525. }
  3526. void
  3527. CHttpRequest::SetState(State state)
  3528. {
  3529. if (_fAsync)
  3530. {
  3531. InterlockedExchange((long *)&_eState, state);
  3532. }
  3533. else
  3534. {
  3535. _eState = state;
  3536. }
  3537. }
  3538. /*
  3539. * CHttpRequest::CreateStreamOnResponse
  3540. *
  3541. * Purpose:
  3542. * Create a Stream containing the Response data
  3543. *
  3544. * Parameters:
  3545. * ppStm IN/OUT Stream
  3546. *
  3547. * Errors:
  3548. * E_INVALIDARG
  3549. * E_OUTOFMEMORY
  3550. */
  3551. HRESULT
  3552. CHttpRequest::CreateStreamOnResponse(IStream ** ppStm)
  3553. {
  3554. HRESULT hr = NOERROR;
  3555. LARGE_INTEGER liReset = { 0, 0 };
  3556. if (!ppStm)
  3557. goto ErrorInvalidArg;
  3558. *ppStm = NULL;
  3559. if (_cbResponseBody)
  3560. {
  3561. INET_ASSERT(_pResponseStream);
  3562. hr = _pResponseStream->Clone(ppStm);
  3563. if (FAILED(hr))
  3564. goto Error;
  3565. }
  3566. else
  3567. {
  3568. //
  3569. // No response body, return an empty stream object
  3570. //
  3571. ULARGE_INTEGER size = { 0, 0 };
  3572. hr = DL(CreateStreamOnHGlobal)(NULL, TRUE, ppStm);
  3573. if (FAILED(hr))
  3574. goto Error;
  3575. (*ppStm)->SetSize(size);
  3576. }
  3577. hr = (*ppStm)->Seek(liReset, STREAM_SEEK_SET, NULL);
  3578. if (FAILED(hr))
  3579. goto Error;
  3580. hr = NOERROR;
  3581. Cleanup:
  3582. return hr;
  3583. ErrorInvalidArg:
  3584. hr = E_INVALIDARG;
  3585. goto Error;
  3586. Error:
  3587. if (ppStm)
  3588. SafeRelease(*ppStm);
  3589. goto Cleanup;
  3590. }
  3591. STDMETHODIMP
  3592. CHttpRequest::get_Option(WinHttpRequestOption Option, VARIANT * Value)
  3593. {
  3594. HRESULT hr;
  3595. if (IsBadWritePtr(Value, sizeof(VARIANT)))
  3596. return E_INVALIDARG;
  3597. switch (Option)
  3598. {
  3599. case WinHttpRequestOption_UserAgentString:
  3600. {
  3601. V_BSTR(Value) = DL(SysAllocString)(GetUserAgentString());
  3602. if (V_BSTR(Value) == NULL)
  3603. goto ErrorOutOfMemory;
  3604. V_VT(Value) = VT_BSTR;
  3605. break;
  3606. }
  3607. case WinHttpRequestOption_URL:
  3608. {
  3609. WCHAR * pwszUrl = NULL;
  3610. DWORD dwBufferSize = 0;
  3611. if (_eState < CHttpRequest::OPENED)
  3612. goto ErrorCannotCallBeforeOpen;
  3613. if (!WinHttpQueryOption(_hHTTP, WINHTTP_OPTION_URL, NULL, &dwBufferSize) &&
  3614. (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
  3615. {
  3616. pwszUrl = New WCHAR[dwBufferSize + 1];
  3617. if (!pwszUrl)
  3618. goto ErrorOutOfMemory;
  3619. if (WinHttpQueryOption(_hHTTP, WINHTTP_OPTION_URL, pwszUrl, &dwBufferSize))
  3620. {
  3621. V_BSTR(Value) = DL(SysAllocString)(pwszUrl);
  3622. V_VT(Value) = VT_BSTR;
  3623. hr = NOERROR;
  3624. }
  3625. else
  3626. {
  3627. hr = E_FAIL;
  3628. }
  3629. delete [] pwszUrl;
  3630. if (FAILED(hr))
  3631. {
  3632. goto ErrorFail;
  3633. }
  3634. else if (V_BSTR(Value) == NULL)
  3635. {
  3636. goto ErrorOutOfMemory;
  3637. }
  3638. }
  3639. break;
  3640. }
  3641. case WinHttpRequestOption_URLCodePage:
  3642. V_I4(Value) = (long) _dwCodePage;
  3643. V_VT(Value) = VT_I4;
  3644. break;
  3645. case WinHttpRequestOption_EscapePercentInURL:
  3646. V_BOOL(Value) = (_dwEscapeFlag & WINHTTP_FLAG_ESCAPE_PERCENT) ? VARIANT_TRUE : VARIANT_FALSE;
  3647. V_VT(Value) = VT_BOOL;
  3648. break;
  3649. case WinHttpRequestOption_EnableCertificateRevocationCheck:
  3650. V_BOOL(Value) = _fCheckForRevocation ? VARIANT_TRUE : VARIANT_FALSE;
  3651. V_VT(Value) = VT_BOOL;
  3652. break;
  3653. case WinHttpRequestOption_SslErrorIgnoreFlags:
  3654. if (_dwSslIgnoreFlags)
  3655. V_I4(Value) = (long) (_dwSslIgnoreFlags & SslErrorFlag_Ignore_All);
  3656. else
  3657. V_I4(Value) = (long) 0;
  3658. V_VT(Value) = VT_I4;
  3659. break;
  3660. case WinHttpRequestOption_UrlEscapeDisable:
  3661. V_BOOL(Value) = (_dwEscapeFlag & WINHTTP_FLAG_ESCAPE_DISABLE) ? VARIANT_TRUE : VARIANT_FALSE;
  3662. V_VT(Value) = VT_BOOL;
  3663. break;
  3664. case WinHttpRequestOption_UrlEscapeDisableQuery:
  3665. V_BOOL(Value) = (_dwEscapeFlag & WINHTTP_FLAG_ESCAPE_DISABLE_QUERY) ? VARIANT_TRUE : VARIANT_FALSE;
  3666. V_VT(Value) = VT_BOOL;
  3667. break;
  3668. case WinHttpRequestOption_EnableRedirects:
  3669. BOOL bEnableRedirects;
  3670. if (_dwRedirectPolicy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER)
  3671. {
  3672. bEnableRedirects = FALSE;
  3673. }
  3674. else
  3675. {
  3676. bEnableRedirects = TRUE; // for this particular query we return TRUE even HTTPS->HTTP is not allowed
  3677. // we are consistent with the SetOption where TRUE means "we allow redirs
  3678. // except HTTPS->HTTP ones
  3679. }
  3680. V_BOOL(Value) = bEnableRedirects ? VARIANT_TRUE: VARIANT_FALSE;
  3681. V_VT(Value) = VT_BOOL;
  3682. break;
  3683. case WinHttpRequestOption_EnableHttpsToHttpRedirects:
  3684. V_BOOL(Value) = ((_dwRedirectPolicy == WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS) ? VARIANT_TRUE : VARIANT_FALSE);
  3685. V_VT(Value) = VT_BOOL;
  3686. break;
  3687. case WinHttpRequestOption_EnablePassportAuthentication:
  3688. V_BOOL(Value) = ((_dwPassportConfig == (WINHTTP_DISABLE_PASSPORT_AUTH | WINHTTP_DISABLE_PASSPORT_KEYRING)) ? VARIANT_FALSE : VARIANT_TRUE);
  3689. V_VT(Value) = VT_BOOL;
  3690. break;
  3691. case WinHttpRequestOption_MaxAutomaticRedirects:
  3692. V_I4(Value) = _lMaxAutomaticRedirects;
  3693. V_VT(Value) = VT_I4;
  3694. break;
  3695. case WinHttpRequestOption_MaxResponseHeaderSize:
  3696. V_I4(Value) = _lMaxResponseHeaderSize;
  3697. V_VT(Value) = VT_I4;
  3698. break;
  3699. case WinHttpRequestOption_MaxResponseDrainSize:
  3700. V_I4(Value) = _lMaxResponseDrainSize;
  3701. V_VT(Value) = VT_I4;
  3702. break;
  3703. case WinHttpRequestOption_EnableTracing:
  3704. {
  3705. BOOL fEnableTracing;
  3706. DWORD dwBufferSize = sizeof(BOOL);
  3707. if (!WinHttpQueryOption(NULL,
  3708. WINHTTP_OPTION_ENABLETRACING,
  3709. (LPVOID)&fEnableTracing,
  3710. &dwBufferSize))
  3711. goto ErrorFail;
  3712. V_BOOL(Value) = fEnableTracing ? VARIANT_TRUE : VARIANT_FALSE;
  3713. V_VT(Value) = VT_BOOL;
  3714. break;
  3715. }
  3716. case WinHttpRequestOption_RevertImpersonationOverSsl:
  3717. V_BOOL(Value) = _bEnableSslImpersonation ? VARIANT_FALSE : VARIANT_TRUE;
  3718. V_VT(Value) = VT_BOOL;
  3719. break;
  3720. case WinHttpRequestOption_EnableHttp1_1:
  3721. V_BOOL(Value) = _bHttp1_1Mode ? VARIANT_TRUE : VARIANT_FALSE;
  3722. V_VT(Value) = VT_BOOL;
  3723. break;
  3724. default:
  3725. DL(VariantInit)(Value);
  3726. hr = E_INVALIDARG;
  3727. goto Error;
  3728. }
  3729. hr = NOERROR;
  3730. Cleanup:
  3731. SetErrorInfo(hr);
  3732. return hr;
  3733. ErrorCannotCallBeforeOpen:
  3734. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN);
  3735. goto Error;
  3736. ErrorOutOfMemory:
  3737. hr = E_OUTOFMEMORY;
  3738. goto Error;
  3739. ErrorFail:
  3740. hr = HRESULT_FROM_WIN32(GetLastError());
  3741. goto Error;
  3742. Error:
  3743. goto Cleanup;
  3744. }
  3745. STDMETHODIMP
  3746. CHttpRequest::put_Option(WinHttpRequestOption Option, VARIANT Value)
  3747. {
  3748. HRESULT hr;
  3749. if (!IsValidVariant(Value))
  3750. return E_INVALIDARG;
  3751. switch (Option)
  3752. {
  3753. case WinHttpRequestOption_UserAgentString:
  3754. {
  3755. BSTR bstrUserAgent;
  3756. hr = GetBSTRFromVariant(Value, &bstrUserAgent);
  3757. if (FAILED(hr) || !bstrUserAgent)
  3758. return E_INVALIDARG;
  3759. if (*bstrUserAgent == L'\0')
  3760. {
  3761. DL(SysFreeString)(bstrUserAgent);
  3762. return E_INVALIDARG;
  3763. }
  3764. if (_hInet)
  3765. {
  3766. if (!WinHttpSetOption(_hInet, WINHTTP_OPTION_USER_AGENT,
  3767. bstrUserAgent,
  3768. lstrlenW(bstrUserAgent)))
  3769. {
  3770. goto ErrorFail;
  3771. }
  3772. }
  3773. if (_hHTTP)
  3774. {
  3775. if (!WinHttpSetOption(_hHTTP, WINHTTP_OPTION_USER_AGENT,
  3776. bstrUserAgent,
  3777. lstrlenW(bstrUserAgent)))
  3778. {
  3779. goto ErrorFail;
  3780. }
  3781. }
  3782. if (_bstrUserAgent)
  3783. DL(SysFreeString)(_bstrUserAgent);
  3784. _bstrUserAgent = bstrUserAgent;
  3785. break;
  3786. }
  3787. case WinHttpRequestOption_URL:
  3788. // The URL cannot be set using the Option property.
  3789. return E_INVALIDARG;
  3790. case WinHttpRequestOption_URLCodePage:
  3791. {
  3792. _dwCodePage = GetDwordFromVariant(Value, CP_UTF8);
  3793. if (_hInet)
  3794. {
  3795. if (!WinHttpSetOption(_hInet, WINHTTP_OPTION_CODEPAGE,
  3796. &_dwCodePage,
  3797. sizeof(_dwCodePage)))
  3798. goto ErrorFail;
  3799. }
  3800. if (_hConnection)
  3801. {
  3802. if (!WinHttpSetOption(_hConnection, WINHTTP_OPTION_CODEPAGE,
  3803. &_dwCodePage,
  3804. sizeof(_dwCodePage)))
  3805. goto ErrorFail;
  3806. }
  3807. break;
  3808. }
  3809. case WinHttpRequestOption_EscapePercentInURL:
  3810. {
  3811. BOOL fEscapePercent = GetBoolFromVariant(Value, FALSE);
  3812. if (fEscapePercent)
  3813. _dwEscapeFlag |= WINHTTP_FLAG_ESCAPE_PERCENT;
  3814. else
  3815. _dwEscapeFlag &= ~(DWORD)WINHTTP_FLAG_ESCAPE_PERCENT;
  3816. break;
  3817. }
  3818. case WinHttpRequestOption_UrlEscapeDisable:
  3819. {
  3820. BOOL fEscape = GetBoolFromVariant(Value, FALSE);
  3821. if (fEscape)
  3822. _dwEscapeFlag |= WINHTTP_FLAG_ESCAPE_DISABLE;
  3823. else
  3824. _dwEscapeFlag &= ~(DWORD)WINHTTP_FLAG_ESCAPE_DISABLE;
  3825. break;
  3826. }
  3827. case WinHttpRequestOption_UrlEscapeDisableQuery:
  3828. {
  3829. BOOL fEscape = GetBoolFromVariant(Value, FALSE);
  3830. if (fEscape)
  3831. _dwEscapeFlag |= WINHTTP_FLAG_ESCAPE_DISABLE_QUERY;
  3832. else
  3833. _dwEscapeFlag &= ~(DWORD)WINHTTP_FLAG_ESCAPE_DISABLE_QUERY;
  3834. break;
  3835. }
  3836. case WinHttpRequestOption_EnableCertificateRevocationCheck:
  3837. {
  3838. _fCheckForRevocation = GetBoolFromVariant(Value, TRUE);
  3839. if (_hHTTP && _fCheckForRevocation)
  3840. {
  3841. DWORD dwOptions = WINHTTP_ENABLE_SSL_REVOCATION;
  3842. WinHttpSetOption(_hHTTP,
  3843. WINHTTP_OPTION_ENABLE_FEATURE,
  3844. (LPVOID)&dwOptions,
  3845. sizeof(dwOptions));
  3846. }
  3847. break;
  3848. }
  3849. case WinHttpRequestOption_SslErrorIgnoreFlags:
  3850. {
  3851. DWORD dwSslIgnoreFlags = GetDwordFromVariant(Value, _dwSslIgnoreFlags);
  3852. if (dwSslIgnoreFlags & ~SECURITY_INTERNET_MASK)
  3853. {
  3854. return E_INVALIDARG;
  3855. }
  3856. dwSslIgnoreFlags &= SslErrorFlag_Ignore_All;
  3857. if (_hHTTP)
  3858. {
  3859. // Set the SSL ignore flags through an undocumented front door
  3860. if (!WinHttpSetOption(_hHTTP,
  3861. WINHTTP_OPTION_SECURITY_FLAGS,
  3862. (LPVOID)&dwSslIgnoreFlags,
  3863. sizeof(dwSslIgnoreFlags)))
  3864. goto ErrorFail;
  3865. }
  3866. _dwSslIgnoreFlags = dwSslIgnoreFlags;
  3867. break;
  3868. }
  3869. case WinHttpRequestOption_SelectCertificate:
  3870. {
  3871. BSTR bstrCertSelection;
  3872. hr = GetBSTRFromVariant(Value, &bstrCertSelection);
  3873. if (FAILED(hr))
  3874. {
  3875. hr = E_INVALIDARG;
  3876. goto Error;
  3877. }
  3878. hr = SetClientCertificate(bstrCertSelection);
  3879. DL(SysFreeString)(bstrCertSelection);
  3880. if (FAILED(hr))
  3881. goto Error;
  3882. break;
  3883. }
  3884. case WinHttpRequestOption_EnableRedirects:
  3885. {
  3886. BOOL fEnableRedirects = GetBoolFromVariant(Value, TRUE);
  3887. DWORD dwRedirectPolicy =
  3888. fEnableRedirects ? WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP : WINHTTP_OPTION_REDIRECT_POLICY_NEVER;
  3889. if ((dwRedirectPolicy == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP)
  3890. && (_dwRedirectPolicy == WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS))
  3891. {
  3892. // "always" -> "disalow" transition no-op
  3893. // this means the app enabled HTTPS->HTTP before this call, and attempt to enable redir
  3894. // should not move us away from the always state
  3895. break;
  3896. }
  3897. if (_hInet)
  3898. {
  3899. if (!WinHttpSetOption(_hInet,
  3900. WINHTTP_OPTION_REDIRECT_POLICY,
  3901. (LPVOID)&dwRedirectPolicy,
  3902. sizeof(DWORD)))
  3903. goto ErrorFail;
  3904. }
  3905. if (_hHTTP)
  3906. {
  3907. if (!WinHttpSetOption(_hHTTP,
  3908. WINHTTP_OPTION_REDIRECT_POLICY,
  3909. (LPVOID)&dwRedirectPolicy,
  3910. sizeof(DWORD)))
  3911. goto ErrorFail;
  3912. }
  3913. _dwRedirectPolicy = dwRedirectPolicy;
  3914. break;
  3915. }
  3916. case WinHttpRequestOption_EnableHttpsToHttpRedirects:
  3917. {
  3918. BOOL fEnableHttpsToHttpRedirects = GetBoolFromVariant(Value, FALSE);
  3919. DWORD dwRedirectPolicy = (fEnableHttpsToHttpRedirects
  3920. ? WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS
  3921. : WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP);
  3922. if (_dwRedirectPolicy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER)
  3923. {
  3924. // "never" -> "always" or "never" -> "disalow" transition not allowed
  3925. // this means the app disabled redirect before this call, it will have to re-enable redirect
  3926. // before it can enable or disable HTTPS->HTTP
  3927. break;
  3928. }
  3929. if (_hInet)
  3930. {
  3931. if (!WinHttpSetOption(_hInet,
  3932. WINHTTP_OPTION_REDIRECT_POLICY,
  3933. (LPVOID)&dwRedirectPolicy,
  3934. sizeof(DWORD)))
  3935. goto ErrorFail;
  3936. }
  3937. if (_hHTTP)
  3938. {
  3939. if (!WinHttpSetOption(_hHTTP,
  3940. WINHTTP_OPTION_REDIRECT_POLICY,
  3941. (LPVOID)&dwRedirectPolicy,
  3942. sizeof(DWORD)))
  3943. goto ErrorFail;
  3944. }
  3945. _dwRedirectPolicy = dwRedirectPolicy;
  3946. break;
  3947. }
  3948. case WinHttpRequestOption_SecureProtocols:
  3949. {
  3950. DWORD dwSecureProtocols = GetDwordFromVariant(Value, _dwSecureProtocols);
  3951. if (dwSecureProtocols & ~WINHTTP_FLAG_SECURE_PROTOCOL_ALL)
  3952. {
  3953. return E_INVALIDARG;
  3954. }
  3955. _dwSecureProtocols = dwSecureProtocols;
  3956. if (_hInet)
  3957. {
  3958. // Set the per session SSL protocols.
  3959. // This can be done at any time, so there's no need to
  3960. // keep track of this here.
  3961. if (!WinHttpSetOption(_hInet,
  3962. WINHTTP_OPTION_SECURE_PROTOCOLS,
  3963. (LPVOID)&dwSecureProtocols,
  3964. sizeof(dwSecureProtocols)))
  3965. goto ErrorFail;
  3966. }
  3967. break;
  3968. }
  3969. case WinHttpRequestOption_EnablePassportAuthentication:
  3970. {
  3971. BOOL fEnablePassportAuth = GetBoolFromVariant(Value, FALSE);
  3972. DWORD dwPassportConfig = (fEnablePassportAuth
  3973. ? (WINHTTP_ENABLE_PASSPORT_AUTH | WINHTTP_ENABLE_PASSPORT_KEYRING)
  3974. : (WINHTTP_DISABLE_PASSPORT_AUTH | WINHTTP_DISABLE_PASSPORT_KEYRING));
  3975. if (_hInet)
  3976. {
  3977. if (!WinHttpSetOption(_hInet,
  3978. WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH,
  3979. (LPVOID)&dwPassportConfig,
  3980. sizeof(DWORD)))
  3981. goto ErrorFail;
  3982. }
  3983. _dwPassportConfig = dwPassportConfig;
  3984. break;
  3985. }
  3986. case WinHttpRequestOption_EnableTracing:
  3987. {
  3988. BOOL fEnableTracing = GetBoolFromVariant(Value, TRUE);
  3989. if (!WinHttpSetOption(NULL,
  3990. WINHTTP_OPTION_ENABLETRACING,
  3991. (LPVOID)&fEnableTracing,
  3992. sizeof(BOOL)))
  3993. goto ErrorFail;
  3994. break;
  3995. }
  3996. case WinHttpRequestOption_RevertImpersonationOverSsl:
  3997. {
  3998. if (_hInet)
  3999. {
  4000. // Must be called before the Open method because
  4001. // the open method also creates a request handle.
  4002. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN);
  4003. goto Error;
  4004. }
  4005. else
  4006. {
  4007. _bEnableSslImpersonation = (GetBoolFromVariant(Value, TRUE) ? FALSE : TRUE);
  4008. }
  4009. break;
  4010. }
  4011. case WinHttpRequestOption_MaxAutomaticRedirects:
  4012. case WinHttpRequestOption_MaxResponseHeaderSize:
  4013. case WinHttpRequestOption_MaxResponseDrainSize:
  4014. {
  4015. DWORD dwSetting = (DWORD)-1;
  4016. LONG* plResultTarget = NULL;
  4017. switch(Option)
  4018. {
  4019. case WinHttpRequestOption_MaxAutomaticRedirects:
  4020. dwSetting = WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS;
  4021. plResultTarget = &_lMaxAutomaticRedirects;
  4022. break;
  4023. case WinHttpRequestOption_MaxResponseHeaderSize:
  4024. dwSetting = WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE;
  4025. plResultTarget = &_lMaxResponseHeaderSize;
  4026. break;
  4027. case WinHttpRequestOption_MaxResponseDrainSize:
  4028. dwSetting = WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE;
  4029. plResultTarget = &_lMaxResponseDrainSize;
  4030. break;
  4031. default:
  4032. INET_ASSERT(0); // shouldn't be possible
  4033. goto ErrorFail;
  4034. }
  4035. LONG lInput = GetLongFromVariant(Value, -1);
  4036. DWORD dwInput = (DWORD)lInput;
  4037. DWORD dwInputSize = sizeof(dwInput);
  4038. if (lInput < 0 || lInput != (LONG)dwInput)
  4039. {
  4040. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  4041. goto Error;
  4042. }
  4043. if (_hHTTP != NULL
  4044. && TRUE != WinHttpSetOption( _hHTTP, dwSetting, &dwInput, dwInputSize))
  4045. {
  4046. goto ErrorFail;
  4047. }
  4048. *plResultTarget = lInput;
  4049. break;
  4050. }
  4051. case WinHttpRequestOption_EnableHttp1_1:
  4052. if (_hHTTP != NULL)
  4053. {
  4054. hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN);
  4055. goto Error;
  4056. }
  4057. _bHttp1_1Mode = GetBoolFromVariant(Value, TRUE);
  4058. break;
  4059. default:
  4060. return E_INVALIDARG;
  4061. }
  4062. hr = NOERROR;
  4063. Cleanup:
  4064. SetErrorInfo(hr);
  4065. return hr;
  4066. ErrorFail:
  4067. hr = HRESULT_FROM_WIN32(GetLastError());
  4068. goto Error;
  4069. Error:
  4070. goto Cleanup;
  4071. }
  4072. IErrorInfo *
  4073. CHttpRequest::CreateErrorObject(HRESULT hr)
  4074. {
  4075. INET_ASSERT(FAILED(hr));
  4076. ICreateErrorInfo * pCErrInfo = NULL;
  4077. IErrorInfo * pErrInfo = NULL;
  4078. DWORD error = hr;
  4079. DWORD dwFmtMsgFlag = FORMAT_MESSAGE_FROM_SYSTEM;
  4080. HMODULE hModule = NULL;
  4081. DWORD rc;
  4082. LPWSTR pwszMessage = NULL;
  4083. const DWORD dwSize = 512;
  4084. pwszMessage = New WCHAR[dwSize];
  4085. if (pwszMessage == NULL)
  4086. return NULL;
  4087. if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
  4088. {
  4089. DWORD errcode = HRESULT_CODE(hr);
  4090. if ((errcode > WINHTTP_ERROR_BASE) && (errcode <= WINHTTP_ERROR_LAST))
  4091. {
  4092. dwFmtMsgFlag = FORMAT_MESSAGE_FROM_HMODULE;
  4093. hModule = GetModuleHandle("winhttp.dll");
  4094. error = errcode;
  4095. }
  4096. }
  4097. rc = ::FormatMessageW(dwFmtMsgFlag, hModule,
  4098. error,
  4099. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  4100. pwszMessage,
  4101. dwSize,
  4102. NULL);
  4103. if (rc != 0)
  4104. {
  4105. if (SUCCEEDED(DL(CreateErrorInfo)(&pCErrInfo)))
  4106. {
  4107. if (SUCCEEDED(pCErrInfo->QueryInterface(IID_IErrorInfo, (void **) &pErrInfo)))
  4108. {
  4109. pCErrInfo->SetSource(L"WinHttp.WinHttpRequest");
  4110. pCErrInfo->SetGUID(IID_IWinHttpRequest);
  4111. pCErrInfo->SetDescription(pwszMessage);
  4112. }
  4113. pCErrInfo->Release();
  4114. }
  4115. }
  4116. delete [] pwszMessage;
  4117. return pErrInfo;
  4118. }
  4119. void
  4120. CHttpRequest::SetErrorInfo(HRESULT hr)
  4121. {
  4122. if (FAILED(hr))
  4123. {
  4124. IErrorInfo * pErrInfo = CreateErrorObject(hr);
  4125. if (pErrInfo)
  4126. {
  4127. DL(SetErrorInfo)(0, pErrInfo);
  4128. pErrInfo->Release();
  4129. }
  4130. }
  4131. }
  4132. BOOL
  4133. CHttpRequest::SelectCertificate()
  4134. {
  4135. HCERTSTORE hCertStore = NULL;
  4136. BOOL fRet = FALSE;
  4137. HANDLE hThreadToken = NULL;
  4138. PCCERT_CONTEXT pCertContext = NULL;
  4139. // Make sure security DLLs are loaded
  4140. if (LoadSecurity() != ERROR_SUCCESS)
  4141. return FALSE;
  4142. // If impersonating, revert while trying to obtain the cert
  4143. if (!_bEnableSslImpersonation && OpenThreadToken(GetCurrentThread(), (TOKEN_IMPERSONATE | TOKEN_READ),
  4144. FALSE,
  4145. &hThreadToken))
  4146. {
  4147. INET_ASSERT(hThreadToken != 0);
  4148. RevertToSelf();
  4149. }
  4150. hCertStore = (*g_pfnCertOpenStore)(CERT_STORE_PROV_SYSTEM,
  4151. 0,
  4152. 0,
  4153. CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
  4154. (_fCertLocalMachine ? CERT_SYSTEM_STORE_LOCAL_MACHINE:
  4155. CERT_SYSTEM_STORE_CURRENT_USER),
  4156. _bstrCertStore ? _bstrCertStore : L"MY");
  4157. if (!hCertStore)
  4158. {
  4159. TRACE_PRINT_API(THRDINFO,
  4160. INFO,
  4161. ("Unable to open certificate store %s\\%Q; GetLastError() = %s [%d]\n",
  4162. _fCertLocalMachine? "Local Machine": "Current User",
  4163. _bstrCertStore ? _bstrCertStore : L"MY",
  4164. InternetMapError(::GetLastError()),
  4165. ::GetLastError()
  4166. ));
  4167. goto Cleanup;
  4168. }
  4169. if (_bstrCertSubject && _bstrCertSubject[0])
  4170. {
  4171. CERT_RDN SubjectRDN;
  4172. CERT_RDN_ATTR rdnAttr;
  4173. rdnAttr.pszObjId = szOID_COMMON_NAME;
  4174. rdnAttr.dwValueType = CERT_RDN_ANY_TYPE;
  4175. rdnAttr.Value.cbData = lstrlenW(_bstrCertSubject) * sizeof(WCHAR);
  4176. rdnAttr.Value.pbData = (BYTE *) _bstrCertSubject;
  4177. SubjectRDN.cRDNAttr = 1;
  4178. SubjectRDN.rgRDNAttr = &rdnAttr;
  4179. //
  4180. // First try an exact match for the certificate lookup.
  4181. // If that fails, then try a prefix match.
  4182. //
  4183. pCertContext = (*g_pfnCertFindCertificateInStore)(hCertStore,
  4184. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4185. CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG |
  4186. CERT_UNICODE_IS_RDN_ATTRS_FLAG,
  4187. CERT_FIND_SUBJECT_ATTR,
  4188. &SubjectRDN,
  4189. NULL);
  4190. if (! pCertContext)
  4191. {
  4192. pCertContext = (*g_pfnCertFindCertificateInStore)(hCertStore,
  4193. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4194. 0,
  4195. CERT_FIND_SUBJECT_STR,
  4196. (LPVOID) _bstrCertSubject,
  4197. NULL);
  4198. }
  4199. }
  4200. else
  4201. {
  4202. pCertContext = (*g_pfnCertFindCertificateInStore)(hCertStore,
  4203. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4204. 0,
  4205. CERT_FIND_ANY,
  4206. NULL,
  4207. NULL);
  4208. }
  4209. if (pCertContext)
  4210. {
  4211. fRet = WinHttpSetOption(_hHTTP,
  4212. WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
  4213. (LPVOID) pCertContext,
  4214. sizeof(CERT_CONTEXT));
  4215. }
  4216. else
  4217. {
  4218. TRACE_PRINT_API(THRDINFO,
  4219. INFO,
  4220. ("Unable to find certificate %Q in store %s\\%Q; GetLastError() = %s [%d]\n",
  4221. _bstrCertSubject,
  4222. _fCertLocalMachine? "Local Machine": "Current User",
  4223. _bstrCertStore ? _bstrCertStore : L"MY",
  4224. InternetMapError(::GetLastError()),
  4225. ::GetLastError()
  4226. ));
  4227. }
  4228. Cleanup:
  4229. if (pCertContext)
  4230. (*g_pfnCertFreeCertificateContext)(pCertContext);
  4231. if (hCertStore)
  4232. (*g_pfnCertCloseStore)(hCertStore, 0);
  4233. // Restore the impersonating state for the current thread.
  4234. if (hThreadToken)
  4235. {
  4236. (void)SetThreadToken(NULL, hThreadToken);
  4237. CloseHandle(hThreadToken);
  4238. }
  4239. return fRet;
  4240. }
  4241. /*
  4242. * ParseSelectedCert
  4243. *
  4244. * Purpose:
  4245. * Given a certificate, breakdown the location
  4246. * (local machine vs. current user), store (MY, CA, etc.), and
  4247. * subject name of the form:
  4248. * "[CURRENT_USER | LOCAL_MACHINE [\store]\]cert_subject_name"
  4249. *
  4250. * The backslash character is the delimiter, and the CURRENT_USER vs.
  4251. * LOCAL_MACHINE choice can optionally include a store (any store
  4252. * can be chosen). If there are more than two backslash characters
  4253. * present in the string, this function assumes everything after the
  4254. * second backslash is the cert subject name fragment to use for finding
  4255. * a match.
  4256. *
  4257. * If the optional pieces are not specified "CURRENT_USER\MY" are
  4258. * the defaults chosen.
  4259. *
  4260. * The pbstrLocation, pbstrStore, and pbstrSubject parameters
  4261. * are allocated and filled in with the default or parsed strings, or set
  4262. * to NULL if a failure occurs (e.g. out of memory or invalid param).
  4263. * The caller should free all params on success via DL(SysFreeString).
  4264. */
  4265. HRESULT ParseSelectedCert(BSTR bstrSelection,
  4266. LPBOOL pfLocalMachine,
  4267. BSTR *pbstrStore,
  4268. BSTR *pbstrSubject
  4269. )
  4270. {
  4271. HRESULT hr = S_OK;
  4272. LPWSTR lpwszSelection = bstrSelection;
  4273. LPWSTR lpwszStart = lpwszSelection;
  4274. *pfLocalMachine = FALSE;
  4275. *pbstrStore = NULL;
  4276. *pbstrSubject = NULL;
  4277. if (!bstrSelection)
  4278. {
  4279. // When NULL, fill in an empty string to simulate first enum
  4280. *pbstrSubject = DL(SysAllocString)(L"");
  4281. if (!*pbstrSubject)
  4282. {
  4283. hr = E_OUTOFMEMORY;
  4284. goto quit;
  4285. }
  4286. // Need to also fill in the default "MY" store.
  4287. goto DefaultStore;
  4288. }
  4289. while (*lpwszSelection && *lpwszSelection != L'\\')
  4290. lpwszSelection++;
  4291. if (*lpwszSelection == L'\\')
  4292. {
  4293. // LOCAL_MACHINE vs. CURRENT_USER was selected.
  4294. // Check for invalid arg since it must match either.
  4295. if (!wcsncmp(lpwszStart, L"LOCAL_MACHINE", lpwszSelection-lpwszStart))
  4296. {
  4297. *pfLocalMachine = TRUE;
  4298. }
  4299. else if (wcsncmp(lpwszStart, L"CURRENT_USER", lpwszSelection-lpwszStart))
  4300. {
  4301. hr = E_INVALIDARG;
  4302. goto quit;
  4303. }
  4304. // else already defaults to having *pfLocalMachine initialized to FALSE
  4305. lpwszStart = ++lpwszSelection;
  4306. // Now look for the optional choice on the store
  4307. while (*lpwszSelection && *lpwszSelection != L'\\')
  4308. lpwszSelection++;
  4309. if (*lpwszSelection == L'\\')
  4310. {
  4311. // Accept any store name.
  4312. // When opening the store, it will fail if the selected
  4313. // store does not exist.
  4314. *pbstrStore = DL(SysAllocStringLen)(lpwszStart, (UINT) (lpwszSelection-lpwszStart));
  4315. if (!*pbstrStore)
  4316. {
  4317. hr = E_OUTOFMEMORY;
  4318. goto Cleanup;
  4319. }
  4320. lpwszStart = ++lpwszSelection;
  4321. }
  4322. }
  4323. // lpwszStart points to the portion designating the subject string
  4324. // which could be part or all of pbstrSelection.
  4325. //
  4326. // If the string is empty, then fill in an empty string, which
  4327. // will mean to use the first enumerated cert.
  4328. *pbstrSubject = DL(SysAllocString)(lpwszStart);
  4329. if (!*pbstrSubject)
  4330. {
  4331. hr = E_OUTOFMEMORY;
  4332. goto Cleanup;
  4333. }
  4334. DefaultStore:
  4335. // Fill in MY store default if the store name wasn't specified.
  4336. if (!*pbstrStore)
  4337. {
  4338. // Default to MY store
  4339. *pbstrStore = DL(SysAllocString)(L"MY");
  4340. if (!*pbstrStore)
  4341. {
  4342. hr = E_OUTOFMEMORY;
  4343. goto Cleanup;
  4344. }
  4345. }
  4346. quit:
  4347. return hr;
  4348. Cleanup:
  4349. if (*pbstrStore)
  4350. {
  4351. DL(SysFreeString)(*pbstrStore);
  4352. *pbstrStore = NULL;
  4353. }
  4354. if (*pbstrSubject)
  4355. {
  4356. DL(SysFreeString)(*pbstrSubject);
  4357. *pbstrSubject = NULL;
  4358. }
  4359. goto quit;
  4360. }
  4361. #ifdef TRUE_ASYNC
  4362. HRESULT
  4363. CHttpRequest::PrepareToReadData(HINTERNET hInternet)
  4364. {
  4365. HRESULT hr = NOERROR;
  4366. BSTR bstrContentType = NULL;
  4367. DWORD dwStatus = 0;
  4368. BOOL fRetCode;
  4369. DWORD cb;
  4370. // Get the content length
  4371. _dwContentLength = 0;
  4372. fRetCode = GetContentLengthIfResponseNotChunked(hInternet, &_dwContentLength);
  4373. INET_ASSERT((_pResponseStream == NULL) && (_cbResponseBody == 0));
  4374. hr = DL(CreateStreamOnHGlobal)(NULL, TRUE, &_pResponseStream);
  4375. if (FAILED(hr))
  4376. goto ErrorFail;
  4377. // pre-set response stream size if we have a Content-Length
  4378. if (fRetCode)
  4379. {
  4380. ULARGE_INTEGER size;
  4381. size.LowPart = _dwContentLength;
  4382. size.HighPart = 0;
  4383. _pResponseStream->SetSize(size);
  4384. }
  4385. else
  4386. {
  4387. // Content-Length was not specified in the response, but this
  4388. // does not mean Content-Length==0. We will keep reading until
  4389. // either no more data is available. Set dwContentLength to 4GB
  4390. // to trick our read loop into reading until QDA reports EOF
  4391. _dwContentLength = (DWORD)(-1L);
  4392. ULARGE_INTEGER size;
  4393. size.LowPart = SIZEOF_BUFFER;
  4394. size.HighPart = 0;
  4395. _pResponseStream->SetSize(size);
  4396. }
  4397. if ((_dwContentLength > 0) && (_Buffer == NULL))
  4398. {
  4399. _Buffer = New BYTE[SIZEOF_BUFFER];
  4400. if (!_Buffer)
  4401. {
  4402. goto ErrorOutOfMemory;
  4403. }
  4404. }
  4405. //get status
  4406. cb = sizeof(dwStatus);
  4407. if (!HttpQueryInfoA(
  4408. hInternet,
  4409. HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  4410. WINHTTP_HEADER_NAME_BY_INDEX,
  4411. &dwStatus,
  4412. &cb,
  4413. 0))
  4414. goto ErrorFail;
  4415. //get content type
  4416. hr = _GetResponseHeader2(L"Content-Type", &bstrContentType, hInternet);
  4417. if (FAILED(hr))
  4418. {
  4419. bstrContentType = DL(SysAllocString)(L"");
  4420. if (bstrContentType == NULL)
  4421. goto ErrorOutOfMemory;
  4422. hr = NOERROR;
  4423. }
  4424. _CP.FireOnResponseStart((long)dwStatus, bstrContentType);
  4425. hr = NOERROR;
  4426. Cleanup:
  4427. if (bstrContentType)
  4428. DL(SysFreeString)(bstrContentType);
  4429. return hr;
  4430. ErrorOutOfMemory:
  4431. hr = E_OUTOFMEMORY;
  4432. goto Error;
  4433. ErrorFail:
  4434. hr = HRESULT_FROM_WIN32(GetLastError());
  4435. goto Error;
  4436. Error:
  4437. SafeRelease(_pResponseStream);
  4438. _cbResponseBody = NULL;
  4439. goto Cleanup;
  4440. }
  4441. #define ASYNC_SEND_CALLBACK_NOTIFICATIONS \
  4442. WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE |\
  4443. WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE |\
  4444. WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE |\
  4445. WINHTTP_CALLBACK_STATUS_READ_COMPLETE |\
  4446. WINHTTP_CALLBACK_STATUS_REQUEST_ERROR |\
  4447. WINHTTP_CALLBACK_STATUS_SECURE_FAILURE
  4448. HRESULT CHttpRequest::StartAsyncSend()
  4449. {
  4450. DEBUG_ENTER((DBG_HTTP,
  4451. Dword,
  4452. "IWinHttpRequest::StartAsyncSend",
  4453. NULL
  4454. ));
  4455. HRESULT hr;
  4456. hr = _CP.CreateEventSinksMarshaller();
  4457. if (FAILED(hr))
  4458. goto Error;
  4459. hr = NOERROR;
  4460. //init vars
  4461. _hrAsyncResult = NOERROR;
  4462. _dwNumberOfBytesAvailable = 0;
  4463. _cbNumberOfBytesRead = 0;
  4464. if (!_hCompleteEvent)
  4465. {
  4466. _hCompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  4467. if (_hCompleteEvent == NULL)
  4468. goto ErrorFail;
  4469. }
  4470. else
  4471. {
  4472. if (!ResetEvent(_hCompleteEvent))
  4473. goto ErrorFail;
  4474. }
  4475. //register callback
  4476. if (WINHTTP_INVALID_STATUS_CALLBACK ==
  4477. WinHttpSetStatusCallback(_hHTTP,
  4478. AsyncCallback,
  4479. ASYNC_SEND_CALLBACK_NOTIFICATIONS,
  4480. NULL))
  4481. goto ErrorFail;
  4482. // Initiate async HTTP request
  4483. SetState(SENDING);
  4484. if (!WinHttpSendRequest(
  4485. _hHTTP,
  4486. NULL, 0, // No header info here
  4487. _szRequestBuffer,
  4488. _cbRequestBody,
  4489. _cbRequestBody,
  4490. reinterpret_cast<DWORD_PTR>(this)))
  4491. goto ErrorFailWinHttpAPI;
  4492. Cleanup:
  4493. DEBUG_LEAVE(hr);
  4494. return hr;
  4495. ErrorFail:
  4496. hr = HRESULT_FROM_WIN32(GetLastError());
  4497. Error:
  4498. if (_hCompleteEvent)
  4499. {
  4500. CloseHandle(_hCompleteEvent);
  4501. _hCompleteEvent = NULL;
  4502. }
  4503. goto Cleanup;
  4504. ErrorFailWinHttpAPI:
  4505. hr = HRESULT_FROM_WIN32(GetLastError());
  4506. _CP.FireOnError(hr);
  4507. goto Error;
  4508. }
  4509. void CHttpRequest::CompleteDataRead(bool bNotAborted, HINTERNET hInternet)
  4510. {
  4511. DEBUG_ENTER((DBG_HTTP,
  4512. None,
  4513. "IWinHttpRequest::CompleteDataRead",
  4514. "bNotAborted: %s",
  4515. bNotAborted ? "true" : "false"
  4516. ));
  4517. //unregister callback
  4518. WinHttpSetStatusCallback(hInternet,
  4519. NULL,
  4520. ASYNC_SEND_CALLBACK_NOTIFICATIONS,
  4521. NULL);
  4522. if (_pResponseStream)
  4523. {
  4524. ULARGE_INTEGER size;
  4525. // set final size on stream
  4526. size.LowPart = _cbResponseBody;
  4527. size.HighPart = 0;
  4528. _pResponseStream->SetSize(size);
  4529. }
  4530. if (bNotAborted)
  4531. _CP.FireOnResponseFinished();
  4532. SetEvent(_hCompleteEvent);
  4533. DEBUG_LEAVE(0);
  4534. }
  4535. void CALLBACK CHttpRequest::SyncCallback(
  4536. HINTERNET hInternet,
  4537. DWORD_PTR dwContext,
  4538. DWORD dwInternetStatus,
  4539. LPVOID lpvStatusInformation,
  4540. DWORD dwStatusInformationLength)
  4541. {
  4542. UNREFERENCED_PARAMETER(hInternet);
  4543. UNREFERENCED_PARAMETER(dwStatusInformationLength);
  4544. DEBUG_ENTER((DBG_HTTP,
  4545. None,
  4546. "CHttpRequest::SyncCallback",
  4547. "hInternet: %#x, dwContext: %#x, dwInternetStatus:%#x, %#x, %#d",
  4548. hInternet,
  4549. dwContext,
  4550. dwInternetStatus,
  4551. lpvStatusInformation,
  4552. dwStatusInformationLength
  4553. ));
  4554. if (dwContext == NULL)
  4555. {
  4556. return;
  4557. }
  4558. CHttpRequest * pRequest = reinterpret_cast<CHttpRequest*>(dwContext);
  4559. // unexpected notification?
  4560. INET_ASSERT(dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE);
  4561. if (!pRequest->_bAborted)
  4562. {
  4563. switch (dwInternetStatus)
  4564. {
  4565. case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
  4566. pRequest->_hrSecureFailure = SecureFailureFromStatus(*((DWORD *)lpvStatusInformation));
  4567. break;
  4568. }
  4569. }
  4570. DEBUG_LEAVE(0);
  4571. }
  4572. void CALLBACK CHttpRequest::AsyncCallback(HINTERNET hInternet,
  4573. DWORD_PTR dwContext,
  4574. DWORD dwInternetStatus,
  4575. LPVOID lpvStatusInformation,
  4576. DWORD dwStatusInformationLength)
  4577. {
  4578. DEBUG_ENTER((DBG_HTTP,
  4579. None,
  4580. "IWinHttpRequest::AsyncCallback",
  4581. "hInternet: %#x, dwContext: %#x, dwInternetStatus:%#x, %#x, %#d",
  4582. hInternet,
  4583. dwContext,
  4584. dwInternetStatus,
  4585. lpvStatusInformation,
  4586. dwStatusInformationLength
  4587. ));
  4588. if (dwContext == NULL)
  4589. {
  4590. DEBUG_PRINT_API(ASYNC, FATAL, ("Unexpected: dwContext parameter is zero!\n"))
  4591. DEBUG_LEAVE(0);
  4592. return;
  4593. }
  4594. CHttpRequest* pRequest = reinterpret_cast<CHttpRequest*>(dwContext);
  4595. if ((dwInternetStatus & ASYNC_SEND_CALLBACK_NOTIFICATIONS) == 0)
  4596. {
  4597. //unexpected notification
  4598. DEBUG_PRINT_API(ASYNC, FATAL, ("Unexpected dwInternetStatus value!\n"))
  4599. pRequest->_hrAsyncResult = HRESULT_FROM_WIN32(ERROR_WINHTTP_INTERNAL_ERROR);
  4600. goto Error;
  4601. }
  4602. if (pRequest->_bAborted)
  4603. goto Aborted;
  4604. DWORD dwBytesToRead = 0;
  4605. switch (dwInternetStatus)
  4606. {
  4607. case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE :
  4608. //SR completed
  4609. pRequest->SetState(SENT);
  4610. if (!::WinHttpReceiveResponse(hInternet, NULL))
  4611. goto ErrorFail;
  4612. break;
  4613. case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE :
  4614. //RR completed, read data
  4615. pRequest->SetState(RECEIVING);
  4616. pRequest->_hrAsyncResult = pRequest->PrepareToReadData(hInternet);
  4617. if (FAILED(pRequest->_hrAsyncResult))
  4618. goto Error;
  4619. if (pRequest->_dwContentLength == 0)
  4620. {
  4621. goto RequestComplete;
  4622. }
  4623. //start reading data
  4624. dwBytesToRead = min(pRequest->_dwContentLength, SIZEOF_BUFFER);
  4625. break;
  4626. case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE :
  4627. //QDA completed
  4628. INET_ASSERT(dwStatusInformationLength == sizeof(DWORD));
  4629. pRequest->_dwNumberOfBytesAvailable = *(LPDWORD)lpvStatusInformation;
  4630. if (pRequest->_dwNumberOfBytesAvailable)
  4631. dwBytesToRead = min(pRequest->_dwNumberOfBytesAvailable, SIZEOF_BUFFER); //continue read
  4632. else
  4633. goto RequestComplete; //no more data to read
  4634. break;
  4635. case WINHTTP_CALLBACK_STATUS_READ_COMPLETE :
  4636. //RD completed
  4637. pRequest->_cbNumberOfBytesRead = dwStatusInformationLength;
  4638. if (pRequest->_cbNumberOfBytesRead)
  4639. {
  4640. HRESULT hr = pRequest->_pResponseStream->Write(pRequest->_Buffer,
  4641. pRequest->_cbNumberOfBytesRead,
  4642. NULL);
  4643. if (FAILED(hr))
  4644. {
  4645. pRequest->_hrAsyncResult = E_OUTOFMEMORY;
  4646. goto Error;
  4647. }
  4648. pRequest->_CP.FireOnResponseDataAvailable((const BYTE *)pRequest->_Buffer, pRequest->_cbNumberOfBytesRead);
  4649. pRequest->_cbResponseBody += pRequest->_cbNumberOfBytesRead;
  4650. if (pRequest->_cbResponseBody >= pRequest->_dwContentLength)
  4651. {
  4652. goto RequestComplete;
  4653. }
  4654. else
  4655. {
  4656. //perform QDA to make sure there is no more data to read
  4657. if (pRequest->_bAborted)
  4658. goto Aborted;
  4659. if (!WinHttpQueryDataAvailable(hInternet, NULL))
  4660. goto ErrorFail;
  4661. }
  4662. }
  4663. else
  4664. goto RequestComplete; //no more data to read
  4665. break;
  4666. case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
  4667. pRequest->_hrSecureFailure = SecureFailureFromStatus(*((DWORD *)lpvStatusInformation));
  4668. goto Cleanup;
  4669. case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR :
  4670. {
  4671. DWORD dwError = ((LPWINHTTP_ASYNC_RESULT)lpvStatusInformation)->dwError;
  4672. if (dwError == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
  4673. {
  4674. if (!pRequest->_bRetriedWithCert)
  4675. {
  4676. pRequest->_bRetriedWithCert = TRUE;
  4677. if (pRequest->SelectCertificate())
  4678. {
  4679. // Initiate async HTTP request
  4680. pRequest->SetState(SENDING);
  4681. if (!WinHttpSendRequest(
  4682. hInternet,
  4683. NULL, 0, // No header info here
  4684. pRequest->_szRequestBuffer,
  4685. pRequest->_cbRequestBody,
  4686. pRequest->_cbRequestBody,
  4687. reinterpret_cast<DWORD_PTR>(pRequest)))
  4688. goto ErrorFail;
  4689. break;
  4690. }
  4691. }
  4692. }
  4693. goto ErrorFail;
  4694. }
  4695. }
  4696. if (dwBytesToRead)
  4697. {
  4698. if (pRequest->_bAborted)
  4699. goto Aborted;
  4700. if (!WinHttpReadData(hInternet,
  4701. pRequest->_Buffer,
  4702. dwBytesToRead,
  4703. NULL))
  4704. goto ErrorFail;
  4705. }
  4706. Cleanup:
  4707. DEBUG_LEAVE(0);
  4708. return;
  4709. Aborted:
  4710. pRequest->CompleteDataRead(false, hInternet);
  4711. goto Cleanup;
  4712. ErrorFail:
  4713. pRequest->_hrAsyncResult = HRESULT_FROM_WIN32(GetLastError());
  4714. if (pRequest->_hrAsyncResult == HRESULT_FROM_WIN32(ERROR_WINHTTP_SECURE_FAILURE))
  4715. {
  4716. INET_ASSERT(FAILED(pRequest->_hrSecureFailure));
  4717. pRequest->_hrAsyncResult = pRequest->_hrSecureFailure;
  4718. }
  4719. pRequest->_CP.FireOnError(pRequest->_hrAsyncResult);
  4720. Error:
  4721. DEBUG_PRINT_API(ASYNC, ERROR, ("Error set: %#x\n", pRequest->_hrAsyncResult))
  4722. pRequest->CompleteDataRead(false, hInternet);
  4723. goto Cleanup;
  4724. RequestComplete:
  4725. pRequest->SetState(RESPONSE);
  4726. pRequest->CompleteDataRead(true, hInternet);
  4727. goto Cleanup;
  4728. }
  4729. #endif//TRUE_ASYNC
  4730. /*
  4731. * BSTRToUTF8
  4732. *
  4733. * Purpose:
  4734. * Convert a BSTR to UTF-8
  4735. *
  4736. */
  4737. static
  4738. HRESULT
  4739. BSTRToUTF8(char ** psz, DWORD * pcbUTF8, BSTR bstr, bool * pbSetUtf8Charset)
  4740. {
  4741. UINT cch = lstrlenW(bstr);
  4742. bool bSimpleConversion = false;
  4743. *pcbUTF8 = 0;
  4744. *psz = NULL;
  4745. if (cch == 0)
  4746. return NOERROR;
  4747. PreWideCharToUtf8(bstr, cch, (UINT *)pcbUTF8, &bSimpleConversion);
  4748. *psz = New char [*pcbUTF8 + 1];
  4749. if (!*psz)
  4750. return E_OUTOFMEMORY;
  4751. WideCharToUtf8(bstr, cch, (BYTE *)*psz, bSimpleConversion);
  4752. (*psz)[*pcbUTF8] = 0;
  4753. if (pbSetUtf8Charset)
  4754. {
  4755. *pbSetUtf8Charset = !bSimpleConversion;
  4756. }
  4757. return NOERROR;
  4758. }
  4759. /**
  4760. * Scans buffer and translates Unicode characters into UTF8 characters
  4761. */
  4762. static
  4763. void
  4764. PreWideCharToUtf8(
  4765. WCHAR * buffer,
  4766. UINT cch,
  4767. UINT * cb,
  4768. bool * bSimpleConversion)
  4769. {
  4770. UINT count = 0;
  4771. DWORD dw1;
  4772. bool surrogate = false;
  4773. for (UINT i = cch; i > 0; i--)
  4774. {
  4775. DWORD dw = *buffer;
  4776. if (surrogate) // is it the second char of a surrogate pair?
  4777. {
  4778. if (dw >= 0xdc00 && dw <= 0xdfff)
  4779. {
  4780. // four bytes 0x11110xxx 0x10xxxxxx 0x10xxxxxx 0x10xxxxxx
  4781. count += 4;
  4782. surrogate = false;
  4783. buffer++;
  4784. continue;
  4785. }
  4786. else // Then dw1 must be a three byte character
  4787. {
  4788. count += 3;
  4789. }
  4790. surrogate = false;
  4791. }
  4792. if (dw < 0x80) // one byte, 0xxxxxxx
  4793. {
  4794. count++;
  4795. }
  4796. else if (dw < 0x800) // two WORDS, 110xxxxx 10xxxxxx
  4797. {
  4798. count += 2;
  4799. }
  4800. else if (dw >= 0xd800 && dw <= 0xdbff) // Assume that it is the first char of surrogate pair
  4801. {
  4802. if (i == 1) // last wchar in buffer
  4803. break;
  4804. dw1 = dw;
  4805. surrogate = true;
  4806. }
  4807. else // three bytes, 1110xxxx 10xxxxxx 10xxxxxx
  4808. {
  4809. count += 3;
  4810. }
  4811. buffer++;
  4812. }
  4813. *cb = count;
  4814. *bSimpleConversion = (cch == count);
  4815. }
  4816. /**
  4817. * Scans buffer and translates Unicode characters into UTF8 characters
  4818. */
  4819. static
  4820. void
  4821. WideCharToUtf8(
  4822. WCHAR * buffer,
  4823. UINT cch,
  4824. BYTE * bytebuffer,
  4825. bool bSimpleConversion)
  4826. {
  4827. DWORD dw1 = 0;
  4828. bool surrogate = false;
  4829. INET_ASSERT(bytebuffer != NULL);
  4830. if (bSimpleConversion)
  4831. {
  4832. for (UINT i = cch; i > 0; i--)
  4833. {
  4834. DWORD dw = *buffer;
  4835. *bytebuffer++ = (byte)dw;
  4836. buffer++;
  4837. }
  4838. }
  4839. else
  4840. {
  4841. for (UINT i = cch; i > 0; i--)
  4842. {
  4843. DWORD dw = *buffer;
  4844. if (surrogate) // is it the second char of a surrogate pair?
  4845. {
  4846. if (dw >= 0xdc00 && dw <= 0xdfff)
  4847. {
  4848. // four bytes 0x11110xxx 0x10xxxxxx 0x10xxxxxx 0x10xxxxxx
  4849. ULONG ucs4 = (dw1 - 0xd800) * 0x400 + (dw - 0xdc00) + 0x10000;
  4850. *bytebuffer++ = (byte)(( ucs4 >> 18) | 0xF0);
  4851. *bytebuffer++ = (byte)((( ucs4 >> 12) & 0x3F) | 0x80);
  4852. *bytebuffer++ = (byte)((( ucs4 >> 6) & 0x3F) | 0x80);
  4853. *bytebuffer++ = (byte)(( ucs4 & 0x3F) | 0x80);
  4854. surrogate = false;
  4855. buffer++;
  4856. continue;
  4857. }
  4858. else // Then dw1 must be a three byte character
  4859. {
  4860. *bytebuffer++ = (byte)(( dw1 >> 12) | 0xE0);
  4861. *bytebuffer++ = (byte)((( dw1 >> 6) & 0x3F) | 0x80);
  4862. *bytebuffer++ = (byte)(( dw1 & 0x3F) | 0x80);
  4863. }
  4864. surrogate = false;
  4865. }
  4866. if (dw < 0x80) // one byte, 0xxxxxxx
  4867. {
  4868. *bytebuffer++ = (byte)dw;
  4869. }
  4870. else if ( dw < 0x800) // two WORDS, 110xxxxx 10xxxxxx
  4871. {
  4872. *bytebuffer++ = (byte)((dw >> 6) | 0xC0);
  4873. *bytebuffer++ = (byte)((dw & 0x3F) | 0x80);
  4874. }
  4875. else if (dw >= 0xd800 && dw <= 0xdbff) // Assume that it is the first char of surrogate pair
  4876. {
  4877. if (i == 1) // last wchar in buffer
  4878. break;
  4879. dw1 = dw;
  4880. surrogate = true;
  4881. }
  4882. else // three bytes, 1110xxxx 10xxxxxx 10xxxxxx
  4883. {
  4884. *bytebuffer++ = (byte)(( dw >> 12) | 0xE0);
  4885. *bytebuffer++ = (byte)((( dw >> 6) & 0x3F) | 0x80);
  4886. *bytebuffer++ = (byte)(( dw & 0x3F) | 0x80);
  4887. }
  4888. buffer++;
  4889. }
  4890. }
  4891. }
  4892. /*
  4893. * AsciiToBSTR
  4894. *
  4895. * Purpose:
  4896. * Convert an ascii string to a BSTR
  4897. *
  4898. * only **STRLEN** to be passed to AsciiToBSTR (not including terminating NULL, if any)
  4899. *
  4900. */
  4901. static
  4902. HRESULT
  4903. AsciiToBSTR(BSTR * pbstr, char * sz, int cch)
  4904. {
  4905. int cwch;
  4906. INET_ASSERT (cch != -1);
  4907. // Determine how big the ascii string will be
  4908. cwch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, cch,
  4909. NULL, 0);
  4910. *pbstr = DL(SysAllocStringLen)(NULL, cwch);
  4911. if (!*pbstr)
  4912. return E_OUTOFMEMORY;
  4913. cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, cch,
  4914. *pbstr, cwch);
  4915. return NOERROR;
  4916. }
  4917. /*
  4918. * GetBSTRFromVariant
  4919. *
  4920. * Purpose:
  4921. * Convert a VARIANT to a BSTR
  4922. *
  4923. * If VariantChangeType raises an exception, then an E_INVALIDARG
  4924. * error is returned.
  4925. */
  4926. static HRESULT GetBSTRFromVariant(VARIANT varVariant, BSTR * pBstr)
  4927. {
  4928. VARIANT varTemp;
  4929. HRESULT hr = NOERROR;
  4930. *pBstr = NULL;
  4931. if (V_VT(&varVariant) != VT_EMPTY && V_VT(&varVariant) != VT_NULL &&
  4932. V_VT(&varVariant) != VT_ERROR)
  4933. {
  4934. DL(VariantInit)(&varTemp);
  4935. __try
  4936. {
  4937. hr = DL(VariantChangeType)(
  4938. &varTemp,
  4939. &varVariant,
  4940. 0,
  4941. VT_BSTR);
  4942. if (SUCCEEDED(hr))
  4943. {
  4944. *pBstr = V_BSTR(&varTemp); // take over ownership of BSTR
  4945. }
  4946. }
  4947. __except (EXCEPTION_EXECUTE_HANDLER)
  4948. {
  4949. hr = E_INVALIDARG;
  4950. }
  4951. }
  4952. // DON'T clear the variant because we stole the BSTR
  4953. //DL(VariantClear)(&varTemp);
  4954. return hr;
  4955. }
  4956. /*
  4957. * GetBoolFromVariant
  4958. *
  4959. * Purpose:
  4960. * Convert a VARIANT to a Boolean
  4961. *
  4962. */
  4963. static BOOL GetBoolFromVariant(VARIANT varVariant, BOOL fDefault)
  4964. {
  4965. HRESULT hr;
  4966. BOOL fResult = fDefault;
  4967. if (V_VT(&varVariant) != VT_EMPTY && V_VT(&varVariant) != VT_NULL &&
  4968. V_VT(&varVariant) != VT_ERROR)
  4969. {
  4970. VARIANT varTemp;
  4971. DL(VariantInit)(&varTemp);
  4972. hr = DL(VariantChangeType)(
  4973. &varTemp,
  4974. &varVariant,
  4975. 0,
  4976. VT_BOOL);
  4977. if (FAILED(hr))
  4978. goto Cleanup;
  4979. fResult = V_BOOL(&varTemp) == VARIANT_TRUE ? TRUE : FALSE;
  4980. }
  4981. hr = NOERROR;
  4982. Cleanup:
  4983. return fResult;
  4984. }
  4985. /*
  4986. * GetDwordFromVariant
  4987. *
  4988. * Purpose:
  4989. * Convert a VARIANT to a DWORD
  4990. *
  4991. */
  4992. static DWORD GetDwordFromVariant(VARIANT varVariant, DWORD dwDefault)
  4993. {
  4994. HRESULT hr;
  4995. DWORD dwResult = dwDefault;
  4996. if (V_VT(&varVariant) != VT_EMPTY && V_VT(&varVariant) != VT_NULL &&
  4997. V_VT(&varVariant) != VT_ERROR)
  4998. {
  4999. VARIANT varTemp;
  5000. DL(VariantInit)(&varTemp);
  5001. hr = DL(VariantChangeType)(
  5002. &varTemp,
  5003. &varVariant,
  5004. 0,
  5005. VT_UI4);
  5006. if (FAILED(hr))
  5007. goto Cleanup;
  5008. dwResult = V_UI4(&varTemp);
  5009. }
  5010. hr = NOERROR;
  5011. Cleanup:
  5012. return dwResult;
  5013. }
  5014. /*
  5015. * GetLongFromVariant
  5016. *
  5017. * Purpose:
  5018. * Convert a VARIANT to a DWORD
  5019. *
  5020. */
  5021. static long GetLongFromVariant(VARIANT varVariant, long lDefault)
  5022. {
  5023. HRESULT hr;
  5024. long lResult = lDefault;
  5025. if (V_VT(&varVariant) != VT_EMPTY && V_VT(&varVariant) != VT_NULL &&
  5026. V_VT(&varVariant) != VT_ERROR)
  5027. {
  5028. VARIANT varTemp;
  5029. DL(VariantInit)(&varTemp);
  5030. hr = DL(VariantChangeType)(
  5031. &varTemp,
  5032. &varVariant,
  5033. 0,
  5034. VT_I4);
  5035. if (FAILED(hr))
  5036. goto Cleanup;
  5037. lResult = V_I4(&varTemp);
  5038. }
  5039. hr = NOERROR;
  5040. Cleanup:
  5041. return lResult;
  5042. }
  5043. /**
  5044. * Helper to create a char safearray from a string
  5045. */
  5046. static
  5047. HRESULT
  5048. CreateVector(VARIANT * pVar, const BYTE * pData, DWORD cElems)
  5049. {
  5050. HRESULT hr;
  5051. BYTE * pB;
  5052. SAFEARRAY * psa = DL(SafeArrayCreateVector)(VT_UI1, 0, cElems);
  5053. if (!psa)
  5054. {
  5055. hr = E_OUTOFMEMORY;
  5056. goto Cleanup;
  5057. }
  5058. hr = DL(SafeArrayAccessData)(psa, (void **)&pB);
  5059. if (FAILED(hr))
  5060. goto Error;
  5061. memcpy(pB, pData, cElems);
  5062. DL(SafeArrayUnaccessData)(psa);
  5063. INET_ASSERT((pVar->vt == VT_EMPTY) || (pVar->vt == VT_NULL));
  5064. V_ARRAY(pVar) = psa;
  5065. pVar->vt = VT_ARRAY | VT_UI1;
  5066. hr = NOERROR;
  5067. Cleanup:
  5068. return hr;
  5069. Error:
  5070. if (psa)
  5071. DL(SafeArrayDestroy)(psa);
  5072. goto Cleanup;
  5073. }
  5074. /*
  5075. * ReadFromStream
  5076. *
  5077. * Purpose:
  5078. * Extract the contents of a stream into a buffer.
  5079. *
  5080. * Parameters:
  5081. * ppBuf IN/OUT Buffer
  5082. * pStm IN Stream
  5083. *
  5084. * Errors:
  5085. * E_INVALIDARG
  5086. * E_OUTOFMEMORY
  5087. */
  5088. static
  5089. HRESULT
  5090. ReadFromStream(char ** ppData, ULONG * pcbData, IStream * pStm)
  5091. {
  5092. HRESULT hr = NOERROR;
  5093. char * pBuffer = NULL; // Buffer
  5094. ULONG cbBuffer = 0; // Bytes in buffer
  5095. ULONG cbData = 0; // Bytes of data in buffer
  5096. ULONG cbRead = 0; // Bytes read from stream
  5097. ULONG cbNewSize = 0;
  5098. char * pNewBuf = NULL;
  5099. if (!ppData || !pStm)
  5100. return E_INVALIDARG;
  5101. *ppData = NULL;
  5102. *pcbData = 0;
  5103. while (TRUE)
  5104. {
  5105. if (cbData + 512 > cbBuffer)
  5106. {
  5107. cbNewSize = (cbData ? cbData*2 : 4096);
  5108. pNewBuf = New char[cbNewSize+1];
  5109. if (!pNewBuf)
  5110. goto ErrorOutOfMemory;
  5111. if (cbData)
  5112. ::memcpy(pNewBuf, pBuffer, cbData);
  5113. cbBuffer = cbNewSize;
  5114. delete[] pBuffer;
  5115. pBuffer = pNewBuf;
  5116. pBuffer[cbData] = 0;
  5117. }
  5118. hr = pStm->Read(
  5119. &pBuffer[cbData],
  5120. cbBuffer - cbData,
  5121. &cbRead);
  5122. if (FAILED(hr))
  5123. goto Error;
  5124. cbData += cbRead;
  5125. pBuffer[cbData] = 0;
  5126. // No more data
  5127. if (cbRead == 0)
  5128. break;
  5129. }
  5130. *ppData = pBuffer;
  5131. *pcbData = cbData;
  5132. hr = NOERROR;
  5133. Cleanup:
  5134. return hr;
  5135. ErrorOutOfMemory:
  5136. hr = E_OUTOFMEMORY;
  5137. goto Error;
  5138. Error:
  5139. if (pBuffer)
  5140. delete [] pBuffer;
  5141. goto Cleanup;
  5142. }
  5143. static
  5144. void
  5145. MessageLoop()
  5146. {
  5147. MSG msg;
  5148. // There is a window message available. Dispatch it.
  5149. while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  5150. {
  5151. TranslateMessage(&msg);
  5152. DispatchMessage(&msg);
  5153. }
  5154. }
  5155. static
  5156. DWORD
  5157. UpdateTimeout(DWORD dwTimeout, DWORD dwStartTime)
  5158. {
  5159. if (dwTimeout != INFINITE)
  5160. {
  5161. DWORD dwTimeNow = GetTickCount();
  5162. DWORD dwElapsedTime;
  5163. if (dwTimeNow >= dwStartTime)
  5164. {
  5165. dwElapsedTime = dwTimeNow - dwStartTime;
  5166. }
  5167. else
  5168. {
  5169. dwElapsedTime = dwTimeNow + (0xFFFFFFFF - dwStartTime);
  5170. }
  5171. if (dwElapsedTime < dwTimeout)
  5172. {
  5173. dwTimeout -= dwElapsedTime;
  5174. }
  5175. else
  5176. {
  5177. dwTimeout = 0;
  5178. }
  5179. }
  5180. return dwTimeout;
  5181. }
  5182. DWORD CSinkArray::Add(IUnknown * pUnk)
  5183. {
  5184. ULONG iIndex;
  5185. IUnknown** pp = NULL;
  5186. if (_nSize == 0) // no connections
  5187. {
  5188. _pUnk = pUnk;
  5189. _nSize = 1;
  5190. return 1;
  5191. }
  5192. else if (_nSize == 1)
  5193. {
  5194. // create array
  5195. pp = (IUnknown **)ALLOCATE_ZERO_MEMORY(sizeof(IUnknown*)* _DEFAULT_VECTORLENGTH);
  5196. if (pp == NULL)
  5197. return 0;
  5198. *pp = _pUnk;
  5199. _ppUnk = pp;
  5200. _nSize = _DEFAULT_VECTORLENGTH;
  5201. }
  5202. for (pp = begin(); pp < end(); pp++)
  5203. {
  5204. if (*pp == NULL)
  5205. {
  5206. *pp = pUnk;
  5207. iIndex = ULONG(pp-begin());
  5208. return iIndex+1;
  5209. }
  5210. }
  5211. int nAlloc = _nSize*2;
  5212. pp = (IUnknown **)REALLOCATE_MEMORY_ZERO(_ppUnk, sizeof(IUnknown*)*nAlloc);
  5213. if (pp == NULL)
  5214. return 0;
  5215. _ppUnk = pp;
  5216. _ppUnk[_nSize] = pUnk;
  5217. iIndex = _nSize;
  5218. _nSize = nAlloc;
  5219. return iIndex+1;
  5220. }
  5221. BOOL CSinkArray::Remove(DWORD dwCookie)
  5222. {
  5223. ULONG iIndex;
  5224. if (dwCookie == NULL)
  5225. return FALSE;
  5226. if (_nSize == 0)
  5227. return FALSE;
  5228. iIndex = dwCookie-1;
  5229. if (iIndex >= (ULONG)_nSize)
  5230. return FALSE;
  5231. if (_nSize == 1)
  5232. {
  5233. _nSize = 0;
  5234. return TRUE;
  5235. }
  5236. begin()[iIndex] = NULL;
  5237. return TRUE;
  5238. }
  5239. void CSinkArray::ReleaseAll()
  5240. {
  5241. for (IUnknown ** pp = begin(); pp < end(); pp++)
  5242. {
  5243. if (*pp != NULL)
  5244. {
  5245. SafeRelease(*pp);
  5246. }
  5247. }
  5248. }
  5249. HRESULT STDMETHODCALLTYPE
  5250. CSinkArray::QueryInterface(REFIID, void **)
  5251. {
  5252. return E_NOTIMPL;
  5253. }
  5254. ULONG STDMETHODCALLTYPE
  5255. CSinkArray::AddRef()
  5256. {
  5257. return 2;
  5258. }
  5259. ULONG STDMETHODCALLTYPE
  5260. CSinkArray::Release()
  5261. {
  5262. return 1;
  5263. }
  5264. void STDMETHODCALLTYPE
  5265. CSinkArray::OnResponseStart(long Status, BSTR bstrContentType)
  5266. {
  5267. for (IUnknown ** pp = begin(); pp < end(); pp++)
  5268. {
  5269. if (*pp != NULL)
  5270. {
  5271. IWinHttpRequestEvents * pSink;
  5272. pSink = static_cast<IWinHttpRequestEvents *>(*pp);
  5273. if (((*(DWORD_PTR **)pSink)[3]) != NULL)
  5274. {
  5275. pSink->OnResponseStart(Status, bstrContentType);
  5276. }
  5277. }
  5278. }
  5279. }
  5280. void STDMETHODCALLTYPE
  5281. CSinkArray::OnResponseDataAvailable(SAFEARRAY ** ppsaData)
  5282. {
  5283. for (IUnknown ** pp = begin(); pp < end(); pp++)
  5284. {
  5285. if (*pp != NULL)
  5286. {
  5287. IWinHttpRequestEvents * pSink;
  5288. pSink = static_cast<IWinHttpRequestEvents *>(*pp);
  5289. if (((*(DWORD_PTR **)pSink)[4]) != NULL)
  5290. {
  5291. pSink->OnResponseDataAvailable(ppsaData);
  5292. }
  5293. }
  5294. }
  5295. }
  5296. void STDMETHODCALLTYPE
  5297. CSinkArray::OnResponseFinished(void)
  5298. {
  5299. for (IUnknown ** pp = begin(); pp < end(); pp++)
  5300. {
  5301. if (*pp != NULL)
  5302. {
  5303. IWinHttpRequestEvents * pSink;
  5304. pSink = static_cast<IWinHttpRequestEvents *>(*pp);
  5305. if (((*(DWORD_PTR **)pSink)[5]) != NULL)
  5306. {
  5307. pSink->OnResponseFinished();
  5308. }
  5309. }
  5310. }
  5311. }
  5312. void STDMETHODCALLTYPE
  5313. CSinkArray::OnError(long ErrorNumber, BSTR ErrorDescription)
  5314. {
  5315. for (IUnknown ** pp = begin(); pp < end(); pp++)
  5316. {
  5317. if (*pp != NULL)
  5318. {
  5319. IWinHttpRequestEvents * pSink;
  5320. pSink = static_cast<IWinHttpRequestEvents *>(*pp);
  5321. if (((*(DWORD_PTR **)pSink)[6]) != NULL)
  5322. {
  5323. pSink->OnError(ErrorNumber, ErrorDescription);
  5324. }
  5325. }
  5326. }
  5327. }
  5328. CWinHttpRequestEventsMarshaller::CWinHttpRequestEventsMarshaller
  5329. (
  5330. CSinkArray * pSinkArray,
  5331. HWND hWnd
  5332. )
  5333. {
  5334. INET_ASSERT((pSinkArray != NULL) && (hWnd != NULL));
  5335. _pSinkArray = pSinkArray;
  5336. _hWnd = hWnd;
  5337. _cRefs = 0;
  5338. _bFireEvents = true;
  5339. _cs.Init();
  5340. }
  5341. CWinHttpRequestEventsMarshaller::~CWinHttpRequestEventsMarshaller()
  5342. {
  5343. INET_ASSERT(_pSinkArray == NULL);
  5344. INET_ASSERT(_hWnd == NULL);
  5345. INET_ASSERT(_cRefs == 0);
  5346. }
  5347. HRESULT
  5348. CWinHttpRequestEventsMarshaller::Create
  5349. (
  5350. CSinkArray * pSinkArray,
  5351. CWinHttpRequestEventsMarshaller ** ppSinkMarshaller
  5352. )
  5353. {
  5354. CWinHttpRequestEventsMarshaller * pSinkMarshaller = NULL;
  5355. HWND hWnd = NULL;
  5356. HRESULT hr = NOERROR;
  5357. if (!RegisterWinHttpEventMarshallerWndClass())
  5358. goto ErrorFail;
  5359. hWnd = CreateWindowEx(0, s_szWinHttpEventMarshallerWndClass, NULL,
  5360. 0, 0, 0, 0, 0,
  5361. (IsPlatformWinNT() && GlobalPlatformVersion5) ? HWND_MESSAGE : NULL,
  5362. NULL, GlobalDllHandle, NULL);
  5363. if (!hWnd)
  5364. goto ErrorFail;
  5365. pSinkMarshaller = New CWinHttpRequestEventsMarshaller(pSinkArray, hWnd);
  5366. if (!pSinkMarshaller)
  5367. goto ErrorOutOfMemory;
  5368. SetLastError(0);
  5369. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) pSinkMarshaller);
  5370. if (GetLastError() != 0)
  5371. goto ErrorFail;
  5372. pSinkMarshaller->AddRef();
  5373. *ppSinkMarshaller = pSinkMarshaller;
  5374. Exit:
  5375. if (FAILED(hr))
  5376. {
  5377. if (pSinkMarshaller)
  5378. {
  5379. delete pSinkMarshaller;
  5380. }
  5381. else if (hWnd)
  5382. {
  5383. DestroyWindow(hWnd);
  5384. }
  5385. }
  5386. return hr;
  5387. ErrorFail:
  5388. hr = HRESULT_FROM_WIN32(GetLastError());
  5389. goto Exit;
  5390. ErrorOutOfMemory:
  5391. hr = E_OUTOFMEMORY;
  5392. goto Exit;
  5393. }
  5394. void
  5395. CWinHttpRequestEventsMarshaller::Shutdown()
  5396. {
  5397. if (_cs.Lock())
  5398. {
  5399. FreezeEvents();
  5400. if (_hWnd)
  5401. {
  5402. MessageLoop();
  5403. DestroyWindow(_hWnd);
  5404. _hWnd = NULL;
  5405. }
  5406. _pSinkArray = NULL;
  5407. _cs.Unlock();
  5408. }
  5409. }
  5410. LRESULT CALLBACK
  5411. CWinHttpRequestEventsMarshaller::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  5412. {
  5413. if (msg >= WHREM_MSG_ON_RESPONSE_START && msg <= WHREM_MSG_ON_ERROR)
  5414. {
  5415. CWinHttpRequestEventsMarshaller * pMarshaller;
  5416. CSinkArray * pSinkArray = NULL;
  5417. bool bOkToFireEvents = false;
  5418. pMarshaller = (CWinHttpRequestEventsMarshaller *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
  5419. if (pMarshaller)
  5420. {
  5421. pSinkArray = pMarshaller->GetSinkArray();
  5422. bOkToFireEvents = pMarshaller->OkToFireEvents();
  5423. }
  5424. switch (msg)
  5425. {
  5426. case WHREM_MSG_ON_RESPONSE_START:
  5427. {
  5428. BSTR bstrContentType = (BSTR) lParam;
  5429. if (bOkToFireEvents)
  5430. {
  5431. pSinkArray->OnResponseStart((long) wParam, bstrContentType);
  5432. }
  5433. if (bstrContentType)
  5434. {
  5435. DL(SysFreeString)(bstrContentType);
  5436. }
  5437. }
  5438. break;
  5439. case WHREM_MSG_ON_RESPONSE_DATA_AVAILABLE:
  5440. {
  5441. SAFEARRAY * psaData = (SAFEARRAY *) wParam;
  5442. if (bOkToFireEvents)
  5443. {
  5444. pSinkArray->OnResponseDataAvailable(&psaData);
  5445. }
  5446. if (psaData)
  5447. {
  5448. DL(SafeArrayDestroy)(psaData);
  5449. }
  5450. }
  5451. break;
  5452. case WHREM_MSG_ON_RESPONSE_FINISHED:
  5453. if (bOkToFireEvents)
  5454. {
  5455. pSinkArray->OnResponseFinished();
  5456. }
  5457. break;
  5458. case WHREM_MSG_ON_ERROR:
  5459. {
  5460. BSTR bstrErrorDescription = (BSTR) lParam;
  5461. if (bOkToFireEvents)
  5462. {
  5463. pSinkArray->OnError((long) wParam, bstrErrorDescription);
  5464. }
  5465. if (bstrErrorDescription)
  5466. {
  5467. DL(SysFreeString)(bstrErrorDescription);
  5468. }
  5469. }
  5470. break;
  5471. }
  5472. return 0;
  5473. }
  5474. else
  5475. {
  5476. return DefWindowProc(hWnd, msg, wParam, lParam);
  5477. }
  5478. }
  5479. HRESULT STDMETHODCALLTYPE
  5480. CWinHttpRequestEventsMarshaller::QueryInterface(REFIID riid, void ** ppv)
  5481. {
  5482. HRESULT hr = NOERROR;
  5483. if (ppv == NULL)
  5484. {
  5485. hr = E_INVALIDARG;
  5486. }
  5487. else if (riid == IID_IWinHttpRequestEvents || riid == IID_IUnknown)
  5488. {
  5489. *ppv = static_cast<IWinHttpRequestEvents *>(this);
  5490. AddRef();
  5491. }
  5492. else
  5493. hr = E_NOINTERFACE;
  5494. return hr;
  5495. }
  5496. ULONG STDMETHODCALLTYPE
  5497. CWinHttpRequestEventsMarshaller::AddRef()
  5498. {
  5499. return InterlockedIncrement(&_cRefs);
  5500. }
  5501. ULONG STDMETHODCALLTYPE
  5502. CWinHttpRequestEventsMarshaller::Release()
  5503. {
  5504. DWORD cRefs = InterlockedDecrement(&_cRefs);
  5505. if (cRefs == 0)
  5506. {
  5507. delete this;
  5508. return 0;
  5509. }
  5510. else
  5511. return cRefs;
  5512. }
  5513. void STDMETHODCALLTYPE
  5514. CWinHttpRequestEventsMarshaller::OnResponseStart(long Status, BSTR bstrContentType)
  5515. {
  5516. if (_cs.Lock())
  5517. {
  5518. if (OkToFireEvents())
  5519. {
  5520. BSTR bstrContentTypeCopy;
  5521. bstrContentTypeCopy = DL(SysAllocString)(bstrContentType);
  5522. PostMessage(_hWnd, WHREM_MSG_ON_RESPONSE_START,
  5523. (WPARAM) Status,
  5524. (LPARAM) bstrContentTypeCopy);
  5525. // Note: ownership of bstrContentTypeCopy is transferred to the
  5526. // message window, so the string is not freed here.
  5527. }
  5528. _cs.Unlock();
  5529. }
  5530. }
  5531. void STDMETHODCALLTYPE
  5532. CWinHttpRequestEventsMarshaller::OnResponseDataAvailable(SAFEARRAY ** ppsaData)
  5533. {
  5534. if (_cs.Lock())
  5535. {
  5536. if (OkToFireEvents())
  5537. {
  5538. SAFEARRAY * psaDataCopy = NULL;
  5539. if (SUCCEEDED(DL(SafeArrayCopy)(*ppsaData, &psaDataCopy)))
  5540. {
  5541. PostMessage(_hWnd, WHREM_MSG_ON_RESPONSE_DATA_AVAILABLE,
  5542. (WPARAM) psaDataCopy, 0);
  5543. }
  5544. // Note: ownership of psaDataCopy is transferred to the
  5545. // message window, so the array is not freed here.
  5546. }
  5547. _cs.Unlock();
  5548. }
  5549. }
  5550. void STDMETHODCALLTYPE
  5551. CWinHttpRequestEventsMarshaller::OnResponseFinished(void)
  5552. {
  5553. if (_cs.Lock())
  5554. {
  5555. if (OkToFireEvents())
  5556. {
  5557. PostMessage(_hWnd, WHREM_MSG_ON_RESPONSE_FINISHED, 0, 0);
  5558. }
  5559. _cs.Unlock();
  5560. }
  5561. }
  5562. void STDMETHODCALLTYPE
  5563. CWinHttpRequestEventsMarshaller::OnError(long ErrorNumber, BSTR ErrorDescription)
  5564. {
  5565. if (_cs.Lock())
  5566. {
  5567. if (OkToFireEvents())
  5568. {
  5569. BSTR bstrErrorDescriptionCopy;
  5570. bstrErrorDescriptionCopy = DL(SysAllocString)(ErrorDescription);
  5571. PostMessage(_hWnd, WHREM_MSG_ON_ERROR,
  5572. (WPARAM) ErrorNumber,
  5573. (LPARAM) bstrErrorDescriptionCopy);
  5574. // Note: ownership of bstrErrorDescriptionCopy is transferred to
  5575. // the message window, so the string is not freed here.
  5576. }
  5577. _cs.Unlock();
  5578. }
  5579. }
  5580. BOOL RegisterWinHttpEventMarshallerWndClass()
  5581. {
  5582. if (s_fWndClassRegistered)
  5583. return TRUE;
  5584. // only one thread should be here
  5585. if (!GeneralInitCritSec.Lock())
  5586. return FALSE;
  5587. if (s_fWndClassRegistered == FALSE)
  5588. {
  5589. WNDCLASS wndclass;
  5590. wndclass.style = 0;
  5591. wndclass.lpfnWndProc = &CWinHttpRequestEventsMarshaller::WndProc;
  5592. wndclass.cbClsExtra = 0;
  5593. wndclass.cbWndExtra = 0;
  5594. wndclass.hInstance = GlobalDllHandle;
  5595. wndclass.hIcon = NULL;
  5596. wndclass.hCursor = NULL;;
  5597. wndclass.hbrBackground = (HBRUSH)NULL;
  5598. wndclass.lpszMenuName = NULL;
  5599. wndclass.lpszClassName = s_szWinHttpEventMarshallerWndClass;
  5600. // Register the window class
  5601. if (RegisterClass(&wndclass))
  5602. {
  5603. s_fWndClassRegistered = TRUE;
  5604. }
  5605. }
  5606. GeneralInitCritSec.Unlock();
  5607. return s_fWndClassRegistered;
  5608. }
  5609. void CleanupWinHttpRequestGlobals()
  5610. {
  5611. if (s_fWndClassRegistered)
  5612. {
  5613. // Register the window class
  5614. if (UnregisterClass(s_szWinHttpEventMarshallerWndClass, GlobalDllHandle))
  5615. {
  5616. s_fWndClassRegistered = FALSE;
  5617. }
  5618. }
  5619. if (g_pMimeInfoCache)
  5620. {
  5621. delete g_pMimeInfoCache;
  5622. g_pMimeInfoCache = NULL;
  5623. }
  5624. }
  5625. static
  5626. BOOL
  5627. IsValidVariant(VARIANT v)
  5628. {
  5629. BOOL fOk = TRUE;
  5630. if (V_ISBYREF(&v))
  5631. {
  5632. if (IsBadReadPtr(v.pvarVal, sizeof(VARIANT)))
  5633. {
  5634. fOk = FALSE;
  5635. goto Exit;
  5636. }
  5637. else
  5638. v = *(v.pvarVal);
  5639. }
  5640. switch (v.vt)
  5641. {
  5642. case VT_BSTR:
  5643. fOk = IsValidBstr(v.bstrVal);
  5644. break;
  5645. case (VT_BYREF | VT_BSTR):
  5646. fOk = !IsBadReadPtr(v.pbstrVal, sizeof(BSTR));
  5647. break;
  5648. case (VT_BYREF | VT_VARIANT):
  5649. fOk = !IsBadReadPtr(v.pvarVal, sizeof(VARIANT)) &&
  5650. IsValidVariant(*(v.pvarVal));
  5651. break;
  5652. case VT_UNKNOWN:
  5653. case VT_DISPATCH:
  5654. fOk = !IsBadReadPtr(v.punkVal, sizeof(void *));
  5655. break;
  5656. }
  5657. Exit:
  5658. return fOk;
  5659. }
  5660. static
  5661. HRESULT
  5662. SecureFailureFromStatus(DWORD dwFlags)
  5663. {
  5664. DWORD error;
  5665. if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)
  5666. {
  5667. error = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
  5668. }
  5669. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE)
  5670. {
  5671. error = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
  5672. }
  5673. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT)
  5674. {
  5675. error = ERROR_WINHTTP_SECURE_INVALID_CERT;
  5676. }
  5677. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED)
  5678. {
  5679. error = ERROR_WINHTTP_SECURE_CERT_REVOKED;
  5680. }
  5681. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
  5682. {
  5683. error = ERROR_WINHTTP_SECURE_INVALID_CA;
  5684. }
  5685. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
  5686. {
  5687. error = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
  5688. }
  5689. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
  5690. {
  5691. error = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
  5692. }
  5693. else if (dwFlags & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR)
  5694. {
  5695. error = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
  5696. }
  5697. else
  5698. {
  5699. error = ERROR_WINHTTP_SECURE_FAILURE;
  5700. }
  5701. return HRESULT_FROM_WIN32(error);
  5702. }