URL Encoding
Overview
The placeholder replacement system enables dynamic injection of values into template strings such as URLs, JSON, or XML.
By default, injected values are escaped according to the target context to maintain validity and prevent injection vulnerabilities.
In specific cases, however, raw (unescaped) injection is required — for example, when a URL path segment legitimately includes / characters.
Example Use Case
Consider the following URL template:
http://my.host/{foo}/upload
A customer wants to dynamically replace {foo} with:
| Input | Expected Output |
|---|---|
bar | http://my.host/bar/upload |
foo/bar | http://my.host/foo/bar/upload |
By default, injected values are URL-encoded, resulting in:
http://my.host/foo%2Fbar/upload
To support raw replacement (http://my.host/foo/bar/upload), an extended placeholder syntax using suffixes was introduced.
Placeholder Syntax
Placeholders follow this pattern:
\{((\w+?)(__(raw|xml|json|url))?)\}
Examples
{user}{foo__raw}{config__xml}{payload__json}
Each placeholder contains:
- A key (
\w+) - An optional suffix (
__raw,__xml,__json,__url) defining escaping behavior
Replacement Logic
- Identify all placeholders in the format
{key}or{key__suffix}. - For each placeholder:
- Extract the base key and optional suffix.
- Look up the value in the
paramsmap. - If no value exists for
{key__suffix}but one exists for{key}, the base key’s value is used. - Apply escaping according to the suffix or inferred context.
- Replace the placeholder with the resulting value.
- If no value is found, replace it with an empty string.
Escaping Rules
| Context Type | Escaping Method | Suffix | Description | Example Placeholder |
|---|---|---|---|---|
| Raw | No escaping | __raw | Inserts value as-is. | {foo__raw} |
| URL | URL-encoding | __url | Escapes using UTF-8 URL rules. | {foo__url} |
| JSON | JSON escaping | __json | Escapes special JSON characters. | {foo__json} |
| XML | XML escaping | __xml | Escapes XML entities. | {foo__xml} |
If foo__raw is not explicitly defined but foo exists, the system uses foo and applies the escaping defined by the suffix.
Example Behavior
Given the parameter map:
foo = "ampersand=&, backspace=\"
| Placeholder | Context Type | Result |
|---|---|---|
{foo} | url | ampersand%3D%26,%20backspace%3D%5C |
{foo} | json | ampersand=&, backspace=\\ |
{foo} | xml | ampersand=&, backspace=\ |
{foo} | (other) | ampersand=&, backspace=\ |
{foo__raw} | (any) | ampersand=&, backspace=\ |
{foo__url} | (any) | ampersand%3D%26,%20backspace%3D%5C |
{foo__json} | (any) | ampersand=&, backspace=\\ |
{foo__xml} | (any) | ampersand=&, backspace=\ |