Search in sources :

Example 26 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class DoSFilter method doFilter.

protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    if (!isEnabled()) {
        filterChain.doFilter(request, response);
        return;
    }
    // Look for the rate tracker for this request.
    RateTracker tracker = (RateTracker) request.getAttribute(__TRACKER);
    if (tracker == null) {
        // This is the first time we have seen this request.
        if (LOG.isDebugEnabled())
            LOG.debug("Filtering {}", request);
        // Get a rate tracker associated with this request, and record one hit.
        tracker = getRateTracker(request);
        // Calculate the rate and check it is over the allowed limit
        final boolean overRateLimit = tracker.isRateExceeded(System.currentTimeMillis());
        // Pass it through if  we are not currently over the rate limit.
        if (!overRateLimit) {
            if (LOG.isDebugEnabled())
                LOG.debug("Allowing {}", request);
            doFilterChain(filterChain, request, response);
            return;
        }
        // We are over the limit.
        // So either reject it, delay it or throttle it.
        long delayMs = getDelayMs();
        boolean insertHeaders = isInsertHeaders();
        switch((int) delayMs) {
            case -1:
                {
                    // Reject this request.
                    LOG.warn("DOS ALERT: Request rejected ip={}, session={}, user={}", request.getRemoteAddr(), request.getRequestedSessionId(), request.getUserPrincipal());
                    if (insertHeaders)
                        response.addHeader("DoSFilter", "unavailable");
                    response.sendError(getTooManyCode());
                    return;
                }
            case 0:
                {
                    // Fall through to throttle the request.
                    LOG.warn("DOS ALERT: Request throttled ip={}, session={}, user={}", request.getRemoteAddr(), request.getRequestedSessionId(), request.getUserPrincipal());
                    request.setAttribute(__TRACKER, tracker);
                    break;
                }
            default:
                {
                    // Insert a delay before throttling the request,
                    // using the suspend+timeout mechanism of AsyncContext.
                    LOG.warn("DOS ALERT: Request delayed={}ms, ip={}, session={}, user={}", delayMs, request.getRemoteAddr(), request.getRequestedSessionId(), request.getUserPrincipal());
                    if (insertHeaders)
                        response.addHeader("DoSFilter", "delayed");
                    request.setAttribute(__TRACKER, tracker);
                    AsyncContext asyncContext = request.startAsync();
                    if (delayMs > 0)
                        asyncContext.setTimeout(delayMs);
                    asyncContext.addListener(new DoSTimeoutAsyncListener());
                    return;
                }
        }
    }
    if (LOG.isDebugEnabled())
        LOG.debug("Throttling {}", request);
    // Throttle the request.
    boolean accepted = false;
    try {
        // Check if we can afford to accept another request at this time.
        accepted = _passes.tryAcquire(getMaxWaitMs(), TimeUnit.MILLISECONDS);
        if (!accepted) {
            // We were not accepted, so either we suspend to wait,
            // or if we were woken up we insist or we fail.
            Boolean throttled = (Boolean) request.getAttribute(__THROTTLED);
            long throttleMs = getThrottleMs();
            if (throttled != Boolean.TRUE && throttleMs > 0) {
                int priority = getPriority(request, tracker);
                request.setAttribute(__THROTTLED, Boolean.TRUE);
                if (isInsertHeaders())
                    response.addHeader("DoSFilter", "throttled");
                AsyncContext asyncContext = request.startAsync();
                request.setAttribute(_suspended, Boolean.TRUE);
                if (throttleMs > 0)
                    asyncContext.setTimeout(throttleMs);
                asyncContext.addListener(_listeners[priority]);
                _queues[priority].add(asyncContext);
                if (LOG.isDebugEnabled())
                    LOG.debug("Throttled {}, {}ms", request, throttleMs);
                return;
            }
            Boolean resumed = (Boolean) request.getAttribute(_resumed);
            if (resumed == Boolean.TRUE) {
                // We were resumed, we wait for the next pass.
                _passes.acquire();
                accepted = true;
            }
        }
        // If we were accepted (either immediately or after throttle)...
        if (accepted) {
            // ...call the chain.
            if (LOG.isDebugEnabled())
                LOG.debug("Allowing {}", request);
            doFilterChain(filterChain, request, response);
        } else {
            // ...otherwise fail the request.
            if (LOG.isDebugEnabled())
                LOG.debug("Rejecting {}", request);
            if (isInsertHeaders())
                response.addHeader("DoSFilter", "unavailable");
            response.sendError(getTooManyCode());
        }
    } catch (InterruptedException e) {
        LOG.ignore(e);
        response.sendError(getTooManyCode());
    } finally {
        if (accepted) {
            try {
                // Wake up the next highest priority request.
                for (int p = _queues.length - 1; p >= 0; --p) {
                    AsyncContext asyncContext = _queues[p].poll();
                    if (asyncContext != null) {
                        ServletRequest candidate = asyncContext.getRequest();
                        Boolean suspended = (Boolean) candidate.getAttribute(_suspended);
                        if (suspended == Boolean.TRUE) {
                            if (LOG.isDebugEnabled())
                                LOG.debug("Resuming {}", request);
                            candidate.setAttribute(_resumed, Boolean.TRUE);
                            asyncContext.dispatch();
                            break;
                        }
                    }
                }
            } finally {
                _passes.release();
            }
        }
    }
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletRequest(javax.servlet.ServletRequest) AsyncContext(javax.servlet.AsyncContext)

Example 27 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class EventSourceServlet method doGet.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    @SuppressWarnings("unchecked") Enumeration<String> acceptValues = request.getHeaders("Accept");
    while (acceptValues.hasMoreElements()) {
        String accept = acceptValues.nextElement();
        if (accept.equals("text/event-stream")) {
            EventSource eventSource = newEventSource(request);
            if (eventSource == null) {
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
            } else {
                respond(request, response);
                AsyncContext async = request.startAsync();
                // Infinite timeout because the continuation is never resumed,
                // but only completed on close
                async.setTimeout(0);
                EventSourceEmitter emitter = new EventSourceEmitter(eventSource, async);
                emitter.scheduleHeartBeat();
                open(eventSource, emitter);
            }
            return;
        }
    }
    super.doGet(request, response);
}
Also used : AsyncContext(javax.servlet.AsyncContext)

Example 28 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class DataRateLimitedServlet method doGet.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Get the path of the static resource to serve.
    String info = request.getPathInfo();
    // We don't handle directories
    if (info.endsWith("/")) {
        response.sendError(503, "directories not supported");
        return;
    }
    // Set the mime type of the response
    String content_type = getServletContext().getMimeType(info);
    response.setContentType(content_type == null ? "application/x-data" : content_type);
    // Look for a matching file path
    String path = request.getPathTranslated();
    // If we have a file path and this is a jetty response, we can use the JettyStream impl
    ServletOutputStream out = response.getOutputStream();
    if (path != null && out instanceof HttpOutput) {
        // If the file exists
        File file = new File(path);
        if (file.exists() && file.canRead()) {
            // Set the content length
            response.setContentLengthLong(file.length());
            // Look for a file mapped buffer in the cache
            ByteBuffer mapped = cache.get(path);
            // Handle cache miss
            if (mapped == null) {
                // TODO implement LRU cache flush
                try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
                    ByteBuffer buf = raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
                    mapped = cache.putIfAbsent(path, buf);
                    if (mapped == null)
                        mapped = buf;
                }
            }
            // start async request handling
            AsyncContext async = request.startAsync();
            // Set a JettyStream as the write listener to write the content asynchronously.
            out.setWriteListener(new JettyDataStream(mapped, async, out));
            return;
        }
    }
    // Jetty API was not used, so lets try the standards approach
    // Can we find the content as an input stream
    InputStream content = getServletContext().getResourceAsStream(info);
    if (content == null) {
        response.sendError(404);
        return;
    }
    // Set a StandardStream as he write listener to write the content asynchronously
    out.setWriteListener(new StandardDataStream(content, request.startAsync(), out));
}
Also used : RandomAccessFile(java.io.RandomAccessFile) ServletOutputStream(javax.servlet.ServletOutputStream) InputStream(java.io.InputStream) AsyncContext(javax.servlet.AsyncContext) HttpOutput(org.eclipse.jetty.server.HttpOutput) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File) ByteBuffer(java.nio.ByteBuffer)

Example 29 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class ServerTimeoutsTest method testAsyncWriteIdleTimeoutFires.

@Test
public void testAsyncWriteIdleTimeoutFires() throws Exception {
    CountDownLatch handlerLatch = new CountDownLatch(1);
    start(new AbstractHandler() {

        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            baseRequest.setHandled(true);
            AsyncContext asyncContext = request.startAsync();
            asyncContext.setTimeout(0);
            ServletOutputStream output = response.getOutputStream();
            output.setWriteListener(new WriteListener() {

                @Override
                public void onWritePossible() throws IOException {
                    output.write(new byte[64 * 1024 * 1024]);
                }

                @Override
                public void onError(Throwable failure) {
                    if (failure instanceof TimeoutException) {
                        asyncContext.complete();
                        handlerLatch.countDown();
                    }
                }
            });
        }
    });
    long idleTimeout = 2500;
    setServerIdleTimeout(idleTimeout);
    BlockingQueue<Callback> callbacks = new LinkedBlockingQueue<>();
    CountDownLatch resultLatch = new CountDownLatch(1);
    client.newRequest(newURI()).onResponseContentAsync((response, content, callback) -> {
        // Do not succeed the callback so the server will block writing.
        callbacks.offer(callback);
    }).send(result -> {
        if (result.isFailed())
            resultLatch.countDown();
    });
    // Async write should timeout.
    Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
    // After the server stopped sending, consume on the client to read the early EOF.
    while (true) {
        Callback callback = callbacks.poll(1, TimeUnit.SECONDS);
        if (callback == null)
            break;
        callback.succeeded();
    }
    Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS));
}
Also used : BadMessageException(org.eclipse.jetty.http.BadMessageException) Request(org.eclipse.jetty.server.Request) ServletException(javax.servlet.ServletException) HttpChannel(org.eclipse.jetty.server.HttpChannel) AbstractHandler(org.eclipse.jetty.server.handler.AbstractHandler) ServletInputStream(javax.servlet.ServletInputStream) AbstractHTTP2ServerConnectionFactory(org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory) TimeoutException(java.util.concurrent.TimeoutException) ByteBuffer(java.nio.ByteBuffer) AsyncContext(javax.servlet.AsyncContext) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletOutputStream(javax.servlet.ServletOutputStream) WriteListener(javax.servlet.WriteListener) DeferredContentProvider(org.eclipse.jetty.client.util.DeferredContentProvider) HttpStatus(org.eclipse.jetty.http.HttpStatus) Callback(org.eclipse.jetty.util.Callback) HttpServletResponse(javax.servlet.http.HttpServletResponse) IOException(java.io.IOException) BlockingQueue(java.util.concurrent.BlockingQueue) Test(org.junit.Test) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) TimeUnit(java.util.concurrent.TimeUnit) CountDownLatch(java.util.concurrent.CountDownLatch) ReadListener(javax.servlet.ReadListener) StacklessLogging(org.eclipse.jetty.util.log.StacklessLogging) Assert(org.junit.Assert) ServletOutputStream(javax.servlet.ServletOutputStream) Request(org.eclipse.jetty.server.Request) HttpServletRequest(javax.servlet.http.HttpServletRequest) HttpServletResponse(javax.servlet.http.HttpServletResponse) AsyncContext(javax.servlet.AsyncContext) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) AbstractHandler(org.eclipse.jetty.server.handler.AbstractHandler) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) Callback(org.eclipse.jetty.util.Callback) WriteListener(javax.servlet.WriteListener) TimeoutException(java.util.concurrent.TimeoutException) Test(org.junit.Test)

Example 30 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class ServerTimeoutsTest method testAsyncReadHttpIdleTimeoutOverridesIdleTimeout.

@Test
public void testAsyncReadHttpIdleTimeoutOverridesIdleTimeout() throws Exception {
    long httpIdleTimeout = 2500;
    long idleTimeout = 3 * httpIdleTimeout;
    httpConfig.setIdleTimeout(httpIdleTimeout);
    CountDownLatch handlerLatch = new CountDownLatch(1);
    start(new AbstractHandler() {

        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            baseRequest.setHandled(true);
            AsyncContext asyncContext = request.startAsync();
            asyncContext.setTimeout(0);
            ServletInputStream input = request.getInputStream();
            input.setReadListener(new ReadListener() {

                @Override
                public void onDataAvailable() throws IOException {
                    Assert.assertEquals(0, input.read());
                    Assert.assertFalse(input.isReady());
                }

                @Override
                public void onAllDataRead() throws IOException {
                }

                @Override
                public void onError(Throwable failure) {
                    if (failure instanceof TimeoutException) {
                        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
                        asyncContext.complete();
                        handlerLatch.countDown();
                    }
                }
            });
        }
    });
    setServerIdleTimeout(idleTimeout);
    DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1));
    CountDownLatch resultLatch = new CountDownLatch(1);
    client.POST(newURI()).content(contentProvider).send(result -> {
        if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500)
            resultLatch.countDown();
    });
    // Async read should timeout.
    Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
    // Complete the request.
    contentProvider.close();
    Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS));
}
Also used : Request(org.eclipse.jetty.server.Request) HttpServletRequest(javax.servlet.http.HttpServletRequest) HttpServletResponse(javax.servlet.http.HttpServletResponse) AsyncContext(javax.servlet.AsyncContext) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) ReadListener(javax.servlet.ReadListener) AbstractHandler(org.eclipse.jetty.server.handler.AbstractHandler) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) ServletInputStream(javax.servlet.ServletInputStream) DeferredContentProvider(org.eclipse.jetty.client.util.DeferredContentProvider) TimeoutException(java.util.concurrent.TimeoutException) Test(org.junit.Test)

Aggregations

AsyncContext (javax.servlet.AsyncContext)194 IOException (java.io.IOException)90 HttpServletResponse (javax.servlet.http.HttpServletResponse)78 HttpServletRequest (javax.servlet.http.HttpServletRequest)76 ServletException (javax.servlet.ServletException)61 Test (org.junit.Test)57 CountDownLatch (java.util.concurrent.CountDownLatch)38 AsyncEvent (javax.servlet.AsyncEvent)35 AsyncListener (javax.servlet.AsyncListener)35 HttpServlet (javax.servlet.http.HttpServlet)34 ServletOutputStream (javax.servlet.ServletOutputStream)27 InterruptedIOException (java.io.InterruptedIOException)24 ReadListener (javax.servlet.ReadListener)20 ServletInputStream (javax.servlet.ServletInputStream)20 ContentResponse (org.eclipse.jetty.client.api.ContentResponse)18 Request (org.eclipse.jetty.server.Request)16 WriteListener (javax.servlet.WriteListener)15 PrintWriter (java.io.PrintWriter)14 UncheckedIOException (java.io.UncheckedIOException)14 ByteBuffer (java.nio.ByteBuffer)13