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.

569 lines
15 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1996 **
  4. //*********************************************************************
  5. /*Included Files------------------------------------------------------------*/
  6. #include "msrating.h"
  7. #pragma hdrstop
  8. #include <npassert.h>
  9. #include <buffer.h>
  10. #include "ratings.h"
  11. #include "mslubase.h"
  12. #include "parselbl.h"
  13. #include "rors.h"
  14. #include "wininet.h"
  15. typedef HINTERNET (WINAPI *PFNInternetOpen)(
  16. IN LPCTSTR lpszCallerName,
  17. IN DWORD dwAccessType,
  18. IN LPCTSTR lpszServerName OPTIONAL,
  19. IN INTERNET_PORT nServerPort,
  20. IN DWORD dwFlags
  21. );
  22. typedef BOOL (WINAPI *PFNInternetCloseHandle)(
  23. IN HINTERNET hInternet
  24. );
  25. typedef HINTERNET (WINAPI *PFNInternetConnect)(
  26. IN HINTERNET hInternet,
  27. IN LPCTSTR lpszServerName,
  28. IN INTERNET_PORT nServerPort,
  29. IN LPCTSTR lpszUsername OPTIONAL,
  30. IN LPCTSTR lpszPassword OPTIONAL,
  31. IN DWORD dwService,
  32. IN DWORD dwFlags,
  33. IN DWORD_PTR dwContext
  34. );
  35. typedef BOOL (WINAPI *PFNInternetReadFile)(
  36. IN HINTERNET hFile,
  37. IN LPVOID lpBuffer,
  38. IN DWORD dwNumberOfBytesToRead,
  39. OUT LPDWORD lpdwNumberOfBytesRead
  40. );
  41. typedef INTERNET_STATUS_CALLBACK (WINAPI *PFNInternetSetStatusCallback)(
  42. IN HINTERNET hInternet,
  43. IN INTERNET_STATUS_CALLBACK lpfnInternetCallback
  44. );
  45. typedef HINTERNET (WINAPI *PFNHttpOpenRequest)(
  46. IN HINTERNET hHttpSession,
  47. IN LPCTSTR lpszVerb,
  48. IN LPCTSTR lpszObjectName,
  49. IN LPCTSTR lpszVersion,
  50. IN LPCTSTR lpszReferrer OPTIONAL,
  51. IN LPCTSTR FAR * lplpszAcceptTypes OPTIONAL,
  52. IN DWORD dwFlags,
  53. IN DWORD_PTR dwContext
  54. );
  55. typedef BOOL (WINAPI *PFNHttpSendRequest)(
  56. IN HINTERNET hHttpRequest,
  57. IN LPCTSTR lpszHeaders OPTIONAL,
  58. IN DWORD dwHeadersLength,
  59. IN LPVOID lpOptional OPTIONAL,
  60. IN DWORD dwOptionalLength
  61. );
  62. typedef BOOL (WINAPI *PFNInternetCrackUrl)(
  63. IN LPCTSTR lpszUrl,
  64. IN DWORD dwUrlLength,
  65. IN DWORD dwFlags,
  66. IN OUT LPURL_COMPONENTS lpUrlComponents
  67. );
  68. typedef BOOL (WINAPI *PFNInternetCanonicalizeUrl)(
  69. IN LPCSTR lpszUrl,
  70. OUT LPSTR lpszBuffer,
  71. IN OUT LPDWORD lpdwBufferLength,
  72. IN DWORD dwFlags
  73. );
  74. PFNInternetReadFile pfnInternetReadFile = NULL;
  75. PFNHttpSendRequest pfnHttpSendRequest = NULL;
  76. PFNInternetOpen pfnInternetOpen = NULL;
  77. PFNInternetSetStatusCallback pfnInternetSetStatusCallback = NULL;
  78. PFNInternetConnect pfnInternetConnect = NULL;
  79. PFNHttpOpenRequest pfnHttpOpenRequest = NULL;
  80. PFNInternetCloseHandle pfnInternetCloseHandle = NULL;
  81. PFNInternetCrackUrl pfnInternetCrackUrl = NULL;
  82. PFNInternetCanonicalizeUrl pfnInternetCanonicalizeUrl = NULL;
  83. #undef InternetReadFile
  84. #undef HttpSendRequest
  85. #undef InternetOpen
  86. #undef InternetSetStatusCallback
  87. #undef InternetConnect
  88. #undef HttpOpenRequest
  89. #undef InternetCloseHandle
  90. #undef InternetCrackUrl
  91. #undef InternetCanonicalizeUrl
  92. #define InternetReadFile pfnInternetReadFile
  93. #define HttpSendRequest pfnHttpSendRequest
  94. #define InternetOpen pfnInternetOpen
  95. #define InternetSetStatusCallback pfnInternetSetStatusCallback
  96. #define InternetConnect pfnInternetConnect
  97. #define HttpOpenRequest pfnHttpOpenRequest
  98. #define InternetCloseHandle pfnInternetCloseHandle
  99. #define InternetCrackUrl pfnInternetCrackUrl
  100. #define InternetCanonicalizeUrl pfnInternetCanonicalizeUrl
  101. struct {
  102. FARPROC *ppfn;
  103. LPCSTR pszName;
  104. } aImports[] = {
  105. #ifndef UNICODE
  106. { (FARPROC *)&pfnInternetReadFile, "InternetReadFile" },
  107. { (FARPROC *)&pfnHttpSendRequest, "HttpSendRequestA" },
  108. { (FARPROC *)&pfnInternetOpen, "InternetOpenA" },
  109. { (FARPROC *)&pfnInternetSetStatusCallback, "InternetSetStatusCallback" },
  110. { (FARPROC *)&pfnInternetConnect, "InternetConnectA" },
  111. { (FARPROC *)&pfnHttpOpenRequest, "HttpOpenRequestA" },
  112. { (FARPROC *)&pfnInternetCloseHandle, "InternetCloseHandle" },
  113. { (FARPROC *)&pfnInternetCrackUrl, "InternetCrackUrlA" },
  114. { (FARPROC *)&pfnInternetCanonicalizeUrl, "InternetCanonicalizeUrlA" },
  115. #else
  116. { (FARPROC *)&pfnInternetReadFile, "InternetReadFile" },
  117. { (FARPROC *)&pfnHttpSendRequest, "HttpSendRequestW" },
  118. { (FARPROC *)&pfnInternetOpen, "InternetOpenW" },
  119. { (FARPROC *)&pfnInternetSetStatusCallback, "InternetSetStatusCallback" },
  120. { (FARPROC *)&pfnInternetConnect, "InternetConnectW" },
  121. { (FARPROC *)&pfnHttpOpenRequest, "HttpOpenRequestW" },
  122. { (FARPROC *)&pfnInternetCloseHandle, "InternetCloseHandle" },
  123. { (FARPROC *)&pfnInternetCrackUrl, "InternetCrackUrlW" },
  124. { (FARPROC *)&pfnInternetCanonicalizeUrl, "InternetCanonicalizeUrlW" },
  125. #endif
  126. };
  127. const UINT cImports = sizeof(aImports) / sizeof(aImports[0]);
  128. HINSTANCE hWinINet = NULL;
  129. BOOL fTriedLoad = FALSE;
  130. HINTERNET hI = NULL;
  131. void _stdcall WinInetCallbackProc(HINTERNET hInternet, DWORD_PTR Context, DWORD Status, LPVOID Info, DWORD Length);
  132. #define USER_AGENT_STRING "Batcave(bcrs)"
  133. BOOL LoadWinINet(void)
  134. {
  135. if (fTriedLoad)
  136. {
  137. return (hWinINet != NULL);
  138. }
  139. fTriedLoad = TRUE;
  140. hWinINet = ::LoadLibrary("WININET.DLL");
  141. if (hWinINet == NULL)
  142. {
  143. return FALSE;
  144. }
  145. for (UINT i=0; i<cImports; i++)
  146. {
  147. *(aImports[i].ppfn) = ::GetProcAddress(hWinINet, aImports[i].pszName);
  148. if (*(aImports[i].ppfn) == NULL)
  149. {
  150. CleanupWinINet();
  151. return FALSE;
  152. }
  153. }
  154. hI = InternetOpen(USER_AGENT_STRING, PRE_CONFIG_INTERNET_ACCESS, NULL, 0, INTERNET_FLAG_ASYNC);
  155. if (hI == NULL)
  156. {
  157. CleanupWinINet();
  158. return FALSE;
  159. }
  160. InternetSetStatusCallback(hI, WinInetCallbackProc);
  161. return TRUE;
  162. }
  163. void CleanupWinINet(void)
  164. {
  165. if (hI != NULL)
  166. {
  167. InternetCloseHandle(hI);
  168. hI = NULL;
  169. }
  170. if (hWinINet != NULL)
  171. {
  172. for (UINT i=0; i<cImports; i++)
  173. {
  174. *(aImports[i].ppfn) = NULL;
  175. }
  176. ::FreeLibrary(hWinINet);
  177. hWinINet = NULL;
  178. }
  179. }
  180. void _stdcall WinInetCallbackProc(HINTERNET hInternet, DWORD_PTR Context, DWORD Status, LPVOID Info, DWORD Length)
  181. {
  182. BOOL unknown = FALSE;
  183. HANDLE hAsyncEvent = (HANDLE) Context;
  184. char *type$;
  185. switch (Status)
  186. {
  187. case INTERNET_STATUS_RESOLVING_NAME:
  188. type$ = "RESOLVING NAME";
  189. break;
  190. case INTERNET_STATUS_NAME_RESOLVED:
  191. type$ = "NAME RESOLVED";
  192. break;
  193. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  194. type$ = "CONNECTING TO SERVER";
  195. break;
  196. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  197. type$ = "CONNECTED TO SERVER";
  198. break;
  199. case INTERNET_STATUS_SENDING_REQUEST:
  200. type$ = "SENDING REQUEST";
  201. break;
  202. case INTERNET_STATUS_REQUEST_SENT:
  203. type$ = "REQUEST SENT";
  204. break;
  205. case INTERNET_STATUS_RECEIVING_RESPONSE:
  206. type$ = "RECEIVING RESPONSE";
  207. break;
  208. case INTERNET_STATUS_RESPONSE_RECEIVED:
  209. type$ = "RESPONSE RECEIVED";
  210. break;
  211. case INTERNET_STATUS_CLOSING_CONNECTION:
  212. type$ = "CLOSING CONNECTION";
  213. break;
  214. case INTERNET_STATUS_CONNECTION_CLOSED:
  215. type$ = "CONNECTION CLOSED";
  216. break;
  217. case INTERNET_STATUS_REQUEST_COMPLETE:
  218. type$ = "REQUEST COMPLETE";
  219. SetEvent(hAsyncEvent);
  220. break;
  221. default:
  222. type$ = "???";
  223. unknown = TRUE;
  224. break;
  225. }
  226. /*
  227. printf("callback: handle %x [context %x ] %s \n",
  228. hInternet,
  229. Context,
  230. type$
  231. );
  232. */
  233. }
  234. #define ABORT_EVENT 0
  235. #define ASYNC_EVENT 1
  236. BOOL ShouldAbort(HANDLE hAbort)
  237. {
  238. return (WAIT_OBJECT_0 == WaitForSingleObject(hAbort, 0));
  239. }
  240. BOOL WaitForAsync(HANDLE rgEvents[])
  241. {
  242. BOOL fAbort;
  243. // if (ERROR_IO_PENDING != GetLastError()) return FALSE;
  244. fAbort = (WAIT_OBJECT_0 == WaitForMultipleObjects(2, rgEvents, FALSE, INFINITE));
  245. // fAbort = (WAIT_OBJECT_0 == WaitForSingleObject(rgEvents[ABORT_EVENT], 0));
  246. return !fAbort;
  247. }
  248. void EncodeUrl(LPCTSTR pszTargetUrl, char *pBuf)
  249. {
  250. while (*pszTargetUrl)
  251. {
  252. switch (*pszTargetUrl)
  253. {
  254. case ':':
  255. *pBuf++ = '%';
  256. *pBuf++ = '3';
  257. *pBuf++ = 'A';
  258. break;
  259. case '/':
  260. *pBuf++ = '%';
  261. *pBuf++ = '2';
  262. *pBuf++ = 'F';
  263. break;
  264. default:
  265. *pBuf++ = *pszTargetUrl;
  266. break;
  267. }
  268. ++pszTargetUrl;
  269. }
  270. *pBuf = 0;
  271. }
  272. STDMETHODIMP CRORemoteSite::QueryInterface(
  273. /* [in] */ REFIID riid,
  274. /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
  275. {
  276. *ppvObject = NULL;
  277. if (IsEqualIID(riid, IID_IUnknown) ||
  278. IsEqualIID(riid, IID_IObtainRating))
  279. {
  280. *ppvObject = (LPVOID)this;
  281. AddRef();
  282. return NOERROR;
  283. }
  284. return ResultFromScode(E_NOINTERFACE);
  285. }
  286. STDMETHODIMP_(ULONG) CRORemoteSite::AddRef(void)
  287. {
  288. RefThisDLL(TRUE);
  289. return ++m_cRef;
  290. }
  291. STDMETHODIMP_(ULONG) CRORemoteSite::Release(void)
  292. {
  293. RefThisDLL(FALSE);
  294. if (!--m_cRef)
  295. {
  296. delete this;
  297. return 0;
  298. }
  299. else
  300. {
  301. return m_cRef;
  302. }
  303. }
  304. LPSTR FindRatingLabel(LPSTR pszResponse)
  305. {
  306. /* pszResponse is the complete response message from the HTTP server.
  307. * It could be a simple response (just the PICS label we want) or it
  308. * could be a full response including headers. In the former case we
  309. * just return the label, in the latter we have to skip the headers
  310. * to the message body.
  311. *
  312. * To be extra tolerant of poorly written label bureaus, we start by
  313. * looking at the start of the data to see if it's a left paren. If
  314. * it isn't, we assume we've got some headers, so we skip to the
  315. * double CRLF which HTTP requires to terminate headers. We don't
  316. * require a Status-Line (such as "HTTP/1.1 200 OK") even though
  317. * technically HTTP does. If we don't find the double CRLF, then
  318. * we look for the string "(PICS-" which is usually what begins a
  319. * PICS label list. If they've done everything else wrong and they're
  320. * also perverse enough to insert whitespace there (such as "( PICS-"),
  321. * tough.
  322. */
  323. SkipWhitespace(&pszResponse); /* skip leading whitespace just in case */
  324. if (*pszResponse != '(')
  325. { /* doesn't seem to start with a label */
  326. LPSTR pszBody = ::strstrf(pszResponse, ::szDoubleCRLF);
  327. if (pszBody != NULL)
  328. { /* found double CRLF, end of HTTP headers */
  329. pszResponse = pszBody + 4; /* length of CRLFCRLF */
  330. }
  331. else
  332. { /* no double CRLF, hunt for PICS label */
  333. pszBody = ::strstrf(pszResponse, ::szPicsOpening);
  334. if (pszBody != NULL)
  335. {
  336. pszResponse = pszBody; /* beginning of PICS label */
  337. }
  338. }
  339. }
  340. return pszResponse;
  341. }
  342. const char szRequestTemplate[] = "?opt=normal&u=\"";
  343. const UINT cchRequestTemplate = sizeof(szRequestTemplate) + 1;
  344. STDMETHODIMP CRORemoteSite::ObtainRating(THIS_ LPCTSTR pszTargetUrl, HANDLE hAbortEvent,
  345. IMalloc *pAllocator, LPSTR *ppRatingOut)
  346. {
  347. HINTERNET hIC, hH;
  348. HANDLE rgEvents[2];
  349. BOOL fRet;
  350. HRESULT hrRet = E_RATING_NOT_FOUND;
  351. char rgBuf[10000], *pBuf; // PERF - way too much stack!
  352. DWORD nRead, nBuf = sizeof(rgBuf) - 1;
  353. LPSTR pszRatingServer;
  354. if (!gPRSI->etstrRatingBureau.fIsInit())
  355. {
  356. return hrRet;
  357. }
  358. if (!LoadWinINet())
  359. {
  360. return hrRet;
  361. }
  362. pszRatingServer = gPRSI->etstrRatingBureau.Get();
  363. BUFFER bufBureauHostName(INTERNET_MAX_HOST_NAME_LENGTH);
  364. BUFFER bufBureauPath(INTERNET_MAX_PATH_LENGTH);
  365. if (!bufBureauHostName.QueryPtr() || !bufBureauPath.QueryPtr())
  366. {
  367. return E_OUTOFMEMORY;
  368. }
  369. URL_COMPONENTS uc;
  370. uc.dwStructSize = sizeof(uc);
  371. uc.lpszScheme = NULL;
  372. uc.dwSchemeLength = 0;
  373. uc.lpszHostName = (LPSTR)bufBureauHostName.QueryPtr();
  374. uc.dwHostNameLength = bufBureauHostName.QuerySize();
  375. uc.lpszUserName = NULL;
  376. uc.dwUserNameLength = 0;
  377. uc.lpszPassword = NULL;
  378. uc.dwPasswordLength = 0;
  379. uc.lpszUrlPath = (LPSTR)bufBureauPath.QueryPtr();
  380. uc.dwUrlPathLength = bufBureauPath.QuerySize();
  381. uc.lpszExtraInfo = NULL;
  382. uc.dwExtraInfoLength = 0;
  383. if (!InternetCrackUrl(pszRatingServer, 0, 0, &uc))
  384. {
  385. return HRESULT_FROM_WIN32(GetLastError());
  386. }
  387. BUFFER bufRequest(INTERNET_MAX_URL_LENGTH + uc.dwUrlPathLength + cchRequestTemplate);
  388. LPSTR pszRequest = (LPSTR)bufRequest.QueryPtr();
  389. if (pszRequest == NULL)
  390. {
  391. return E_OUTOFMEMORY;
  392. }
  393. LPSTR pszCurrent = pszRequest;
  394. ::strcpyf(pszCurrent, uc.lpszUrlPath);
  395. pszCurrent += uc.dwUrlPathLength;
  396. ::strcpyf(pszCurrent, szRequestTemplate);
  397. pszCurrent += ::strlenf(pszCurrent);
  398. /* Encode the target URL. */
  399. EncodeUrl(pszTargetUrl, pszCurrent);
  400. ::strcatf(pszCurrent, "\"");
  401. hIC = hH = NULL;
  402. rgEvents[ABORT_EVENT] = hAbortEvent;
  403. rgEvents[ASYNC_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
  404. if (!rgEvents[ASYNC_EVENT])
  405. {
  406. goto STATE_CLEANUP;
  407. }
  408. hIC = InternetConnect(hI, uc.lpszHostName, uc.nPort, NULL, NULL,
  409. INTERNET_SERVICE_HTTP, 0, (DWORD_PTR) rgEvents[ASYNC_EVENT]);
  410. if (hIC == NULL || ShouldAbort(hAbortEvent))
  411. {
  412. goto STATE_CLEANUP;
  413. }
  414. hH = HttpOpenRequest(hIC, "GET", pszRequest, NULL, NULL, NULL,
  415. INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD,
  416. (DWORD_PTR) rgEvents[ASYNC_EVENT]);
  417. if (hH == NULL || ShouldAbort(hAbortEvent))
  418. {
  419. goto STATE_CLEANUP;
  420. }
  421. fRet = HttpSendRequest(hH, NULL, (DWORD) 0, NULL, 0);
  422. if (!fRet && !WaitForAsync(rgEvents))
  423. {
  424. goto STATE_CLEANUP;
  425. }
  426. pBuf = rgBuf;
  427. nRead = 0;
  428. do
  429. {
  430. fRet = InternetReadFile(hH, pBuf, nBuf-nRead, &nRead);
  431. if (!fRet && !WaitForAsync(rgEvents))
  432. {
  433. goto STATE_CLEANUP;
  434. }
  435. if (nRead)
  436. {
  437. pBuf += nRead;
  438. hrRet = NOERROR;
  439. }
  440. } while (nRead);
  441. STATE_CLEANUP:
  442. if (hH) InternetCloseHandle(hH);
  443. if (hIC) InternetCloseHandle(hIC);
  444. if (rgEvents[ASYNC_EVENT])
  445. {
  446. CloseHandle(rgEvents[ASYNC_EVENT]);
  447. }
  448. if (hrRet == NOERROR)
  449. {
  450. (*ppRatingOut) = (char*) pAllocator->Alloc((int)(pBuf - rgBuf + 1));
  451. if (*ppRatingOut != NULL)
  452. {
  453. *pBuf = '\0';
  454. LPSTR pszLabel = FindRatingLabel(rgBuf);
  455. strcpyf(*ppRatingOut, pszLabel);
  456. }
  457. else
  458. {
  459. hrRet = ResultFromScode(E_OUTOFMEMORY);
  460. }
  461. }
  462. if (hrRet == NOERROR)
  463. {
  464. hrRet = S_RATING_FOUND;
  465. }
  466. return hrRet;
  467. }
  468. STDMETHODIMP_(ULONG) CRORemoteSite::GetSortOrder(THIS)
  469. {
  470. return RATING_ORDER_REMOTESITE;
  471. }