📄 httpparser.c
字号:
/************************************************************************* 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, 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 voidparser_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_tparser_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_tparser_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_tparser_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 ) { parser->msg.method = SOAPMETHOD_POST; } header_id = Http_Header_Names[index].id; orig_header = httpmsg_find_hdr( &parser->msg, header_id, NULL ); } else { header_id = HDR_UNKNOWN; save_char = token.buf[token.length]; token.buf[token.length] = '\0'; orig_header = httpmsg_find_hdr_str( &parser->msg, token.buf ); token.buf[token.length] = save_char; // restore } if( orig_header == NULL ) { // // add new header // header = ( http_header_t * ) malloc( sizeof( http_header_t ) ); if( header == NULL ) { parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; return PARSE_FAILURE; } membuffer_init( &header->name_buf ); membuffer_init( &header->value ); // value can be 0 length if( hdr_value.length == 0 ) { hdr_value.buf = "\0"; hdr_value.length = 1; } // save in header in buffers if( membuffer_assign ( &header->name_buf, token.buf, token.length ) != 0 || membuffer_assign( &header->value, hdr_value.buf, hdr_value.length ) != 0 ) { // not enuf mem parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; return PARSE_FAILURE; } header->name.buf = header->name_buf.buf; header->name.length = header->name_buf.length; header->name_id = header_id; ListAddTail( &parser->msg.headers, header ); //NNS: ret = dlist_append( &parser->msg.headers, header );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -