From fab25e1eb2639f0740ae8f1b93cedbf4f1a49b5e Mon Sep 17 00:00:00 2001 From: ctlove0523 <478309639@qq.com> Date: Mon, 16 Aug 2021 19:52:32 +0800 Subject: [PATCH] Add an API for removing a route Related to #1669 Co-authored-by: Violeta Georgieva --- .../http/server/DefaultHttpServerRoutes.java | 28 ++++++++++-- .../http/server/HttpRouteHandlerMetadata.java | 10 +++++ .../netty/http/server/HttpServerRoutes.java | 10 +++++ .../netty/http/server/HttpServerTests.java | 43 +++++++++++++++++++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpServerRoutes.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpServerRoutes.java index 36e7a5d6c0..4415e9b525 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpServerRoutes.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpServerRoutes.java @@ -29,6 +29,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import io.netty.handler.codec.http.HttpMethod; import org.reactivestreams.Publisher; import reactor.core.Exceptions; import reactor.core.publisher.Mono; @@ -74,6 +75,15 @@ public HttpServerRoutes directory(String uri, Path directory, }); } + @Override + public HttpServerRoutes removeIf(Predicate condition) { + Objects.requireNonNull(condition, "condition"); + + handlers.removeIf(condition); + + return this; + } + @Override public HttpServerRoutes route(Predicate condition, BiFunction> handler) { @@ -81,16 +91,16 @@ public HttpServerRoutes route(Predicate condition, Objects.requireNonNull(handler, "handler"); if (condition instanceof HttpPredicate) { + HttpPredicate predicate = (HttpPredicate) condition; HttpRouteHandler httpRouteHandler = new HttpRouteHandler(condition, - handler, - (HttpPredicate) condition, ((HttpPredicate) condition).uri); + handler, predicate, predicate.uri, predicate.method); handlers.add(httpRouteHandler); initialOrderHandlers.add(httpRouteHandler); } else { - HttpRouteHandler httpRouteHandler = new HttpRouteHandler(condition, handler, null, null); + HttpRouteHandler httpRouteHandler = new HttpRouteHandler(condition, handler, null, null, null); handlers.add(httpRouteHandler); initialOrderHandlers.add(httpRouteHandler); } @@ -119,6 +129,7 @@ public HttpServerRoutes noComparator() { @Override public Publisher apply(HttpServerRequest request, HttpServerResponse response) { + // find I/0 handler to process this request final Iterator iterator = handlers.iterator(); HttpRouteHandler cursor; @@ -149,14 +160,18 @@ static final class HttpRouteHandler final String path; + final HttpMethod method; + HttpRouteHandler(Predicate condition, BiFunction> handler, @Nullable Function> resolver, - @Nullable String path) { + @Nullable String path, + @Nullable HttpMethod method) { this.condition = Objects.requireNonNull(condition, "condition"); this.handler = Objects.requireNonNull(handler, "handler"); this.resolver = resolver; this.path = path; + this.method = method; } @Override @@ -174,5 +189,10 @@ public boolean test(HttpServerRequest o) { public String getPath() { return path; } + + @Override + public HttpMethod getMethod() { + return method; + } } } diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpRouteHandlerMetadata.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpRouteHandlerMetadata.java index 72a5cd5534..98c758a0d5 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpRouteHandlerMetadata.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpRouteHandlerMetadata.java @@ -15,6 +15,7 @@ */ package reactor.netty.http.server; +import io.netty.handler.codec.http.HttpMethod; import reactor.util.annotation.Nullable; import java.util.Comparator; @@ -35,4 +36,13 @@ public interface HttpRouteHandlerMetadata { */ @Nullable String getPath(); + + /** + * Get the http method this handler can handle + * + * @return the http method {@link HttpMethod} + * @since 1.0.11 + */ + @Nullable + HttpMethod getMethod(); } diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerRoutes.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerRoutes.java index d11debdcce..b4b3a65eb0 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerRoutes.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerRoutes.java @@ -251,6 +251,16 @@ default HttpServerRoutes put(String path, return route(HttpPredicate.put(path), handler); } + /** + * A generic route predicate that if matched already register I/O handler use + * {@link HttpServerRoutes#route(Predicate, BiFunction)} will be removed. + * + * @param condition a predicate given each http route handler {@link HttpRouteHandlerMetadata} + * @return this {@link HttpServerRoutes} + * @since 1.0.11 + */ + HttpServerRoutes removeIf(Predicate condition); + /** * A generic route predicate that if matched invoke the passed I/O handler. * diff --git a/reactor-netty-http/src/test/java/reactor/netty/http/server/HttpServerTests.java b/reactor-netty-http/src/test/java/reactor/netty/http/server/HttpServerTests.java index e03b036d4a..f4b51270a8 100644 --- a/reactor-netty-http/src/test/java/reactor/netty/http/server/HttpServerTests.java +++ b/reactor-netty-http/src/test/java/reactor/netty/http/server/HttpServerTests.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -2612,4 +2613,46 @@ private void doTestConnectionClosePropagatedAsError(String request) throws Excep .isInstanceOf(AbortedException.class) .hasMessage("Connection has been closed"); } + + @Test + void testRemoveRoutes() { + HttpServerRoutes serverRoutes = HttpServerRoutes.newRoutes() + .get("/route1", (request, response) -> response.sendString(Mono.just("/route1"))) + .get("/route2", (request, response) -> response.sendString(Mono.just("/route2"))); + + try { + disposableServer = HttpServer.create().handle(serverRoutes).bindNow(); + + StepVerifier.create(createClient(disposableServer.port()).get().uri("/route1") + .responseSingle((response, byteBufMono) -> byteBufMono.asString())) + .expectNext("/route1") + .verifyComplete(); + + StepVerifier.create(createClient(disposableServer.port()).get().uri("/route2") + .responseSingle((response, byteBufMono) -> byteBufMono.asString())) + .expectNext("/route2") + .verifyComplete(); + } + finally { + if (disposableServer != null) { + disposableServer.disposeNow(); + } + } + + HttpServerRoutes serverRoutes1 = serverRoutes.removeIf(metadata -> Objects.equals(metadata.getPath(), "/route1") + && metadata.getMethod().equals(HttpMethod.GET)); + + disposableServer = HttpServer.create().handle(serverRoutes1) + .bindNow(); + + StepVerifier.create(createClient(disposableServer.port()).get().uri("/route1") + .response()) + .expectNextMatches(response -> response.status().equals(HttpResponseStatus.NOT_FOUND)) + .verifyComplete(); + + StepVerifier.create(createClient(disposableServer.port()).get().uri("/route2") + .responseSingle((response, byteBufMono) -> byteBufMono.asString())) + .expectNext("/route2") + .verifyComplete(); + } }