|
HTTP Parser and message builder / objects in plain C Snapshot
|
base class of both http request and http response parsers More...
base class of both http request and http response parsers
| typedef struct tagHTTP_PARSER HTTP_PARSER |
| typedef int(* HTTP_PROCESS_MSG_DATA)(HTTP_MESSAGE *msg, void *data, size_t data_size, void *ctx) |
| typedef int(* HTTP_REQ_FINISHED)(HTTP_REQUEST *request, void *ctx) |
| typedef int(* HTTP_REQ_HEADER_PARSED)(HTTP_REQUEST *request, void *ctx) |
| typedef int(* HTTP_REQ_MESSAGE_BODY_DATA)(HTTP_REQUEST *request, void *data, size_t data_size, void *ctx) |
| typedef enum tagHTTP_STATE_PARSING HTTP_STATE_PARSING |
| enum HTTP_TK_TYPE |
| enum PARSER_STATUS |
Definition at line 237 of file http.h.
{
PARSER_STATUS_ERROR = -1,
PARSER_STATUS_COMPLETED = 0,
PARSER_STATUS_NEED_MORE_DATA = 1,
}
| int HTTP_add_header_parser | ( | HTTP_PARSER * | parser, |
| const char * | header_name, | ||
| HEADER_ACTION | action | ||
| ) |
add a parser for a specific http header type
Definition at line 191 of file http.c.
{
HEADER_HASH_ACTION * action;
action = ( HEADER_HASH_ACTION *) malloc( sizeof( HEADER_HASH_ACTION ) ) ;
if (!action) {
return -1;
}
action->key = strdup( header_name );
action->key_size = strlen( header_name );
action->action = action_func;
return HASH_insert( &parser->header_action, &action->entry, (void *) header_name, strlen(header_name) );
}
| int HTTP_get_header_token | ( | HTTP_PARSER * | parser | ) |
return next token while parsing http header value.
Definition at line 275 of file http.c.
{
char ch;
size_t token_pos;
if (*parser->tokpos == '\0') {
return HTTP_TK_EOF;
}
// skip leading spaces
for( ;http_is_space( *parser->tokpos ); ++parser->tokpos );
ch = *parser->tokpos;
if (http_is_separator(ch)) {
parser->token[ 0 ] = ch;
parser->token[ 1 ] = '\0';
++ parser->tokpos;
return HTTP_TK_SEPARATOR;
}
if (ch == '"') {
token_pos = 0;
do {
ch = *parser->tokpos ++ ;
chk:
if (http_is_ctl( ch )) {
return -1;
}
if (ch == '"') {
if (token_pos > parser->token_length) {
return -1;
}
parser->token[ token_pos++ ] = '\0';
return HTTP_TK_QUOTED_STRING;
} else {
if (ch == '\\') {
goto chk;
}
}
// add character.
if (token_pos > parser->token_length) {
return -1;
}
parser->token[ token_pos++ ] = ch;
} while (ch != '\0');
}
if ( !http_is_separator( ch ) ) {
token_pos = 0;
do {
if (token_pos >= parser->token_length) {
return -1;
}
parser->token[ token_pos++ ] = ch;
ch = *( ++ parser->tokpos );
} while( ch != 0 && ! http_is_ctl( ch ) && ! http_is_separator( ch ) );
parser->token[ token_pos ] = '\0';
return HTTP_TK_TEXT;
}
return -1;
}
| PARSER_STATUS HTTP_get_line | ( | BF * | bf, |
| char ** | start_line | ||
| ) |
returns next raw line from http header, adjoins line continuations.
Definition at line 208 of file http.c.
{
uint8_t *pos;
#if 0
uint8_t *prev;
#endif
char *line;
pos = bf->get_pos;
line = BF_get_line_ext( bf, HTTP_EOF_LINE, HTTP_EOF_LINE_LEN );
if (!line) {
if (BF_is_full( bf ) ) {
// whole buffer does not even contain a line. untennable.
return PARSER_STATUS_ERROR;
}
BF_compact(bf);
return PARSER_STATUS_NEED_MORE_DATA;
}
#if 0
// check if this line is continued.
while ( 1 ) {
prev = bf->get_pos;
line = BF_get_line_ext( bf, HTTP_EOF_LINE, HTTP_EOF_LINE_LEN );
if (!line) {
// restore the line marker.
*(bf->get_pos - 2) = '\r';
if (BF_is_full( bf ) ) {
// a continuation line spans the whole input buffer,
// That's very bad, unfortunately we can't support this.
return PARSER_STATUS_ERROR;
}
bf->get_pos = pos;
return PARSER_STATUS_NEED_MORE_DATA;
}
if (!is_space( *line )) {
*(bf->get_pos - 2) = '\r';
bf->get_pos = prev;
break;
}
// adjoin the previous line to this line.
*(bf->get_pos - 2) = ' ';
*(bf->get_pos - 1) = ' ';
}
#endif
*start_line = (char *) pos;
return PARSER_STATUS_COMPLETED;
}
| PARSER_STATUS HTTP_parse_header_line | ( | HTTP_PARSER * | parser, |
| HTTP_MESSAGE * | request, | ||
| BF * | bf, | ||
| int * | eof_header | ||
| ) |
dispatch parsing of one http header
Definition at line 347 of file http.c.
{
PARSER_STATUS rt;
HEADER_HASH_ACTION *action;
char *line, *pos;
*eof_header = 0;
rt = HTTP_get_line( bf, &line );
if (rt != PARSER_STATUS_COMPLETED) {
return rt;
}
if (! *line ) {
*eof_header = 1;
return PARSER_STATUS_COMPLETED;
}
if (is_space(*line)) {
return -1;
}
// good enough, do not test for all separators though.
for( pos = line ;!http_is_ctl_or_space( *pos ) && *pos != ':'; ++pos ) {
to_lower( pos );
}
if (*pos != ':') {
return -1;
}
*pos = '\0';
if (HTTP_MESSAGE_add_header( request, line, pos+1 )) {
return -1;
}
// got the header line. find header processor.
action = (HEADER_HASH_ACTION *) HASH_find( &parser->header_action, line, pos - line );
if (action) {
parser->tokpos = pos + 1;
action->action( request, parser );
}
// recored header value in http request (optional)
return 0;
}
| int HTTP_PARSER_chunked_data_init | ( | HTTP_PARSER * | parser | ) |
start parsing chunked data
Definition at line 437 of file http.c.
{
parser->state = HTTP_STATE_PARSING_BODY_CHUNK_HEADER;
return 0;
}
| PARSER_STATUS HTTP_PARSER_chunked_data_process | ( | HTTP_PARSER * | parser, |
| BF * | bf, | ||
| HTTP_PROCESS_MSG_DATA | cb, | ||
| HTTP_MESSAGE * | msg, | ||
| void * | ctx | ||
| ) |
finish parsind chunked content data.
Definition at line 459 of file http.c.
{
char *line,*pos,*cur, *endptr;
int rt, eof_header;
long val;
switch( parser->state ) {
case HTTP_STATE_PARSING_BODY_CHUNK_HEADER:
chunk_header:
line = BF_get_line_ext( bf, HTTP_EOF_LINE, HTTP_EOF_LINE_LEN );
if (!line) {
BF_compact(bf);
return PARSER_STATUS_NEED_MORE_DATA;
}
for(pos = line; is_space(*pos); ++pos);
for(cur = pos; is_hex(*cur); ++cur);
*cur = '\0';
val = strtol( pos, &endptr, 16 );
if (val != 0) {
parser->content_left = (size_t) val;
parser->state = HTTP_STATE_PARSING_BODY_CHUNK_DATA;
goto chunk_data;
} else {
parser->state = HTTP_STATE_PARSING_BODY_CHUNK_TRAILER;
goto chunk_trailer;
}
case HTTP_STATE_PARSING_BODY_CHUNK_DATA:
chunk_data:
rt = HTTP_PARSER_content_length_process( parser, bf, cb, msg, ctx );
if (rt != 0) {
return rt;
}
parser->state = HTTP_STATE_PARSING_BODY_CHUNK_EOF_AFTER_DATA;
goto chunk_eof_data;
case HTTP_STATE_PARSING_BODY_CHUNK_EOF_AFTER_DATA:
chunk_eof_data:
line = BF_get_line_ext( bf, HTTP_EOF_LINE, HTTP_EOF_LINE_LEN );
if (!line) {
BF_compact(bf);
return PARSER_STATUS_NEED_MORE_DATA;
}
parser->state = HTTP_STATE_PARSING_BODY_CHUNK_HEADER;
goto chunk_header;
case HTTP_STATE_PARSING_BODY_CHUNK_TRAILER:
chunk_trailer:
rt = HTTP_parse_header_line( parser, msg , bf, &eof_header );
if (rt != PARSER_STATUS_COMPLETED) {
return rt;
}
if (eof_header) {
BF_compact(bf);
return PARSER_STATUS_COMPLETED;
}
return PARSER_STATUS_NEED_MORE_DATA;
default:
return -1;
}
return 0;
}
| int HTTP_PARSER_content_length_init | ( | HTTP_PARSER * | parser, |
| HTTP_MESSAGE * | msg | ||
| ) |
start parsing content length message body
Definition at line 395 of file http.c.
{
parser->state = HTTP_STATE_PARSING_BODY_CONTENT_LENGTH;
parser->content_left = msg-> content_length;
return 0;
}
| PARSER_STATUS HTTP_PARSER_content_length_process | ( | HTTP_PARSER * | parser, |
| BF * | bf, | ||
| HTTP_PROCESS_MSG_DATA | cb, | ||
| HTTP_MESSAGE * | msg, | ||
| void * | ctx | ||
| ) |
consume content length message body.
Definition at line 402 of file http.c.
{
size_t bytes_to_take;
size_t bytes_available;
bytes_available = BF_get_size( bf );
if (bytes_available == 0) {
return PARSER_STATUS_NEED_MORE_DATA;
}
bytes_to_take = parser->content_left;
if (bytes_to_take == 0) {
return PARSER_STATUS_ERROR;
}
if (bytes_available < bytes_to_take) {
bytes_to_take = bytes_available;
}
if (cb( msg, bf->get_pos, bytes_to_take, ctx )) {
return PARSER_STATUS_ERROR;
}
parser->content_left -= bytes_to_take;
bf->get_pos += bytes_to_take;
if (parser->content_left == 0) {
parser->state = HTTP_STATE_PARSING_REQUEST_LINE;
return PARSER_STATUS_COMPLETED;
}
BF_compact(bf);
return PARSER_STATUS_NEED_MORE_DATA;
}
| int HTTP_PARSER_free | ( | HTTP_PARSER * | parser | ) |
| int HTTP_PARSER_init | ( | HTTP_PARSER * | parser | ) |
Definition at line 165 of file http.c.
{
parser->state = HTTP_STATE_PARSING_REQUEST_LINE;
parser->token = malloc( MAX_HTTP_TOKEN_SIZE );
if (! parser->token ) {
return -1;
}
parser->token_length = MAX_HTTP_TOKEN_SIZE;
if (HASH_init( &parser->header_action, 32, 0, hash_compare, 0 ) ) {
return -1;
}
return 0;
}
1.7.4