400 lines
10 KiB
C
400 lines
10 KiB
C
/*++
|
|
|
|
Copyright (c) 1998-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
parse.h
|
|
|
|
Abstract:
|
|
|
|
Contains all of the public definitions for the HTTP parsing code.
|
|
|
|
Author:
|
|
|
|
Henry Sanders (henrysa) 04-May-1998
|
|
|
|
Revision History:
|
|
|
|
Paul McDaniel (paulmcd) 14-Apr-1999
|
|
|
|
--*/
|
|
|
|
#ifndef _PARSE_H_
|
|
#define _PARSE_H_
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define WILDCARD_SIZE (STRLEN_LIT("*/*") + sizeof(CHAR))
|
|
#define WILDCARD_SPACE '*/* '
|
|
#define WILDCARD_COMMA '*/*,'
|
|
|
|
|
|
//
|
|
// Size of Connection: header values
|
|
//
|
|
|
|
#define CONN_CLOSE_HDR "close"
|
|
#define CONN_CLOSE_HDR_LENGTH STRLEN_LIT(CONN_CLOSE_HDR)
|
|
|
|
#define CONN_KEEPALIVE_HDR "keep-alive"
|
|
#define CONN_KEEPALIVE_HDR_LENGTH STRLEN_LIT(CONN_KEEPALIVE_HDR)
|
|
|
|
#define CHUNKED_HDR "chunked"
|
|
#define CHUNKED_HDR_LENGTH STRLEN_LIT(CHUNKED_HDR)
|
|
|
|
|
|
#define MIN_VERSION_SIZE STRLEN_LIT("HTTP/1.1")
|
|
#define STATUS_CODE_LENGTH 3
|
|
|
|
#define HTTP_VERSION_11 "HTTP/1.1"
|
|
#define HTTP_VERSION_10 "HTTP/1.0"
|
|
#define HTTP_VERSION_OTHER "HTTP/"
|
|
#define VERSION_SIZE STRLEN_LIT(HTTP_VERSION_11)
|
|
#define VERSION_OTHER_SIZE STRLEN_LIT(HTTP_VERSION_OTHER)
|
|
|
|
#define MAX_KNOWN_VERB_LENGTH STRLEN_LIT("PROPPATCH") + sizeof(CHAR)
|
|
|
|
#define MAX_VERB_LENGTH 255
|
|
|
|
|
|
// "HTTP/1.x" backwards because of endianness
|
|
#define HTTP_11_VERSION 0x312e312f50545448ui64
|
|
#define HTTP_10_VERSION 0x302e312f50545448ui64
|
|
|
|
//
|
|
// These are backwards because of little endian.
|
|
//
|
|
|
|
#define HTTP_PREFIX 'PTTH'
|
|
#define HTTP_PREFIX_SIZE 4
|
|
#define HTTP_PREFIX_MASK 0xdfdfdfdf
|
|
|
|
C_ASSERT((HTTP_PREFIX & HTTP_PREFIX_MASK) == HTTP_PREFIX);
|
|
|
|
#define HTTP_PREFIX1 '\0//:'
|
|
#define HTTP_PREFIX1_SIZE 3
|
|
#define HTTP_PREFIX1_MASK 0x00ffffff
|
|
|
|
C_ASSERT((HTTP_PREFIX1 & HTTP_PREFIX1_MASK) == HTTP_PREFIX1);
|
|
|
|
#define HTTP_PREFIX2 '//:S'
|
|
#define HTTP_PREFIX2_SIZE 4
|
|
#define HTTP_PREFIX2_MASK 0xffffffdf
|
|
|
|
C_ASSERT((HTTP_PREFIX2 & HTTP_PREFIX2_MASK) == HTTP_PREFIX2);
|
|
|
|
#define MAX_HEADER_LONG_COUNT (3)
|
|
#define MAX_HEADER_LENGTH (MAX_HEADER_LONG_COUNT * sizeof(ULONGLONG))
|
|
|
|
#define NUMBER_HEADER_INDICES (26)
|
|
|
|
#define NUMBER_HEADER_HINT_INDICES (9)
|
|
|
|
//
|
|
// Default Server: header if none provided by the application.
|
|
//
|
|
|
|
#define DEFAULT_SERVER_HDR "Microsoft-HTTPAPI/1.0"
|
|
#define DEFAULT_SERVER_HDR_LENGTH STRLEN_LIT(DEFAULT_SERVER_HDR)
|
|
|
|
//
|
|
// One second in 100ns system time units. Used for generating
|
|
// Date: headers.
|
|
//
|
|
|
|
#define ONE_SECOND (10000000)
|
|
|
|
|
|
//
|
|
// Structure of the fast verb lookup table. The table consists of a series of
|
|
// entries where each entry contains an HTTP verb represented as a ulonglong,
|
|
// a mask to use for comparing that verb, the length of the verb, and the
|
|
// translated id. This is used for all known verbs that are 7 characters
|
|
// or less.
|
|
//
|
|
|
|
typedef struct _FAST_VERB_ENTRY
|
|
{
|
|
ULONGLONG RawVerbMask;
|
|
union
|
|
{
|
|
UCHAR Char[sizeof(ULONGLONG)+1];
|
|
ULONGLONG LongLong;
|
|
} RawVerb;
|
|
ULONG RawVerbLength;
|
|
HTTP_VERB TranslatedVerb;
|
|
|
|
} FAST_VERB_ENTRY, *PFAST_VERB_ENTRY;
|
|
|
|
//
|
|
// Macro for defining fast verb table entries. Note that we don't subtract 1
|
|
// from the various sizeof occurences because we'd just have to add it back
|
|
// in to account for the separating space.
|
|
//
|
|
|
|
#define CREATE_FAST_VERB_ENTRY(verb) \
|
|
{ \
|
|
(0xffffffffffffffffui64 >> ((8 - (sizeof(#verb))) * 8)), \
|
|
{#verb " "}, \
|
|
(sizeof(#verb)), \
|
|
HttpVerb##verb \
|
|
}
|
|
|
|
//
|
|
// Stucture of the all verb lookup table. This table holds all verbs
|
|
// that are too long to fit in the fast verb table.
|
|
//
|
|
|
|
typedef struct _LONG_VERB_ENTRY
|
|
{
|
|
ULONG RawVerbLength;
|
|
UCHAR RawVerb[MAX_KNOWN_VERB_LENGTH];
|
|
HTTP_VERB TranslatedVerb;
|
|
|
|
} LONG_VERB_ENTRY, *PLONG_VERB_ENTRY;
|
|
|
|
//
|
|
// Macro for defining all long verb table entries.
|
|
//
|
|
|
|
#define CREATE_LONG_VERB_ENTRY(verb) \
|
|
{ sizeof(#verb) - 1, #verb, HttpVerb##verb }
|
|
|
|
//
|
|
// Header handler callback functions
|
|
//
|
|
|
|
typedef NTSTATUS (*PFN_SERVER_HEADER_HANDLER)(
|
|
PUL_INTERNAL_REQUEST pRequest,
|
|
PUCHAR pHeader,
|
|
USHORT HeaderLength,
|
|
HTTP_HEADER_ID HeaderID,
|
|
ULONG * pBytesTaken
|
|
);
|
|
|
|
typedef NTSTATUS (*PFN_CLIENT_HEADER_HANDLER)(
|
|
PUC_HTTP_REQUEST pRequest,
|
|
PUCHAR pHeader,
|
|
ULONG HeaderLength,
|
|
HTTP_HEADER_ID HeaderID
|
|
);
|
|
|
|
|
|
//
|
|
// Structure for a header map entry. Each header map entry contains a
|
|
// verb and a series of masks to use in checking that verb.
|
|
//
|
|
|
|
typedef struct _HEADER_MAP_ENTRY
|
|
{
|
|
ULONG HeaderLength;
|
|
ULONG ArrayCount;
|
|
ULONG MinBytesNeeded;
|
|
union
|
|
{
|
|
UCHAR HeaderChar[MAX_HEADER_LENGTH];
|
|
ULONGLONG HeaderLong[MAX_HEADER_LONG_COUNT];
|
|
} Header;
|
|
ULONGLONG HeaderMask[MAX_HEADER_LONG_COUNT];
|
|
UCHAR MixedCaseHeader[MAX_HEADER_LENGTH];
|
|
|
|
HTTP_HEADER_ID HeaderID;
|
|
BOOLEAN AutoGenerate;
|
|
PFN_SERVER_HEADER_HANDLER pServerHandler;
|
|
PFN_CLIENT_HEADER_HANDLER pClientHandler;
|
|
LONG HintIndex;
|
|
|
|
} HEADER_MAP_ENTRY, *PHEADER_MAP_ENTRY;
|
|
|
|
|
|
//
|
|
// Structure for a header index table entry.
|
|
//
|
|
|
|
typedef struct _HEADER_INDEX_ENTRY
|
|
{
|
|
PHEADER_MAP_ENTRY pHeaderMap;
|
|
ULONG Count;
|
|
|
|
} HEADER_INDEX_ENTRY, *PHEADER_INDEX_ENTRY;
|
|
|
|
|
|
//
|
|
// Structure for a header hint index table entry.
|
|
//
|
|
|
|
typedef struct _HEADER_HINT_INDEX_ENTRY
|
|
{
|
|
PHEADER_MAP_ENTRY pHeaderMap;
|
|
UCHAR c;
|
|
|
|
} HEADER_HINT_INDEX_ENTRY, *PHEADER_HINT_INDEX_ENTRY, **PPHEADER_HINT_INDEX_ENTRY;
|
|
|
|
|
|
//
|
|
// A (complex) macro to create a mask for a header map entry,
|
|
// given the header length and the mask offset (in bytes). This
|
|
// mask will need to be touched up for non-alphabetic characters.
|
|
//
|
|
|
|
#define UPCASE_MASK 0xDFDFDFDFDFDFDFDFui64
|
|
|
|
#define CREATE_HEADER_MASK(hlength, maskoffset) \
|
|
((hlength) > (maskoffset) ? UPCASE_MASK : \
|
|
(((maskoffset) - (hlength)) >= 8 ? 0 : \
|
|
(UPCASE_MASK >> ( ((maskoffset) - (hlength)) * 8ui64))))
|
|
|
|
|
|
//
|
|
// Macro for creating header map entries. The mask entries are created
|
|
// by the init code.
|
|
//
|
|
|
|
#define CREATE_HEADER_MAP_ENTRY(header, ID, auto, serverhandler, clienthandler, HintIndex)\
|
|
{ \
|
|
sizeof(#header) - 1, \
|
|
((sizeof(#header) - 1) / 8) + \
|
|
(((sizeof(#header) - 1) % 8) == 0 ? 0 : 1), \
|
|
(((sizeof(#header) - 1) / 8) + \
|
|
(((sizeof(#header) - 1) % 8) == 0 ? 0 : 1)) * 8, \
|
|
{ #header }, \
|
|
{ 0, 0, 0}, \
|
|
{ #header }, \
|
|
ID, \
|
|
auto, \
|
|
serverhandler, \
|
|
clienthandler, \
|
|
HintIndex \
|
|
}
|
|
|
|
//
|
|
// Parser states for parsing a chunk header extension.
|
|
//
|
|
typedef enum
|
|
{
|
|
CHStart,
|
|
CHSeenCR,
|
|
CHInChunkExtName,
|
|
CHSeenChunkExtNameAndEquals,
|
|
CHInChunkExtValToken,
|
|
CHInChunkExtValQuotedString,
|
|
CHSeenChunkExtValQuotedStringTerminator,
|
|
CHSuccess,
|
|
CHError
|
|
} CH_PARSER_STATE, *PCH_PARSER_STATE;
|
|
|
|
//
|
|
// Parser states for parsing message header field content.
|
|
//
|
|
typedef enum
|
|
{
|
|
HFCStart,
|
|
HFCSeenCR,
|
|
HFCSeenLF,
|
|
HFCSeenCRLF,
|
|
HFCFolding,
|
|
HFCInQuotedString
|
|
} HFC_PARSER_STATE, *PHFC_PARSER_STATE;
|
|
|
|
//
|
|
// Parser states for parsing a quoted string.
|
|
//
|
|
typedef enum
|
|
{
|
|
QSInString,
|
|
QSSeenBackSlash,
|
|
QSSeenCR,
|
|
QSSeenLF,
|
|
QSSeenCRLF,
|
|
QSFolding
|
|
} QS_PARSER_STATE, *PQS_PARSER_STATE;
|
|
|
|
//
|
|
// External variables.
|
|
//
|
|
|
|
extern ULONG g_RequestHeaderMap[HttpHeaderMaximum];
|
|
extern ULONG g_ResponseHeaderMap[HttpHeaderMaximum];
|
|
|
|
extern HEADER_MAP_ENTRY g_RequestHeaderMapTable[];
|
|
extern HEADER_MAP_ENTRY g_ResponseHeaderMapTable[];
|
|
|
|
extern HEADER_INDEX_ENTRY g_RequestHeaderIndexTable[];
|
|
extern HEADER_INDEX_ENTRY g_ResponseHeaderIndexTable[];
|
|
|
|
extern HEADER_HINT_INDEX_ENTRY g_RequestHeaderHintIndexTable[];
|
|
|
|
//
|
|
// Function prototypes.
|
|
//
|
|
|
|
PUCHAR
|
|
FindHexToken(
|
|
IN PUCHAR pBuffer,
|
|
IN ULONG BufferLength,
|
|
OUT ULONG *TokenLength
|
|
);
|
|
|
|
NTSTATUS
|
|
InitializeParser(
|
|
VOID
|
|
);
|
|
|
|
ULONG
|
|
UlpParseHttpVersion(
|
|
PUCHAR pString,
|
|
ULONG StringLength,
|
|
PHTTP_VERSION pVersion
|
|
);
|
|
|
|
NTSTATUS
|
|
FindHeaderEndReadOnly(
|
|
IN PUCHAR pHeader,
|
|
IN ULONG HeaderLength,
|
|
OUT PULONG pBytesTaken
|
|
);
|
|
|
|
NTSTATUS
|
|
FindHeaderEnd(
|
|
IN PUCHAR pHeader,
|
|
IN ULONG HeaderLength,
|
|
OUT PULONG pBytesTaken
|
|
);
|
|
|
|
NTSTATUS
|
|
FindRequestHeaderEnd(
|
|
IN PUL_INTERNAL_REQUEST pRequest,
|
|
IN PUCHAR pHeader,
|
|
IN ULONG HeaderLength,
|
|
OUT PULONG pBytesTaken
|
|
);
|
|
|
|
NTSTATUS
|
|
FindChunkHeaderEnd(
|
|
IN PUCHAR pHeader,
|
|
IN ULONG HeaderLength,
|
|
OUT PULONG pBytesTaken
|
|
);
|
|
|
|
NTSTATUS
|
|
ParseChunkLength(
|
|
IN ULONG FirstChunkParsed,
|
|
IN PUCHAR pBuffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG pBytesTaken,
|
|
OUT PULONGLONG pChunkLength
|
|
);
|
|
|
|
NTSTATUS
|
|
ParseQuotedString(
|
|
IN PUCHAR pInput,
|
|
IN ULONG InputLength,
|
|
IN PUCHAR pOutput,
|
|
OUT PULONG pBytesTaken
|
|
);
|
|
|
|
#endif // _PARSE_H_
|