httpparser.c
来自「原来由英特尔制定的UPnP SDK的」· C语言 代码 · 共 2,179 行 · 第 1/5 页
C
2,179 行
static UPNP_INLINE intmatch_int( INOUT scanner_t * scanner, IN int base, OUT int *value ){ memptr token; token_type_t tok_type; parse_status_t status; long 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 UPNP_INLINE 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************************************************************************/#ifndef WIN32#warning There are currently no uses of the function 'skip_to_end_of_header()' in the code.#warning 'skip_to_end_of_header()' is a candidate for removal.#else#pragma message("There are currently no uses of the function 'skip_to_end_of_header()' in the code.")#pragma message("'skip_to_end_of_header()' is a candidate for removal.")#endifstatic UPNP_INLINE 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 UPNP_INLINE 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;}/************************************************************************* Function: matchstr** Parameters:* IN char *str ; String to be matched* IN size_t slen ; Length of the string* IN const char* fmt ; Pattern format* ...** Description: Matches a variable parameter list with a string* and takes actions based on the data type specified.** Returns:* PARSE_OK* PARSE_NO_MATCH -- failure to match pattern 'fmt'* PARSE_FAILURE -- 'str' is bad input************************************************************************/intmatchstr( IN char *str, IN size_t slen,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?