Recursive URL Substitution Syntax

From Second Life Wiki
Revision as of 11:24, 3 August 2007 by Phoenix Linden (talk | contribs) (→‎Strings)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Like any substitution syntax, using untrusted formatted strings or untrusted sources of data can lead to exploits. Be careful when designing the usage so that no tainted input winds up in the context.


Syntax

The syntax is based on placing curly braces inside an URL to indicate that the curly brace and everything inside should be replaced with a substitution. Each type of substitution will have it's own rules but every time you see { and } then all contents inside those braces are to be replaced.

Strings

String substitution uses an open curly brace '{' followed by a dollar symbol '$' followed by the name of the substitution and a closing curly brace '}'. The name is used as a key into a map whose value will be replaced into the original format string. The key must only contain alphanumeric characters and '+', '-', '_', and spaces.

Values which appear in the map but not referenced in the format string are ignored.


String Substitution Examples
Format Map Contents Result
{$bucket}.agent.lindenlab.com 'bucket':'a' a.agent.lindenlab.com
agent/{$agent-id}/inventory/item/{$item-id} 'agent-id':foo, 'item-id':bar agent/foo/inventory/item/bar

Values which are lists/tuples will have their elements urlquoted and joined with '/'. I.e. they are assumed to be exploded paths. E.g.:

Format Map Contents Result
foo/{$stuff}/baz 'stuff':['one','two','three'] foo/one/two/three/baz

Query Strings

Query strings are a specialized url syntax for representing the contents of a map as an ampersand delimited url query string including the leading '?'. Query string use an open curly brace '{' followed by a percent symbol '%' followed by the name of a dictionary in the replacement context followed by a closing curly brace '}'.

Unlike string substitution, if the named value is not a key in the map contents, the russ directive will be stripped.

Query String Substitution Examples
Format Map Contents Result
/sql/{$query}{%params} { 'query':'get-agent-name-by-id', 'params':{'agent_id':123}} /sql/get-agent-name-by-id?agent_id=123
/proc/{$proc}{%params} { 'proc':'messages/dir/DirFindPeople', 'params':{'estate':1, 'query':'designer clothing'}} /proc/messages/dir/DirFindPeople?estate=1&query=designer+clothing

Functions

Function substitution uses an open curly brace '{' followed by a bang symbol '!' followed by the name of the substitution function and a closing curly brace '}'. The name is a function that is available to the substitution engine, and may be implementation specific. The function is prototyped as accepting a map context and returning a string.

For example, {!region-host-port} could be a function which takes a map which is assumed to contain a key 'region-id'. The function will perform a service lookup for region presence with the region-id in the service builder, and then parse the return document for the region host and port.

REST Requests

For REST Request substitution, the embedded URL is fetched, parsed for a single LLSD document which is embedded inside the curly braces.

The simple syntax is an opening curly brace '{', followed by the URL, and terminated with a closing curly brace '}'. The document at the url is parsed and treated as a string. Containers, the undefined element, and non-parseable documents are considered errors.

For http request, no instructions to the protocol means to perform a normal GET.

Rest Request Substitution Examples
Format Results
{http://gridtool.agni.lindenlab.com/agents/online-now} 58582
{http://blondie.lindenlab.com/lookup/agentname/phoenix/linden||agent-id} 3c115e51-04f4-523c-9fa6-98aff1034730

Supported protocols: http, https

We should probably support file.

Recursive Substitution

In theory, this grammar can be used recursively, though only python currently supports this feature.

Formating Examples
Format
{http://sim1028.{$grid}.{$domain}/agent/{$agent-id}/location}
{{$node}{$domain}}

Syntax Specification

The full syntax is an opening curly brace '{', followed by the URL, followed by a vline '|', followed by protocol specific instructions, followed by a 'vline', followed by a path to follow through the document to the element which will be treated as a string.

russ-statement : open-russ substitution close-russ
open-russ: '{'
close-russ: '}'
substituion: string-substitution| query-string-substitution | url-substitution | function-substitution
string-substition: '$' llsd-key
query-string-substition: '%' llsd-key
function-substitution: '!' function-name
function-name: llsd-key
url-substitution: url [ vline [ url-parameters ] vline llsd-path]
url: protocol ':' (normal url authority & host & path & parameters & opaque parts)
protocol: 'http' | 'https'
vline: '|'
url-parameters: verb [ body ]
verb: 'GET' | 'PUT' | 'POST' | 'DELETE'
body: ???
llsd-path: segment * [ "/" segment ]
segment: llsd-key

Please note that the following elements in the syntax rules are not well defined:

  • llsd-key
  • body
  • function-name

Implementations

python

Our indra python libs have a russ implementation in russ.py which supports:

  • string substitution
  • query string substitution
  • url substitution
  • recursive substitution

c++

In indra/llmessage libs has a russ implementation inside of the LLServiceBuilder class which supports:

  • string substitution
  • url substitution

perl

In Indra::WebServices, you can call buildService($service_name) to make a client to that service. The current implementation supports:

  • string substitution
  • query string substitution
  • recursive substitution