package io.mangoo.routing.handlers;
import java.util.Objects;
import com.google.inject.Inject;
import io.mangoo.cache.Cache;
import io.mangoo.core.Application;
import io.mangoo.enums.CacheName;
import io.mangoo.enums.Required;
import io.mangoo.helpers.RequestHelper;
import io.mangoo.providers.CacheProvider;
import io.mangoo.routing.Attachment;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderValues;
import io.undertow.util.Headers;
import io.undertow.util.StatusCodes;
/**
*
* @author svenkubiak
*
*/
public class LimitHandler implements HttpHandler {
private Attachment attachment;
private Cache cache;
private final RequestHelper requestHelper;
@Inject
public LimitHandler(CacheProvider cacheProvider, RequestHelper requestHelper) {
Objects.requireNonNull(cacheProvider, Required.CACHE_PROVIDER.toString());
this.cache = cacheProvider.getCache(CacheName.REQUEST);
this.requestHelper = Objects.requireNonNull(requestHelper, Required.REQUEST_HELPER.toString());
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
this.attachment = exchange.getAttachment(RequestHelper.ATTACHMENT_KEY);
if (this.attachment.hasLimit()) {
String key = getCacheKey(exchange);
if (this.cache.increment(key).get() > this.attachment.getLimit()) {
endRequest(exchange);
} else {
nextHandler(exchange);
}
} else {
nextHandler(exchange);
}
}
/**
* Creates a key for used for limit an request containing the
* requested url and the source host
*
* @param exchange The HttpServerExchange
* @return The key url + host
*/
private String getCacheKey(HttpServerExchange exchange) {
String host;
HeaderValues headerValues = exchange.getRequestHeaders().get(Headers.X_FORWARDED_FOR);
if (headerValues != null) {
host = headerValues.element();
} else {
host = exchange.getSourceAddress().getHostString();
}
return exchange.getRequestURL() + host;
}
/**
* Ends the current request by sending a HTTP 429 status code
* @param exchange The HttpServerExchange
*/
private void endRequest(HttpServerExchange exchange) {
exchange.setStatusCode(StatusCodes.TOO_MANY_REQUESTS);
exchange.endExchange();
}
/**
* Handles the next request in the handler chain
*
* @param exchange The HttpServerExchange
* @throws Exception Thrown when an exception occurs
*/
@SuppressWarnings("all")
protected void nextHandler(HttpServerExchange exchange) throws Exception {
if (this.attachment.hasAuthentication()) {
HttpHandler httpHandler = this.requestHelper.wrapSecurity(
Application.getInstance(LocaleHandler.class),
this.attachment.getUsername(),
this.attachment.getPassword());
httpHandler.handleRequest(exchange);
} else {
Application.getInstance(LocaleHandler.class).handleRequest(exchange);
}
}
}