This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/3.4.x-fixes by this push:
     new 8f7b5e9  CXF-8557: Incorrect Proxy Path Segmenting when @Path 
Annotation RegexExpression Contains '/' (#822)
8f7b5e9 is described below

commit 8f7b5e9421428b8cfc8d6b898d85dbb288358e94
Author: Andriy Redko <[email protected]>
AuthorDate: Wed Jul 7 21:52:21 2021 -0400

    CXF-8557: Incorrect Proxy Path Segmenting when @Path Annotation 
RegexExpression Contains '/' (#822)
    
    * CXF-8557: Incorrect Proxy Path Segmenting when @Path Annotation Regex 
Expression Contains '/'
    
    * Added more sophisticated handling of the incorrect template definitions 
and fallback to simple split by path segment separator
    
    (cherry picked from commit c0cae301ccfcb75b5ad011fd2192b5385539d9dd)
---
 .../org/apache/cxf/jaxrs/utils/JAXRSUtils.java     |  73 ++++++++++++---
 .../apache/cxf/jaxrs/impl/UriBuilderImplTest.java  | 100 +++++++++++++++++++++
 2 files changed, 161 insertions(+), 12 deletions(-)

diff --git 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
index 96e97b2..302e435 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
@@ -181,20 +181,69 @@ public final class JAXRSUtils {
         return getPathSegments(thePath, decode, true);
     }
 
+    /**
+     * Parses path segments taking into account the URI templates and template 
regexes. Per RFC-3986, 
+     * "A path consists of a sequence of path segments separated by a slash 
("/") character.", however
+     * it is possible to include slash ("/") inside template regex, for 
example "/my/path/{a:b/c}", see 
+     * please {@link URITemplate}. In this case, the whole template definition 
is extracted as a path 
+     * segment, without breaking it.
+     * @param thePath path
+     * @param decode should the path segments be decoded or not
+     * @param ignoreLastSlash should the last slash be ignored or not
+     * @return
+     */
     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;
+        
+        final List<PathSegment> segments = new ArrayList<>();
+        int templateDepth = 0;
+        int start = 0;
+        for (int i = 0; i < thePath.length(); ++i) {
+            if (thePath.charAt(i) == '/') {
+                // The '/' is in template (possibly, with arbitrary regex) 
definition
+                if (templateDepth != 0) {
+                    continue;
+                } else if (start != i) {
+                    final String segment = thePath.substring(start, i);
+                    segments.add(new PathSegmentImpl(segment, decode));
+                }
+                
+                // advance the positions, empty path segments
+                start = i + 1;
+            } else if (thePath.charAt(i) == '{') {
+                ++templateDepth;
+            } else if (thePath.charAt(i) == '}') {
+                --templateDepth; // could go negative, since the template 
could be unbalanced
+            }
+        }
+        
+        // the URI has unbalanced curly braces, backtrack to the last seen 
position of the path
+        // segment separator and just split segments as-is from there
+        if (templateDepth != 0) {
+            segments.addAll(
+                Arrays
+                    .stream(thePath.substring(start).split("/"))
+                    .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 ? "" : "/";
+                segments.add(new PathSegmentImpl(value, false));
+            }
+        } else {
+            // the last symbol is slash
+            if (start == thePath.length() && start > 0 && thePath.charAt(start 
- 1) == '/') {
+                String value = ignoreLastSlash ? "" : "/";
+                segments.add(new PathSegmentImpl(value, false));
+            } else if (!thePath.isEmpty()) {
+                final String segment = thePath.substring(start);
+                segments.add(new PathSegmentImpl(segment, decode));
+            }
+        }
+        
+        return segments;
     }
 
     private static String[] getUserMediaTypes(Object provider, boolean 
consumes) {
diff --git 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
index 289003b..9232344 100644
--- 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
+++ 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
@@ -1875,4 +1875,104 @@ public class UriBuilderImplTest {
             .toTemplate();
         assertEquals("my/path?p=%25250%25", template);
     }
+    
+    @Test
+    public void pathParamFromTemplateWithOrRegex() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{p:my|his}")
+            .build("my");
+        assertEquals("my/path/my", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromTemplateWithRegex() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{p:his/him}")
+            .buildFromEncoded("his/him");
+        assertEquals("my/path/his/him", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromNestedTemplateWithRegex() {
+        // The nested templates are not supported and are not detected 
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{{p:his/him}}")
+            .build();
+        assertEquals("my/path/%7B%7Bp:his/him%7D%7D", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplateNested() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{p{d}}")
+            .build("my");
+        assertEquals("my/path/%7Bp%7Bd%7D%7D", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplateUnopened() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("p{d}/}")
+            .build("my");
+        assertEquals("my/path/pmy/%7D", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplateUnclosed() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{p/{d}")
+            .build("my");
+        assertEquals("my/path/%7Bp/my", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromEmpty() {
+        final URI uri = UriBuilder
+            .fromUri("/")
+            .path("/")
+            .build();
+        assertEquals("/", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromEmptyWithSpaces() {
+        final URI uri = UriBuilder
+            .fromUri("/")
+            .path("   /   ")
+            .build();
+        assertEquals("/%20%20%20/%20%20%20", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplateUnopenedAndEnclosedSlash() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("p{d:my/day}/}")
+            .buildFromEncoded("my/day");
+        assertEquals("my/path/pmy/day/%7D", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplateUnclosedAndEnclosedSlash() {
+        final URI uri = UriBuilder
+            .fromUri("my/path")
+            .path("{p/{d:my/day}")
+            .build();
+        assertEquals("my/path/%7Bp/%7Bd:my/day%7D", uri.toString());
+    }
+    
+    @Test
+    public void pathParamFromBadTemplate() {
+        final URI uri = UriBuilder
+            .fromUri("/")
+            .path("{")
+            .build();
+        assertEquals("/%7B", uri.toString());
+    }
 }
\ No newline at end of file

Reply via email to