sip_parse_uri.c revision 40cb5e5daa7b80bb70fcf8dadfb20f9281566331
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sip_parse_uri.h"
/*
* SIP-URI = "sip:" [ userinfo ] hostport uri-parameters [ headers ]
* SIPS-URI = "sips:" [ userinfo ] hostport uri-parameters [ headers ]
* userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
* user = 1*( unreserved / escaped / user-unreserved )
* user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
* password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
* hostport = host [ ":" port ]
* host = hostname / IPv4address / IPv6reference
* hostname = *( domainlabel "." ) toplabel [ "." ]
* domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
* toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
* IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
* IPv6reference = "[" IPv6address "]"
* IPv6address = hexpart [ ":" IPv4address ]
* hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
* hexseq = hex4 *( ":" hex4)
* hex4 = 1*4HEXDIG
* port = 1*DIGIT
*
* The BNF for telephone-subscriber can be found in RFC 2806 [9]. Note,
* however, that any characters allowed there that are not allowed in
* the user part of the SIP URI MUST be escaped.
*
* uri-parameters = *( ";" uri-parameter)
* uri-parameter = transport-param / user-param / method-param
* / ttl-param / maddr-param / lr-param / other-param
* transport-param = "transport="( "udp" / "tcp" / "sctp" / "tls"
* / other-transport)
* other-transport = token
* user-param = "user=" ( "phone" / "ip" / other-user)
* other-user = token
* method-param = "method=" Method
* ttl-param = "ttl=" ttl
* maddr-param = "maddr=" host
* lr-param = "lr"
* other-param = pname [ "=" pvalue ]
* pname = 1*paramchar
* pvalue = 1*paramchar
* paramchar = param-unreserved / unreserved / escaped
* param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
* headers = "?" header *( "&" header )
* header = hname "=" hvalue
* hname = 1*( hnv-unreserved / unreserved / escaped )
* hvalue = *( hnv-unreserved / unreserved / escaped )
* hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
*
*/
#define SIP_URI_MSG_BUF_SZ 100
#define SIP_URI_ISHEX(c) \
(((int)(c) >= 0x30 && (int)(c) <= 0x39) || \
((int)(c) >= 0x41 && (int)(c) <= 0x46) || \
((int)(c) >= 0x61 && (int)(c) <= 0x66))
/*
* URL character classes
* mark - _ . ! ~ * ' ()
* reserved ; / ? : @ & = + $ , also [] for IPv6
* unreserved alphanum mark
* pchar : @ & = + $ , unreserved
* userinfo ; : & = + $ , unreserved escaped
* relsegment ; @ & = + $ , unreserved escaped
* reg_name ; : @ & = + $ , unreserved escaped
* token - _ . ! ~ * ' % + `
* param-unreserved [ ] / : + $ &
* hnv-unreserved [ ] / : + $ ?
*/
#define SIP_URI_ALPHA_BIT 0x0001
#define SIP_URI_DIGIT_BIT 0x0002
#define SIP_URI_ALNUM_BITS 0x0003
#define a SIP_URI_ALPHA_BIT
#define d SIP_URI_DIGIT_BIT
#define s SIP_URI_SCHEME_BIT
#define t SIP_URI_TOKEN_BIT
#define q SIP_URI_QUEST_BIT
#define m SIP_URI_AT_BIT
#define c SIP_URI_COLON_BIT
#define i SIP_URI_SEMI_BIT
#define h SIP_URI_DASH_BIT
#define k SIP_URI_MARK_BIT
#define n SIP_URI_AND_BIT
#define o SIP_URI_PHCOMM_BIT
#define r SIP_URI_OTHER_BIT
#define l SIP_URI_SLASH_BIT
#define v SIP_URI_VISUALSEP_BIT
#define f SIP_URI_DTMFURI_DIGIT_BIT
static const unsigned short sip_uri_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, t|k, 0, 0, o|r, t, n, t|k,
k|v, k|v, t|k|f, s|t|r|o, r, h|s|t|k|v, s|t|k|v, o|l,
d, d, d, d, d, d, d, d,
d, d, c|o, i, 0, r, 0, q,
m, a|f, a|f, a|f, a|f, a, a, a,
a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a,
a, a, a, o, 0, o, 0, t|k,
t, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a,
a, a, a, 0, 0, 0, t|k, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
#undef a
#undef d
#undef s
#undef t
#undef q
#undef m
#undef c
#undef i
#undef h
#undef k
#undef n
#undef o
#undef r
#undef l
#undef v
#undef f
#define SIP_URI_UT(c) sip_uri_table[(unsigned char)(c)]
#define SIP_URI_ISSCHEME(c) \
#define SIP_URI_ISTOKEN(c) \
#define SIP_URI_ISSIPDELIM(c) \
#define SIP_URI_ISSIPHDELIM(c) \
#define SIP_URI_ISHOST(c) \
#define SIP_URI_ISUSER(c) \
#define SIP_URI_ISABSHDELIM(c) \
(SIP_URI_UT(c) & \
#define SIP_URI_ISABSDELIM(c) \
#define SIP_URI_ISUNRESERVED(c) \
#define SIP_URI_ISPARAM(c) \
#define SIP_URI_ISHEADER(c) \
#define SIP_URI_ISRESERVED(c) \
#define SIP_URI_ISPCHAR(c) \
#define SIP_URI_ISREGNAME(c) \
(SIP_URI_UT(c) & \
#define SIP_URI_ISPHONEDIGIT(c) \
static int sip_uri_url_casecmp(const char *, const char *, unsigned);
static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
static int sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
static int sip_uri_parse_ipv6(char *, char *);
static int sip_uri_parse_ipv4(char *, char *);
static int sip_uri_parse_hostname(char *, char *);
static int sip_uri_parse_tel(char *, char *);
static int sip_uri_parse_tel_areaspe(char *, char *);
static int sip_uri_parse_tel_servicepro(char *, char *);
static int sip_uri_parse_tel_futureext(char *, char *);
static int sip_uri_isTokenchar(char **, char *);
static int sip_uri_isEscapedPound(char **, char *);
static int sip_uri_hexVal(char *, char *);
static int SIP_URI_HEXVAL(int);
/*
* get the hex value of a char
*/
static int
SIP_URI_HEXVAL(int c)
{
if (c >= 0x30 && c <= 0x39)
return (c - '0');
if (c >= 0x41 && c <= 0x46)
return (c - 'A' + 10);
if (c >= 0x61 && c <= 0x66)
return (c - 'a' + 10);
return (c);
}
/*
* basic ASCII case-insensitive comparison
*/
static int
{
unsigned j;
str1[j] != '\0'; ++j) {
;
}
}
/*
* telephone-subscriber = global-phone-number / local-phone-number
* Please refer to RFC 2806
*/
static int
{
char *mark = (char *)0;
int ret = 0;
int isGlobal = 0;
int quote = 0;
return (0);
if (*scan == '+') {
++scan;
isGlobal = 1;
}
if (isGlobal) {
++scan;
} else {
(SIP_URI_ISPHONEDIGIT(*scan) ||
SIP_URI_ISDTMFDIGIT(*scan) ||
++scan;
}
}
return (0);
/*
* parse isdn-subaddress
*/
scan += 6;
++scan;
return (0);
}
/*
* parse post-dial
*/
scan += 7;
(SIP_URI_ISPHONEDIGIT(*scan) ||
SIP_URI_ISDTMFDIGIT(*scan) ||
++scan;
}
return (0);
}
if (!isGlobal) {
/*
* parse area-specifier
*/
scan += 15;
++scan;
}
} else {
ret = 1;
}
/*
* parse area-specifier, service-provider, future-extension
*/
scan += 15;
++scan;
scan += 5;
++scan;
} else {
++scan;
scan += 3;
} else {
++scan;
}
}
}
}
}
/*
* area-specifier = ";" phone-context-tag "=" phone-context-ident
* phone-context-tag = "phone-context"
* phone-context-ident = network-prefix / private-prefix
* network-prefix = global-network-prefix / local-network-prefix
* global-network-prefix = "+" 1*phonedigit
* local-network-prefix = 1*(phonedigit / dtmf-digit / pause-character)
* private-prefix = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
* %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
* %x65-6F / %x71-76 / %x78-7E)
* *(%x21-3A / %x3C-7E)
* phonedigit = DIGIT / visual-separator
* visual-separator = "-" / "." / "(" / ")"
* pause-character = one-second-pause / wait-for-dial-tone
* one-second-pause = "p"
* wait-for-dial-tone = "w"
* dtmf-digit = "*" / "#" / "A" / "B" / "C" / "D"
*/
static int
{
int uri_hexValue;
return (0);
/*
* parse global-network-prefix
*/
if (*scan == '+') {
++scan;
return (0);
++scan;
/*
* parse local-network-prefix
*/
++scan;
(SIP_URI_ISPHONEDIGIT(*scan) ||
SIP_URI_ISDTMFDIGIT(*scan) ||
++scan;
}
} else {
/*
* parse private-prefix
*
* any characters allowed in RFC 2806 that are not allowed in
* the user part of the SIP URI MUST be escaped
*
* private-prefix = (! $ & ', / = ? _
* EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
* { } | ~ [ ] \ ^ ` " % : < > @)
* *(%x21-3A / %x3C-7E)
*
* following characters are allowed in RFC 2806 and
* the user part of SIP URI
* ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
*/
++scan;
} else {
uri_hexValue == 0x3a ||
scan += 3;
} else {
return (0);
}
}
/*
* parse *(%x21-3A / %x3C-7E)
*/
if (SIP_URI_ISUNRESERVED(*scan) ||
++scan;
} else {
if (uri_hexValue >= 0x21 &&
uri_hexValue <= 0x7e &&
uri_hexValue != 0x3b) {
scan += 3;
} else {
return (0);
}
}
}
}
return (0);
return (1);
}
static int
{
int ret = -1;
}
return (ret);
}
/*
* service-provider = ";" provider-tag "=" provider-hostname
* provider-tag = "tsp"
* provider-hostname = domain
*/
static int
{
char *mark = (char *)0;
return (0);
/*
* parse domain=" "
*/
return (1);
++scan;
return (0);
}
++scan;
}
return (0);
return (1);
}
/*
* future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
* ["?" 1*(token-char)]) / quoted-string )]
* token-char = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
* / %x41-5A / %x5E-7A / %x7C / %x7E)
*/
static int
{
char *mark;
int uri_hexValue = 0;
return (0);
/*
* parse 1*(token-char)
*/
;
return (0);
}
return (1);
++scan;
/*
* parse 1*token-char ["?" 1*token-char]
*/
;
if (*scan != '?')
return (0);
++scan;
;
return (0);
}
} else { /* parse quoted-string */
if (uri_hexValue != 0x22)
return (0);
scan += 3;
/*
* parse "\" CHAR
*/
scan += 3;
if (SIP_URI_ISUNRESERVED(*scan) ||
SIP_URI_ISUSER(*scan)) {
++scan;
0x00 &&
0x7f) {
scan += 3;
} else {
return (0);
}
} else {
return (0);
}
} else {
if (SIP_URI_ISUNRESERVED(*scan) ||
SIP_URI_ISUSER(*scan)) {
++scan;
} else {
if ((uri_hexValue >= 0x20 &&
uri_hexValue <= 0x21) ||
(uri_hexValue >= 0x23 &&
uri_hexValue <= 0x7e) ||
(uri_hexValue >= 0x80 &&
uri_hexValue <= 0xff)) {
scan += 3;
} else {
return (0);
}
}
}
}
return (0);
}
scan += 3;
}
return (0);
return (1);
}
/*
* Any characters allowed in RFC2806 tel URL that are not allowed in
* the user part of the SIP URI MUST be escaped.
* token-char = - _ . ! ~ * ' $ & + DIGIT ALPHA # % ^ ` |
*/
static int
{
int uri_hexValue = 0;
return (0);
/*
* for ALPAH DIGIT - _ . ! ~ * ' $ & +
*/
++scan;
return (1);
}
uri_hexValue == 0x7e ||
scan += 3;
return (1);
}
return (0);
}
/*
* '#' is not allowed in the telephone-subscriber part of SIP URI
* it must be escaped
*/
static int
{
return (0);
scan += 2;
return (1);
}
return (0);
}
/*
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
*/
static int
{
return (0);
}
++scan;
++scan;
}
return (1);
}
/*
* The format of params is supposed to be;XXX;XXX;XXX
* uri-parameters = *(";" uri-parameter)
* uri-parameter = transport-param / user-param / method-param
* / ttl-param / maddr-param / lr-param / other-param
* transport-param = "transport="
* ("udp" / "tcp" / "sctp" / "tls" / other-transport)
* other-transport = token
* user-param = "user=" ("phone" / "ip" / other-user)
* other-user = token
* method-param = "method=" Method
* ttl-param = "ttl=" ttl
* maddr-param = "maddr=" host
* lr-param = "lr"
* other-param = pname [ "=" pvalue ]
* pname = 1*paramchar
* pvalue = 1*paramchar
* paramchar = param-unreserved / unreserved / escaped
* param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
*/
static void
{
char *mark = (char *)0;
char *equal = (char *)0;
int i = 0;
int ttl = 0;
int paramleftlen = 0;
int gothost = 0;
return;
}
++scan;
return;
}
return;
}
else
if (equal == (char *)0) {
++mark;
}
} else {
return;
}
if ((paramleftlen == 10 &&
(paramleftlen == 5 &&
(paramleftlen == 7 &&
return;
}
++mark;
} else if (paramleftlen == 4 &&
return;
}
for (i = 0; i < 3; ++i) {
++mark;
SIP_URI_ISDIGIT(*mark)) {
}
if (ttl > 255) {
return;
}
}
} else if (paramleftlen == 6 &&
gothost = 0;
scan);
}
/*
* not valid syntax for a host or user name,
* try IPv6 literal
*/
scan);
}
/*
* look for a valid host name:
* *(domainlabel ".") toplabel ["."]
*/
if (!(gothost =
scan))) {
}
}
if (gothost)
} else if (paramleftlen == 3 &&
return;
} else {
++mark;
}
}
}
return;
}
}
}
/*
* The format of headers is supposed to be ?XXX&XXX&XXX
* headers = "?" header *("&" header
* header = hname "=" hvalue
* hname = 1*(hnv-unreserved / unreserved / escaped
* hvalue = *(hnv-unreserved / unreserved / escaped
* hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
*/
static void
{
return;
}
++scan;
return;
}
return;
}
(SIP_URI_ISHEADER(*mark) ||
++mark;
}
return;
}
}
}
/*
* opaque-part = uric-no-slash *uric
* uric = reserved / unreserved / escaped
* uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
* / "&" / "=" / "+" / "$" / ","
*/
static void
{
return;
}
++scan;
} else {
return;
}
++scan;
}
}
/*
* format of query is supposed to be ?XXX
* query = *uric
* uric = reserved / unreserved / escaped
*/
static void
{
return;
++scan;
++scan;
}
}
/*
* abs-path = "/" path-segments
* path-segments = segment *( "/" segment )
* segment = *pchar *( ";" param )
* param = *pchar
* pchar = unreserved / escaped /
* ":" / "@" / "&" / "=" / "+" / "$" / ","
*/
static void
{
return;
++scan;
++scan;
}
}
/*
* reg-name = 1*( unreserved / escaped / "$" / "," / ";"
* / ":" / "@" / "&" / "=" / "+" )
*/
static void
{
return;
++scan;
}
}
/*
* The format of the password is supposed to be :XXX
* password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
*/
static void
{
return;
++scan;
*scan == '&')) {
++scan;
}
}
/*
* user = 1*( unreserved / escaped / user-unreserved )
* user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
*/
static void
{
return;
}
} else {
++scan;
}
}
}
/*
* the format of port is supposed to be :XXX
* port = 1*DIGIT
*/
static void
{
return;
}
++scan;
/*
* parse numeric port number
*/
if (SIP_URI_ISDIGIT(*scan)) {
outurl->sip_uri_port = 0;
break;
}
}
}
outurl->sip_uri_port = 0;
}
}
/*
* parse an IPv4 address
* 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
* advances pscan to end of IPv4 address, or after last "." that was
* a valid IPv4 or domain name.
* returns 1 if ipv4 found, 0 otherwise
*/
static int
{
int j = 0;
int val = 0;
for (j = 0; j < 4; ++j) {
if (!SIP_URI_ISDIGIT(*scan))
break;
if (val > 255)
return (0);
}
if (j < 3) {
if (*scan != '.')
break;
++scan;
}
}
return (1);
return (0);
}
/*
* parse an IPv6 address
* IPv6address = hexpart [ ":" IPv4address ]
* IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
* hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
* hexseq = hex4 *( ":" hex4)
* hex4 = 1*4HEXDIG
* if not found, leaves pscan unchanged, otherwise advances to end
* returns 1 if valid,
* 0 if invalid
*/
static int
{
char *mark;
unsigned j = 0; /* index for addr */
unsigned val = 0; /* hex value */
int zpad = 0; /* index of :: delimiter */
if (*scan != '[')
return (0);
++scan;
j = 0;
/*
* check for leading "::", set zpad to the position of the "::"
*/
zpad = 0;
scan += 2;
} else {
zpad = -1;
}
/*
* loop through up to 16 bytes of IPv6 address
*/
if (!SIP_URI_ISHEX(*scan))
break;
if (val > 0xffff)
return (0);
}
/*
* always require a delimiter or ]
*/
return (0);
j += 4;
break;
}
/*
* set address
*/
j += 2;
/*
* check for delimiter or ]
*/
if (*scan == ':') {
/*
* found ":" delimiter, check for "::"
*/
if (zpad != -1)
return (0);
zpad = j;
++scan;
break;
}
}
++scan;
break;
} else {
/*
* not a valid delimiter
*/
return (0);
}
}
return (0);
if (zpad != -1) {
if (j > 15)
return (0);
}
return (1);
return (0);
}
/*
* hostname = *( domainlabel "." ) toplabel [ "." ]
* domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
* toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
*/
static int
{
int sawalpha = 0;
do {
while (SIP_URI_ISHOST(*scan))
++scan;
if (*scan != '.')
break;
++scan;
}
return (1);
return (0);
}
/*
* parse the network path portion of a full URL
*/
static void
{
char *mark = (char *)0;
char *mark2 = (char *)0;
int gothost = 0;
/*
* look for the first high-level delimiter
*/
++scan;
/*
* handle userinfo section of URL
*/
/*
* parse user
*/
++mark;
/*
* parse password
*/
if (*mark == ':')
}
++scan;
++scan;
gothost = 1;
}
} else {
++scan;
}
/*
* look for an IPv4 address
*/
gothost = 1;
}
/*
* look for a valid host name
*/
gothost = 1;
}
}
/*
* handle invalid host name
*/
if (!gothost)
/*
* save host name
*/
/*
* parse the port number
*/
++scan;
}
}
/*
* set return pointer
*/
}
/*
* parse a URL
* URL = SIP-URI / SIPS-URI / absoluteURI
*/
void
{
char *mark;
char *scan;
char *uend;
/*
* reset output parameters
*/
/*
* strip enclosing angle brackets
*/
urlen -= 2;
++str;
}
/*
* strip off space prefix and trailing spaces
*/
++str;
--urlen;
}
--uend;
--urlen;
}
/*
* strip off "URL:" prefix
*/
str += 4;
urlen -= 4;
}
/*
* parse the scheme name
*/
++scan;
return;
}
SIP_SCHEME_LEN)) ||
SIPS_SCHEME_LEN))) {
} else {
}
++scan; /* skip ':' */
if (outurl->sip_uri_issip) {
/*
* parse SIP URL
*/
/*
* parse parameters
*/
++scan;
}
/*
* parse headers
*/
++scan;
/*
* parse authority
* authority = srvr / reg-name
* srvr = [ [ userinfo "@" ] hostport ]
* reg-name = 1*(unreserved / escaped / "$" / ","
* / ";" / ":" / "@" / "&" / "=" / "+")
*/
++scan;
/*
* take authority as srvr
*/
/*
* if srvr failed, take it as reg-name
* parse reg-name
*/
*scan != '?') {
++scan;
}
if (!(outurl->sip_uri_errflags &
/*
* remove error info of user,
* password, host, port
*/
NULL;
0;
outurl->sip_uri_port = 0;
}
}
} else {
/*
* there is no net-path
*/
--scan;
}
/*
* parse abs-path
*/
++scan;
}
/*
* parse query
*/
} else {
/*
* parse opaque-part
*/
}
}