Session Groups and Classification
ESB3024 Router provides a flexible classification engine, allowing the assignment of clients into session groups that can then be used to base routing decisions on.
Session Classification
In order to perform routing it is necessary to classify incoming sessions according to the relevant parameters. This is done through session groups and their associated classifiers.
There are different ways of classifying a request:
Anonymous IP: Classifies clients using an anonymous IP database. See Geographic Databases for information about the database.ASN IDs: Checks to see if a client’s IP belongs to any of the specified ASN IDs. See Geographic Databases for information about the ASN database.Content URL path: Matches the given pattern against the path part of the URL requested by the client. The match can be either a case-insensitive wildcard match or a regular expression match.Content URL query parameters: Matches the given pattern against the query parameters of the URL requested by the client. The query parameters are passed as a single string. The match can be either a case-insensitive wildcard match or a regular expression match.GeoIP: Based on the geographic location of the client, supporting wildcard matching. See Route on GeoIP/ASN for more details. The possible values to match with are any combinations of:- Continent
- Country
- Region
- Cities
- ASN
Host name: Matches the given pattern against the name of the host that the request was sent to. The match can be either a case-insensitive wildcard match or a regular expression match.IP ranges: Classifies a client based on whether its IP address belongs to any of the listed IP ranges or not.Random: Randomly classifies clients according to a given probability. The classifier is deterministic, meaning that a session will always get the same classification, even if evaluated multiple times.Regular expression matcher: Matches the given pattern against a configurable source. The match is case-insensitive and supports regular expressions. The following sources are available:content_url_path: The path part of the URL requested by the client.content_url_query_params: The query parameters of the URL requested by the client. The query parameters are passed as a single string.hostname: The name of the host that the request was sent to.user_agent: The user agent string in the HTTP request from the client.
Request Header: Classifies clients based on the value of a specified HTTP header in the request from the client.String matcher: Matches the given pattern against a configurable source. The match is case-insensitive and supports wildcards (’*’). The following sources are available:content_url_path: The path part of the URL requested by the client.content_url_query_params: The query parameters of the URL requested by the client. The query parameters are passed as a single string.hostname: The name of the host that the request was sent to.user_agent: The user agent string in the HTTP request from the client.
Subnet: Tests if a client’s IP belongs to a named subnet, see Subnets for more details.User agent: Matches the given pattern against the user agent string in the HTTP request from the client. The match can be either a case-insensitive wildcard match or a regular expression match.
A session group may have more than one classifier. If it does, all the classifiers must match the incoming client request for it to belong to the session group. It is also possible for a request to belong to multiple session groups, or to none.
To send certain clients to a specific host you first need to create a suitable
classifier using confcli in wizard mode. The wizard will guide you through the
process of creating a new entry, asking you what value to input for each field
and helping you by telling you what inputs are allowed for restricted fields
such as the string comparison source mentioned above:
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: anonymousIp
Adding a 'anonymousIp' element
classifier : {
name (default: ): anon_ip_matcher
type (default: anonymousIp):
inverted (default: False):
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "anon_ip_matcher",
"type": "anonymousIp",
"inverted": false
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: asnIds
Adding a 'asnIds' element
classifier : {
name (default: ): asn_matcher
type (default: asnIds): ⏎
inverted (default: False): ⏎
asnIds <The list of ASN IDs to accept. (default: [])>: [
asnId: 1
Add another 'asnId' element to array 'asnIds'? [y/N]: y
asnId: 2
Add another 'asnId' element to array 'asnIds'? [y/N]: y
asnId: 3
Add another 'asnId' element to array 'asnIds'? [y/N]: ⏎
]
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "asn_matcher",
"type": "asnIds",
"inverted": false,
"asnIds": [
1,
2,
3
]
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: contentUrlPath
Adding a 'contentUrlPath' element
classifier : {
name (default: ): vod_matcher
type (default: contentUrlPath): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): *vod*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "vod_matcher",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*vod*"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: contentUrlQueryParameters
Adding a 'contentUrlQueryParameters' element
classifier : {
name (default: ): bitrate_matcher
type (default: contentUrlQueryParameters): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): regex
pattern (default: ): .*bitrate=100000.*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "bitrate_matcher",
"type": "contentUrlQueryParameters",
"inverted": false,
"patternType": "regex",
"pattern": ".*bitrate=100000.*"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: geoip
Adding a 'geoip' element
classifier : {
name (default: ): sweden_matcher
type (default: geoip): ⏎
inverted (default: False): ⏎
continent (default: ): ⏎
country (default: ): sweden
cities : [
city (default: ): ⏎
Add another 'city' element to array 'cities'? [y/N]: ⏎
]
asn (default: ): ⏎
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "sweden_matcher",
"type": "geoip",
"inverted": false,
"continent": "",
"country": "sweden",
"cities": [
""
],
"asn": ""
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: hostName
Adding a 'hostName' element
classifier : {
name (default: ): host_name_classifier
type (default: hostName): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): *live.example*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "host_name_classifier",
"type": "hostName",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*live.example*"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: ipranges
Adding a 'ipranges' element
classifier : {
name (default: ): company_matcher
type (default: ipranges): ⏎
inverted (default: False): ⏎
ipranges : [
iprange (default: ): 90.128.0.0/12
Add another 'iprange' element to array 'ipranges'? [y/N]: ⏎
]
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "company_matcher",
"type": "ipranges",
"inverted": false,
"ipranges": [
"90.128.0.0/12"
]
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: random
Adding a 'random' element
classifier <A classifier randomly applying to clients based on the provided probability. (default: OrderedDict())>: {
name (default: ): random_matcher
type (default: random):
probability (default: 0.5): 0.7
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "random_matcher",
"type": "random",
"probability": 0.7
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: regexMatcher
Adding a 'regexMatcher' element
classifier : {
name (default: ): content_matcher
type (default: regexMatcher): ⏎
inverted (default: False): ⏎
source (default: content_url_path): ⏎
pattern (default: ): .*/(live|news_channel)/.*m3u8
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "content_matcher",
"type": "regexMatcher",
"inverted": false,
"source": "content_url_path",
"pattern": ".*/(live|news_channel)/.*m3u8"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: requestHeader
Adding a 'requestHeader' element
classifier <A classifier that matches on headers in the HTTP request. (default: OrderedDict())>: {
name (default: ): curl
type (default: requestHeader): ⏎
inverted (default: False): ⏎
header (default: ): User-Agent
patternType (default: stringMatch): ⏎
patternSource (default: inline): ⏎
pattern (default: ): curl*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "curl",
"type": "requestHeader",
"inverted": false,
"header": "User-Agent",
"patternType": "stringMatch",
"patternSource": "inline",
"pattern": "curl*"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: stringMatcher
Adding a 'stringMatcher' element
classifier : {
name (default: ): apple_matcher
type (default: stringMatcher): ⏎
inverted (default: False): ⏎
source (default: content_url_path): user_agent
pattern (default: ): *apple*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "apple_matcher",
"type": "stringMatcher",
"inverted": false,
"source": "user_agent",
"pattern": "*apple*"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: subnet
Adding a 'subnet' element
classifier : {
name (default: ): company_matcher
type (default: subnet): ⏎
inverted (default: False): ⏎
patternSource (default: inline): ⏎
pattern (default: ): company
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "company_matcher",
"type": "subnet",
"inverted": false,
"patternSource": "inline",
"pattern": "company"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: requestHeader
11: stringMatcher
12: subnet
13: userAgent
Choose element index or name: userAgent
Adding a 'userAgent' element
classifier : {
name (default: ): iphone_matcher
type (default: userAgent): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): regex
pattern (default: ): i(P|p)hone
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "iphone_matcher",
"type": "userAgent",
"inverted": false,
"patternType": "regex",
"pattern": "i(P|p)hone"
}
]
}
Merge and apply the config? [y/n]: y
These classifiers can now be used to construct session groups and properly classify clients. Using the examples above, let’s create a session group classifying clients from Sweden using an Apple device:
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): inSwedenUsingAppleDevice
classifiers : [
classifier (default: ): 'sweden_matcher' and 'apple_matcher'
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "inSwedenUsingAppleDevice",
"classifiers": [
"'sweden_matcher' and 'apple_matcher'"
]
}
]
}
Merge and apply the config? [y/n]: y
Clients classified by the sweden_matcher and apple_matcher classifiers
will now be put in the session group inSwedenUsingAppleDevice. Note the
single quotation marks around the classifier names.
Using session groups in routing will be demonstrated later in this document.
Classifier Boolean Logic
Session groups combine classifiers using boolean logic expressions. Each classifier
is referenced by its name enclosed in single quotes (e.g. 'sweden_matcher') and
multiple classifiers can be combined using the keywords and, or and not to
create sophisticated matching rules.
Operator precedence order:
- “Parentheses”
( )group items together; expressions within parentheses are evaluated first. - “not” negates the immediately following classifier or parenthesis expression
- “and” evaluates to true if both expressions surrounding it are true
- “or” evaluates to true if either expression surrounding it is true
Since “and” is higher than “or” the expression 'live' and 'spain' or 'sweden'
is functionally identical to ('live' and 'spain') or 'sweden'. If you want
the session group to accept any live content that is in either Spain or Sweden
you need to write 'live' and ('spain' or 'sweden').
To match against all incoming traffic requesting live content but coming from
outside of either Spain or Sweden, you’d write 'live' and not ('spain' or 'sweden').
It is permitted to nest several levels of parentheses and conjunctions if necessary to achieve the desired match.
Alternative form:
The "classifiers" property on a session group is an array, and each expression
in it must be true for the session group to trigger. This means that
"classifiers": ["('sweden' or 'spain') and 'live'"] is equivalent
to "classifiers": ["'sweden' or 'spain'", "'live'"].
This fact can be used for example if expressions become so long that it is necessary to break them up into smaller parts in order to be able to read them.
Pattern Source
The requestHeader and subnet classifiers have a patternSource field,
which can be either inline or selectionInput. When set to inline, the
pattern is taken directly from the pattern field.
If it is selectionInput, the pattern field is used as a path in the
selection input that points
to the pattern to use for classification. The selection input path may contain
a wildcard ("*"), which matches all elements inside an object or array.
For example, if patternSource contains /blocked_user_agents/*/agent, the
classifier will take its pattern from all agent fields in objects inside
/blocked_user_agents.
If the selection input contains the following data:
{
"blocked_user_agents": {
{ "agent1": { "agent": "Firefox" }},
{ "agent2": { "agent": "Chrome" }}
}
}
then the classifier will match either Firefox or Chrome.
Pattern Type
Several classifiers support pattern matching using either regular expressions or a simpler wildcard string matcher.
stringMatch:
The stringMatch pattern type uses shell-style wildcard matching for simple, readable patterns. Matching is case-insensitive.
Supported Wildcards:
*- Matches any sequence of characters (including none)*vod*matches/vod/,/content/vod/stream.m3u8,/my-vod-content/live/*/manifest.m3u8matches/live/sports/manifest.m3u8,/live/news/manifest.m3u8
?- Matches exactly one character/video?.mp4matches/video1.mp4,/videoA.mp4, but not/video10.mp4/test/?????/filematches any path with exactly 5 characters between/test/and/file
[characters]- Matches any single character from the set[abc]matchesa,b, orc[0-9]matches any single digit/video[12].mp4matches/video1.mp4or/video2.mp4
[!characters]or[^characters]- Matches any single character NOT in the set[!xyz]matches any character exceptx,y, orz[^0-9]matches any non-digit character/file[!0-9].txtmatches/fileA.txtbut not/file3.txt
[[:class:]]- POSIX character classes for matching character types[[:alnum:]]- alphanumeric (letters and digits)[[:alpha:]]- letters only[[:digit:]]- digits only[[:lower:]]- lowercase letters[[:upper:]]- uppercase letters[[:space:]]- whitespace characters- Example:
/user[[:digit:]][[:digit:]]/filematches/user12/file,/user00/file
\(backslash) - Escapes special characters to match them literallyfile\*.txtmatches the literal stringfile*.txt(asterisk is not a wildcard)test\?markmatchestest?mark(question mark is not a wildcard)
regex:
The regex pattern type uses full regular expression matching for complex
patterns. Matching is case-sensitive and follows the ECMAScript regular
expression syntax (the same syntax used by JavaScript).
Common Examples:
.*\.m3u8$- matches paths ending with .m3u8.*/(?:live|vod)/.*- matches paths containing /live/ or /vod/^/api/v[0-9]+/.*- matches paths starting with /api/v1/, /api/v2/, etc..*bitrate=[0-9]{6,}.*- matches query strings with bitrate= followed by 6+ digits
When to use:
Use regex when you need:
- Alternation (
a|b) - Precise quantifiers (
{n,m}) - Anchoring (
^start,$end) - Non-capturing groups (
(?:...)) - Lookaheads or other advanced features
For simple wildcard matching, stringMatch is more readable and performs better.
The complete ECMAScript regular expression syntax is documented at: