📄 httpparser.c
字号:
scanner->cursor = save_pos;
done = TRUE;
}
}
if( status == PARSE_OK ) {
// trim whitespace on right side of value
while( raw_value->length > 0 ) {
// get last char
c = raw_value->buf[raw_value->length - 1];
if( c != ' ' && c != '\t' &&
c != TOKCHAR_CR && c != TOKCHAR_LF ) {
// done; no more whitespace
break;
}
// remove whitespace
raw_value->length--;
}
}
return status;
}
/************************************************************************
* Function: match_int
*
* Parameters:
* INOUT scanner_t* scanner ; Scanner Object
* IN int base : Base of number in the string;
* valid values: 10 or 16
* OUT int* value ; Number stored here
*
* Description: Matches an unsigned integer value in the input. The
* integer is returned in 'value'. Except for PARSE_OK result, the
* scanner's cursor is moved back to its original position on error.
*
* Returns:
* PARSE_OK
* PARSE_NO_MATCH -- got different kind of token
* PARSE_FAILURE -- bad input
* PARSE_INCOMPLETE
************************************************************************/
static XINLINE int
match_int( INOUT scanner_t * scanner,
IN int base,
OUT int *value )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
int num;
char *end_ptr;
size_t save_pos;
save_pos = scanner->cursor;
status = scanner_get_token( scanner, &token, &tok_type );
if( status == PARSE_OK ) {
if( tok_type == TT_IDENTIFIER ) {
errno = 0;
num = strtol( token.buf, &end_ptr, base );
if( ( num < 0 )
// all and only those chars in token should be used for num
|| ( end_ptr != token.buf + token.length )
|| ( ( num == LONG_MIN || num == LONG_MAX )
&& ( errno == ERANGE ) )
) {
status = PARSE_NO_MATCH;
}
*value = num; // save result
} else {
status = PARSE_NO_MATCH; // token must be an identifier
}
}
if( status != PARSE_OK ) {
// restore scanner position for bad values
scanner->cursor = save_pos;
}
return status;
}
/************************************************************************
* Function: read_until_crlf
*
* Parameters:
* INOUT scanner_t* scanner ; Scanner Object
* OUT memptr* str ; Buffer to copy scanner buffer contents to
*
* Description: Reads data until end of line; the crlf at the end of
* line is not consumed. On error, scanner is not restored. On
* success, 'str' points to a string that runs until eol
*
* Returns:
* PARSE_OK
* PARSE_FAILURE
* PARSE_INCOMPLETE
************************************************************************/
static XINLINE int
read_until_crlf( INOUT scanner_t * scanner,
OUT memptr * str )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
size_t start_pos;
start_pos = scanner->cursor;
str->buf = scanner_get_str( scanner );
// read until we hit a crlf
do {
status = scanner_get_token( scanner, &token, &tok_type );
} while( status == PARSE_OK && tok_type != TT_CRLF );
if( status == PARSE_OK ) {
// pushback crlf in stream
scanner->cursor -= token.length;
// str should include all strings except crlf at the end
str->length = scanner->cursor - start_pos;
}
return status;
}
/************************************************************************
* Function: skip_to_end_of_header
*
* Parameters:
* INOUT scanner_t* scanner ; Scanner Object
*
* Description: Skip to end of header
*
* Returns:
* PARSE_OK
* PARSE_FAILURE
* PARSE_INCOMPLETE
************************************************************************/
static XINLINE int
skip_to_end_of_header( INOUT scanner_t * scanner )
{
memptr dummy_raw_value;
parse_status_t status;
status = match_raw_value( scanner, &dummy_raw_value );
return status;
}
/************************************************************************
* Function: match_char
*
* Parameters:
* INOUT scanner_t* scanner ; Scanner Object
* IN char c ; Character to be compared with
* IN xboolean case_sensitive; Flag indicating whether comparison should
* be case sensitive
*
* Description: Compares a character to the next char in the scanner;
* on error, scanner chars are not restored
*
* Returns:
* PARSE_OK
* PARSE_NO_MATCH
* PARSE_INCOMPLETE
************************************************************************/
static XINLINE parse_status_t
match_char( INOUT scanner_t * scanner,
IN char c,
IN xboolean case_sensitive )
{
char scan_char;
if( scanner->cursor >= scanner->msg->length ) {
return PARSE_INCOMPLETE;
}
// read next char from scanner
scan_char = scanner->msg->buf[scanner->cursor++];
if( case_sensitive ) {
return c == scan_char ? PARSE_OK : PARSE_NO_MATCH;
} else {
return tolower( c ) == tolower( scan_char ) ?
PARSE_OK : PARSE_NO_MATCH;
}
}
////////////////////////////////////////////////////////////////////////
// args for ...
// %d, int * (31-bit positive integer)
// %x, int * (31-bit postive number encoded as hex)
// %s, memptr* (simple identifier)
// %q, memptr* (quoted string)
// %S, memptr* (non-whitespace string)
// %R, memptr* (raw value)
// %U, uri_type* (url)
// %L, memptr* (string until end of line)
// %P, int * (current index of the string being scanned)
//
// no args for
// ' ' LWS*
// \t whitespace
// "%%" matches '%'
// "% " matches ' '
// %c matches CRLF
// %i ignore case in literal matching
// %n case-sensitive matching in literals
// %w optional whitespace; (similar to '\t',
// except whitespace is optional)
// %0 (zero) match null-terminator char '\0'
// (can only be used as last char in fmt)
// use only in matchstr(), not match()
// other chars match literally
//
// returns:
// PARSE_OK
// PARSE_INCOMPLETE
// PARSE_FAILURE -- bad input
// PARSE_NO_MATCH -- input does not match pattern
/************************************************************************
* Function : vfmatch
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
* IN const char* fmt ; Pattern Format
* va_list argp ; List of variable arguments
*
* Description : Extracts variable parameters depending on the passed
* in format parameter. Parses data also based on the passed in
* format parameter.
*
* Return : int ;
* PARSE_OK
* PARSE_INCOMPLETE
* PARSE_FAILURE - bad input
* PARSE_NO_MATCH - input does not match pattern
*
* Note :
************************************************************************/
static int
vfmatch( INOUT scanner_t * scanner,
IN const char *fmt,
va_list argp )
{
char c;
const char *fmt_ptr = fmt;
parse_status_t status;
memptr *str_ptr;
memptr temp_str;
int *int_ptr;
uri_type *uri_ptr;
size_t save_pos;
int stat;
xboolean case_sensitive = TRUE;
memptr token;
token_type_t tok_type;
int base;
assert( scanner != NULL );
assert( fmt != NULL );
// save scanner pos; to aid error recovery
save_pos = scanner->cursor;
status = PARSE_OK;
while( ( ( c = *fmt_ptr++ ) != 0 ) && ( status == PARSE_OK )
) {
if( c == '%' ) {
c = *fmt_ptr++;
switch ( c ) {
case 'R': // raw value
str_ptr = va_arg( argp, memptr * );
assert( str_ptr != NULL );
status = match_raw_value( scanner, str_ptr );
break;
case 's': // simple identifier
str_ptr = va_arg( argp, memptr * );
assert( str_ptr != NULL );
status = scanner_get_token( scanner, str_ptr,
&tok_type );
if( status == PARSE_OK && tok_type != TT_IDENTIFIER ) {
// not an identifier
status = PARSE_NO_MATCH;
}
break;
case 'c': // crlf
status = scanner_get_token( scanner,
&token, &tok_type );
if( status == PARSE_OK && tok_type != TT_CRLF ) {
// not CRLF token
status = PARSE_NO_MATCH;
}
break;
case 'd': // integer
case 'x': // hex number
int_ptr = va_arg( argp, int * );
assert( int_ptr != NULL );
base = ( c == 'd' ? 10 : 16 );
status = match_int( scanner, base, int_ptr );
break;
case 'S': // non-whitespace string
case 'U': // uri
if( c == 'S' ) {
str_ptr = va_arg( argp, memptr * );
} else {
str_ptr = &temp_str;
}
assert( str_ptr != NULL );
status = match_non_ws_string( scanner, str_ptr );
if( c == 'U' && status == PARSE_OK ) {
uri_ptr = va_arg( argp, uri_type * );
assert( uri_ptr != NULL );
stat = parse_uri( str_ptr->buf, str_ptr->length,
uri_ptr );
if( stat != HTTP_SUCCESS ) {
status = PARSE_NO_MATCH;
}
}
break;
case 'L': // string till eol
str_ptr = va_arg( argp, memptr * );
assert( str_ptr != NULL );
status = read_until_crlf( scanner, str_ptr );
break;
case ' ': // match space
case '%': // match percentage symbol
status = match_char( scanner, c, case_sensitive );
break;
case 'n': // case-sensitive match
case_sensitive = TRUE;
break;
case 'i': // ignore case
case_sensitive = FALSE;
break;
case 'q': // quoted string
str_ptr = ( memptr * ) va_arg( argp, memptr * );
status =
scanner_get_token( scanner, str_ptr, &tok_type );
if( status == PARSE_OK && tok_type != TT_QUOTEDSTRING ) {
status = PARSE_NO_MATCH; // not a quoted string
}
break;
case 'w': // optional whitespace
status = scanner_get_token( scanner,
&token, &tok_type );
if( status == PARSE_OK && tok_type != TT_WHITESPACE ) {
// restore non-whitespace token
scanner->cursor -= token.length;
}
break;
case 'P': // current pos of scanner
int_ptr = va_arg( argp, int * );
assert( int_ptr != NULL );
*int_ptr = scanner->cursor;
break;
// valid only in matchstr()
case '0': // end of msg?
// check that we are 1 beyond last char
if( scanner->cursor == scanner->msg->length &&
scanner->msg->buf[scanner->cursor] == '\0' ) {
status = PARSE_OK;
} else {
status = PARSE_NO_MATCH;
}
break;
default:
assert( 0 ); // unknown option
}
} else {
switch ( c ) {
case ' ': // LWS*
status = skip_lws( scanner );
break;
case '\t': // Whitespace
status = scanner_get_token( scanner,
&token, &tok_type );
if( status == PARSE_OK && tok_type != TT_WHITESPACE ) {
// not whitespace token
status = PARSE_NO_MATCH;
}
break;
default: // match characters
{
status = match_char( scanner, c, case_sensitive );
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -