📄 httpparser.c
字号:
/***********************************************************************/
/************* parser **************/
/***********************************************************************/
/***********************************************************************/
/************* http_message_t **************/
/***********************************************************************/
/************************************************************************
* Function : httpmsg_compare
*
* Parameters :
* void* param1 ;
* void* param2 ;
*
* Description : Compares name id in the http headers.
*
* Return : int ;
*
* Note :
************************************************************************/
static int
httpmsg_compare( void *param1,
void *param2 )
{
assert( param1 != NULL );
assert( param2 != NULL );
return ( ( http_header_t * ) param1 )->name_id ==
( ( http_header_t * ) param2 )->name_id;
}
/************************************************************************
* Function : httpheader_free
*
* Parameters :
* void *msg ;
*
* Description : Free memory allocated for the http header
*
* Return : void ;
*
* Note :
************************************************************************/
static void
httpheader_free( void *msg )
{
http_header_t *hdr = ( http_header_t * ) msg;
membuffer_destroy( &hdr->name_buf );
membuffer_destroy( &hdr->value );
free( hdr );
}
/************************************************************************
* Function : httpmsg_init
*
* Parameters :
* INOUT http_message_t* msg ; HTTP Message Object
*
* Description : Initialize and allocate memory for http message
*
* Return : void ;
*
* Note :
************************************************************************/
void
httpmsg_init( INOUT http_message_t * msg )
{
msg->initialized = 1;
msg->entity.buf = NULL;
msg->entity.length = 0;
ListInit( &msg->headers, httpmsg_compare, httpheader_free );
membuffer_init( &msg->msg );
membuffer_init( &msg->status_msg );
}
/************************************************************************
* Function : httpmsg_destroy
*
* Parameters :
* INOUT http_message_t* msg ; HTTP Message Object
*
* Description : Free memory allocated for the http message
*
* Return : void ;
*
* Note :
************************************************************************/
void
httpmsg_destroy( INOUT http_message_t * msg )
{
assert( msg != NULL );
if( msg->initialized == 1 ) {
ListDestroy( &msg->headers, 1 );
membuffer_destroy( &msg->msg );
membuffer_destroy( &msg->status_msg );
free( msg->urlbuf );
msg->initialized = 0;
}
}
/************************************************************************
* Function : httpmsg_find_hdr_str
*
* Parameters :
* IN http_message_t* msg ; HTTP Message Object
* IN const char* header_name ; Header name to be compared with
*
* Description : Compares the header name with the header names stored
* in the linked list of messages
*
* Return : http_header_t* - Pointer to a header on success;
* NULL on failure
*
* Note :
************************************************************************/
http_header_t *
httpmsg_find_hdr_str( IN http_message_t * msg,
IN const char *header_name )
{
http_header_t *header;
ListNode *node;
node = ListHead( &msg->headers );
while( node != NULL ) {
header = ( http_header_t * ) node->item;
if( memptr_cmp_nocase( &header->name, header_name ) == 0 ) {
return header;
}
node = ListNext( &msg->headers, node );
}
return NULL;
}
/************************************************************************
* Function : httpmsg_find_hdr
*
* Parameters :
* IN http_message_t* msg ; HTTP Message Object
* IN int header_name_id ; Header Name ID to be compared with
* OUT memptr* value ; Buffer to get the ouput to.
*
* Description : Finds header from a list, with the given 'name_id'.
*
* Return : http_header_t* - Pointer to a header on success; *
* NULL on failure
*
* Note :
************************************************************************/
http_header_t *
httpmsg_find_hdr( IN http_message_t * msg,
IN int header_name_id,
OUT memptr * value )
{
http_header_t header; // temp header for searching
ListNode *node;
http_header_t *data;
header.name_id = header_name_id;
node = ListFind( &msg->headers, NULL, &header );
if( node == NULL ) {
return NULL;
}
data = ( http_header_t * ) node->item;
if( value != NULL ) {
value->buf = data->value.buf;
value->length = data->value.length;
}
return data;
}
/***********************************************************************/
/************* http_parser_t **************/
/***********************************************************************/
/************************************************************************
* Function : skip_blank_lines
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
*
* Description : skips blank lines at the start of a msg.
*
* Return : int ;
*
* Note :
************************************************************************/
static XINLINE int
skip_blank_lines( INOUT scanner_t * scanner )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
// skip ws, crlf
do {
status = scanner_get_token( scanner, &token, &tok_type );
} while( status == PARSE_OK &&
( tok_type == TT_WHITESPACE || tok_type == TT_CRLF ) );
if( status == PARSE_OK ) {
// pushback a non-whitespace token
scanner->cursor -= token.length;
//scanner_pushback( scanner, token.length );
}
return status;
}
/************************************************************************
* Function : skip_lws
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
*
* Description : skip linear whitespace.
*
* Return : int ;
* PARSE_OK: (LWS)* removed from input
* PARSE_FAILURE: bad input
* PARSE_INCOMPLETE: incomplete input
*
* Note :
************************************************************************/
static XINLINE int
skip_lws( INOUT scanner_t * scanner )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
size_t save_pos;
xboolean matched;
do {
save_pos = scanner->cursor;
matched = FALSE;
// get CRLF or WS
status = scanner_get_token( scanner, &token, &tok_type );
if( status == PARSE_OK ) {
if( tok_type == TT_CRLF ) {
// get WS
status = scanner_get_token( scanner, &token, &tok_type );
}
if( status == PARSE_OK && tok_type == TT_WHITESPACE ) {
matched = TRUE;
} else {
// did not match LWS; pushback token(s)
scanner->cursor = save_pos;
}
}
} while( matched );
// if entire msg is loaded, ignore an 'incomplete' warning
if( status == PARSE_INCOMPLETE && scanner->entire_msg_loaded ) {
status = PARSE_OK;
}
return status;
}
/************************************************************************
* Function : match_non_ws_string
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
* OUT memptr* str ; Buffer to get the scanner buffer contents.
*
* Description : Match a string without whitespace or CRLF (%S)
*
* Return : XINLINE parse_status_t ;
* PARSE_OK
* PARSE_NO_MATCH
* PARSE_FAILURE
* PARSE_INCOMPLETE
*
* Note :
************************************************************************/
static XINLINE parse_status_t
match_non_ws_string( INOUT scanner_t * scanner,
OUT memptr * str )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
xboolean done = FALSE;
size_t save_cursor;
save_cursor = scanner->cursor;
str->length = 0;
str->buf = scanner_get_str( scanner ); // point to next char in input
while( !done ) {
status = scanner_get_token( scanner, &token, &tok_type );
if( status == PARSE_OK &&
tok_type != TT_WHITESPACE && tok_type != TT_CRLF ) {
// append non-ws token
str->length += token.length;
} else {
done = TRUE;
}
}
if( status == PARSE_OK ) {
// last token was WS; push it back in
scanner->cursor -= token.length;
}
// tolerate 'incomplete' msg
if( status == PARSE_OK ||
( status == PARSE_INCOMPLETE && scanner->entire_msg_loaded )
) {
if( str->length == 0 ) {
// no strings found
return PARSE_NO_MATCH;
} else {
return PARSE_OK;
}
} else {
// error -- pushback tokens
scanner->cursor = save_cursor;
return status;
}
}
/************************************************************************
* Function : match_raw_value
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
* OUT memptr* raw_value ; Buffer to get the scanner buffer
* contents
*
* Description : Matches a raw value in a the input; value's length
* can be 0 or more. Whitespace after value is trimmed. On success,
* scanner points the CRLF that ended the value
*
* Return : parse_status_t ;
* PARSE_OK
* PARSE_INCOMPLETE
* PARSE_FAILURE
*
* Note :
************************************************************************/
static XINLINE parse_status_t
match_raw_value( INOUT scanner_t * scanner,
OUT memptr * raw_value )
{
memptr token;
token_type_t tok_type;
parse_status_t status;
xboolean done = FALSE;
xboolean saw_crlf = FALSE;
size_t pos_at_crlf = 0;
size_t save_pos;
char c;
save_pos = scanner->cursor;
// value points to start of input
raw_value->buf = scanner_get_str( scanner );
raw_value->length = 0;
while( !done ) {
status = scanner_get_token( scanner, &token, &tok_type );
if( status == PARSE_OK ) {
if( !saw_crlf ) {
if( tok_type == TT_CRLF ) {
// CRLF could end value
saw_crlf = TRUE;
// save input position at start of CRLF
pos_at_crlf = scanner->cursor - token.length;
}
// keep appending value
raw_value->length += token.length;
} else // already seen CRLF
{
if( tok_type == TT_WHITESPACE ) {
// start again; forget CRLF
saw_crlf = FALSE;
raw_value->length += token.length;
} else {
// non-ws means value ended just before CRLF
done = TRUE;
// point to the crlf which ended the value
scanner->cursor = pos_at_crlf;
}
}
} else {
// some kind of error; restore scanner position
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -