This is an automated email from the ASF dual-hosted git repository. uce pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/flink.git
commit 371379381d9a1a260df29444bcab3744c8d79007 Author: Ufuk Celebi <[email protected]> AuthorDate: Tue May 28 09:21:30 2024 +0200 [FLINK-26808][rest] Add MultipartRoutes utility --- .../rest/handler/router/MultipartRoutes.java | 84 ++++++++++++++++++++++ .../runtime/rest/handler/router/PathPattern.java | 5 ++ .../flink/runtime/rest/handler/router/Router.java | 2 +- .../rest/handler/router/MultipartRoutesTest.java | 34 +++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutes.java b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutes.java new file mode 100644 index 00000000000..4dc2bffe43d --- /dev/null +++ b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutes.java @@ -0,0 +1,84 @@ +package org.apache.flink.runtime.rest.handler.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A utility for {@link org.apache.flink.runtime.rest.FileUploadHandler} to determine whether it + * should accept a request. + */ +public class MultipartRoutes { + + private final List<PathPattern> postRoutes; + private final List<PathPattern> fileUploadRoutes; + + private MultipartRoutes(List<PathPattern> postRoutes, List<PathPattern> fileUploadRoutes) { + this.postRoutes = new ArrayList<>(postRoutes); + this.fileUploadRoutes = new ArrayList<>(fileUploadRoutes); + } + + /** + * Returns <code>true</code> if the handler at the provided <code>requestUri</code> endpoint + * accepts POST requests. + * + * @param requestUri URI for the request + */ + public boolean isPostRoute(String requestUri) { + return checkRoutes(requestUri, postRoutes); + } + + /** + * Returns <code>true</code> if the handler at the provided <code>requestUri</code> endpoint + * accepts file uploads. + * + * @param requestUri URI for the request + */ + public boolean isFileUploadRoute(String requestUri) { + return checkRoutes(requestUri, fileUploadRoutes); + } + + @Override + public String toString() { + return "MultipartRoutes{" + + "postRoutes=" + + postRoutes + + ", fileUploadRoutes=" + + fileUploadRoutes + + '}'; + } + + private boolean checkRoutes(String requestUri, List<PathPattern> routes) { + String[] pathTokens = Router.decodePathTokens(requestUri); + Map<String, String> params = new HashMap<>(); + for (PathPattern route : routes) { + if (route.match(pathTokens, params)) { + return true; + } + } + return false; + } + + public static class Builder { + + private final List<PathPattern> postRoutes = new ArrayList<>(); + private final List<PathPattern> fileUploadRoutes = new ArrayList<>(); + + public Builder() {} + + public MultipartRoutes.Builder addPostRoute(String pattern) { + postRoutes.add(new PathPattern(pattern)); + return this; + } + + public MultipartRoutes.Builder addFileUploadRoute(String pattern) { + fileUploadRoutes.add(new PathPattern(pattern)); + return this; + } + + public MultipartRoutes build() { + return new MultipartRoutes(postRoutes, fileUploadRoutes); + } + } +} diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/PathPattern.java b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/PathPattern.java index a2a3817922d..a1a0c91517d 100644 --- a/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/PathPattern.java +++ b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/PathPattern.java @@ -93,6 +93,11 @@ final class PathPattern { return tokens; } + @Override + public String toString() { + return pattern; + } + // -------------------------------------------------------------------------- // Instances of this class can be conveniently used as Map keys. diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/Router.java b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/Router.java index 2faa37b9725..664b7d90ba9 100644 --- a/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/Router.java +++ b/flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/router/Router.java @@ -235,7 +235,7 @@ public class Router<T> { // -------------------------------------------------------------------------- - private String[] decodePathTokens(String uri) { + static String[] decodePathTokens(String uri) { // Need to split the original URI (instead of QueryStringDecoder#path) then decode the // tokens (components), // otherwise /test1/123%2F456 will not match /test1/:p1 diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutesTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutesTest.java new file mode 100644 index 00000000000..33520dbb9d6 --- /dev/null +++ b/flink-runtime/src/test/java/org/apache/flink/runtime/rest/handler/router/MultipartRoutesTest.java @@ -0,0 +1,34 @@ +package org.apache.flink.runtime.rest.handler.router; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MultipartRoutesTest { + + @Test + public void testRoutePatternMatching() { + MultipartRoutes.Builder builder = new MultipartRoutes.Builder(); + builder.addPostRoute("/jobs"); + builder.addPostRoute("/jobs/:jobid/stop"); + builder.addPostRoute("/jobs/:jobid/savepoints/:savepointid/delete"); + + builder.addFileUploadRoute("/jobs"); + builder.addFileUploadRoute("/jobs/:jobid/stop"); + builder.addFileUploadRoute("/jobs/:jobid/savepoints/:savepointid/delete"); + + MultipartRoutes routes = builder.build(); + + assertThat(routes.isPostRoute("/jobs")).isTrue(); + assertThat(routes.isPostRoute("/jobs?q1=p1&q2=p2")).isTrue(); + assertThat(routes.isPostRoute("/jobs/abc")).isFalse(); + assertThat(routes.isPostRoute("/jobs/abc/stop")).isTrue(); + assertThat(routes.isPostRoute("/jobs/abc/savepoints/def/delete")).isTrue(); + + assertThat(routes.isFileUploadRoute("/jobs")).isTrue(); + assertThat(routes.isFileUploadRoute("/jobs?q1=p1&q2=p2")).isTrue(); + assertThat(routes.isFileUploadRoute("/jobs/abc")).isFalse(); + assertThat(routes.isFileUploadRoute("/jobs/abc/stop")).isTrue(); + assertThat(routes.isFileUploadRoute("/jobs/abc/savepoints/def/delete")).isTrue(); + } +}
