脚本转换
前言
Transformation一般用于变量(脚本变量,伪变量,AVPS,静态字符串)的函数,以获取特定值,原始变量的值不受影响。
在opensips脚本中使用不同变量的示例如下
# check if username in From header is equal with username in To header
if($fU==$tU) {
...
}
# r-uri username based processing
switch($ruri.user) {
case "1234":
...
break;
case "5678":
...
break;
default:
...
}
# assign integer value to an AVP
$avp(i:11) = 1;
#assing string value to an AVP
$avp(i:22) = "opensips";
# write ruri in an AVP
$avp(i:33) = $ruri;
# concat "sip:" + From username + "@" + To domain in a script variable x
$var(x) = "sip:" + $fU +"@" + $td;
transformations旨在便于访问变量的不同属性(字符串长度,变量的一部分,子串)或者变量的不同值(hexa,md5编码,db操作的escape/unescape)。
transformation在’{‘和’}‘直接,后面跟变量名。当使用transformations时,变量名和transformations必须包含在’(‘和’)'中间;
使用用例
# the length of From URI ($fu is pseudo-variable for From URI)
$(fu{s.len})
对于一个变量可以同时使用多个transformations。
# the length of escaped 'Test' header body
$(hdr(Test){s.escape.common}{s.len})
返回字符串的所有transformations在错误或操作失败的情况下返回空字符串(例如URI的一个不存在的参数"{uri.param,name}")。
transformations可以在任何地方使用,作为脚本变量支持的一部分。在xlog, avpops或者其他模块的函数和参数中,在右侧赋值表达式中或在比较表达式中。
提醒:为了学习在transformation中使用的变量请查看Scripting variables list.
字符串转换
这些transformation的名字以’s’开始。可以对变零进行各种字符串操作。
可用的字符串如下:
{s.len}
返回变量值的长度
$var(x) = "abc";
if($(var(x){s.len}) == 3)
{
...
}
{s.int}
转化给定字符串的初始部分转化为整数。如果没有数字返回0。
$var(dur) = "2868.12 sec";
if ($(var(dur){s.int}) < 3600) {
...
}
{s.md5}
返回变量值的md5
xlog("MD4 over From username: $(fU{s.md5})");
{s.substr,offset,length}
返回字符串从’offset’开始’length’个字符的子串。如果offset是负数,那么从字符串结尾开始计数:-1是最后一个字符。如果是正数,0是第一个字符。length必须是正数:当取值为0时,返回到结尾的所有字符。offset和length也可以是变量。
使用用例
$var(x) = "abcd";
$(var(x){s.substr,1,0}) = "bcd"
{s.select,index,separator}
返回变量值的一个域。该域基于separator和index.separator用于标识域。index必须为整数或者一个变量。如果Index是负数,域即计数从结尾开始:-1指最后一个域。如果index是正数,0指代第一个域。
使用用例
$var(x) = "12,34,56";
$(var(x){s.select,1,,}) => "34" ;
$var(x) = "12,34,56";
$(var(x){s.select,-2,,}) => "34"
{s.encode.hexa}
返回变量值的hexa编码。
{s.decode.hexa}
返回变量值的hexa解码
{s.escape.common}
返回变量值的转义字符串。转义的字符串有 ’ , " 和 0.在数据库查询时非常有用(应该注意非拉丁字符集)。
{s.unescape.common}
返回变量值的非转义字符串。
{s.escape.user}
返回变量值的转义字符串。将符合RFC要求的SIP URI的user部分中不允许的字符更改为’%hexa’。
{s.unescape.user}
返回变量值的非转义字符串。将’%hexa’更改为字符码。和上面的transformation相反。
{s.escape.param}
返回变量值的转移字符串。将符合RFC要求的SIP URI的param部分中不允许的字符更改为’%hexa’。
{s.unescape.param}
返回变量值的非转义字符串。将’%hexa’更改为字符码。和上面的transformation相反。
{s.tolower}
返回小写ASCII字母的字符串。
{s.toupper}
返回大写ASCII字母的字符串。
{s.index}
从另一个字符串开始位置搜索该字符串。如果发现返回字符串的开始index,如果没有发现返回-1。变量index指定开始搜索的起始位置。支持负数并将wrap。
$var(strtosearch) = 'onetwothreeone';
$var(str) = 'one';
# Search the string starting at 0 index
$(var(strtosearch){s.index, $var(str)}) # will return 0
$(var(strtosearch){s.index, $var(str), 0}) # Same as above
$(var(strtosearch){s.index, $var(str), 3}) # returns 11
# Negative offset
$(var(strtosearch){s.index, $var(str), -11}) # Same as above
# Negative wrapping offset
$(var(strtosearch){s.index, $var(str), -25}) # Same as above
#Test for existence of string in another
if ($(var(strtosearch){s.index, $var(str)}) >=0)
xlog("found $var(sstr) in $var(strtosearch)");
{s.rindex}
从另一个字符串的结尾开始搜索一个字符。如果找到返回字符串的开始位置,如果没有找到返回-1.参数index指定了开始搜索的偏移位置。发现的字符串的位置要在提供的offset之前。支持负数并且将wrap。
$(var(strtosearch){s.rindex, $var(str)}) # will return 11
$(var(strtosearch){s.rindex, $var(str), -3}) # will return 11
$(var(strtosearch){s.rindex, $var(str), 11}) # will return 11
$(var(strtosearch){s.rindex, $var(str), -4}) # will return 0
{s.fill.left, tok, len}
使用字符或者字符串向左填充字符串,直到达到给定的最终长度。如果初始字符串的长度大于或者等于给定的最终长度,则返回该字符串。
$var(in) = "485"; (also works for integer PVs)
$(var(in){s.fill.left, 0, 3}) => 485
$(var(in){s.fill.left, 0, 6}) => 000485
$(var(in){s.fill.left, abc, 8}) => bcabc485
为优化速度,不支持与变量参数或者连续的"s.fill"级联。
{s.fill.right, tok, len}
使用字符或者字符串向右填充字符串。如果字符串的长度大于或者等于给定的最终长度直接返回原始字符串。
$var(in) = 485; (also works for string PVs)
$(var(in){s.fill.right, 0, 3}) => 485
$(var(in){s.fill.right, 0, 6}) => 485000
$(var(in){s.fill.right, abc, 8}) => 485abcab
{s.width, len}
截取或者扩展输入到指定长度len。扩展通过使用空格’ '向右扩展实现。截取同样的从右边开始。
示例:
$var(in) = "transformation";
$(var(in){s.width, 14}) => "transformation"
$(var(in){s.width, 16}) => "transformation "
$(var(in){s.width, 9}) => "transform"
{s.trim}
从输入字符串中删除任何前导或者尾随的空格。清理的字符包括 " "(空格), \t (tab), \n (new line) 和 \r(回车符号)。
$var(in) = "\t \n input string \r ";
$(var(in){s.trim}) => "input string"
{s.trimr}
从输入字符串中删除任何尾随的空格。清理的字符包括 " "(空格), \t (tab), \n (new line) 和 \r(回车符号)。
$var(in) = "\t \n input string \r ";
$(var(in){s.trimr}) => "\t \n input string"
{s.triml}
从输入字符串中删除任何前导的空格。清理的字符包括 " "(空格), \t (tab), \n (new line) 和 \r(回车符号)。
$var(in) = "\t \n input string \r ";
$(var(in){s.triml}) => "input string \r "
{s.dec2hex}
将十进制(基数10)转化为十六进制(基数16),表示为字符串。
{s.hex2dec}
将十六进制(基数16)转化为十进制(基数10)。
{s.b64encode}
表示ASCII字符串格式的二进制输入数据。
$var(in) = "\x2\x3\x4\x5!@#%^&*";
$(var(in){s.b64encode}) => "AgMEBSFAIyVeJio="
{s.b64decode}
假设输入是Base64字符串并且家吗尽可能多的字符。
$var(in) = "AgMEBSFAIyVeJio=";
$(var(in){s.b64decode}) => "\x2\x3\x4\x5!@#%^&*"
{s.xor,secret}
根据两个字符串的长度,对’secret’字符串参数和输入字符串的执行一个或多个逻辑XOR操作。
$var(in) = "aaaaaabbbbbb";
$(var(in){s.xor,x}) => "!/>^P!/>^P!^U2^Q!^U2^Q"
URI转换
transformation的名字以’uri.'开始。变量的值视为SIP URI。trnasformation返回SIP URI的一部分(see struct sip_uri)。如果那部分不存在,则返回空串。
struct sip_uri {
str user; /* Username */
str passwd; /* Password */
str host; /* Host name */
str port; /* Port number */
str params; /* Parameters */
str headers;
unsigned short port_no;
unsigned short proto; /* from transport */
uri_type type; /* uri scheme */
/* parameters */
str transport;
str ttl;
str user_param;
str maddr;
str method;
str lr;
str r2; /* ser specific rr parameter */
str gr; /* GRUU */
/* values */
str transport_val;
str ttl_val;
str user_param_val;
str maddr_val;
str method_val;
str lr_val; /* lr value placeholder for lr=on a.s.o*/
str r2_val;
str gr_val;
/* unknown params */
str u_name[URI_MAX_U_PARAMS]; /* Unknown param names */
str u_val[URI_MAX_U_PARAMS]; /* Unknown param valss */
unsigned short u_params_no; /* No of unknown params */
};
可用的transformation如下:
{uri.user}
返回URI模式的user部分。
{uri.host}
(类似于 {uri.domain})
返回URI模式的domain部分。
{uri.passwd}
返回URI模式的password部分。
{uri.port}
返回URI模式的port部分。
{uri.params}
以字符串形式返回所有URI的parameter
{uri.param,name}
返回名称为"name"的parameter的值。
{uri.headers}
返回URI headers.
{uri.transport}
返回transport URI参数的值。
{uri.ttl}
返回ttl URI参数的值。
{uri.uparam}
返回user URI参数的值。
{uri.maddr}
返回maddr URI参数的值。
{uri.method}
返回method URI参数的值。
{uri.lr}
返回lr URI参数的值
{uri.r2}
返回r2 URI参数的值
{uri.schema}
返回给定URI的schema部分。
VIA transformations
这些transformations用于解析Via header并且全部以’via.'开始。变量的值被认为是SIP Via header。transformation返回via header的部分信息(see struct via_body)。如果没有找到请求的部分,返回空串。如果持有的Via header不存在,则transformation将失败(with script error)。除非在下面的描述中特殊说明,否则transform返回字符串(不是整数)。
/* Format: name/version/transport host:port;params comment */
/* WARNING: keep in sync with tm/sip_msg.c via_body_cloner */
struct via_body {
int error;
str hdr; /* Contains "Via" or "v" */
str name;
str version;
str transport;
str host;
unsigned short proto; /* transport */
unsigned short port;
str port_str;
str params;
str comment;
unsigned int bsize; /* body size, not including hdr */
struct via_param* param_lst; /* list of parameters*/
struct via_param* last_param; /*last via parameter, internal use*/
/* shortcuts to "important" params*/
struct via_param* branch;
str tid; /* transaction id, part of branch */
struct via_param* received;
struct via_param* rport;
struct via_param* i;
struct via_param* alias; /* alias see draft-ietf-sip-connect-reuse-00 */
struct via_param* maddr;
struct via_body* next; /* pointer to next via body string if
compact via or null */
};
示例:
$var(upstreamtransport) = $(hdr(Via)[1]{via.transport}{s.tolower});
$var(upstreamip) = $(hdr(Via)[1]{via.param,received});
$var(clientport) = $(hdr(Via)[-1]{via.param,rport});
可用的transformations如下:
{via.name}
返回协议名称(RFC3261 BNF),通常是SIP。
{via.version}
返回协议版本号(RFC3261 BNF),通常是2.0。
{via.transport}
返回传输协议(RFC3261 BNF),如UDP,TCP,TLS。指用于发送请求信息的传输协议。
{via.host}
(类似于{via.domain})
返回send-by(RFC3261 BNF)的host部分。一般是请求消息发送方的IP地址,也是相应发送到的地址。
{via.port}
返回send-by(RFC3261 BNF)的port部分。一般是请求消息发送方的端口,也是相应发送到的地址。transform的接口可以是integer或者string。
{via.comment}
与via header关联的comment。结构体via_body包含此字段,但是不清楚RFC3261是否允许Via头具有comment(请参阅221页,BNF没有明确是否在Via允许comment)。comment是在parens中包含的文本。
{via.params}
返回所有的Via headers parameters(RFC3261的via-param)。返回结果可以使用’{param.*}'转换。这基本上是host和port之后的所有内容。
{via.param,name}
返回名称为name的Via header参数的值。典型参数包含branch,rport和received。
{via.branch}
返回VIA header的branch参数的值。
{via.received}
返回VIA header的received参数的值。
{via.rport}
返回VIA header的rport参数的值。
Parameters List Transformations
transformation的名字以’param.'开始。变量的值是类似"name1=value1;name2=value2;…"的字符串。transformations返回特定参数的值,或者指定位置参数的名字。
可用transformations如下
{param.value,name}
返回参数name的值。
示例
"a=1;b=2;c=3"{param.value,c} = "3"
'name’可以是变量。
{param.exist,name}
如果参数名字(不论是否有值)存在返回1,否则返回0。返回值可以是integer或者string。name可以是变量。可以用于检查没有只的参数的存在。
示例
"a=0;b=2;ob;c=3"{param.exist,ob}; # returns 1
"a=0;b=2;ob;c=3"{param.exist,a}; # returns 1
"a=0;b=2;ob;c=3"{param.exist,foo}; # returns 0
{param.valueat,index}
返回’index’指定位置参数值(从0开始)。
示例
"a=1;b=2;c=3"{param.valueat,1} = "2"
{param.name,index}
返回’index’指定位置参数名。
"a=1;b=2;c=3"{param.name,1} = "b"
{param.count}
返回列表中参数的个数。
"a=1;b=2;c=3"{param.count} = 3
Name-address Transformations
transformation名称以’nameaddr.‘开始。变量值为类似’[display_name] uri’的字符串。transformations返回特定域的值。
可用的transformations如下:
{nameaddr.name}
返回display name的值。
示例
'"test" <sip:test@opensips.org>' {nameaddr.name} = "test"
{nameaddr.uri}
返回URI的值
示例
'"test" <sip:test@opensips.org>' {nameaddr.uri} = sip:test@opensips.org
{nameaddr.len}
返回name-addr部分的长度。
{nameaddr.param,param_name}
返回名称为param_name的参数的值。
示例:
'"test" <sip:test@opensips.org>;tag=dat43h' {nameaddr.param,tag} = dat43h
{nameaddr.params}
返回所有参数对应的值。
IP Transformations
transformation的名字以’ip.'开始。此类中可用的transformations:
{ip.pton}
返回标识IP字符串的二进制表示形式。示例:
"192.268.2.234" {ip.pton} returns a 4 byte binary representation of the IP provided
{ip.ntop}
返回提供的二进制ip的字符串表示。示例:
"192.268.2.234"{ip.pton}{ip.ntop} = "192.268.2.234"
{ip.isip}
判断字符串是否是IP,是返回1否则0.示例:
"192.268.2.234" {ip.isip} = 1
"192.268.2.234.1" {ip.isip} = 0
{ip.family}
如果提供的二进制IP位IPV4或者IPB6,相应返回INET或INET6。示例:
"192.268.2.234" {ip.pton}{ip.family} = "INET"
{ip.resolve}
返回根据提供的字符串域解析的IP地址。如果提供的是字符串IP,则transformation对字符串无影响。示例:
"opensips.org" {ip.resolve} = "78.46.64.50"
CSV Transformations
transformation的名称以’csv.'开始。变量值假定为类似"field1,field2,…"的字符串。transformation返回提供的csv的实体的个数,或者csv特定位置的字段。
此类中可用的transformation如下:
{csv.count}
返回提供的CSV的条目数。示例:
"a,b,c" {csv.count} = 3
{csv.value}
返回csv特定位置的字段,计数从0开始。示例:
"a,b,c" {csv.value,2} = c
SDP Transformations
transformation的名字以"sdp."开始。变量值假定为有效的sdp body。transformation返回sdp body的特定行。
此类中可用的transformation如下
{sdp.line}
返回sdp body的特定行。这个参数也接受第二个参数:指定从sdp body中获取的第一个参数类型的行号,索引从0开始。
示例:
if (is_method("INVITE"))
{
$var(aline) = $(rb{sdp.line,a,1});
xlog("The second a line in the SDP body is $var(aline)\n");
}
if (is_method("INVITE"))
{
$var(mline) = $(rb{sdp.line,m});
xlog("The first m line in the SDP body is $var(mline)\n");
}
Regular Expression Transformations
transformation的名字一般以"re."开始。输入可以是任何字符串。
{re.subst,reg_exp}
reg_exp可以是普通字符串或者变量。reg_exp的格式如下:
/posix_match_expression/replacement_expression/flags
flag可以是
- i - 匹配忽略大小写。
- s - 在多行字符串匹配
- g - 替换所有匹配项
示例
$var(reg_input)="abc";
$var(reg) = "/a/A/g";
xlog("Applying reg exp $var(reg) to $var(reg_input) : $(var(reg_input){re.subst,$var(reg)})\n");
...
...
xlog("Applying reg /b/B/g to $var(reg_input) : $(var(reg_input){re.subst,/b/B/g})\n");
Examples
- parameter在位置1对应值的长度(0是第一个位置,1是第二个位置)。
$var(x) = "a=1;b=22;c=333";
$(var(x){param.value,$(var(x){param.name,1})}{s.len}) = 2
- 判断是否未注册状态
if(is_method("REGISTER") && is_present_hf("Expires") && $(hdr(Expires){s.int})==0)
xlog("This is an un-registration");