Requirements for abstracting the parsing code out of UL: Functions exported by the parser: InitializeParser() ParseHttp() ParseChunkLength() Types used by the interface: HTTP_REQUEST * UL_HTTP_VERB Verb * PUCHAR pRawVerb * ULONG RawVerbLength * ULONG TotalRequestSize * struct {} RawUrl * ULONG PortInHost * LIST_ENTRY UnknownHeaderList * ULONG UnknownHeaderCount * ULONGLONG BytesLeftInChunk * ULONG LastChunk * PARSE_STATE ParseState * UL_HTTP_VERSION Version * HTTP_HEADER Headers[] * ULONGLONG ContentLength * ULONG Chunked * struct {} CookedUrl PHTTP_CONNECTION pHttpConn -- For UlIpAddressFromConnection typedef struct _HTTP_PARSE_INFO { // // Structure signature. // ULONG Signature; // // Current state of our parsing effort. // PARSE_STATE ParseState; // // Verb of this request. // UL_HTTP_VERB Verb; // // Request version. // UL_HTTP_VERSION Version; // // Array of headers we do know about. // HTTP_HEADER Headers[UlHeaderMaximum]; // // Pointer to the raw verb, valid only if Verb == UlHttpVerbUnknown. // PUCHAR pRawVerb; // // Length of the raw verb. // ULONG RawVerbLength; // // Total bytes needed for this request, including string terminators. // ULONG TotalRequestSize; // // List of headers we don't know about. // LIST_ENTRY UnknownHeaderList; // // The number of "unknown" headers we have. // ULONG UnknownHeaderCount; // // The content length, if any. // ULONGLONG ContentLength; // // The number of bytes remaining in the current chunk. // ULONGLONG BytesLeftInChunk; // // Is this chunk encoded? // ULONG Chunked:1; ULONG :3; // makes debugging easier // // Is this the last chunk? // ULONG LastChunk:1; ULONG :3; // makes debugging easier // // Is the port number in the host? // ULONG PortInHost:1; ULONG :3; // makes debugging easier struct { // // The raw URL. // // All of the following pointers point into pUrl. // PUCHAR pUrl; // // Host part, if any. // PUCHAR pHost; // // Pointer to the absolute path part. // PUCHAR pAbsPath; // // Length of the raw URL. // ULONG Length; } RawUrl; struct { // // The canonicalized, fully qualified URL. // // All of the following pointers point into pUrl. // PWSTR pUrl; // // Pointer to the host part. // PWSTR pHost; // // Pointer to the absolute path part. // PWSTR pAbsPath; // // Pointer to the query string, if any. // PWSTR pQueryString; // // The entire length (in bytes). // ULONG Length; // // The hash of the entire fully qualified URL. // ULONG Hash; } CookedUrl; // // Pointer to the local transport address for the network connection. // PTRANSPORT_ADDRESS pLocalAddress; } HTTP_PARSE_INFO, *PHTTP_PARSE_INFO; Imports needed by the parser: Pool stuff w/ usual debug support KeGetCurrentIrql() #ifdef UL_KERNEL_RUNTIME #define UL_GET_CURRENT_IRQL() KeGetCurrentIrql() #else #define UL_GET_CURRENT_IRQL() 0 // // Types stolen from ntos\inc\ex.h. // typedef enum _POOL_TYPE { NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, NonPagedPoolCacheAligned, PagedPoolCacheAligned, NonPagedPoolCacheAlignedMustS, MaxPoolType // end_wdm , // // Note these per session types are carefully chosen so that the appropriate // masking still applies as well as MaxPoolType above. // NonPagedPoolSession = 32, PagedPoolSession = NonPagedPoolSession + 1, NonPagedPoolMustSucceedSession = PagedPoolSession + 1, DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1, } POOL_TYPE; #endif Pool tags used in the parser: HTTP_UNKNOWN_HEADER_POOL_TAG URL_POOL_TAG HEADER_VALUE_POOL_TAG typedef PVOID (NTAPI * PFN_MEM_ALLOC)( IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag, #if DBG , IN PSTR pFileName, IN ULONG LineNumber #endif ); typedef VOID (NTAPI * PFN_MEM_FREE)( IN PVOID pBuffer, IN ULONG Tag ); typedef VOID (NTAPI * PFN_ASSERT)( IN PVOID pFailedAssertion, IN PVOID pFileName, IN ULONG LineNumber, IN PSTR pMessage ); typedef struct _UL_PARSER_ENVIRONMENT { PFN_MEM_ALLOC pAllocRoutine; PFN_MEM_FREE pFreeRoutine; PFN_ASSERT pAssertRoutine; ULONG UrlPoolTag; ULONG HeaderValuePoolTag; ULONG UnknownHeaderPoolTag; } UL_PARSER_ENVIRONMENT, *PUL_PARSER_ENVIRONMENT; NTSTATUS UlInitializeParser( IN PUL_PARSER_ENVIRONMENT pEnvironment ); VOID UlTerminateParser( VOID ); NTSTATUS UlInitializeParseInfo( OUT PHTTP_PARSE_INFO pParseInfo, IN PTRANSPORT_ADDRESS pLocalAddress ); VOID UlDestroyParseInfo( IN OUT PHTTP_PARSE_INFO pParseInfo ); NTSTATUS UlParseHttp( IN OUT PHTTP_PARSE_INFO pParseInfo, IN PUCHAR pHttpRequest, IN ULONG HttpRequestLength, OUT PULONG pBytesTaken ); NTSTATUS UlBuildUserRequest( OUT PUL_HTTP_REQUEST pHttpRequest, IN PHTTP_PARSE_INFO pParseInfo, IN UL_HTTP_CONNECTION_ID ConnectionId, IN UL_HTTP_REQUEST_ID RequestId, IN UL_URL_CONTEXT UrlContext, IN UL_REQUEST_REASON RequestReason ); NTSTATUS status; UL_PARSER_ENVIRONMENT env; #if DBG env.pAllocRoutine = &UlAllocatePool; env.pFreeRoutine = &UlFreePool; #else env.pAllocRoutine = &ExAllocatePoolWithTag; #if USE_FREE_POOL_WITH_TAG env.pFreeRoutine = &ExFreePoolWithTag; #else env.pFreeRoutine = &UlpFreePoolWithTag; #endif #endif env.pAssertRoutine = &RtlAssert; env.UrlPoolTag = URL_POOL_TAG; env.HeaderValuePoolTag = HEADER_VALUE_POOL_TAG; env.UnknownHeaderPoolTag = HTTP_UNKNOWN_HEADER_POOL_TAG; status = UlInitializeParser( &env ); if (!NT_SUCCESS(status)) { // Oh no! ... } #if DBG #define UL_ALLOCATE_POOL(a,b,t,p) \ (g_Environment.pAllocRoutine)( \ (a), \ (b), \ (t), \ (p) \ ) #else #define UL_ALLOCATE_POOL(a,b,t,p) \ (g_Environment.pAllocRoutine)( \ (a), \ (b), \ (t), \ (p), \ __FILE__, \ __LINE__ \ ) #endif #define UL_FREE_POOL(a,t) \ (g_Environment.pFreeRoutine)( \ (a), \ (t) \ ) #define UL_ASSERT(exp) \ (g_Environment.pAssertRoutine)( \ #exp, \ __FILE__, \ __LINE__, \ NULL \ );