405 lines
8.6 KiB
Plaintext
405 lines
8.6 KiB
Plaintext
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 \
|
|
);
|
|
|