📄 sip_parser.c
字号:
pj_list_insert_before(err_list, err_info);
}
if (parsing_headers) {
if (!pj_scan_is_eof(scanner)) {
/* Skip until next line.
* Watch for header continuation.
*/
do {
pj_scan_skip_line(scanner);
} while (IS_SPACE(*scanner->curptr));
}
/* Restore flag. Flag may be set in int_parse_sip_url() */
scanner->skip_ws = PJ_SCAN_AUTOSKIP_WS_HEADER;
/* Continue parse next header, if any. */
if (!pj_scan_is_eof(scanner) && !IS_NEWLINE(*scanner->curptr)) {
goto parse_headers;
}
}
msg = NULL;
}
PJ_END;
return msg;
}
/* Parse parameter (pname ["=" pvalue]). */
static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *pname, pj_str_t *pvalue,
const pj_cis_t *spec, const pj_cis_t *esc_spec,
unsigned option)
{
/* pname */
parser_get_and_unescape(scanner, pool, spec, esc_spec, pname);
/* init pvalue */
pvalue->ptr = NULL;
pvalue->slen = 0;
/* pvalue, if any */
if (*scanner->curptr == '=') {
pj_scan_get_char(scanner);
if (!pj_scan_is_eof(scanner)) {
/* pvalue can be a quoted string. */
if (*scanner->curptr == '"') {
pj_scan_get_quote( scanner, '"', '"', pvalue);
if (option & PJSIP_PARSE_REMOVE_QUOTE) {
pvalue->ptr++;
pvalue->slen -= 2;
}
} else if(pj_cis_match(spec, *scanner->curptr)) {
parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue);
}
}
}
}
/* Parse parameter (pname ["=" pvalue]) using token. */
void pjsip_parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *pname, pj_str_t *pvalue,
unsigned option)
{
parse_param_imp(scanner, pool, pname, pvalue, &pjsip_TOKEN_SPEC,
&pjsip_TOKEN_SPEC_ESC, option);
}
/* Parse parameter (pname ["=" pvalue]) using paramchar. */
void pjsip_parse_uri_param_imp(pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *pname, pj_str_t *pvalue,
unsigned option)
{
parse_param_imp(scanner, pool, pname, pvalue, &pjsip_PARAM_CHAR_SPEC,
&pjsip_PARAM_CHAR_SPEC_ESC, option);
}
/* Parse parameter (";" pname ["=" pvalue]) in header. */
static void int_parse_param( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *pname, pj_str_t *pvalue)
{
/* Get ';' character */
pj_scan_get_char(scanner);
/* Get pname and optionally pvalue */
pjsip_parse_param_imp(scanner, pool, pname, pvalue,
PJSIP_PARSE_REMOVE_QUOTE);
}
/* Parse parameter (";" pname ["=" pvalue]) in URI. */
static void int_parse_uri_param( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *pname, pj_str_t *pvalue)
{
/* Get ';' character */
pj_scan_get_char(scanner);
/* Get pname and optionally pvalue */
pjsip_parse_uri_param_imp(scanner, pool, pname, pvalue,
PJSIP_PARSE_REMOVE_QUOTE);
}
/* Parse header parameter. */
static void int_parse_hparam( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *hname, pj_str_t *hvalue )
{
/* Get '?' or '&' character. */
pj_scan_get_char(scanner);
/* hname */
parser_get_and_unescape(scanner, pool, &pjsip_HDR_CHAR_SPEC,
&pjsip_HDR_CHAR_SPEC_ESC, hname);
/* Init hvalue */
hvalue->ptr = NULL;
hvalue->slen = 0;
/* pvalue, if any */
if (*scanner->curptr == '=') {
pj_scan_get_char(scanner);
if (!pj_scan_is_eof(scanner) &&
pj_cis_match(&pjsip_HDR_CHAR_SPEC, *scanner->curptr))
{
parser_get_and_unescape(scanner, pool, &pjsip_HDR_CHAR_SPEC,
&pjsip_HDR_CHAR_SPEC_ESC, hvalue);
}
}
}
/* Parse host:port in URI. */
static void int_parse_uri_host_port( pj_scanner *scanner,
pj_str_t *host, int *p_port)
{
pj_scan_get( scanner, &pjsip_HOST_SPEC, host);
/* RFC3261 section 19.1.2: host don't need to be unescaped */
if (*scanner->curptr == ':') {
pj_str_t port;
pj_scan_get_char(scanner);
pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port);
*p_port = pj_strtoul(&port);
} else {
*p_port = 0;
}
}
/* Determine if the next token in an URI is a user specification. */
static int int_is_next_user(pj_scanner *scanner)
{
pj_str_t dummy;
int is_user;
/* Find character '@'. If this character exist, then the token
* must be a username.
*/
if (pj_scan_peek( scanner, &pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@')
is_user = 1;
else
is_user = 0;
return is_user;
}
/* Parse user:pass tokens in an URI. */
static void int_parse_user_pass( pj_scanner *scanner, pj_pool_t *pool,
pj_str_t *user, pj_str_t *pass)
{
parser_get_and_unescape(scanner, pool, &pjsip_USER_SPEC,
&pjsip_USER_SPEC_ESC, user);
if ( *scanner->curptr == ':') {
pj_scan_get_char( scanner );
parser_get_and_unescape(scanner, pool, &pjsip_PASSWD_SPEC,
&pjsip_PASSWD_SPEC_ESC, pass);
} else {
pass->ptr = NULL;
pass->slen = 0;
}
/* Get the '@' */
pj_scan_get_char( scanner );
}
/* Parse all types of URI. */
static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *pool,
unsigned opt)
{
pjsip_uri *uri;
int is_name_addr = 0;
/* Exhaust any whitespaces. */
pj_scan_skip_whitespace(scanner);
if (*scanner->curptr=='"' || *scanner->curptr=='<') {
uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
is_name_addr = 1;
} else {
pj_str_t scheme;
int next_ch;
next_ch = pj_scan_peek( scanner, &pjsip_DISPLAY_SPEC, &scheme);
if (next_ch==':') {
pjsip_parse_uri_func *func = find_uri_handler(&scheme);
if (func == NULL) {
/* Unsupported URI scheme */
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
uri = (*func)( scanner, pool,
(opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);
} else {
uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
is_name_addr = 1;
}
}
/* Should we return the URI object as name address? */
if (opt & PJSIP_PARSE_URI_AS_NAMEADDR) {
if (is_name_addr == 0) {
pjsip_name_addr *name_addr;
name_addr = pjsip_name_addr_create(pool);
name_addr->uri = uri;
uri = (pjsip_uri*)name_addr;
}
}
return uri;
}
/* Parse URI. */
static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool,
pj_bool_t parse_params)
{
/* Bug:
* This function should not call back int_parse_name_addr() because
* it is called by that function. This would cause stack overflow
* with PROTOS test #1223.
if (*scanner->curptr=='"' || *scanner->curptr=='<') {
return (pjsip_uri*)int_parse_name_addr( scanner, pool );
} else {
*/
pj_str_t scheme;
int colon;
pjsip_parse_uri_func *func;
/* Get scheme. */
colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme);
if (colon != ':') {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
func = find_uri_handler(&scheme);
if (func) {
return (pjsip_uri*)(*func)(scanner, pool, parse_params);
} else {
/* Unsupported URI scheme */
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
UNREACHED({ return NULL; /* Not reached. */ })
}
/*
}
*/
}
/* Parse "sip:" and "sips:" URI.
* This actually returns (pjsip_sip_uri*) type,
*/
static void* int_parse_sip_url( pj_scanner *scanner,
pj_pool_t *pool,
pj_bool_t parse_params)
{
pj_str_t scheme;
pjsip_sip_uri *url = NULL;
int colon;
int skip_ws = scanner->skip_ws;
scanner->skip_ws = 0;
pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme);
colon = pj_scan_get_char(scanner);
if (colon != ':') {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
url = pjsip_sip_uri_create(pool, 0);
} else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
url = pjsip_sip_uri_create(pool, 1);
} else {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
/* should not reach here */
UNREACHED({
pj_assert(0);
return 0;
})
}
if (int_is_next_user(scanner)) {
int_parse_user_pass(scanner, pool, &url->user, &url->passwd);
}
/* Get host:port */
int_parse_uri_host_port(scanner, &url->host, &url->port);
/* Get URL parameters. */
if (parse_params) {
while (*scanner->curptr == ';' ) {
pj_str_t pname, pvalue;
int_parse_uri_param( scanner, pool, &pname, &pvalue);
if (!parser_stricmp(pname, pjsip_USER_STR) && pvalue.slen) {
url->user_param = pvalue;
} else if (!parser_stricmp(pname, pjsip_METHOD_STR) && pvalue.slen) {
url->method_param = pvalue;
} else if (!parser_stricmp(pname,pjsip_TRANSPORT_STR) && pvalue.slen) {
url->transport_param = pvalue;
} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {
url->ttl_param = pj_strtoul(&pvalue);
} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {
url->maddr_param = pvalue;
} else if (!parser_stricmp(pname, pjsip_LR_STR)) {
url->lr_param = 1;
} else {
pjsip_param *p = pj_pool_alloc(pool, sizeof(pjsip_param));
p->name = pname;
p->value = pvalue;
pj_list_insert_before(&url->other_param, p);
}
}
}
/* Get header params. */
if (parse_params && *scanner->curptr == '?') {
do {
pjsip_param *param;
param = pj_pool_alloc(pool, sizeof(pjsip_param));
int_parse_hparam(scanner, pool, ¶m->name, ¶m->value);
pj_list_insert_before(&url->header_param, param);
} while (*scanner->curptr == '&');
}
scanner->skip_ws = skip_ws;
pj_scan_skip_whitespace(scanner);
return url;
}
/* Parse nameaddr. */
static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner,
pj_pool_t *pool )
{
int has_bracket;
pjsip_name_addr *name_addr;
name_addr = pjsip_name_addr_create(pool);
if (*scanner->curptr == '"') {
pj_scan_get_quote( scanner, '"', '"', &name_addr->display);
/* Trim the leading and ending quote */
name_addr->display.ptr++;
name_addr->display.slen -= 2;
} else if (*scanner->curptr != '<') {
int next;
pj_str_t dummy;
/* This can be either the start of display name,
* the start of URL ("sip:", "sips:", "tel:", etc.), or '<' char.
* We're only interested in display name, because SIP URL
* will be parser later.
*/
next = pj_scan_peek(scanner, &pjsip_DISPLAY_SPEC, &dummy);
if (next == '<') {
/* Ok, this is what we're looking for, a display name. */
pj_scan_get_until_ch( scanner, '<', &name_addr->display);
pj_strtrim(&name_addr->display);
}
}
/* Manually skip whitespace. */
pj_scan_skip_whitespace(scanner);
/* Get the SIP-URL */
has_bracket = (*scanner->curptr == '<');
if (has_bracket)
pj_scan_get_char(scanner);
name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE );
if (has_bracket) {
if (pj_scan_get_char(scanner) != '>')
PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
}
return name_addr;
}
/* Parse SIP request line. */
static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool,
pjsip_request_line *req_line)
{
pj_str_t token;
pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &token);
pjsip_method_init_np( &req_line->method, &token);
req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE);
if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) != 0)
PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
pj_scan_advance_n (scanner, 7, 1);
pj_scan_get_newline( scanner );
}
/* Parse status line. */
static void int_parse_status_line( pj_scanner *scanner,
pjsip_status_line *status_line)
{
pj_str_t token;
if (pj_scan_stricmp_alnum(scanner, PJSIP_VERSION, 7) != 0)
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
pj_scan_advance_n( scanner, 7, 1);
pj_scan_get( scanner, &pjsip_DIGIT_SPEC, &token);
status_line->code = pj_strtoul(&token);
pj_scan_get( scanner, &pjsip_NOT_NEWLINE, &status_line->reason);
pj_scan_get_newline( scanner );
}
/*
* Public API to parse SIP status line.
*/
PJ_DEF(pj_status_t) pjsip_parse_status_line( char *buf, pj_size_t size,
pjsip_status_line *status_line)
{
pj_scanner scanner;
PJ_USE_EXCEPTION;
pj_bzero(status_line, sizeof(*status_line));
pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);
PJ_TRY {
int_parse_status_line(&scanner, status_line);
}
PJ_CATCH_ANY {
/* Tolerate the error if it is caused only by missing newline */
if (status_line->code == 0 && status_line->reason.slen == 0) {
pj_scan_fini(&scanner);
return PJSIP_EINVALIDMSG;
}
}
PJ_END;
pj_scan_fini(&scanner);
return PJ_SUCCESS;
}
/* Parse ending of header. */
static void parse_hdr_end( pj_scanner *scanner )
{
if (pj_scan_is_eof(scanner)) {
; /* Do nothing. */
} else if (*scanner->curptr == '&') {
pj_scan_get_char(scanner);
} else {
pj_scan_get_newline(scanner);
}
}
/* Parse ending of header. */
void pjsip_parse_end_hdr_imp( pj_scanner *scanner )
{
parse_hdr_end(scanner);
}
/* Parse generic array header. */
static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr,
pj_scanner *scanner)
{
/* Some header fields allow empty elements in the value:
* Accept, Allow, Supported
*/
if (*scanner->curptr == '\r' || *scanner->curptr == '\n') {
goto end;
}
pj_scan_get( scanner, &pjsip_NOT_COMMA_OR_NEWLINE, &hdr->values[0]);
hdr->count++;
while (*scanner->curptr == ',') {
pj_scan_get_char(scanner);
pj_scan_get( scanner, &pjsip_NOT_COMMA_OR_NEWLINE,
&hdr->values[hdr->count]);
hdr->count++;
}
end:
parse_hdr_end(scanner);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -