Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
ref_manual:selects [2009/05/05 21:50] andrei note about obsolete way of testing select and some minor updates |
ref_manual:selects [2012/03/15 09:03] 109.230.216.225 FQMiCeqSQnI |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== The Select Framework ====== | + | Hmm it seems like your site ate my first comment |
- | //(written by Michal Matyska)// | + | |
- | + | ||
- | You might ask, why the select framework | + | |
- | was that everytime you wanted to check any part (header, etc.) of the | + | |
- | incomming message you had to write new module/new function which did that. | + | |
- | Moreover this function (due to historic limitations) might get at most two | + | |
- | parameters. If you need more you have to use workaround and set attributes | + | |
- | which are then checked from this function. So to make the route script more | + | |
- | readable and understandable a new element has started to be supported - the | + | |
- | select framework. | + | |
- | + | ||
- | In the script the select is identified by it's unique name. The intention is | + | |
- | to make the identifier as much understandable as possible, | + | |
- | '' | + | |
- | present in the " | + | |
- | script, it is actually its value, which is then used during the route script | + | |
- | process. | + | |
- | + | ||
- | To make the select framework speed efficient, the identifier of the select is | + | |
- | parsed and fixed on the SER startup. If it is not valid select identifier, | + | |
- | error message is dumped and SER does not start at all. But then, during the | + | |
- | request route script execution, there is just single function call invocation, | + | |
- | which gets the parsed select identifier as parameter if it needs it for any | + | |
- | purpose. From the performance point of view there is almost no difference | + | |
- | between calling specialized function from any module | + | |
- | which represents the select identifier. | + | |
- | + | ||
- | ===== Overview of Operation ===== | + | |
- | What we call select is basically unified notation for calling function which | + | |
- | is defined as select function either in SER's core or from any module. The | + | |
- | identifier starts with at sign and consists of few text elements denoted by | + | |
- | dot optionally adding single integer or string parameter enclosed in square | + | |
- | brackets. | + | |
- | + | ||
- | You can use selects in the routing script in the expression evaluation, as | + | |
- | right side of attribute assignment and as parameters in some function calls. | + | |
- | (This is limited to functions which support this and the parameter is actually | + | |
- | text with the select identifier, so it must be enclosed in double quotes.) | + | |
- | Xlog formatting also support selects as a element while composing the final | + | |
- | value - the formatting element is '' | + | |
- | + | ||
- | Return value of the select is text string, | + | |
- | string with 0 length (empty string) if such value is allowed (e.g. some uri | + | |
- | parameter value) or when select function signalizes that expected value was | + | |
- | not found in the header or message parsing encountered syntax error. This kind | + | |
- | of error has influence on the conditional expression - if there is problem | + | |
- | with the select evaluation, the result is false regardless it matches the | + | |
- | empty string. | + | |
- | + | ||
- | ===== Select Identifiers ===== | + | |
- | Select identifier starts with at sign (@) followed by at least one (at most | + | |
- | 30) text elements each separated by dot (.) from the previous one. The | + | |
- | identifier elements are case insensitive, | + | |
- | emphasize some of them, but lower case is preferred. Some of the select | + | |
- | functions accept parameters (like index of the repetead headers, or the header | + | |
- | name or authorization realm) - this parameter is expressed in the identifier | + | |
- | by enclosing it with square brackets. The index starts counting from 1 | + | |
- | (programmers be aware), because it is more natural and you can also express | + | |
- | that you want count the headers in the opposite direction and get the last | + | |
- | header (using -1 as the index). | + | |
- | + | ||
- | Examples of identifiers (syntactically valid): | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | + | ||
- | ===== Nested Selects ===== | + | |
- | You might find some repeating patterns in the SIP requests, like that there is | + | |
- | URI element present in quite a lot of SIP headers. The select framework has | + | |
- | possibility | + | |
- | function already included in the core (or parser of parameter values (either | + | |
- | header or URI), or any other if you are able to think it off) and apply it on | + | |
- | intermediate select result. This so called nested select (see developers' | + | |
- | if you are interested) divides the select call to two (or more) separate | + | |
- | function calls, where the first one returns the URI text as temporary result, | + | |
- | which is then passed to the built-in URI select machinery as the value which | + | |
- | should be used for the final result. | + | |
- | '' | + | |
- | header, assuming it is conforming to the name-addr RFC specification and | + | |
- | passes the header value to the name-addr select-parser, | + | |
- | username from the URI and returns that as the final value of the select. | + | |
- | + | ||
- | So every of these URIs (select' | + | |
- | select, which makes individual URI parts accessible. | + | |
- | + | ||
- | @request_uri, | + | |
- | @rpid.uri, @contact.uri, | + | |
- | @hf_value![" | + | |
- | + | ||
- | Now if you want just the username, append .user to the select identifier and | + | |
- | you get the username. The .user identifier part is everytime same regardless | + | |
- | which URI was selected in the first step. | + | |
- | + | ||
- | Here is the list of all URI's nested select identifiers: | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | + | ||
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | + | ||
- | ===== Selects in Expressions ===== | + | |
- | You can use the select in the conditional expressions like these: | + | |
- | + | ||
- | if (@select.value) {...} | + | |
- | + | ||
- | the test is true, when the select returns NON-EMPTY string. | + | |
- | + | ||
- | < | + | |
- | This way of using select is obsolete and it will generate a warning message on start-up. | + | |
- | For sip-router the if will be true only if it returns a non-empty, non-zero numerical string (e.g. " | + | |
- | The preferred correct ways for sip-router are: | + | |
- | + | ||
- | if (@select.value!="" | + | |
- | + | ||
- | or | + | |
- | + | ||
- | if (!strempty(@select.value)) | + | |
- | + | ||
- | </ | + | |
- | + | ||
- | + | ||
- | if (@select.value==" | + | |
- | if (" | + | |
- | + | ||
- | the result is true, when the select is error-free and its return value is equal to " | + | |
- | Instead of a constant value, you can use any expression (it could involve avps, pvars or other selects). | + | |
- | + | ||
- | if (@select.value!=" | + | |
- | if (" | + | |
- | + | ||
- | in this case the test checks whether the two strings are different. If | + | |
- | there is error during the select evaluation, the result is also false. | + | |
- | + | ||
- | if (@select.value=~" | + | |
- | + | ||
- | true, when the string returned by select function matches the regular | + | |
- | expression. In this case swapping of the left and right values matter, so | + | |
- | + | ||
- | if (" | + | |
- | + | ||
- | is true when the " | + | |
- | obtained as select's return value. This is what you usually don't want. | + | |
- | + | ||
- | You can also use the select in any kind of expression, be it in the right hand of an assignment, in an if, while() or switch(). | + | |
- | + | ||
- | E.g.: | + | |
- | $attribute=@the.select.you.want | + | |
- | + | ||
- | ===== Selects in Parameters ===== | + | |
- | Some functions allow to pass the select' | + | |
- | function must support that, so it is not possible for every function. The | + | |
- | parameter holds the select identifier and the function is responsible to | + | |
- | resolve and fixup the indetifier at SER startup and then call the select | + | |
- | function to obtain the return value. | + | |
- | + | ||
- | If the select' | + | |
- | the function is false and the rest of the function' | + | |
- | over. | + | |
- | + | ||
- | ===== System Selects ===== | + | |
- | As the select framework has begun to show its strength, new ideas whatever | + | |
- | else could be accessible using select call has emerged. The example of that | + | |
- | are system selects which' | + | |
- | + | ||
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | * '' | + | |
- | + | ||
- | ===== Selects in Modules ===== | + | |
- | As you can see, the select framework is very powerfull tool, which can be | + | |
- | easily extended using the SER's modules concept. E.g. the TLS module, there is | + | |
- | lot of TLS information you can get/check in the script, but only when the TLS | + | |
- | module is used. So all the TLS related selects are part of the TLS module... | + | |
- | if you use the module, then they are available, if you don't use the module, | + | |
- | they are not and SER will complain about the wrong select identifier and | + | |
- | decline to start. | + | |
- | + | ||
- | On the other hand, there is no difference between the module' | + | |
- | core's selects, so you don't really need to care where is the source of the | + | |
- | select, just make sure you have loaded all neccessary modules. | + |