Source code of Windows XP (NT5)
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.

386 lines
10 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: D E S C R Q S T . C P P
  7. //
  8. // Contents: Implementation of description request processing for the
  9. // UPnP Device Host ISAPI Extension
  10. //
  11. // Notes:
  12. //
  13. // Author: spather 2000/08/31
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include <wininet.h>
  19. #include "descrqst.h"
  20. #include "udhiutil.h"
  21. #include "hostp.h"
  22. #include "uhcommon.h"
  23. #include "ncstring.h"
  24. //+---------------------------------------------------------------------------
  25. //
  26. // Function: HrValidateDescriptionMethod
  27. //
  28. // Purpose: Validates that the HTTP verb used is valid for this
  29. // type of request.
  30. //
  31. // Arguments:
  32. // pszaMethod [in] The HTTP verb
  33. //
  34. // Returns:
  35. // If the method is valid, the return value is S_OK. If the method is
  36. // not valid, the function returns one of the COM error codes defined
  37. // in WinError.h.
  38. //
  39. // Author: spather 2000/09/21
  40. //
  41. // Notes:
  42. //
  43. HRESULT
  44. HrValidateDescriptionMethod(
  45. IN LPSTR pszaMethod)
  46. {
  47. HRESULT hr = S_OK;
  48. AssertSz(pszaMethod,
  49. "HrValidateDescriptionMethod(): NULL Method passed");
  50. if (0 != lstrcmpiA(pszaMethod, "GET"))
  51. {
  52. hr = E_FAIL;
  53. }
  54. TraceError("HrValidateDescriptionMethod(): Exiting",
  55. hr);
  56. return hr;
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: HrParseDescriptionQueryString
  61. //
  62. // Purpose: Parses a description request's query string and extracts
  63. // the content GUID from it.
  64. //
  65. // Arguments:
  66. // pszaQueryString [in] The query string to parse
  67. // rguidContent [out] Points to a GUID structure that will be
  68. // initialized with the content GUID as parsed
  69. //
  70. // Returns:
  71. // If the function succeeds, the return value is S_OK. Otherwise, the
  72. // function returns one of the COM error codes defined in WinError.h.
  73. //
  74. // Author: spather 2000/09/14
  75. //
  76. // Notes:
  77. //
  78. HRESULT
  79. HrParseDescriptionQueryString(
  80. IN LPSTR pszaQueryString,
  81. OUT GUID & rguidContent)
  82. {
  83. HRESULT hr = S_OK;
  84. LPWSTR szQueryString;
  85. Assert(pszaQueryString);
  86. szQueryString = WszFromSz(pszaQueryString);
  87. if (szQueryString)
  88. {
  89. hr = HrContentURLToGUID(szQueryString, rguidContent);
  90. delete [] szQueryString;
  91. }
  92. else
  93. {
  94. hr = E_OUTOFMEMORY;
  95. TraceError("HrParseDescriptionQueryString(): "
  96. "Unable to allocate memory for content URL",
  97. hr);
  98. }
  99. TraceError("HrParseDescriptionQueryString(): "
  100. "Exiting",
  101. hr);
  102. return hr;
  103. }
  104. //+---------------------------------------------------------------------------
  105. //
  106. // Function: HrReturnContent
  107. //
  108. // Purpose: Retrieves content from a content source and sends it back
  109. // to the originator of a description request
  110. //
  111. // Arguments:
  112. // pecb [in] The extension control block for the description
  113. // request
  114. // pudcs [in] The dynamic content source
  115. // rguidContent [in] The GUID identifying the content being requested.
  116. //
  117. // Returns:
  118. // If the function succeeds, the return value is S_OK. Otherwise, the
  119. // function returns one of the COM error codes defined in WinError.h.
  120. //
  121. // Author: spather 2000/09/14
  122. //
  123. // Notes:
  124. //
  125. HRESULT
  126. HrReturnContent(
  127. LPEXTENSION_CONTROL_BLOCK pecb,
  128. IUPnPDynamicContentSource * pudcs,
  129. REFGUID rguidContent)
  130. {
  131. HRESULT hr = S_OK;
  132. LONG nHeaders = 0;
  133. LPWSTR * rgszHeaders = NULL;
  134. LONG nBytes = 0;
  135. BYTE * rgBytes = NULL;
  136. hr = pudcs->GetContent(rguidContent,
  137. &nHeaders,
  138. &rgszHeaders,
  139. &nBytes,
  140. &rgBytes);
  141. if (SUCCEEDED(hr))
  142. {
  143. DWORD cchHeaders = 0;
  144. LPSTR pszaHeaders = NULL;
  145. Assert(rgszHeaders);
  146. Assert(rgBytes);
  147. // Need to merge the headers into a single ASCII string. Each
  148. // Headers will be delimited by \r\n pairs and the last header
  149. // will be followed by 2 \r\n pairs.
  150. for (LONG i = 0; i < nHeaders; i++)
  151. {
  152. cchHeaders += lstrlenW(rgszHeaders[i]);
  153. cchHeaders += 2; // For the "\r\n" pair
  154. }
  155. cchHeaders += 2; // For the final "\r\n"
  156. pszaHeaders = new CHAR[cchHeaders+1];
  157. if (pszaHeaders)
  158. {
  159. LPSTR pszaNextHeader = pszaHeaders;
  160. for (LONG i = 0; i < nHeaders; i++)
  161. {
  162. DWORD cchCurHeader;
  163. cchCurHeader = lstrlenW(rgszHeaders[i]);
  164. wsprintfA(pszaNextHeader,
  165. "%S\r\n",
  166. rgszHeaders[i]);
  167. pszaNextHeader += cchCurHeader+2; // +2 for \r\n
  168. }
  169. lstrcpyA(pszaNextHeader,
  170. "\r\n");
  171. if (bSendResponseToClient(pecb,
  172. "200 OK",
  173. cchHeaders,
  174. pszaHeaders,
  175. nBytes,
  176. (LPCSTR) rgBytes))
  177. {
  178. pecb->dwHttpStatusCode = HTTP_STATUS_OK;
  179. TraceTag(ttidUDHISAPI,
  180. "HrReturnContent(): "
  181. "Successfully sent response to client");
  182. }
  183. delete [] pszaHeaders;
  184. pszaHeaders = NULL;
  185. }
  186. else
  187. {
  188. hr = E_OUTOFMEMORY;
  189. TraceError("HrReturnContent(): "
  190. "Failed to allocate memory for headers",
  191. hr);
  192. }
  193. // Free memory returned from GetContent().
  194. for (LONG i = 0; i < nHeaders; i++)
  195. {
  196. CoTaskMemFree(rgszHeaders[i]);
  197. rgszHeaders[i] = NULL;
  198. }
  199. CoTaskMemFree(rgszHeaders);
  200. rgszHeaders = NULL;
  201. CoTaskMemFree(rgBytes);
  202. rgBytes = NULL;
  203. }
  204. else
  205. {
  206. TraceError("HrReturnContent(): "
  207. "Failed to get content",
  208. hr);
  209. }
  210. TraceError("HrReturnContent(): "
  211. "Exiting",
  212. hr);
  213. return hr;
  214. }
  215. DWORD WINAPI
  216. DwHandleContentRequest(
  217. LPVOID lpParameter)
  218. {
  219. LPEXTENSION_CONTROL_BLOCK pecb = NULL;
  220. DWORD dwStatus = HSE_STATUS_SUCCESS ;
  221. HCONN ConnID;
  222. HRESULT hr = S_OK;
  223. GUID guidContent;
  224. BOOL fKeepConn = FALSE;
  225. pecb = (LPEXTENSION_CONTROL_BLOCK) lpParameter;
  226. AssertSz(pecb,
  227. "DwHandleContentRequest(): "
  228. "NULL extension control block");
  229. pecb->ServerSupportFunction(
  230. pecb->ConnID,
  231. HSE_REQ_IS_KEEP_CONN,
  232. &fKeepConn,
  233. NULL,
  234. NULL);
  235. if(fKeepConn)
  236. dwStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  237. else
  238. dwStatus = HSE_STATUS_SUCCESS;
  239. ConnID = pecb->ConnID;
  240. AssertSz(pecb->lpszQueryString,
  241. "DwHandleContentRequest(): "
  242. "NULL query string passed");
  243. // Validate the method.
  244. hr = HrValidateDescriptionMethod(pecb->lpszMethod);
  245. if (SUCCEEDED(hr))
  246. {
  247. // Get the content GUID.
  248. TraceTag(ttidUDHISAPI,
  249. "DwHandleContentRequest(): ConnID(0x%x) "
  250. "Query string is %s",
  251. ConnID,
  252. pecb->lpszQueryString);
  253. hr = HrParseDescriptionQueryString(pecb->lpszQueryString,
  254. guidContent);
  255. if (SUCCEEDED(hr))
  256. {
  257. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  258. if (SUCCEEDED(hr))
  259. {
  260. IUPnPDynamicContentSource * pudcs = NULL;
  261. hr = CoCreateInstance(CLSID_UPnPDynamicContentSource,
  262. NULL,
  263. CLSCTX_INPROC_SERVER,
  264. IID_IUPnPDynamicContentSource,
  265. (void **) &pudcs);
  266. if (SUCCEEDED(hr))
  267. {
  268. hr = HrReturnContent(pecb,
  269. pudcs,
  270. guidContent);
  271. pudcs->Release();
  272. }
  273. else
  274. {
  275. TraceTag(ttidUDHISAPI,
  276. "DwHandleContentRequest(): ConnID(0x%x): "
  277. "Failed to CoCreate dynamic content source, "
  278. " HRESULT == 0x%x",
  279. ConnID,
  280. hr);
  281. }
  282. CoUninitialize();
  283. }
  284. else
  285. {
  286. TraceTag(ttidUDHISAPI,
  287. "DwHandleContentRequest(): ConnID(0x%x): "
  288. "Failed to initialize COM, HRESULT == 0x%x",
  289. ConnID,
  290. hr);
  291. }
  292. }
  293. else
  294. {
  295. TraceTag(ttidUDHISAPI,
  296. "DwHandleContentRequest(): ConnID(0x%x): "
  297. "Failed to get content GUID, HRESULT == 0x%x",
  298. ConnID,
  299. hr);
  300. }
  301. }
  302. else
  303. {
  304. TraceTag(ttidUDHISAPI,
  305. "DwHandleContentRequest(): ConnID(0x%x): "
  306. "Failed to validate method %s, HRESULT == 0x%x",
  307. ConnID,
  308. pecb->lpszMethod,
  309. hr);
  310. }
  311. if (FAILED(hr))
  312. {
  313. LPCSTR pcszErrorHeaders = "\r\n";
  314. dwStatus = HSE_STATUS_ERROR;
  315. if (bSendResponseToClient(pecb,
  316. "500 Internal Server Error",
  317. lstrlenA(pcszErrorHeaders),
  318. pcszErrorHeaders,
  319. 0,
  320. NULL))
  321. {
  322. pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  323. }
  324. }
  325. return dwStatus ;
  326. }