📄 httpparser.c
字号:
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 int
match( 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
************************************************************************/
int
matchstr( IN char *str,
IN size_t slen,
IN const char *fmt,
... )
{
int ret_code;
char save_char;
scanner_t scanner;
membuffer buf;
va_list arg_list;
// null terminate str
save_char = str[slen];
str[slen] = '\0';
membuffer_init( &buf );
// under no circumstances should this buffer be modifed because its memory
// might have not come from malloc()
membuffer_attach( &buf, str, slen );
scanner_init( &scanner, &buf );
scanner.entire_msg_loaded = TRUE;
va_start( arg_list, fmt );
ret_code = vfmatch( &scanner, fmt, arg_list );
va_end( arg_list );
// restore str
str[slen] = save_char;
// don't destroy buf
return ret_code;
}
/************************************************************************
* Function: parser_init
*
* Parameters:
* OUT http_parser_t* parser ; HTTP Parser object
*
* Description: Initializes the parser object.
*
* Returns:
* void
************************************************************************/
static XINLINE void
parser_init( OUT http_parser_t * parser )
{
memset( parser, 0, sizeof( http_parser_t ) );
parser->http_error_code = HTTP_BAD_REQUEST; // err msg by default
parser->ent_position = ENTREAD_DETERMINE_READ_METHOD;
parser->valid_ssdp_notify_hack = FALSE;
httpmsg_init( &parser->msg );
scanner_init( &parser->scanner, &parser->msg.msg );
}
/************************************************************************
* Function: parser_parse_requestline
*
* Parameters:
* INOUT http_parser_t* parser ; HTTP Parser object
*
* Description: Get HTTP Method, URL location and version information.
*
* Returns:
* PARSE_OK
* PARSE_SUCCESS
* PARSE_FAILURE
************************************************************************/
static parse_status_t
parser_parse_requestline( INOUT http_parser_t * parser )
{
parse_status_t status;
http_message_t *hmsg = &parser->msg;
memptr method_str;
memptr version_str;
int index;
char save_char;
int num_scanned;
memptr url_str;
assert( parser->position == POS_REQUEST_LINE );
status = skip_blank_lines( &parser->scanner );
if( status != PARSE_OK ) {
return status;
}
//simple get http 0.9 as described in http 1.0 spec
status =
match( &parser->scanner, "%s\t%S%w%c", &method_str, &url_str );
if( status == PARSE_OK ) {
index =
map_str_to_int( method_str.buf, method_str.length,
Http_Method_Table, NUM_HTTP_METHODS, TRUE );
if( index < 0 ) {
// error; method not found
parser->http_error_code = HTTP_NOT_IMPLEMENTED;
return PARSE_FAILURE;
}
if( Http_Method_Table[index].id != HTTPMETHOD_GET ) {
parser->http_error_code = HTTP_BAD_REQUEST;
return PARSE_FAILURE;
}
hmsg->method = HTTPMETHOD_SIMPLEGET;
// store url
hmsg->urlbuf = str_alloc( url_str.buf, url_str.length );
if( hmsg->urlbuf == NULL ) {
// out of mem
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
return PARSE_FAILURE;
}
if( parse_uri( hmsg->urlbuf, url_str.length, &hmsg->uri ) !=
HTTP_SUCCESS ) {
return PARSE_FAILURE;
}
parser->position = POS_COMPLETE; // move to headers
return PARSE_SUCCESS;
}
status = match( &parser->scanner,
"%s\t%S\t%ihttp%w/%w%L%c", &method_str, &url_str,
&version_str );
if( status != PARSE_OK ) {
return status;
}
// store url
hmsg->urlbuf = str_alloc( url_str.buf, url_str.length );
if( hmsg->urlbuf == NULL ) {
// out of mem
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
return PARSE_FAILURE;
}
if( parse_uri( hmsg->urlbuf, url_str.length, &hmsg->uri ) !=
HTTP_SUCCESS ) {
return PARSE_FAILURE;
}
// scan version
save_char = version_str.buf[version_str.length];
version_str.buf[version_str.length] = '\0'; // null-terminate
num_scanned = sscanf( version_str.buf, "%d . %d",
&hmsg->major_version, &hmsg->minor_version );
version_str.buf[version_str.length] = save_char; // restore
if( num_scanned != 2 ||
hmsg->major_version < 0 || hmsg->minor_version < 0 ) {
// error; bad http version
return PARSE_FAILURE;
}
index =
map_str_to_int( method_str.buf, method_str.length,
Http_Method_Table, NUM_HTTP_METHODS, TRUE );
if( index < 0 ) {
// error; method not found
parser->http_error_code = HTTP_NOT_IMPLEMENTED;
return PARSE_FAILURE;
}
hmsg->method = Http_Method_Table[index].id;
parser->position = POS_HEADERS; // move to headers
return PARSE_OK;
}
/************************************************************************
* Function: parser_parse_responseline
*
* Parameters:
* INOUT http_parser_t* parser ; HTTP Parser object
*
* Description: Get HTTP Method, URL location and version information.
*
* Returns:
* PARSE_OK
* PARSE_SUCCESS
* PARSE_FAILURE
************************************************************************/
parse_status_t
parser_parse_responseline( INOUT http_parser_t * parser )
{
parse_status_t status;
http_message_t *hmsg = &parser->msg;
memptr line;
char save_char;
int num_scanned;
int i;
char *p;
assert( parser->position == POS_RESPONSE_LINE );
status = skip_blank_lines( &parser->scanner );
if( status != PARSE_OK ) {
return status;
}
// response line
//status = match( &parser->scanner, "%ihttp%w/%w%d\t.\t%d\t%d\t%L%c",
// &hmsg->major_version, &hmsg->minor_version,
// &hmsg->status_code, &hmsg->status_msg );
status = match( &parser->scanner, "%ihttp%w/%w%L%c", &line );
if( status != PARSE_OK ) {
return status;
}
save_char = line.buf[line.length];
line.buf[line.length] = '\0'; // null-terminate
// scan http version and ret code
num_scanned = sscanf( line.buf, "%d . %d %d",
&hmsg->major_version, &hmsg->minor_version,
&hmsg->status_code );
line.buf[line.length] = save_char; // restore
if( num_scanned != 3 ||
hmsg->major_version < 0 ||
hmsg->minor_version < 0 || hmsg->status_code < 0 ) {
// bad response line
return PARSE_FAILURE;
}
//
// point to status msg
//
p = line.buf;
// skip 3 ints
for( i = 0; i < 3; i++ ) {
// go to start of num
while( !isdigit( *p ) ) {
p++;
}
// skip int
while( isdigit( *p ) ) {
p++;
}
}
// whitespace must exist after status code
if( *p != ' ' && *p != '\t' ) {
return PARSE_FAILURE;
}
// skip whitespace
while( *p == ' ' || *p == '\t' ) {
p++;
}
// now, p is at start of status msg
if( membuffer_assign( &hmsg->status_msg, p,
line.length - ( p - line.buf ) ) != 0 ) {
// out of mem
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
return PARSE_FAILURE;
}
parser->position = POS_HEADERS; // move to headers
return PARSE_OK;
}
/************************************************************************
* Function: parser_parse_headers
*
* Parameters:
* INOUT http_parser_t* parser ; HTTP Parser object
*
* Description: Get HTTP Method, URL location and version information.
*
* Returns:
* PARSE_OK
* PARSE_SUCCESS
* PARSE_FAILURE
************************************************************************/
parse_status_t
parser_parse_headers( INOUT http_parser_t * parser )
{
parse_status_t status;
memptr token;
memptr hdr_value;
token_type_t tok_type;
scanner_t *scanner = &parser->scanner;
size_t save_pos;
http_header_t *header;
int header_id;
int ret = 0;
int index;
http_header_t *orig_header;
char save_char;
int ret2;
assert( parser->position == POS_HEADERS ||
parser->ent_position == ENTREAD_CHUNKY_HEADERS );
while( TRUE ) {
save_pos = scanner->cursor;
//
// check end of headers
//
status = scanner_get_token( scanner, &token, &tok_type );
if( status != PARSE_OK ) {
return status;
}
if( tok_type == TT_CRLF ) {
// end of headers
if( ( parser->msg.is_request )
&& ( parser->msg.method == HTTPMETHOD_POST ) ) {
parser->position = POS_COMPLETE; //post entity parsing
//is handled separately
return PARSE_SUCCESS;
}
parser->position = POS_ENTITY; // read entity next
return PARSE_OK;
}
//
// not end; read header
//
if( tok_type != TT_IDENTIFIER ) {
return PARSE_FAILURE; // didn't see header name
}
status = match( scanner, " : %R%c", &hdr_value );
if( status != PARSE_OK ) {
// pushback tokens; useful only on INCOMPLETE error
scanner->cursor = save_pos;
return status;
}
//
// add header
//
// find header
index = map_str_to_int( token.buf, token.length, Http_Header_Names,
NUM_HTTP_HEADER_NAMES, FALSE );
if( index != -1 ) {
//Check if it is a soap header
if( Http_Header_Names[index].id == HDR_SOAPACTION ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -