Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.x] - Add Max Re-Route configurable #5587

Merged
merged 4 commits into from
Dec 2, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ public final class HttpRouting implements Routing {
private final ServiceRoute rootRoute;
private final ErrorHandlers errorHandlers;
private final List<HttpFeature> features;
private final int maxReRouteCount;

private HttpRouting(Builder builder) {
this.errorHandlers = ErrorHandlers.create(builder.errorHandlers);
this.filters = Filters.create(errorHandlers, List.copyOf(builder.filters));
this.rootRoute = builder.rootRules.build();
this.features = List.copyOf(builder.features);

this.maxReRouteCount = builder.maxReRouteCount;
}

/**
Expand Down Expand Up @@ -96,7 +97,7 @@ public static HttpRouting empty() {
* @param response routing response
*/
public void route(ConnectionContext ctx, RoutingRequest request, RoutingResponse response) {
RoutingExecutor routingExecutor = new RoutingExecutor(ctx, rootRoute, request, response);
RoutingExecutor routingExecutor = new RoutingExecutor(ctx, rootRoute, request, response, maxReRouteCount);
// we cannot throw an exception to the filters, as then the filter would not have information about actual status
// code, so error handling is done in routing executor and for each filter
filters.filter(ctx, request, response, routingExecutor);
Expand Down Expand Up @@ -130,6 +131,7 @@ public static class Builder implements HttpRules, io.helidon.common.Builder<Buil
private final ServiceRules rootRules = new ServiceRules();
private final List<HttpFeature> features = new ArrayList<>();
private final Map<Class<? extends Throwable>, ErrorHandler<?>> errorHandlers = new IdentityHashMap<>();
private int maxReRouteCount = 10;

private Builder() {
}
Expand Down Expand Up @@ -319,22 +321,40 @@ public Builder any(String pattern, Handler handler) {
.path(pattern)
.handler(handler));
}

/**
* Maximal number of allowed re-routes within routing.
*
* @param maxReRouteCount
* @return updated builder
*
* @see io.helidon.nima.webserver.http.ServerResponse#reroute(String)
* @see io.helidon.nima.webserver.http.ServerResponse#reroute(String, io.helidon.common.uri.UriQuery)
*/
public Builder maxReRouteCount(int maxReRouteCount){
this.maxReRouteCount = maxReRouteCount;
return this;
}

}

private static final class RoutingExecutor implements Callable<Void> {
private final ConnectionContext ctx;
private final RoutingRequest request;
private final RoutingResponse response;
private final ServiceRoute rootRoute;
private final int maxReRouteCount;

private RoutingExecutor(ConnectionContext ctx,
ServiceRoute rootRoute,
RoutingRequest request,
RoutingResponse response) {
RoutingResponse response,
int maxReRouteCount) {
this.ctx = ctx;
this.rootRoute = rootRoute;
this.request = request;
this.response = response;
this.maxReRouteCount = maxReRouteCount;
}

@Override
Expand All @@ -350,11 +370,12 @@ public Void call() throws Exception {
}

// rerouting, do the more heavyweight while loop
int counter = 0;
int counter = 1;
while (result == RoutingResult.ROUTE) {
counter++;
if (counter == 9) {
LOGGER.log(System.Logger.Level.ERROR, "Rerouted more than 10 times. Will not attempt further routing");
if (counter == maxReRouteCount) {
LOGGER.log(System.Logger.Level.ERROR, "Rerouted more than " + maxReRouteCount
+ " times. Will not attempt further routing");

throw new HttpException("Too many reroutes", Http.Status.INTERNAL_SERVER_ERROR_500, true);
}
Expand Down