Add PathSegmentContainer subPath extracting method
This commit is contained in:
		
							parent
							
								
									1018bf771b
								
							
						
					
					
						commit
						97917aa57d
					
				| 
						 | 
					@ -19,6 +19,7 @@ import java.nio.charset.Charset;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.util.Assert;
 | 
					import org.springframework.util.Assert;
 | 
				
			||||||
import org.springframework.util.CollectionUtils;
 | 
					import org.springframework.util.CollectionUtils;
 | 
				
			||||||
| 
						 | 
					@ -56,7 +57,7 @@ class DefaultPathSegmentContainer implements PathSegmentContainer {
 | 
				
			||||||
	private final boolean trailingSlash;
 | 
						private final boolean trailingSlash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DefaultPathSegmentContainer(String path, List<PathSegment> segments) {
 | 
						private DefaultPathSegmentContainer(String path, List<PathSegment> segments) {
 | 
				
			||||||
		this.path = path;
 | 
							this.path = path;
 | 
				
			||||||
		this.absolute = path.startsWith("/");
 | 
							this.absolute = path.startsWith("/");
 | 
				
			||||||
		this.pathSegments = Collections.unmodifiableList(segments);
 | 
							this.pathSegments = Collections.unmodifiableList(segments);
 | 
				
			||||||
| 
						 | 
					@ -188,6 +189,21 @@ class DefaultPathSegmentContainer implements PathSegmentContainer {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static PathSegmentContainer subPath(PathSegmentContainer container, int fromIndex, int toIndex) {
 | 
				
			||||||
 | 
							List<PathSegment> segments = container.pathSegments();
 | 
				
			||||||
 | 
							if (fromIndex == 0 && toIndex == segments.size()) {
 | 
				
			||||||
 | 
								return container;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Assert.isTrue(fromIndex < toIndex, "fromIndex: " + fromIndex + " should be < toIndex " + toIndex);
 | 
				
			||||||
 | 
							Assert.isTrue(fromIndex >= 0 && fromIndex < segments.size(), "Invalid fromIndex: " + fromIndex);
 | 
				
			||||||
 | 
							Assert.isTrue(toIndex >= 0 && toIndex <= segments.size(), "Invalid toIndex: " + toIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							List<PathSegment> subList = segments.subList(fromIndex, toIndex);
 | 
				
			||||||
 | 
							String prefix = fromIndex > 0 || container.isAbsolute() ? "/" : "";
 | 
				
			||||||
 | 
							String suffix = toIndex == segments.size() && container.hasTrailingSlash() ? "/" : "";
 | 
				
			||||||
 | 
							String path = subList.stream().map(PathSegment::value).collect(Collectors.joining(prefix, "/", suffix));
 | 
				
			||||||
 | 
							return new DefaultPathSegmentContainer(path, subList);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static class DefaultPathSegment implements PathSegment {
 | 
						private static class DefaultPathSegment implements PathSegment {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@ package org.springframework.http.server.reactive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.net.URI;
 | 
					import java.net.URI;
 | 
				
			||||||
import java.nio.charset.Charset;
 | 
					import java.nio.charset.Charset;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.util.Assert;
 | 
					import org.springframework.util.Assert;
 | 
				
			||||||
| 
						 | 
					@ -41,16 +40,15 @@ class DefaultRequestPath implements RequestPath {
 | 
				
			||||||
	DefaultRequestPath(URI uri, String contextPath, Charset charset) {
 | 
						DefaultRequestPath(URI uri, String contextPath, Charset charset) {
 | 
				
			||||||
		this.fullPath = PathSegmentContainer.parse(uri.getRawPath(), charset);
 | 
							this.fullPath = PathSegmentContainer.parse(uri.getRawPath(), charset);
 | 
				
			||||||
		this.contextPath = initContextPath(this.fullPath, contextPath);
 | 
							this.contextPath = initContextPath(this.fullPath, contextPath);
 | 
				
			||||||
		this.pathWithinApplication = initPathWithinApplication(this.fullPath, this.contextPath);
 | 
							this.pathWithinApplication = extractPathWithinApplication(this.fullPath, this.contextPath);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DefaultRequestPath(RequestPath requestPath, String contextPath) {
 | 
						DefaultRequestPath(RequestPath requestPath, String contextPath) {
 | 
				
			||||||
		this.fullPath = requestPath;
 | 
							this.fullPath = requestPath;
 | 
				
			||||||
		this.contextPath = initContextPath(this.fullPath, contextPath);
 | 
							this.contextPath = initContextPath(this.fullPath, contextPath);
 | 
				
			||||||
		this.pathWithinApplication = initPathWithinApplication(this.fullPath, this.contextPath);
 | 
							this.pathWithinApplication = extractPathWithinApplication(this.fullPath, this.contextPath);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static PathSegmentContainer initContextPath(PathSegmentContainer path, String contextPath) {
 | 
						private static PathSegmentContainer initContextPath(PathSegmentContainer path, String contextPath) {
 | 
				
			||||||
		if (!StringUtils.hasText(contextPath) || "/".equals(contextPath)) {
 | 
							if (!StringUtils.hasText(contextPath) || "/".equals(contextPath)) {
 | 
				
			||||||
			return DefaultPathSegmentContainer.EMPTY_PATH;
 | 
								return DefaultPathSegmentContainer.EMPTY_PATH;
 | 
				
			||||||
| 
						 | 
					@ -62,14 +60,13 @@ class DefaultRequestPath implements RequestPath {
 | 
				
			||||||
		int length = contextPath.length();
 | 
							int length = contextPath.length();
 | 
				
			||||||
		int counter = 0;
 | 
							int counter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		List<PathSegment> result = new ArrayList<>();
 | 
							for (int i=0; i < path.pathSegments().size(); i++) {
 | 
				
			||||||
		for (PathSegment pathSegment : path.pathSegments()) {
 | 
								PathSegment pathSegment = path.pathSegments().get(i);
 | 
				
			||||||
			result.add(pathSegment);
 | 
								counter += 1; // for slash separators
 | 
				
			||||||
			counter += 1; // for '/' separators
 | 
					 | 
				
			||||||
			counter += pathSegment.value().length();
 | 
								counter += pathSegment.value().length();
 | 
				
			||||||
			counter += pathSegment.semicolonContent().length();
 | 
								counter += pathSegment.semicolonContent().length();
 | 
				
			||||||
			if (length == counter) {
 | 
								if (length == counter) {
 | 
				
			||||||
				return new DefaultPathSegmentContainer(contextPath, result);
 | 
									return DefaultPathSegmentContainer.subPath(path, 0, i + 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,13 +75,10 @@ class DefaultRequestPath implements RequestPath {
 | 
				
			||||||
				" given path='" + path.value() + "'");
 | 
									" given path='" + path.value() + "'");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static PathSegmentContainer initPathWithinApplication(PathSegmentContainer path,
 | 
						private static PathSegmentContainer extractPathWithinApplication(PathSegmentContainer fullPath,
 | 
				
			||||||
			PathSegmentContainer contextPath) {
 | 
								PathSegmentContainer contextPath) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		String value = path.value().substring(contextPath.value().length());
 | 
							return PathSegmentContainer.subPath(fullPath, contextPath.pathSegments().size());
 | 
				
			||||||
		List<PathSegment> pathSegments = new ArrayList<>(path.pathSegments());
 | 
					 | 
				
			||||||
		pathSegments.removeAll(contextPath.pathSegments());
 | 
					 | 
				
			||||||
		return new DefaultPathSegmentContainer(value, pathSegments);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,4 +67,14 @@ public interface PathSegmentContainer {
 | 
				
			||||||
		return DefaultPathSegmentContainer.parsePath(path, encoding);
 | 
							return DefaultPathSegmentContainer.parsePath(path, encoding);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Extract a sub-path starting at the given offset into the path segment list.
 | 
				
			||||||
 | 
						 * @param path the path to extract from
 | 
				
			||||||
 | 
						 * @param pathSegmentIndex the start index (inclusive)
 | 
				
			||||||
 | 
						 * @return the sub-path
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static PathSegmentContainer subPath(PathSegmentContainer path, int pathSegmentIndex) {
 | 
				
			||||||
 | 
							return DefaultPathSegmentContainer.subPath(path, pathSegmentIndex, path.pathSegments().size());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ import org.springframework.util.MultiValueMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static java.nio.charset.StandardCharsets.UTF_8;
 | 
					import static java.nio.charset.StandardCharsets.UTF_8;
 | 
				
			||||||
import static org.junit.Assert.assertEquals;
 | 
					import static org.junit.Assert.assertEquals;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertSame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Unit tests for {@link DefaultPathSegmentContainer}.
 | 
					 * Unit tests for {@link DefaultPathSegmentContainer}.
 | 
				
			||||||
| 
						 | 
					@ -121,4 +122,17 @@ public class DefaultPathSegmentContainerTests {
 | 
				
			||||||
		assertEquals("hasTrailingSlash: '" + input + "'", trailingSlash, path.hasTrailingSlash());
 | 
							assertEquals("hasTrailingSlash: '" + input + "'", trailingSlash, path.hasTrailingSlash());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void subPath() throws Exception {
 | 
				
			||||||
 | 
							// basic
 | 
				
			||||||
 | 
							PathSegmentContainer path = PathSegmentContainer.parse("/a/b/c", UTF_8);
 | 
				
			||||||
 | 
							assertSame(path, PathSegmentContainer.subPath(path, 0));
 | 
				
			||||||
 | 
							assertEquals("/b/c", PathSegmentContainer.subPath(path, 1).value());
 | 
				
			||||||
 | 
							assertEquals("/c", PathSegmentContainer.subPath(path, 2).value());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// trailing slash
 | 
				
			||||||
 | 
							path = PathSegmentContainer.parse("/a/b/", UTF_8);
 | 
				
			||||||
 | 
							assertEquals("/b/", PathSegmentContainer.subPath(path, 1).value());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue