Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-8557

Incorrect Proxy Path Segmenting when @Path Annotation Regex Expression Contains "/"

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 3.4.4, 3.3.11
    • 3.5.0, 3.3.12, 3.4.5
    • JAX-RS
    • Moderate

    Description

      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:

      if (this.isRoot) {
          this.addNonEmptyPath(builder, ori.getClassResourceInfo().getURITemplate().getValue());
      }
      
      this.addNonEmptyPath(builder, ori.getURITemplate().getValue());
      

      This leads to the doPath method in the UriBuilderImpl.java class, which calls the following with checkSegments equal to true:

      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));
      }
      

      The getPathSegments method is as follows and is where the ArrayList mentioned above gets populated:

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

      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 : foobar}, 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.

      Attachments

        Issue Links

          Activity

            People

              reta Andriy Redko
              nrickles3 Noah Rickles
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: