Grails 3.3.9 Static URL tokens not encoded by RegexUrlMapping
- Dominant language
- Groovy
- Stars
- 2.9k
- Forks
- 975
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 92
Description
### Task List
- [x] Steps to reproduce provided
- [x] ~~Stacktrace (if present) provided~~
- [ ] Example that reproduces the problem uploaded to Github
- [x] Full description of the issue provided (see below)
### Steps to Reproduce
1. Create an empty grails 3.3.9 project
2. Create Controller `EncodingTestController.groovy`
```
package staticurltokenencoding
class EncodingTestController {
def index() { }
def staticToken() {
render text: """
Static Token
${g.createLink(mapping: 'staticToken')}
${g.createLink(mapping: 'semiStaticToken', params: [foo: 'bar']}
""".stripIndent(),
contentType: 'text/plain'
}
def semiStaticToken() {
render text: """
Semi Static Token
${g.createLink(mapping: 'staticToken')}
${g.createLink(mapping: 'semiStaticToken', params: [foo: params.foo])}
""".stripIndent(),
contentType: 'text/plain'
}
}
```
3. Change `UrlMappings.groovy` to
```
package staticurltokenencoding
class UrlMappings {
static final UML_a = '\u00e4' // ä -- LATIN SMALL LETTER A WITH DIAERESIS
static mappings = {
// "/StäticToken" would be equivalent with correct file encoding
name staticToken: "/St${UML_a}ticToken" (controller: 'encodingTest', action: 'staticToken')
// "/StäticToken-$foo" would be equivalent with correct file encoding
name semiStaticToken: "/St${UML_a}ticToken-$foo" (controller: 'encodingTest', action: 'semiStaticToken')
"/"(view:"/index")
"500"(view:'/error')
"404"(view:'/notFound')
}
}
```
4. Run the app on localhost:8080
### Expected Behaviour
Creating Links with `mapping: 'staticToken'` and `mapping: 'semiStaticToken'` will behave consistently.
So the response body of `http://localhost:8080/St%C3%A4ticToken` is expected to be
```
Static Token
/St%C3%A4ticToken
/St%C3%A4ticToken-bar
```
### Actual Behaviour
Creating Links with `mapping: 'staticToken'` and `mapping: 'semiStaticToken'` behaves inconsistently.
The response body of `http://localhost:8080/St%C3%A4ticToken` actually is
```
Static Token
/StäticToken
/St%C3%A4ticToken-bar
```
So the static URL-Token `StäticToken` of the mapping `staticToken` gets not encoded while link creation, but the static part of the semi static token `StäticToken-$foo` gets encoded.
This Behavior is hardcoded in `org.grails.web.mapping.RegexUrlMapping.createURLInternal(Map paramValues, String encoding, boolean includeContextPath):409ff`:
```
// tokenize URL by '/'
// for each token
// if token has placeholder(s), do replacements and encode
else {
uri.append(SLASH).append(token);
}
```
### Environment Information
Tested on various envoronments e.g.:
- **Operating System**: Ubuntu 18.04, CentOS 6
- **Grails Version:** 3.2.9, 3.3.9
- **JDK Version:** 8
- **Container Version (If Applicable):** `grails run-app`, jetty, …
### Workarround
Because we have many of those mappings with static and semi-static tokens, containing umlauts, targeting multiple controllers and actions, the only practical workarround was to provide our own Version of `org.grails.web.mapping.RegexUrlMapping`, doing this instead:
```
else {
/**
* TBSEOWNT-12821 also encode static URL tokens
*/
try {
uri.append(SLASH).append(encode(token,encoding));
} catch (UnsupportedEncodingException e) {
throw new ControllerExecutionException("Error creating URL for parameters [" +
paramValues + "], problem encoding URL part [" + token + "]: " + e.getMessage(), e);
}
}
```
If there is any good reason for not encoding static URL tokens, the behavior should be configurable. Also the handling of static URL tokens and static parts of non static URL tokens should be the same.
Contributor guide
Research direction
Start in org.grails.web.mapping.RegexUrlMapping.createURLInternal(Map paramValues, String encoding, boolean includeContextPath) around line 409, then reproduce the issue with the provided EncodingTestController and UrlMappings.groovy. Compare staticToken with semiStaticToken and verify that both generated links encode the static URL token consistently as /St%C3%A4ticToken.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- groovy
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100