Search in sources :

Example 1 with ReadListener

use of jakarta.servlet.ReadListener in project tomcat by apache.

the class CoyoteAdapter method asyncDispatch.

// -------------------------------------------------------- Adapter Methods
@Override
public boolean asyncDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res, SocketEvent status) throws Exception {
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);
    if (request == null) {
        throw new IllegalStateException(sm.getString("coyoteAdapter.nullRequest"));
    }
    boolean success = true;
    AsyncContextImpl asyncConImpl = request.getAsyncContextInternal();
    req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
    req.setRequestThread();
    try {
        if (!request.isAsync()) {
            // Error or timeout
            // Lift any suspension (e.g. if sendError() was used by an async
            // request) to allow the response to be written to the client
            response.setSuspended(false);
        }
        if (status == SocketEvent.TIMEOUT) {
            if (!asyncConImpl.timeout()) {
                asyncConImpl.setErrorState(null, false);
            }
        } else if (status == SocketEvent.ERROR) {
            // An I/O error occurred on a non-container thread which means
            // that the socket needs to be closed so set success to false to
            // trigger a close
            success = false;
            Throwable t = (Throwable) req.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
            Context context = request.getContext();
            ClassLoader oldCL = null;
            try {
                oldCL = context.bind(false, null);
                if (req.getReadListener() != null) {
                    req.getReadListener().onError(t);
                }
                if (res.getWriteListener() != null) {
                    res.getWriteListener().onError(t);
                }
                res.action(ActionCode.CLOSE_NOW, t);
                asyncConImpl.setErrorState(t, true);
            } finally {
                context.unbind(false, oldCL);
            }
        }
        // Check to see if non-blocking writes or reads are being used
        if (!request.isAsyncDispatching() && request.isAsync()) {
            WriteListener writeListener = res.getWriteListener();
            ReadListener readListener = req.getReadListener();
            if (writeListener != null && status == SocketEvent.OPEN_WRITE) {
                Context context = request.getContext();
                ClassLoader oldCL = null;
                try {
                    oldCL = context.bind(false, null);
                    res.onWritePossible();
                    if (request.isFinished() && req.sendAllDataReadEvent() && readListener != null) {
                        readListener.onAllDataRead();
                    }
                    // User code may have swallowed an IOException
                    if (response.getCoyoteResponse().isExceptionPresent()) {
                        throw response.getCoyoteResponse().getErrorException();
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    // Need to trigger the call to AbstractProcessor.setErrorState()
                    // before the listener is called so the listener can call complete
                    // Therefore no need to set success=false as that would trigger a
                    // second call to AbstractProcessor.setErrorState()
                    // https://bz.apache.org/bugzilla/show_bug.cgi?id=65001
                    writeListener.onError(t);
                    res.action(ActionCode.CLOSE_NOW, t);
                    asyncConImpl.setErrorState(t, true);
                } finally {
                    context.unbind(false, oldCL);
                }
            } else if (readListener != null && status == SocketEvent.OPEN_READ) {
                Context context = request.getContext();
                ClassLoader oldCL = null;
                try {
                    oldCL = context.bind(false, null);
                    // onDataAvailable() is not called in this case.
                    if (!request.isFinished()) {
                        req.onDataAvailable();
                    }
                    if (request.isFinished() && req.sendAllDataReadEvent()) {
                        readListener.onAllDataRead();
                    }
                    // User code may have swallowed an IOException
                    if (request.getCoyoteRequest().isExceptionPresent()) {
                        throw request.getCoyoteRequest().getErrorException();
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    // Need to trigger the call to AbstractProcessor.setErrorState()
                    // before the listener is called so the listener can call complete
                    // Therefore no need to set success=false as that would trigger a
                    // second call to AbstractProcessor.setErrorState()
                    // https://bz.apache.org/bugzilla/show_bug.cgi?id=65001
                    readListener.onError(t);
                    res.action(ActionCode.CLOSE_NOW, t);
                    asyncConImpl.setErrorState(t, true);
                } finally {
                    context.unbind(false, oldCL);
                }
            }
        }
        // if the application doesn't define one)?
        if (!request.isAsyncDispatching() && request.isAsync() && response.isErrorReportRequired()) {
            connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
        }
        if (request.isAsyncDispatching()) {
            connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
            Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
            if (t != null) {
                asyncConImpl.setErrorState(t, true);
            }
        }
        if (!request.isAsync()) {
            request.finishRequest();
            response.finishResponse();
        }
        // Check to see if the processor is in an error state. If it is,
        // bail out now.
        AtomicBoolean error = new AtomicBoolean(false);
        res.action(ActionCode.IS_ERROR, error);
        if (error.get()) {
            if (request.isAsyncCompleting()) {
                // Connection will be forcibly closed which will prevent
                // completion happening at the usual point. Need to trigger
                // call to onComplete() here.
                res.action(ActionCode.ASYNC_POST_PROCESS, null);
            }
            success = false;
        }
    } catch (IOException e) {
        success = false;
    // Ignore
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        success = false;
        log.error(sm.getString("coyoteAdapter.asyncDispatch"), t);
    } finally {
        if (!success) {
            res.setStatus(500);
        }
        // Access logging
        if (!success || !request.isAsync()) {
            long time = 0;
            if (req.getStartTimeNanos() != -1) {
                time = System.nanoTime() - req.getStartTimeNanos();
            }
            Context context = request.getContext();
            if (context != null) {
                context.logAccess(request, response, time, false);
            } else {
                log(req, res, time);
            }
        }
        req.getRequestProcessor().setWorkerThreadName(null);
        // Recycle the wrapper request and response
        if (!success || !request.isAsync()) {
            updateWrapperErrorCount(request, response);
            request.recycle();
            response.recycle();
        }
    }
    return success;
}
Also used : Context(org.apache.catalina.Context) AsyncContextImpl(org.apache.catalina.core.AsyncContextImpl) IOException(java.io.IOException) ReadListener(jakarta.servlet.ReadListener) HttpServletResponse(jakarta.servlet.http.HttpServletResponse) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) WriteListener(jakarta.servlet.WriteListener)

Example 2 with ReadListener

use of jakarta.servlet.ReadListener in project tomcat by apache.

the class CoyoteAdapter method service.

@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception {
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);
    if (request == null) {
        // Create objects
        request = connector.createRequest();
        request.setCoyoteRequest(req);
        response = connector.createResponse();
        response.setCoyoteResponse(res);
        // Link objects
        request.setResponse(response);
        response.setRequest(request);
        // Set as notes
        req.setNote(ADAPTER_NOTES, request);
        res.setNote(ADAPTER_NOTES, response);
        // Set query string encoding
        req.getParameters().setQueryStringCharset(connector.getURICharset());
    }
    if (connector.getXpoweredBy()) {
        response.addHeader("X-Powered-By", POWERED_BY);
    }
    boolean async = false;
    boolean postParseSuccess = false;
    req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
    req.setRequestThread();
    try {
        // Parse and set Catalina and configuration specific
        // request parameters
        postParseSuccess = postParseRequest(req, request, res, response);
        if (postParseSuccess) {
            // check valves if we support async
            request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
            // Calling the container
            connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
        }
        if (request.isAsync()) {
            async = true;
            ReadListener readListener = req.getReadListener();
            if (readListener != null && request.isFinished()) {
                // Possible the all data may have been read during service()
                // method so this needs to be checked here
                ClassLoader oldCL = null;
                try {
                    oldCL = request.getContext().bind(false, null);
                    if (req.sendAllDataReadEvent()) {
                        req.getReadListener().onAllDataRead();
                    }
                } finally {
                    request.getContext().unbind(false, oldCL);
                }
            }
            Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
            // the async error process
            if (!request.isAsyncCompleting() && throwable != null) {
                request.getAsyncContextInternal().setErrorState(throwable, true);
            }
        } else {
            request.finishRequest();
            response.finishResponse();
        }
    } catch (IOException e) {
    // Ignore
    } finally {
        AtomicBoolean error = new AtomicBoolean(false);
        res.action(ActionCode.IS_ERROR, error);
        if (request.isAsyncCompleting() && error.get()) {
            // Connection will be forcibly closed which will prevent
            // completion happening at the usual point. Need to trigger
            // call to onComplete() here.
            res.action(ActionCode.ASYNC_POST_PROCESS, null);
            async = false;
        }
        // Access log
        if (!async && postParseSuccess) {
            // Log only if processing was invoked.
            // If postParseRequest() failed, it has already logged it.
            Context context = request.getContext();
            Host host = request.getHost();
            // If the context is null, it is likely that the endpoint was
            // shutdown, this connection closed and the request recycled in
            // a different thread. That thread will have updated the access
            // log so it is OK not to update the access log here in that
            // case.
            // The other possibility is that an error occurred early in
            // processing and the request could not be mapped to a Context.
            // Log via the host or engine in that case.
            long time = System.nanoTime() - req.getStartTimeNanos();
            if (context != null) {
                context.logAccess(request, response, time, false);
            } else if (response.isError()) {
                if (host != null) {
                    host.logAccess(request, response, time, false);
                } else {
                    connector.getService().getContainer().logAccess(request, response, time, false);
                }
            }
        }
        req.getRequestProcessor().setWorkerThreadName(null);
        // Recycle the wrapper request and response
        if (!async) {
            updateWrapperErrorCount(request, response);
            request.recycle();
            response.recycle();
        }
    }
}
Also used : HttpServletResponse(jakarta.servlet.http.HttpServletResponse) Context(org.apache.catalina.Context) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Host(org.apache.catalina.Host) IOException(java.io.IOException) ReadListener(jakarta.servlet.ReadListener)

Aggregations

ReadListener (jakarta.servlet.ReadListener)2 HttpServletResponse (jakarta.servlet.http.HttpServletResponse)2 IOException (java.io.IOException)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 Context (org.apache.catalina.Context)2 WriteListener (jakarta.servlet.WriteListener)1 Host (org.apache.catalina.Host)1 AsyncContextImpl (org.apache.catalina.core.AsyncContextImpl)1