📄 httpparser.c
字号:
* 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 intmatch_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 intread_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 intskip_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_tmatch_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 intvfmatch( 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 ); } } } } if( status != PARSE_OK ) { // on error, restore original scanner pos scanner->cursor = save_pos; } return status;}/************************************************************************* Function: match * * Parameters: * INOUT scanner_t* scanner ; Scanner Object * IN const char* fmt; Pattern format * ... * * Description: matches a variable parameter list and takes necessary * actions based on the data type specified. * * Returns: * PARSE_OK * PARSE_NO_MATCH * PARSE_INCOMPLETE ************************************************************************/static intmatch( INOUT scanner_t * scanner, IN const char *fmt, ... ){ int ret_code; va_list args; va_start( args, fmt ); ret_code = vfmatch( scanner, fmt, args ); va_end( args ); return ret_code;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -