isapir commented on code in PR #607: URL: https://github.com/apache/tomcat/pull/607#discussion_r1154702239
########## java/org/apache/catalina/filters/RateLimitFilter.java: ########## @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.filters; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.GenericFilter; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.catalina.util.TimeBucketCounter; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.res.StringManager; + +import java.io.IOException; + +public class RateLimitFilter extends GenericFilter { + + /** + * default duration in seconds + */ + public static final int DEFAULT_BUCKET_DURATION = 60; + + /** + * default number of requests per duration + */ + public static final int DEFAULT_BUCKET_REQUESTS = 300; + + /** + * default value for enforce + */ + public static final boolean DEFAULT_ENFORCE = true; + + /** + * default status code to return if requests per duration exceeded + */ + public static final int DEFAULT_STATUS_CODE = 429; + + /** + * default status message to return if requests per duration exceeded + */ + public static final String DEFAULT_STATUS_MESSAGE = "Too many requests"; + + /** + * request attribute that will contain the number of requests per duration + */ + public static final String RATE_LIMIT_ATTRIBUTE_COUNT = "org.apache.catalina.filters.RateLimitFilter.Count"; + + /** + * filter init-param to set the bucket duration in seconds + */ + public static final String PARAM_BUCKET_DURATION = "ratelimit.bucket.duration"; + + /** + * filter init-param to set the bucket number of requests + */ + public static final String PARAM_BUCKET_REQUESTS = "ratelimit.bucket.requests"; + + /** + * filter init-param to set the enforce flag + */ + public static final String PARAM_ENFORCE = "ratelimit.enforce"; + + /** + * filter init-param to set a custom status code if requests per duration exceeded + */ + public static final String PARAM_STATUS_CODE = "ratelimit.status.code"; + + /** + * filter init-param to set a custom status message if requests per duration exceeded + */ + public static final String PARAM_STATUS_MESSAGE = "ratelimit.status.message"; + + TimeBucketCounter bucketCounter; + + private int actualRequests; + + private int bucketRequests = DEFAULT_BUCKET_REQUESTS; + + private int bucketDuration = DEFAULT_BUCKET_DURATION; + + private boolean enforce = DEFAULT_ENFORCE; + private int statusCode = DEFAULT_STATUS_CODE; + + private String statusMessage = DEFAULT_STATUS_MESSAGE; + + private transient Log log = LogFactory.getLog(RateLimitFilter.class); + + private static final StringManager sm = StringManager.getManager(RateLimitFilter.class); + + /** + * @return the actual maximum allowed requests per time bucket + */ + public int getActualRequests() { + return actualRequests; + } + + /** + * @return the actual duration of a time bucket in milliseconds + */ + public int getActualDurationInSeconds() { + return bucketCounter.getActualDuration() / 1000; + } + + @Override + public void init() throws ServletException { + + FilterConfig config = getFilterConfig(); + + String param; + param = config.getInitParameter(PARAM_BUCKET_DURATION); + if (param != null) + bucketDuration = Integer.parseInt(param); + + param = config.getInitParameter(PARAM_BUCKET_REQUESTS); + if (param != null) + bucketRequests = Integer.parseInt(param); + + param = config.getInitParameter(PARAM_ENFORCE); + if (param != null) + enforce = Boolean.parseBoolean(param); + + param = config.getInitParameter(PARAM_STATUS_CODE); + if (param != null) + statusCode = Integer.parseInt(param); + + param = config.getInitParameter(PARAM_STATUS_MESSAGE); + if (param != null) + statusMessage = param; + + bucketCounter = new TimeBucketCounter(bucketDuration); + + actualRequests = (int) Math.round(bucketCounter.getRatio() * bucketRequests); + + log.info(sm.getString("rateLimitFilter.initialized", + super.getFilterName(), bucketRequests, bucketDuration, getActualRequests(), + getActualDurationInSeconds(), (!enforce ? "Not " : "") + "enforcing") + ); + } + + /** Review Comment: Chris - sounds good. Will do. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org