Noah Rickles created CXF-8557:
---------------------------------

             Summary: 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


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}}:

{{@Path("/\{a : foo/bar}")}}

{{@Path("/\{a : foo\\/bar}")}}

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 {{@Path("/\{a : foo/bar}/\{id}")}} segments the path into the 
following: {{{a : foo}}, {{bar}}}, and {{{id}}}.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to