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.

597 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. Url.c
  5. Abstract:
  6. User-mode interface to HTTP.SYS: URL handler for Server APIs.
  7. Author:
  8. Keith Moore (keithmo) 15-Dec-1998
  9. Revision History:
  10. Eric Stenson (ericsten) 01-Jun-2001
  11. Add public "shims" for Transient API
  12. Eric Stenson (ericsten) 19-Jul-2001
  13. Split up HTTPAPI/HTTPIIS DLLs.
  14. --*/
  15. #include "precomp.h"
  16. //
  17. // Private prototypes.
  18. //
  19. extern NTSTATUS
  20. HttpApiConfigGroupInformationSanityCheck(
  21. IN HTTP_CONFIG_GROUP_INFORMATION_CLASS InformationClass,
  22. IN PVOID pConfigGroupInformation,
  23. IN ULONG Length
  24. );
  25. static CRITICAL_SECTION g_CGListCritSec;
  26. static LIST_ENTRY g_ConfigGroupListHead;
  27. static DWORD g_ConfigGroupInitialized = 0;
  28. typedef struct _tagCONFIG_GROUP_INFO {
  29. LIST_ENTRY ListEntry;
  30. HTTP_CONFIG_GROUP_ID ConfigGroupId;
  31. LPWSTR Url;
  32. } CONFIG_GROUP_INFO, *PCONFIG_GROUP_INFO;
  33. ULONG
  34. AddConfigGroupToTable(
  35. HTTP_CONFIG_GROUP_ID CGId,
  36. LPCWSTR wszUrl
  37. );
  38. VOID
  39. DeleteConfigIdFromTable(
  40. HTTP_CONFIG_GROUP_ID CGId
  41. );
  42. HTTP_CONFIG_GROUP_ID
  43. DeleteUrlFromTable(
  44. LPCWSTR wszUrl
  45. );
  46. //
  47. // Public functions.
  48. //
  49. /***************************************************************************++
  50. Routine Description:
  51. Add a URL to the Request Queue (App Pool). The Request Queue will
  52. listen for all requests for longest matching URI for the URL. We
  53. create a new Config Group object for this URL and associate the
  54. Config Group to the App Pool.
  55. Arguments:
  56. ReqQueueHandle - App Pool Handle
  57. pFullyQualifiedUrl - full URL with port descriptor & path
  58. pReserved - Must be NULL
  59. Return Value:
  60. ULONG - Completion status.
  61. --***************************************************************************/
  62. HTTPAPI_LINKAGE
  63. ULONG
  64. WINAPI
  65. HttpAddUrl(
  66. IN HANDLE ReqQueueHandle,
  67. IN PCWSTR pFullyQualifiedUrl,
  68. IN PVOID pReserved
  69. )
  70. {
  71. ULONG status;
  72. HTTP_CONFIG_GROUP_ID configId = HTTP_NULL_ID;
  73. HTTP_CONFIG_GROUP_APP_POOL configAppPool;
  74. HTTP_CONFIG_GROUP_STATE configState;
  75. //
  76. // Verify we've been init'd.
  77. //
  78. if ( !HttpIsInitialized(HTTP_INITIALIZE_SERVER) )
  79. {
  80. return ERROR_DLL_INIT_FAILED;
  81. }
  82. //
  83. // Validate ReqQueue and URL
  84. //
  85. if ( (NULL != pReserved) ||
  86. (NULL == ReqQueueHandle) ||
  87. (NULL == pFullyQualifiedUrl) ||
  88. (0 == wcslen(pFullyQualifiedUrl)) )
  89. {
  90. return ERROR_INVALID_PARAMETER;
  91. }
  92. //
  93. // Create Config Group (get new Config Group ID)
  94. //
  95. status = HttpCreateConfigGroup(
  96. g_ControlChannel,
  97. &configId
  98. );
  99. if (status != NO_ERROR)
  100. {
  101. HttpTrace1( "HttpCreateConfigGroup failed, error %lu\n", status );
  102. goto cleanup;
  103. }
  104. //
  105. // Add a URL to the configuration group.
  106. //
  107. status = HttpAddUrlToConfigGroup(
  108. g_ControlChannel,
  109. configId,
  110. pFullyQualifiedUrl,
  111. 0
  112. );
  113. if (status != NO_ERROR)
  114. {
  115. HttpTrace1( "HttpAddUrlToConfigGroup failed, error %lu\n", status );
  116. goto cleanup;
  117. }
  118. //
  119. // Associate the configuration group with the application pool.
  120. //
  121. configAppPool.Flags.Present = 1;
  122. configAppPool.AppPoolHandle = ReqQueueHandle;
  123. status = HttpSetConfigGroupInformation(
  124. g_ControlChannel,
  125. configId,
  126. HttpConfigGroupAppPoolInformation,
  127. &configAppPool,
  128. sizeof(configAppPool)
  129. );
  130. if (status != NO_ERROR)
  131. {
  132. HttpTrace1( "Set HttpConfigGroupAppPoolInformation failed, error %lu\n", status );
  133. goto cleanup;
  134. }
  135. //
  136. // Set the config group state.
  137. //
  138. configState.Flags.Present = 1;
  139. configState.State = HttpEnabledStateActive;
  140. status = HttpSetConfigGroupInformation(
  141. g_ControlChannel,
  142. configId,
  143. HttpConfigGroupStateInformation,
  144. &configState,
  145. sizeof(configState)
  146. );
  147. if (status != NO_ERROR)
  148. {
  149. HttpTrace1( "Set HttpConfigGroupStateInformation failed, error %lu\n", status );
  150. goto cleanup;
  151. }
  152. // Store URL & Config Group ID in hash table, keyed on URL
  153. status = AddConfigGroupToTable(
  154. configId,
  155. pFullyQualifiedUrl
  156. );
  157. if (status != NO_ERROR)
  158. {
  159. HttpTrace1( "AddConfigGroupToTable failed, error %lu\n", status );
  160. goto cleanup;
  161. }
  162. cleanup:
  163. if ( NO_ERROR != status )
  164. {
  165. // Failed. Clean up whatever needs to be cleaned up.
  166. if ( HTTP_NULL_ID != configId )
  167. {
  168. // Delete config group
  169. HttpDeleteConfigGroup(
  170. g_ControlChannel,
  171. configId
  172. );
  173. // Remove config group from table
  174. DeleteConfigIdFromTable( configId );
  175. }
  176. }
  177. return status;
  178. } // HttpAddUrl
  179. /***************************************************************************++
  180. Routine Description:
  181. Removes an existing URL from the Request Queue (App Pool).
  182. NOTE: The associated Config Group should be cleaned up here. (NYI).
  183. Arguments:
  184. ReqQueueHandle - App Pool Handle
  185. pFullyQualifiedUrl - full URL with port descriptor & path
  186. Return Value:
  187. ULONG - Completion status.
  188. --***************************************************************************/
  189. HTTPAPI_LINKAGE
  190. ULONG
  191. WINAPI
  192. HttpRemoveUrl(
  193. IN HANDLE ReqQueueHandle,
  194. IN PCWSTR pFullyQualifiedUrl
  195. )
  196. {
  197. ULONG status;
  198. HTTP_CONFIG_GROUP_ID CGId;
  199. //
  200. // Verify we've been init'd.
  201. //
  202. if ( !HttpIsInitialized(HTTP_INITIALIZE_SERVER) )
  203. {
  204. return ERROR_DLL_INIT_FAILED;
  205. }
  206. //
  207. // Validate ReqQueue and URL
  208. //
  209. if ( !ReqQueueHandle ||
  210. !pFullyQualifiedUrl ||
  211. !wcslen(pFullyQualifiedUrl) )
  212. {
  213. return ERROR_INVALID_PARAMETER;
  214. }
  215. // REVIEW: Do we need to do some sort of access check before we zap
  216. // REVIEW: the URL & Config Group?
  217. //
  218. // Look up Config Group ID from URL
  219. //
  220. CGId = DeleteUrlFromTable( pFullyQualifiedUrl );
  221. if ( HTTP_NULL_ID != CGId )
  222. {
  223. //
  224. // Del All URLs from Config Group
  225. //
  226. HttpRemoveAllUrlsFromConfigGroup(
  227. g_ControlChannel,
  228. CGId
  229. );
  230. //
  231. // Del Config Group
  232. //
  233. status = HttpDeleteConfigGroup(
  234. g_ControlChannel,
  235. CGId
  236. );
  237. } else
  238. {
  239. status = ERROR_FILE_NOT_FOUND;
  240. }
  241. return status;
  242. } // HttpRemoveUrl
  243. /***************************************************************************++
  244. Routine Description:
  245. Initializes the config group hash table
  246. Return Value:
  247. ULONG - Completion status.
  248. --***************************************************************************/
  249. ULONG
  250. InitializeConfigGroupTable(
  251. VOID
  252. )
  253. {
  254. if (!InitializeCriticalSectionAndSpinCount(
  255. &g_CGListCritSec,
  256. HTTP_CS_SPIN_COUNT
  257. ))
  258. {
  259. return GetLastError();
  260. }
  261. // CODEWORK: actually implement this as a hash table and not just a list
  262. InitializeListHead( &g_ConfigGroupListHead );
  263. InterlockedIncrement( (PLONG)&g_ConfigGroupInitialized );
  264. return NO_ERROR;
  265. } // InitializeConfigGroupTable
  266. /***************************************************************************++
  267. Routine Description:
  268. Terminates the config group hash table.
  269. Return Value:
  270. ULONG - Completion status.
  271. --***************************************************************************/
  272. VOID
  273. TerminateConfigGroupTable(
  274. VOID
  275. )
  276. {
  277. PCONFIG_GROUP_INFO pCGInfo;
  278. PLIST_ENTRY pEntry;
  279. ASSERT( g_ControlChannel );
  280. // If not initialized, bail out.
  281. if ( g_ConfigGroupInitialized == 0 )
  282. {
  283. return;
  284. }
  285. // CODEWORK: actually implement this as a hash table and not just a list
  286. EnterCriticalSection( &g_CGListCritSec );
  287. for ( ;; )
  288. {
  289. pEntry = RemoveTailList( &g_ConfigGroupListHead );
  290. if (pEntry == &g_ConfigGroupListHead )
  291. {
  292. break;
  293. }
  294. pCGInfo = CONTAINING_RECORD( pEntry, CONFIG_GROUP_INFO, ListEntry );
  295. HttpTrace1( "TerminateConfigGroupTable: Removing %S\n", pCGInfo->Url );
  296. //
  297. // Delete Config Group by ID
  298. //
  299. ASSERT( HTTP_NULL_ID != pCGInfo->ConfigGroupId );
  300. HttpRemoveAllUrlsFromConfigGroup(
  301. g_ControlChannel,
  302. pCGInfo->ConfigGroupId
  303. );
  304. HttpDeleteConfigGroup(
  305. g_ControlChannel,
  306. pCGInfo->ConfigGroupId
  307. );
  308. FREE_MEM( pCGInfo );
  309. }
  310. LeaveCriticalSection( &g_CGListCritSec );
  311. } // TerminateEventCache
  312. //
  313. // Private functions.
  314. //
  315. /***************************************************************************++
  316. Routine Description:
  317. Adds a Config Group ID/URL pair to a hash table, keyed on URL.
  318. CODEWORK: Need to re-implement as hash table
  319. Arguments:
  320. CGId - Config Group ID to add to hash table.
  321. wszUrl - URL associated with config group (always 1:1 mapping)
  322. Return Value:
  323. ULONG - Completion status.
  324. --***************************************************************************/
  325. ULONG
  326. AddConfigGroupToTable(
  327. HTTP_CONFIG_GROUP_ID CGId,
  328. LPCWSTR wszUrl
  329. )
  330. {
  331. PCONFIG_GROUP_INFO pCGInfo;
  332. size_t cbSize;
  333. ASSERT( wszUrl );
  334. cbSize = sizeof( CONFIG_GROUP_INFO );
  335. cbSize += sizeof( WCHAR ) * (wcslen( wszUrl ) + 1);
  336. pCGInfo = ALLOC_MEM( cbSize );
  337. if ( NULL == pCGInfo )
  338. {
  339. return ERROR_NOT_ENOUGH_MEMORY;
  340. }
  341. pCGInfo->ConfigGroupId = CGId;
  342. if ( wcslen(wszUrl) )
  343. {
  344. pCGInfo->Url = (LPWSTR) (((PCHAR)pCGInfo) + sizeof( CONFIG_GROUP_INFO ));
  345. wcscpy( pCGInfo->Url, wszUrl );
  346. }
  347. EnterCriticalSection( &g_CGListCritSec );
  348. InsertTailList(
  349. &g_ConfigGroupListHead,
  350. &pCGInfo->ListEntry
  351. );
  352. LeaveCriticalSection( &g_CGListCritSec );
  353. return NO_ERROR;
  354. } // AddConfigGroupToTable
  355. /***************************************************************************++
  356. Routine Description:
  357. Removes an entry from the hash table (by Config Group ID)
  358. Arguments:
  359. CGId - Config Group ID.
  360. --***************************************************************************/
  361. VOID
  362. DeleteConfigIdFromTable(
  363. HTTP_CONFIG_GROUP_ID CGId
  364. )
  365. {
  366. PLIST_ENTRY pEntry;
  367. PCONFIG_GROUP_INFO pCGInfo;
  368. // Grab crit sec
  369. EnterCriticalSection( &g_CGListCritSec );
  370. // Walk List looking for matching entry
  371. pEntry = g_ConfigGroupListHead.Flink;
  372. while( pEntry != &g_ConfigGroupListHead )
  373. {
  374. pCGInfo = CONTAINING_RECORD( pEntry, CONFIG_GROUP_INFO, ListEntry );
  375. if ( pCGInfo->ConfigGroupId == CGId )
  376. {
  377. // Remove entry from List
  378. RemoveEntryList( pEntry );
  379. // Free structure.
  380. FREE_MEM( pCGInfo );
  381. break;
  382. }
  383. pEntry = pEntry->Flink;
  384. }
  385. // Release crit sec
  386. LeaveCriticalSection( &g_CGListCritSec );
  387. } // DeleteConfigIdFromTable
  388. /***************************************************************************++
  389. Routine Description:
  390. Removes an entry from the hash table (by URL)
  391. Arguments:
  392. wszUrl - URL associated with Config Group Id.
  393. Returns:
  394. HTTP_CONFIG_GROUP_ID - ID of config group associated with wszUrl;
  395. HTTP_NULL_ID if no match found.
  396. --***************************************************************************/
  397. HTTP_CONFIG_GROUP_ID
  398. DeleteUrlFromTable(
  399. LPCWSTR wszUrl
  400. )
  401. {
  402. PLIST_ENTRY pEntry;
  403. PCONFIG_GROUP_INFO pCGInfo;
  404. HTTP_CONFIG_GROUP_ID CGId = HTTP_NULL_ID;
  405. // Grab crit sec
  406. EnterCriticalSection( &g_CGListCritSec );
  407. // Walk List looking for matching entry
  408. pEntry = g_ConfigGroupListHead.Flink;
  409. while( pEntry != &g_ConfigGroupListHead )
  410. {
  411. pCGInfo = CONTAINING_RECORD( pEntry, CONFIG_GROUP_INFO, ListEntry );
  412. if ( 0 == wcscmp( pCGInfo->Url, wszUrl ) )
  413. {
  414. // Remove entry from List
  415. RemoveEntryList( pEntry );
  416. // Free structure.
  417. CGId = pCGInfo->ConfigGroupId;
  418. FREE_MEM( pCGInfo );
  419. break;
  420. }
  421. pEntry = pEntry->Flink;
  422. }
  423. // Release crit sec
  424. LeaveCriticalSection( &g_CGListCritSec );
  425. return CGId;
  426. } // DeleteUrlFromTable