[
https://issues.apache.org/jira/browse/CXF-8557?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17367887#comment-17367887
]
Noah Rickles edited comment on CXF-8557 at 6/23/21, 6:25 AM:
-------------------------------------------------------------
Another thing to note, on a path at a sub-resource level, let's say
hypothetically the regex expression did not contain "/" and was just something
like
{code:java}
@GET
@Path("/{a : (.+)z}/{id}")
ResponseData get(@BeanParam Integer id){code}
In this scenario, if the class path is {{/class/path}}, a request could be
received through {{/class/path/abcz/123}} and should be caught by this method.
In the path segmentation, it is correctly split up so that there are two
variables, {{a}} and {{id}}. How does the proxy implementation get the value
for {{a}} in this situation? The {{varValues}} varargs only applies to class
level template variables.
In the invocation of the proxy ( {{proxy.get(123)}} ), the only path parameter
retrieved is the value of the bean param, 123, from the call to
{code:java}
List<Object> pathParams = this.getPathParamValues(m, params, types,
beanParamsList, ori, bodyIndex);{code}
When the URI is built via
{code:java}
URI uri = builder.buildFromEncoded(pathParams.toArray()).normalize();
{code}
it throws an exception here in {{substituteVarArgs}}:
{code:java}
Set<String> uniqueVars = new LinkedHashSet<>(templ.getVariables());
if (!allowUnresolved && values.length + alreadyResolvedTs.size() +
alreadyResolvedTsEnc.size()
+ alreadyResolvedTsPathEnc.size() < uniqueVars.size()) {
throw new IllegalArgumentException("Unresolved variables; only " +
values.length
+ " value(s) given for " +
uniqueVars.size()
+ " unique variable(s)");
}
{code}
"Unresolved variables; only 1 value(s) given for 2 unique variable(s)"
The template has two variables, {{a}} and {{id}} but only has one value to
replace them with, the 123 passed in and retrieved as a path parameter.
On the other hand, if the class level path is
{code:java}
@Path("/{a : (.+)z}")
{code}
and the resource-level path is
{code:java}
@Path("/{id}")
{code}
the {{getPathParamValues}} retrieves both the value from the {{varValues}}
determined in the proxy's creation ({{abcz}}), along with the bean parameter
(123), so the URI is built correctly.
This is slightly off topic from the point of this issue, so I can post it in a
separate ticket if this is deemed a problem. I haven't read the specification,
but I would think this is a valid scenario?
was (Author: nrickles3):
Another thing to note, on a path at a sub-resource level, let's say
hypothetically the regex expression did not contain "/" and was just something
like
{code:java}
@GET
@Path("/{a : (.+)z}/{id}")
ResponseData get(@BeanParam Integer id){code}
In this scenario, if the class path is {{/class/path}}, a request could be
received through {{/class/path/abcz/123}} and should be caught by this method.
In the path segmentation, it is correctly split up so that there are two
variables, {{a}} and {{id}}. How does the proxy implementation get the value
for {{a}} in this situation? The {{varValues}} varargs only applies to class
level template variables.
In the invocation of the proxy ( {{proxy.get(123)}} ), the only path parameter
retrieved is the value of the bean param, 123, from the call to
{code:java}
List<Object> pathParams = this.getPathParamValues(m, params, types,
beanParamsList, ori, bodyIndex);{code}
When the URI is built via
{code:java}
URI uri = builder.buildFromEncoded(pathParams.toArray()).normalize();
{code}
it throws an exception here in {{substituteVarArgs}}:
{code:java}
Set<String> uniqueVars = new LinkedHashSet<>(templ.getVariables());
if (!allowUnresolved && values.length + alreadyResolvedTs.size() +
alreadyResolvedTsEnc.size()
+ alreadyResolvedTsPathEnc.size() < uniqueVars.size()) {
throw new IllegalArgumentException("Unresolved variables; only " +
values.length
+ " value(s) given for " +
uniqueVars.size()
+ " unique variable(s)");
}
{code}
"Unresolved variables; only 1 value(s) given for 2 unique variable(s)"
The template has two variables, {{a}} and {{id}} but only has one value to
replace them with, the 123 passed in and retrieved as a path parameter.
On the other hand, if the class level path is
{code:java}
@Path("/{a : (.+)z}")
{code}
and the resource-level path is
{code:java}
@Path("/{id}")
{code}
the {{getPathParamValues}} retrieves both the value from the {{varValues}}
determined in the proxy's creation ({{abcz}}), along with the bean parameter
(123), so the URI is built correctly.
This is slightly off topic from the point of this issue, so I can post it in a
separate ticket if this is deemed a problem. I haven't read the specification,
but I would think this is a valid scenario?
> Incorrect Proxy Path Segmenting when @Path Annotation Regex Expression
> Contains "/"
> -----------------------------------------------------------------------------------
>
> Key: CXF-8557
> URL: https://issues.apache.org/jira/browse/CXF-8557
> Project: CXF
> Issue Type: Bug
> Components: JAX-RS
> Affects Versions: 3.4.4
> Reporter: Noah Rickles
> Priority: Major
> Labels: Bug
>
> Follow up to https://issues.apache.org/jira/browse/CXF-8556.
> A service in question needs to be reachable via multiple paths. The {{@Path}}
> param allows for regex matching on a class-level like the following:
> {{@Path("/\{a: regexExpression}")}}. A class-level {{@PathParam}} is created
> by the name of {{a}}. The following annotations both correctly receive
> requests at {{/foo/bar}}:
> {code:java}
> @Path("/{a : foo/bar}")
> @Path("/{a : foo\\/bar}")
> {code}
> When the proxy implementation is invoked, these paths are segmented as an
> ArrayList with two entries: {{{a : foo}} and {{bar}}} and {a : foo\ and
> {{bar}}} respectively. The expected behavior is for there to be one segment
> corresponding to this path, \{a : foo/bar}, so that when variables are
> replaced later ({{substituteVarargs}} method in {{UriBuilderImpl.java}}), the
> path parameter {{a}} can be recognized as a vararg and replaced by a phrase
> matching the regex expression.
> The flow that results in the fragmented segments begins here in the
> {{invoke}} method of the {{ClientProxyImpl.java}} class:
> {code:java}
> if (this.isRoot) {
> this.addNonEmptyPath(builder,
> ori.getClassResourceInfo().getURITemplate().getValue());
> }
> this.addNonEmptyPath(builder, ori.getURITemplate().getValue());
> {code}
> This leads to the {{doPath}} method in the {{UriBuilderImpl.java}} class,
> which calls the following with {{checkSegments}} equal to {{true}}:
> {code:java}
> List<PathSegment> segments;
> if (checkSegments) {
> segments = JAXRSUtils.getPathSegments(path, false, false);
> } else {
> segments = new ArrayList<>();
> path = path.replaceAll("/", "%2F");
> segments.add(new PathSegmentImpl(path, false));
> }
> {code}
> The {{getPathSegments}} method is as follows and is where the {{ArrayList}}
> mentioned above gets populated:
> {code:java}
> public static List<PathSegment> getPathSegments(String thePath, boolean
> decode,
> boolean ignoreLastSlash) {
> List<PathSegment> theList =
> Arrays.asList(thePath.split("/")).stream()
> .filter(StringUtils.notEmpty())
> .map(p -> new PathSegmentImpl(p, decode))
> .collect(Collectors.toList());
> int len = thePath.length();
> if (len > 0 && thePath.charAt(len - 1) == '/') {
> String value = ignoreLastSlash ? "" : "/";
> theList.add(new PathSegmentImpl(value, false));
> }
> return theList;
> }
> {code}
> The path is split based on the presence of "/", without regard for if the
> path segment is defined as a path parameter regex expression.
> The same behavior applies on paths not at a class-level also. For example,
> the path denoted by a {{@Path("/\{a : foo/bar}/\{id}")}} on a lower level
> resource segments the path into the following: {{{a : foo}}, {{bar}}}, and
> \{id}, when it would be expected to segment into two segments, \{a : foo/bar}
> and \{id}. The only difference here being when the path is segmented. Since
> it is not a root path, it happens after the {{isRoot}} check, with the same
> {{addNonEmptyPath}} method.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)