📄 httpparser.c
字号:
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2003 Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
/************************************************************************
* Purpose: This file contains functions for scanner and parser for http
* messages.
************************************************************************/
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#include "strintmap.h"
#include "httpparser.h"
#include "statcodes.h"
#include "unixutil.h"
// Content Type Header
const char *ClientContentTypeHeader =
"CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n";
// entity positions
#define NUM_HTTP_METHODS 9
static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = {
{"GET", HTTPMETHOD_GET},
{"HEAD", HTTPMETHOD_HEAD},
{"M-POST", HTTPMETHOD_MPOST},
{"M-SEARCH", HTTPMETHOD_MSEARCH},
{"NOTIFY", HTTPMETHOD_NOTIFY},
{"POST", HTTPMETHOD_POST},
{"SUBSCRIBE", HTTPMETHOD_SUBSCRIBE},
{"UNSUBSCRIBE", HTTPMETHOD_UNSUBSCRIBE},
{"POST", SOAPMETHOD_POST},
};
#define NUM_HTTP_HEADER_NAMES 33
str_int_entry Http_Header_Names[NUM_HTTP_HEADER_NAMES] = {
{"ACCEPT", HDR_ACCEPT},
{"ACCEPT-CHARSET", HDR_ACCEPT_CHARSET},
{"ACCEPT-ENCODING", HDR_ACCEPT_ENCODING},
{"ACCEPT-LANGUAGE", HDR_ACCEPT_LANGUAGE},
{"ACCEPT-RANGES", HDR_ACCEPT_RANGE},
{"CACHE-CONTROL", HDR_CACHE_CONTROL},
{"CALLBACK", HDR_CALLBACK},
{"CONTENT-ENCODING", HDR_CONTENT_ENCODING},
{"CONTENT-LANGUAGE", HDR_CONTENT_LANGUAGE},
{"CONTENT-LENGTH", HDR_CONTENT_LENGTH},
{"CONTENT-LOCATION", HDR_CONTENT_LOCATION},
{"CONTENT-RANGE", HDR_CONTENT_RANGE},
{"CONTENT-TYPE", HDR_CONTENT_TYPE},
{"DATE", HDR_DATE},
{"EXT", HDR_EXT},
{"HOST", HDR_HOST},
{"IF-RANGE", HDR_IF_RANGE},
{"LOCATION", HDR_LOCATION},
{"MAN", HDR_MAN},
{"MX", HDR_MX},
{"NT", HDR_NT},
{"NTS", HDR_NTS},
{"RANGE", HDR_RANGE},
{"SEQ", HDR_SEQ},
{"SERVER", HDR_SERVER},
{"SID", HDR_SID},
{"SOAPACTION", HDR_SOAPACTION},
{"ST", HDR_ST},
{"TE", HDR_TE},
{"TIMEOUT", HDR_TIMEOUT},
{"TRANSFER-ENCODING", HDR_TRANSFER_ENCODING},
{"USER-AGENT", HDR_USER_AGENT},
{"USN", HDR_USN}
};
/***********************************************************************/
/************* scanner **************/
/***********************************************************************/
#define TOKCHAR_CR 0xD
#define TOKCHAR_LF 0xA
/************************************************************************
* Function : scanner_init
*
* Parameters :
* OUT scanner_t* scanner ; Scanner Object to be initialized
* IN membuffer* bufptr ; Buffer to be copied
*
* Description : Intialize scanner
*
* Return : void ;
*
* Note :
************************************************************************/
static XINLINE void
scanner_init( OUT scanner_t * scanner,
IN membuffer * bufptr )
{
scanner->cursor = 0;
scanner->msg = bufptr;
scanner->entire_msg_loaded = FALSE;
}
/************************************************************************
* Function : is_separator_char
*
* Parameters :
* IN char c ; character to be tested against used separator values
*
* Description : Finds the separator character.
*
* Return : xboolean ;
*
* Note :
************************************************************************/
static XINLINE xboolean
is_separator_char( IN char c )
{
return strchr( " \t()<>@,;:\\\"/[]?={}", c ) != NULL;
}
/************************************************************************
* Function : is_identifier_char
*
* Parameters :
* IN char c ; character to be tested for separator values
*
* Description : Calls the function to indentify separator character
*
* Return : xboolean ;
*
* Note :
************************************************************************/
static XINLINE xboolean
is_identifier_char( IN char c )
{
return ( c >= 32 && c <= 126 ) && !is_separator_char( c );
}
/************************************************************************
* Function : is_control_char
*
* Parameters :
* IN char c ; character to be tested for a control character
*
* Description : Determines if the passed value is a control character
*
* Return : xboolean ;
*
* Note :
************************************************************************/
static XINLINE xboolean
is_control_char( IN char c )
{
return ( ( c >= 0 && c <= 31 ) || ( c == 127 ) );
}
/************************************************************************
* Function : is_qdtext_char
*
* Parameters :
* IN char cc ; character to be tested for CR/LF
*
* Description : Checks to see if the passed in value is CR/LF
*
* Return : xboolean ;
*
* Note :
************************************************************************/
static XINLINE xboolean
is_qdtext_char( IN char cc )
{
unsigned char c = ( unsigned char )cc;
// we don't check for this; it's checked in get_token()
assert( c != '"' );
if( ( c >= 32 && c != 127 ) ||
( c == TOKCHAR_CR || c == TOKCHAR_LF || c == '\t' )
) {
return TRUE;
} else {
return FALSE;
}
}
/************************************************************************
* Function : scanner_get_token
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
* OUT memptr* token ; Token
* OUT token_type_t* tok_type ; Type of token
*
* Description : reads next token from the input stream
* note: 0 and is used as a marker, and will not be valid in a quote
*
* Return : parse_status_t ;
* PARSE_OK
* PARSE_INCOMPLETE -- not enuf chars to get a token
* PARSE_FAILURE -- bad msg format
*
* Note :
************************************************************************/
static parse_status_t
scanner_get_token( INOUT scanner_t * scanner,
OUT memptr * token,
OUT token_type_t * tok_type )
{
char *cursor;
char *null_terminator; // point to null-terminator in buffer
char c;
token_type_t token_type;
xboolean got_end_quote;
assert( scanner );
assert( token );
assert( tok_type );
// point to next char in buffer
cursor = scanner->msg->buf + scanner->cursor;
null_terminator = scanner->msg->buf + scanner->msg->length;
// not enough chars in input to parse
if( cursor == null_terminator ) {
return PARSE_INCOMPLETE;
}
c = *cursor;
if( is_identifier_char( c ) ) {
// scan identifier
token->buf = cursor++;
token_type = TT_IDENTIFIER;
while( is_identifier_char( *cursor ) ) {
cursor++;
}
if( !scanner->entire_msg_loaded && cursor == null_terminator ) {
// possibly more valid chars
return PARSE_INCOMPLETE;
}
// calc token length
token->length = cursor - token->buf;
} else if( c == ' ' || c == '\t' ) {
token->buf = cursor++;
token_type = TT_WHITESPACE;
while( *cursor == ' ' || *cursor == '\t' ) {
cursor++;
}
if( !scanner->entire_msg_loaded && cursor == null_terminator ) {
// possibly more chars
return PARSE_INCOMPLETE;
}
token->length = cursor - token->buf;
} else if( c == TOKCHAR_CR ) {
// scan CRLF
token->buf = cursor++;
if( cursor == null_terminator ) {
// not enuf info to determine CRLF
return PARSE_INCOMPLETE;
}
if( *cursor != TOKCHAR_LF ) {
// couldn't match CRLF; match as CR
token_type = TT_CTRL; // ctrl char
token->length = 1;
} else {
// got CRLF
token->length = 2;
token_type = TT_CRLF;
cursor++;
}
} else if( c == TOKCHAR_LF ) // accept \n as CRLF
{
token->buf = cursor++;
token->length = 1;
token_type = TT_CRLF;
} else if( c == '"' ) {
// quoted text
token->buf = cursor++;
token_type = TT_QUOTEDSTRING;
got_end_quote = FALSE;
while( cursor < null_terminator ) {
c = *cursor++;
if( c == '"' ) {
got_end_quote = TRUE;
break;
} else if( c == '\\' ) {
if( cursor < null_terminator ) {
c = *cursor++;
//if ( !(c > 0 && c <= 127) )
if( c == 0 ) {
return PARSE_FAILURE;
}
}
// else, while loop handles incomplete buf
} else if( is_qdtext_char( c ) ) {
// just accept char
} else {
// bad quoted text
return PARSE_FAILURE;
}
}
if( got_end_quote ) {
token->length = cursor - token->buf;
} else // incomplete
{
assert( cursor == null_terminator );
return PARSE_INCOMPLETE;
}
} else if( is_separator_char( c ) ) {
// scan separator
token->buf = cursor++;
token_type = TT_SEPARATOR;
token->length = 1;
} else if( is_control_char( c ) ) {
// scan ctrl char
token->buf = cursor++;
token_type = TT_CTRL;
token->length = 1;
} else {
return PARSE_FAILURE;
}
scanner->cursor += token->length; // move to next token
*tok_type = token_type;
return PARSE_OK;
}
/************************************************************************
* Function : scanner_get_str
*
* Parameters :
* IN scanner_t* scanner ; Scanner Object
*
* Description : returns ptr to next char in string
*
* Return : char* ;
*
* Note :
************************************************************************/
static XINLINE char *
scanner_get_str( IN scanner_t * scanner )
{
return scanner->msg->buf + scanner->cursor;
}
/************************************************************************
* Function : scanner_pushback
*
* Parameters :
* INOUT scanner_t* scanner ; Scanner Object
* IN size_t pushback_bytes ; Bytes to be moved back
*
* Description : Move back by a certain number of bytes.
* This is used to put back one or more tokens back into the input
*
* Return : void ;
*
* Note :
************************************************************************/
static XINLINE void
scanner_pushback( INOUT scanner_t * scanner,
IN size_t pushback_bytes )
{
scanner->cursor -= pushback_bytes;
}
/***********************************************************************/
/************* end of scanner **************/
/***********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -