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.

367 lines
9.8 KiB

  1. #include <pch.h>
  2. #pragma hdrstop
  3. #include <httpext.h>
  4. #include <wininet.h>
  5. #include "ncstring.h"
  6. #include "udhiutil.h"
  7. #include "descrqst.h"
  8. #include "ctrlrqst.h"
  9. #include "evtrqst.h"
  10. #include "hostp.h"
  11. #include "hostp_i.c"
  12. static LONG g_fTracingInit = 0;
  13. typedef LPTHREAD_START_ROUTINE PFN_UPNP_REQUEST_HANDLER;
  14. typedef enum {
  15. URT_CONTENT = 0,
  16. URT_CONTROL = 1,
  17. URT_EVENTING = 2,
  18. // URT_INVALID __MUST__ be last. Insert new types before URT_INVALID
  19. URT_INVALID
  20. } UPNP_REQUEST_TYPE;
  21. typedef struct tagUPNP_REQUEST_DISPATCH_ENTRY
  22. {
  23. LPCSTR pszaTypeString;
  24. UPNP_REQUEST_TYPE urt;
  25. PFN_UPNP_REQUEST_HANDLER pfnHandler;
  26. } UPNP_REQUEST_DISPATCH_ENTRY;
  27. const UPNP_REQUEST_DISPATCH_ENTRY gc_DispatchTable[] =
  28. {
  29. {"content", URT_CONTENT, DwHandleContentRequest}, // URT_CONTENT
  30. {"control", URT_CONTROL, DwHandleControlRequest}, // URT_CONTROL
  31. {"event", URT_EVENTING, DwHandleEventRequest}, // URT_EVENTING
  32. {NULL, URT_INVALID, NULL} // URT_INVALID - MUST be last
  33. };
  34. //+---------------------------------------------------------------------------
  35. //
  36. // Function: UPnPRequestTypeFromQueryString
  37. //
  38. // Purpose: Parses a query string and determines the type of request
  39. // it specifies.
  40. //
  41. // Arguments:
  42. // pszaQueryString [in] Query string to parse
  43. // purt [out] Receives a reference to the UPNP_REQUEST_TYPE
  44. // value corresponding to the query string
  45. //
  46. // Returns:
  47. // (none) - See Notes section below.
  48. //
  49. // Author: spather 2000/08/31
  50. //
  51. // Notes:
  52. // If the query string does not specify a valid request, the value
  53. // returned at purt is URT_INVALID.
  54. //
  55. VOID
  56. UPnPRequestTypeFromQueryString(
  57. IN LPSTR pszaQueryString,
  58. OUT UPNP_REQUEST_TYPE * purt)
  59. {
  60. AssertSz(pszaQueryString,
  61. "UPnPRequestTypeFromQueryString(): "
  62. "NULL query string passed");
  63. if (purt)
  64. {
  65. UPNP_REQUEST_TYPE urt = URT_INVALID;
  66. DWORD cchQueryString = 0;
  67. int i = 0;
  68. cchQueryString = lstrlenA(pszaQueryString);
  69. // Loop through the dispatch table, looking for an entry with
  70. // a request type string matching the one in the query string.
  71. while (gc_DispatchTable[i].urt != URT_INVALID)
  72. {
  73. DWORD cchTypeString = 0;
  74. LPCSTR pcszaTypeString = NULL;
  75. pcszaTypeString = gc_DispatchTable[i].pszaTypeString;
  76. cchTypeString = lstrlenA(pcszaTypeString);
  77. // If the query string is shorter than the request type string
  78. // then this is obviously not a match.
  79. if (cchQueryString >= cchTypeString)
  80. {
  81. if (_strnicmp(pszaQueryString,
  82. pcszaTypeString,
  83. cchTypeString) == 0)
  84. {
  85. urt = gc_DispatchTable[i].urt;
  86. break;
  87. }
  88. }
  89. i++;
  90. }
  91. *purt = urt;
  92. }
  93. }
  94. //+---------------------------------------------------------------------------
  95. //
  96. // Function: UPnPRequestHandlerFromRequestType
  97. //
  98. // Purpose: Retrieves a pointer to a handler function for a particular
  99. // request type.
  100. //
  101. // Arguments:
  102. // urt [in] The UPnP request type
  103. // ppfnHandler [out] Receives a pointer to a handler function for the
  104. // UPnP request type
  105. //
  106. // Returns:
  107. // (none) - See Notes section below.
  108. //
  109. // Author: spather 2000/09/1
  110. //
  111. // Notes:
  112. // If urt is URT_INVALID, then a NULL pointer is returned at ppfnHandler.
  113. //
  114. VOID
  115. UPnPRequestHandlerFromRequestType(
  116. IN UPNP_REQUEST_TYPE urt,
  117. OUT PFN_UPNP_REQUEST_HANDLER * ppfnHandler)
  118. {
  119. if (ppfnHandler)
  120. {
  121. int i = 0;
  122. PFN_UPNP_REQUEST_HANDLER pfnHandler = NULL;
  123. if (urt != URT_INVALID)
  124. {
  125. // Loop through the dispatch table, looking for an entry
  126. // with a matching request type. If one is found, we return
  127. // the handler function from it.
  128. while (gc_DispatchTable[i].urt != URT_INVALID)
  129. {
  130. if (gc_DispatchTable[i].urt == urt)
  131. {
  132. pfnHandler = gc_DispatchTable[i].pfnHandler;
  133. break;
  134. }
  135. i++;
  136. }
  137. }
  138. *ppfnHandler = pfnHandler;
  139. }
  140. }
  141. static const LPCSTR c_rgszHeaders[] =
  142. {
  143. "HOST",
  144. "NT",
  145. "CALLBACK",
  146. "TIMEOUT",
  147. "SID"
  148. };
  149. static const int c_cHeaders = celems(c_rgszHeaders);
  150. BOOL FExistDuplicateHeaders(LPEXTENSION_CONTROL_BLOCK pecb)
  151. {
  152. LPSTR szHeaders;
  153. if (DwQueryHeader(pecb, "ALL_RAW", &szHeaders) == ERROR_SUCCESS)
  154. {
  155. INT ih;
  156. AssertSz(szHeaders, "No headers?");
  157. for (ih = 0; ih < c_cHeaders; ih++)
  158. {
  159. LPSTR szMatch;
  160. szMatch = stristr(szHeaders, c_rgszHeaders[ih]);
  161. if (szMatch)
  162. {
  163. if ((szMatch == szHeaders) ||
  164. (((*(szMatch - 1) == '\n') &&
  165. (szMatch - 1 != szHeaders) &&
  166. (*(szMatch - 2) == '\r'))))
  167. {
  168. szMatch += lstrlenA(c_rgszHeaders[ih]);
  169. LPSTR szMatch2;
  170. szMatch2 = stristr(szMatch, c_rgszHeaders[ih]);
  171. while (szMatch2)
  172. {
  173. if ((szMatch2 == szHeaders) ||
  174. (((*(szMatch2 - 1) == '\n') &&
  175. (szMatch2 - 1 != szHeaders) &&
  176. (*(szMatch2 - 2) == '\r'))))
  177. {
  178. // Got another header! Duplicate!
  179. TraceTag(ttidIsapiCtl, "Header %s is duplicated!",
  180. c_rgszHeaders[ih]);
  181. delete [] szHeaders;
  182. return TRUE;
  183. }
  184. else
  185. {
  186. szMatch2 += lstrlenA(c_rgszHeaders[ih]);
  187. szMatch2 = stristr(szMatch2, c_rgszHeaders[ih]);
  188. }
  189. }
  190. }
  191. }
  192. }
  193. delete [] szHeaders;
  194. }
  195. return FALSE;
  196. }
  197. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpv)
  198. {
  199. return TRUE;
  200. }
  201. BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * pver)
  202. {
  203. TraceTag(ttidIsapiCtl, "GetExtensionVersion");
  204. if (pver)
  205. {
  206. pver->dwExtensionVersion = MAKELONG(1, 0);
  207. lstrcpyA(pver->lpszExtensionDesc, "UPnP Device Host ISAPI Extension");
  208. }
  209. return TRUE;
  210. }
  211. DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK pecb)
  212. {
  213. DWORD hseStatus = HSE_STATUS_SUCCESS;
  214. UPNP_REQUEST_TYPE urt = URT_INVALID;
  215. DWORD dwReturn ;
  216. LPSTR szaHost = NULL;
  217. BOOL fKeepConn = FALSE;
  218. pecb->ServerSupportFunction(
  219. pecb->ConnID,
  220. HSE_REQ_IS_KEEP_CONN,
  221. &fKeepConn,
  222. NULL,
  223. NULL);
  224. if(fKeepConn)
  225. hseStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  226. else
  227. hseStatus = HSE_STATUS_SUCCESS;
  228. AssertSz(pecb,
  229. "HttpExtensionProc(): "
  230. "NULL extenion control block passed!");
  231. if (!InterlockedCompareExchange(&g_fTracingInit, 1, 0))
  232. {
  233. InitializeDebugging();
  234. TraceTag(ttidUDHISAPI, "Debugging initialized");
  235. }
  236. #if DBG
  237. CHAR szAddr[256];
  238. DWORD cb = sizeof(szAddr);
  239. pecb->GetServerVariable(pecb->ConnID, "REMOTE_ADDR", (LPVOID)szAddr,
  240. &cb);
  241. TraceTag(ttidUDHISAPI,
  242. "HttpExtensionProc(): "
  243. "--------Enter: NEW REQUEST from %s--------", szAddr);
  244. #endif
  245. // Determine the type of request.
  246. UPnPRequestTypeFromQueryString(pecb->lpszQueryString,
  247. &urt);
  248. if (URT_INVALID != urt)
  249. {
  250. if (FExistDuplicateHeaders(pecb))
  251. {
  252. TraceTag(ttidUDHISAPI,
  253. "HttpExtensionProc(): Duplicate headers exist for %s!",
  254. pecb->lpszQueryString);
  255. SendSimpleResponse(pecb, HTTP_STATUS_BAD_REQUEST);
  256. }
  257. else
  258. {
  259. dwReturn = DwQueryHeader(pecb, "HTTP_HOST", &szaHost);
  260. if ((dwReturn == ERROR_SUCCESS) && szaHost && *szaHost )
  261. {
  262. PFN_UPNP_REQUEST_HANDLER pfnHandler = NULL;
  263. TraceTag(ttidUDHISAPI,
  264. "HttpExtensionProc(): Request type is %d",
  265. urt);
  266. // Valid request type found. Find a handler for it.
  267. UPnPRequestHandlerFromRequestType(urt, &pfnHandler);
  268. AssertSz(pfnHandler,
  269. "HttpExtensionProc(): "
  270. "Got NULL handler function for request type");
  271. pfnHandler(pecb);
  272. }
  273. else
  274. {
  275. TraceTag(ttidUDHISAPI, "Host Header is not present");
  276. pecb->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
  277. SendSimpleResponse(pecb, HTTP_STATUS_BAD_REQUEST);
  278. }
  279. delete[] szaHost;
  280. }
  281. }
  282. else
  283. {
  284. TraceTag(ttidUDHISAPI,
  285. "HttpExtensionProc(): "
  286. "Query string (%s) did not contain a valid request type",
  287. pecb->lpszQueryString);
  288. SendSimpleResponse(pecb, HTTP_STATUS_BAD_REQUEST);
  289. }
  290. TraceTag(ttidUDHISAPI,
  291. "HttpExtensionProc(): Exit, returning %d",
  292. hseStatus);
  293. return hseStatus;
  294. }
  295. BOOL WINAPI TerminateExtension(DWORD dwFlags)
  296. {
  297. if (g_fTracingInit)
  298. {
  299. UnInitializeDebugging();
  300. }
  301. return TRUE;
  302. }