2025-04-27 07:49:33 -04:00

493 lines
13 KiB
C

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
urlmap.c
Abstract:
Contains the URL map code.
Author:
Henry Sanders (henrysa) 21-Jun-1998
Revision History:
--*/
#include "precomp.h"
#include "urlmapp.h"
#if 0
/******************************************************************************
Routine Description:
The URL map lookup routine. This routine is called with the URL map header
referenced, so the URL map can be examined without locks.
The current algorithm is a linear search. This is temporary until we get
something running, at which point we'll move to a more sophisticated
algorithm, probably some variation on an alphabetic trie.
Arguments:
pHttpConn - Pointer to HTTP connection on which data was received.
pMapHeader - Pointer to the URL map header to be searched.
Return Value:
A pointer to the map entry if we find one, or NULL if we don't.
******************************************************************************/
PHTTP_URL_MAP_ENTRY
FindURLMapEntry(
PHTTP_CONNECTION pHttpConn,
PHTTP_URL_MAP_HEADER pMapHeader
)
{
PHTTP_URL_MAP_ENTRY pCurrentMapEntry;
PUCHAR pURL;
SIZE_T URLLength;
pURL = pHttpConn->pURL;
URLLength = pHttpConn->URLLength;
for (pCurrentMapEntry = pMapHeader->Table.pFirstMapEntry;
pCurrentMapEntry != NULL;
pCurrentMapEntry = pCurrentMapEntry->pNextMapEntry
)
{
if (URLLength >= pCurrentMapEntry->URLPrefixLength)
{
if (_strnicmp(pURL,
pCurrentMapEntry->URLPrefix,
pCurrentMapEntry->URLPrefixLength) == 0
)
{
// We have a match, so return it.
return pCurrentMapEntry;
}
}
}
return NULL;
}
/******************************************************************************
Routine Description:
Dereference a URL map. If the reference count goes to 0, we're done with
this one, so schedule a worker thread to free it.
Arguments:
pMapHeader - Pointer to the URL map header to be dereferenced.
Return Value:
******************************************************************************/
VOID
DelayedDereferenceURLMap(
PHTTP_URL_MAP_HEADER pMapHeader
)
{
if (InterlockedDecrement(&pMapHeader->RefCount) == 0)
{
UlQueueWorkItem( &g_UlThreadPool,
&pMapHeader->WorkItem,
&CleanupURLMapWorker);
}
}
/******************************************************************************
Routine Description:
Dereference a URL map. If the reference count goes to 0, we're done with
this one.
Arguments:
pMapHeader - Pointer to the URL map header to be dereferenced.
Return Value:
******************************************************************************/
VOID
DereferenceURLMap(
PHTTP_URL_MAP_HEADER pMapHeader
)
{
if (InterlockedDecrement(&pMapHeader->RefCount) == 0)
{
DeleteURLMapHeader(pMapHeader);
}
}
/******************************************************************************
Routine Description:
Cleanup a URL map in thread context. All we do is call delete URL
map routine.
Arguments:
pWorkItem - Supplies a pointer to the work item queued. This should point
to the WORK_ITEM structure embedded in a URL map header.
Return Value:
******************************************************************************/
VOID
CleanupURLMapWorker(
IN PUL_WORK_ITEM pWorkItem
)
{
PHTTP_URL_MAP_HEADER pMapHeader;
pMapHeader = CONTAINING_RECORD(
pWorkItem,
HTTP_URL_MAP_HEADER,
WorkItem
);
DeleteURLMapHeader(pMapHeader);
}
/******************************************************************************
Routine Description:
Delete a URL map header.
Arguments:
pMapHeader - Pointer to the URL map header to be deleted.
Return Value:
******************************************************************************/
VOID
DeleteURLMapHeader(
PHTTP_URL_MAP_HEADER pMapHeader
)
{
ASSERT(pMapHeader->RefCount == 0);
// BUGBUG Not done yet! Need to walk the map, dereferenceing the NSGO
// we're pointing at.
KdPrint(("DeleteURLMapHeader: Not really deleting, leaking memory instead.\n"));
}
/******************************************************************************
Routine Description:
Create a URL map header.
Arguments:
Return Value:
Pointer to the newly created URL map header, or NULL if we couldn't create
one.
******************************************************************************/
PHTTP_URL_MAP_HEADER
CreateURLMapHeader(
VOID
)
{
PHTTP_URL_MAP_HEADER pMapHeader;
pMapHeader = UL_ALLOCATE_POOL(NonPagedPool,
sizeof(HTTP_URL_MAP_HEADER),
UL_URLMAP_POOL_TAG
);
if (pMapHeader == NULL)
{
return NULL;
}
pMapHeader->RefCount = 1;
pMapHeader->EntryCount = 0;
pMapHeader->Table.pFirstMapEntry = NULL;
return pMapHeader;
}
/******************************************************************************
Routine Description:
Add an entry to a URL map. We copy the existing map, add our entry to
the copy, then swap the new copy in.
Arguments:
pVirtHostID - Pointer to virtual host ID identifying the virtual
host on which to set the URL map.
pNewURL - Pointer to new name space URL entry to be added.
pNSGO - Pointer to NSGO of which the new entry is a member.
pStatus - Where to return the status of the attempt.
Return Value:
The number of entries in the newly created map table, or 0 if the set failed.
Also, *pStatus is set with the status of the attempt.
******************************************************************************/
SIZE_T
AddURLMapEntry(
PVIRTUAL_HOST_ID pVirtHostID,
PNAME_SPACE_URL_ENTRY pNewURL,
PNAME_SPACE_GROUP_OBJECT pNSGO,
NTSTATUS *pStatus
)
{
PHTTP_URL_MAP_HEADER pMapHeader;
PHTTP_URL_MAP_HEADER pNewMapHeader;
PHTTP_URL_MAP_ENTRY pNewMapEntry;
PHTTP_URL_MAP_ENTRY pPrevMapEntry;
PVIRTUAL_HOST pVirtHost;
SIZE_T URLMapCount;
// Allocate a new map entry now and fill it in.
pNewMapEntry = UL_ALLOCATE_POOL( NonPagedPool,
FIELD_OFFSET(HTTP_URL_MAP_ENTRY,
URLPrefix) +
pNewURL->URLLength,
UL_URLMAP_POOL_TAG
);
if (pNewMapEntry == NULL)
{
*pStatus = STATUS_INSUFFICIENT_RESOURCES;
return 0;
}
pNewMapEntry->pNSGO = pNSGO;
pNewMapEntry->URLPrefixLength = pNewURL->URLLength;
RtlCopyMemory(pNewMapEntry->URLPrefix, pNewURL->URL, pNewURL->URLLength);
//
// Now lock the virtual host from other updates.
//
pVirtHost = AcquireVirtualHostUpdateResource(pVirtHostID);
if (pVirtHost == NULL)
{
// Virtual host must have gone away, somehow.
UL_FREE_POOL( pNewMapEntry, UL_URLMAP_POOL_TAG);
*pStatus = STATUS_INVALID_DEVICE_REQUEST;
return 0;
}
//
// Copy the existing map. No need to interlock this specially, no one else
// can modify it while we've got the update resource.
//
pMapHeader = GetURLMapFromVirtualHost(pVirtHost);
if (pMapHeader != NULL)
{
pNewMapHeader = CopyURLMap(pMapHeader);
// If we managed to copy it, add our new map entry.
if (pNewMapHeader != NULL)
{
pPrevMapEntry = CONTAINING_RECORD(
&pNewMapHeader->Table.pFirstMapEntry,
HTTP_URL_MAP_ENTRY,
pNextMapEntry
);
// Loop through until we find an entry with a shorter prefix
// then ours, or the next entry is NULL, and insert ourselves
// before that.
while (pPrevMapEntry->pNextMapEntry != NULL)
{
if (pPrevMapEntry->pNextMapEntry->URLPrefixLength <
pNewURL->URLLength)
{
break;
}
pPrevMapEntry = pPrevMapEntry->pNextMapEntry;
}
pNewMapEntry->pNextMapEntry = pPrevMapEntry->pNextMapEntry;
pPrevMapEntry->pNextMapEntry = pNewMapEntry;
// Update the count.
pNewMapHeader->EntryCount++;
URLMapCount = pNewMapHeader->EntryCount;
}
else
{
// Couldn't copy it.
*pStatus = STATUS_INSUFFICIENT_RESOURCES;
URLMapCount = 0;
}
}
else
{
pNewMapHeader = CreateURLMapHeader();
if (pNewMapHeader == NULL)
{
// Couldn't create it.
*pStatus = STATUS_INSUFFICIENT_RESOURCES;
URLMapCount = 0;
}
pNewMapEntry->pNextMapEntry = NULL;
pNewMapHeader->Table.pFirstMapEntry = pNewMapEntry;
pNewMapHeader->EntryCount = 1;
URLMapCount = 1;
}
if (URLMapCount != 0)
{
UpdateURLMapTable(pVirtHost, pVirtHostID, pNewMapHeader);
*pStatus = STATUS_SUCCESS;
}
ReleaseVirtualHostUpdateResource(pVirtHost, pVirtHostID);
if (URLMapCount == 0)
{
UL_FREE_POOL( pNewMapEntry, UL_URLMAP_POOL_TAG);
}
return URLMapCount;
}
/******************************************************************************
Routine Description:
Copy a URL map.
Arguments:
pMapHeader - Pointer to URL map header for URL map to be
copied.
Return Value:
A pointer to the newly created URL map, or NULL if we couldn't copy
it.
******************************************************************************/
PHTTP_URL_MAP_HEADER
CopyURLMap(
PHTTP_URL_MAP_HEADER pMapHeader
)
{
PHTTP_URL_MAP_HEADER pNewMapHeader;
PHTTP_URL_MAP_ENTRY pPreviousMapEntry;
PHTTP_URL_MAP_ENTRY pCurrentMapEntry;
PHTTP_URL_MAP_ENTRY pNewMapEntry;
pNewMapHeader = CreateURLMapHeader();
if (pNewMapHeader == NULL)
{
return NULL;
}
// Walk down the passed in table. For each element in the table, allocate
// a new one and stick it on.
pPreviousMapEntry = CONTAINING_RECORD( &pNewMapHeader->Table.pFirstMapEntry,
HTTP_URL_MAP_ENTRY,
pNextMapEntry
);
pCurrentMapEntry = pMapHeader->Table.pFirstMapEntry;
while (pCurrentMapEntry != NULL)
{
SIZE_T CurrentMapEntrySize;
CurrentMapEntrySize = FIELD_OFFSET(HTTP_URL_MAP_ENTRY, URLPrefix) +
pCurrentMapEntry->URLPrefixLength;
pNewMapEntry = UL_ALLOCATE_POOL(
NonPagedPool,
CurrentMapEntrySize,
UL_URLMAP_POOL_TAG
);
if (pNewMapEntry == NULL)
{
PHTTP_URL_MAP_ENTRY pNextMapEntry;
// Ran out of resources. Free what we've allocated to far.
//
pCurrentMapEntry = pNewMapHeader->Table.pFirstMapEntry;
while (pCurrentMapEntry != NULL)
{
pNextMapEntry = pCurrentMapEntry->pNextMapEntry;
UL_FREE_POOL(pCurrentMapEntry, UL_URLMAP_POOL_TAG);
pCurrentMapEntry = pNextMapEntry;
}
UL_FREE_POOL(pNewMapHeader, UL_URLMAP_POOL_TAG);
return NULL;
}
// Allocated the memory, copy the old stuff over and link the new
// entry on.
//
RtlCopyMemory(pNewMapEntry, pCurrentMapEntry, CurrentMapEntrySize);
pPreviousMapEntry->pNextMapEntry = pNewMapEntry;
pNewMapEntry->pNextMapEntry = NULL;
pNewMapHeader->EntryCount++;
pPreviousMapEntry = pNewMapEntry;
pCurrentMapEntry = pCurrentMapEntry->pNextMapEntry;
}
return pNewMapHeader;
}
#endif