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                                                            \
        );