Hello,

I wanted to introduce a constraint on the number of requests my server tries to handle at a time and played around with RequestLimitingHandler a little bit. However, I observed unexpected behavior once RequestLimit's queue gets full.

I've created a RequestLimitingHandler with both maximumConcurrentRequests and queueSize set to 1 and nextHandler that responds after a 3 second sleep. This is what I observed:

When I sent 2 concurrent requests with a curl, I got the first response after 3 seconds and the second one after 6 - just as expected, the second request got queued.

When I sent 3 concurrent requests, I got two correct responses and one 513 - just as expected, my third request couldn't fit into the queue so a failure handler got called. 

Now it got tricky - this made RequestLimit enter an invalid state, where its "state" field got decremented below the value that represents 0 current requests. Now "state & MASK_CURRENT" gives 2147483647 instead of 0, so the next time I make a single request, RequestLimit thinks there are 2147483647 requests in the system currently and queues my request instead of handling it. Then I make yet another request and now the queue is full, so 513 error is generated instantly which in turn makes RequestLimit poll my first pending request from the queue and dispatch it for handling. RequestLimit got corrupted and is unusable from now on.

I hope I explained my observations clearly. Is there something wrong in my setup, my understanding of Undertow or it's a bug? This is my code snippet, tested with undertow 1.1.0.Final and 1.2.0.Beta5:

import io.undertow.Undertow;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.RequestLimitingHandler;
import io.undertow.util.Headers;

public class Main {

    public static void main(String[] args) {
        Undertow server = Undertow.builder()
                .addHttpListener(8080, "localhost")
                .setHandler(new RequestLimitingHandler(1, 1, handler()))
                .build();

        server.start();
    }

    private static HttpHandler handler() {
        return new HttpHandler() {
            @Override
            public void handleRequest(final HttpServerExchange exchange) throws Exception {
                Thread.sleep(3000);
                exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                exchange.getResponseSender().send("Hello World");
            }
        };
    }

}


Cheers,
Piotr