Lukasz Lenart created WW-5688:
---------------------------------
Summary: RestActionMapper maps URIs with an id into the empty
namespace, so actions declared at namespace "/" 404
Key: WW-5688
URL: https://issues.apache.org/jira/browse/WW-5688
Project: Struts 2
Issue Type: Bug
Components: Plugin - REST
Affects Versions: 2.1.2
Reporter: Lukasz Lenart
Fix For: 7.4.0
Split out of [WW-2820|https://issues.apache.org/jira/browse/WW-2820], a 2008
umbrella of five unrelated REST plugin claims. This is the only one of the five
that still reproduces on {{main}}. Originally reported by Alvin Singh.
h3. Symptom
When a package is declared at {{namespace="/"}}, REST URIs that carry an id are
mapped into a _different_ namespace than those that do not. The result is that
{{index}} works while {{show}} / {{update}} / {{destroy}} return 404 for the
very same action.
Given:
[package name="rest-root" namespace="/" extends="rest-default"]
[action name="dog" class="com.example.DogAction"/]
[/package]
||Request||namespace from RestActionMapper||action resolves?||
|{{GET /dog}}|{{/}}|yes|
|{{GET /dog/1}}|(empty)|*no - 404*|
The reporter's original phrasing was "if you want a blank namespace, do not use
/ as your namespace ... inconsistent behavior starts to occur", which is
accurate.
h3. Root cause
{{RestActionMapper.parseNameAndNamespace()}} has two disjoint paths:
* {{lastSlash == 0}} hardcodes {{namespace = "/"}} (the WW-1046 root case).
* Any deeper URI instead runs the longest-matching-namespace loop. That loop's
guard, {{prefix.charAt(ns.length()) == '/'}}, can never select {{"/"}} - it
would require a {{//}} prefix - so it falls through to its default of {{""}}.
{{RuntimeConfiguration.getActionConfig()}} then only fails over {{"/"}} to
{{""}}, never {{""}} to {{"/"}} (see
{{DefaultConfiguration.shouldFallbackToEmptyNamespace}}). So the {{""}} branch
is a dead end for an action declared at {{"/"}}.
Note that the loop computes {{name = uri.substring(namespace.length() + 1)}},
which assumes a non-root namespace. Simply allowing {{"/"}} to match in the
loop is therefore not sufficient on its own.
h3. Reproduction
Against a configuration holding only the package above:
PROBE index -> ns='/' name='dog'
PROBE show -> ns='' name='dog'
junit.framework.AssertionFailedError:
GET /dog/1 must resolve to the action declared in namespace "/"
The companion assertion for {{GET /dog}} passes against the same configuration,
so the failure is specific to the id-bearing URI and not an artefact of the
fixture.
h3. Security assessment
Not a security issue. The defect makes actions _less_ reachable rather than
more, and aligning {{/dog/1}} with what {{/dog}} already resolves to exposes no
surface that the {{/dog}} path does not already expose.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)