Search in sources :

Example 61 with HttpServletResponse

use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.

the class CorsFilter method doFilter.

@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
    if (!(servletRequest instanceof HttpServletRequest) || !(servletResponse instanceof HttpServletResponse)) {
        throw new ServletException(sm.getString("corsFilter.onlyHttp"));
    }
    // Safe to downcast at this point.
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    // Determines the CORS request type.
    CorsFilter.CORSRequestType requestType = checkRequestType(request);
    // Adds CORS specific attributes to request.
    if (isDecorateRequest()) {
        CorsFilter.decorateCORSProperties(request, requestType);
    }
    switch(requestType) {
        case SIMPLE:
        // Handles a Simple CORS request.
        case ACTUAL:
            // Handles an Actual CORS request.
            this.handleSimpleCORS(request, response, filterChain);
            break;
        case PRE_FLIGHT:
            // Handles a Pre-flight CORS request.
            this.handlePreflightCORS(request, response, filterChain);
            break;
        case NOT_CORS:
            // Handles a Normal request that is not a cross-origin request.
            this.handleNonCORS(request, response, filterChain);
            break;
        default:
            // Handles a CORS request that violates specification.
            this.handleInvalidCORS(request, response, filterChain);
            break;
    }
}
Also used : HttpServletRequest(jakarta.servlet.http.HttpServletRequest) ServletException(jakarta.servlet.ServletException) HttpServletResponse(jakarta.servlet.http.HttpServletResponse)

Example 62 with HttpServletResponse

use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.

the class CsrfPreventionFilter method doFilter.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    ServletResponse wResponse = null;
    if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        boolean skipNonceCheck = false;
        if (Constants.METHOD_GET.equals(req.getMethod()) && entryPoints.contains(getRequestedPath(req))) {
            if (log.isTraceEnabled()) {
                log.trace("Skipping CSRF nonce-check for GET request to entry point " + getRequestedPath(req));
            }
            skipNonceCheck = true;
        }
        HttpSession session = req.getSession(false);
        @SuppressWarnings("unchecked") LruCache<String> nonceCache = (session == null) ? null : (LruCache<String>) session.getAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME);
        if (!skipNonceCheck) {
            String previousNonce = req.getParameter(nonceRequestParameterName);
            if (previousNonce == null) {
                if (log.isDebugEnabled()) {
                    log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " with no CSRF nonce found in request");
                }
                res.sendError(getDenyStatus());
                return;
            } else if (nonceCache == null) {
                if (log.isDebugEnabled()) {
                    log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " due to empty / missing nonce cache");
                }
                res.sendError(getDenyStatus());
                return;
            } else if (!nonceCache.contains(previousNonce)) {
                if (log.isDebugEnabled()) {
                    log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " due to invalid nonce " + previousNonce);
                }
                res.sendError(getDenyStatus());
                return;
            }
            if (log.isTraceEnabled()) {
                log.trace("Allowing request to " + getRequestedPath(req) + " with valid CSRF nonce " + previousNonce);
            }
        }
        if (nonceCache == null) {
            if (log.isDebugEnabled()) {
                log.debug("Creating new CSRF nonce cache with size=" + nonceCacheSize + " for session " + (null == session ? "(will create)" : session.getId()));
            }
            nonceCache = new LruCache<>(nonceCacheSize);
            if (session == null) {
                if (log.isDebugEnabled()) {
                    log.debug("Creating new session to store CSRF nonce cache");
                }
                session = req.getSession(true);
            }
            session.setAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME, nonceCache);
        }
        String newNonce = generateNonce();
        nonceCache.add(newNonce);
        // Take this request's nonce and put it into the request
        // attributes so pages can make direct use of it, rather than
        // requiring the use of response.encodeURL.
        request.setAttribute(Constants.CSRF_NONCE_REQUEST_ATTR_NAME, newNonce);
        wResponse = new CsrfResponseWrapper(res, nonceRequestParameterName, newNonce);
    } else {
        wResponse = response;
    }
    chain.doFilter(request, wResponse);
}
Also used : HttpServletRequest(jakarta.servlet.http.HttpServletRequest) ServletResponse(jakarta.servlet.ServletResponse) HttpServletResponse(jakarta.servlet.http.HttpServletResponse) HttpSession(jakarta.servlet.http.HttpSession) HttpServletResponse(jakarta.servlet.http.HttpServletResponse)

Example 63 with HttpServletResponse

use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.

the class FailedRequestFilter method doFilter.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if (!isGoodRequest(request)) {
        FailReason reason = (FailReason) request.getAttribute(Globals.PARAMETER_PARSE_FAILED_REASON_ATTR);
        int status;
        switch(reason) {
            case IO_ERROR:
                // Not the client's fault
                status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
                break;
            case POST_TOO_LARGE:
                status = HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE;
                break;
            case TOO_MANY_PARAMETERS:
            // Assume the client is at fault
            case UNKNOWN:
            // a specific status code so use the default.
            case INVALID_CONTENT_TYPE:
            case MULTIPART_CONFIG_INVALID:
            case NO_NAME:
            case REQUEST_BODY_INCOMPLETE:
            case URL_DECODING:
            case CLIENT_DISCONNECT:
            // for the access logs. The default is fine.
            default:
                // 400
                status = HttpServletResponse.SC_BAD_REQUEST;
                break;
        }
        ((HttpServletResponse) response).sendError(status);
        return;
    }
    chain.doFilter(request, response);
}
Also used : HttpServletResponse(jakarta.servlet.http.HttpServletResponse) FailReason(org.apache.tomcat.util.http.Parameters.FailReason)

Example 64 with HttpServletResponse

use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.

the class DefaultServlet method serveResource.

/**
 * Serve the specified resource, optionally including the data content.
 *
 * @param request       The servlet request we are processing
 * @param response      The servlet response we are creating
 * @param content       Should the content be included?
 * @param inputEncoding The encoding to use if it is necessary to access the
 *                      source as characters rather than as bytes
 *
 * @exception IOException if an input/output error occurs
 * @exception ServletException if a servlet-specified error occurs
 */
protected void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content, String inputEncoding) throws IOException, ServletException {
    boolean serveContent = content;
    // Identify the requested resource path
    String path = getRelativePath(request, true);
    if (debug > 0) {
        if (serveContent) {
            log("DefaultServlet.serveResource:  Serving resource '" + path + "' headers and data");
        } else {
            log("DefaultServlet.serveResource:  Serving resource '" + path + "' headers only");
        }
    }
    if (path.length() == 0) {
        // Context root redirect
        doDirectoryRedirect(request, response);
        return;
    }
    WebResource resource = resources.getResource(path);
    boolean isError = DispatcherType.ERROR == request.getDispatcherType();
    if (!resource.exists()) {
        // Check if we're included so we can return the appropriate
        // missing resource name in the error
        String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
        if (requestUri == null) {
            requestUri = request.getRequestURI();
        } else {
            // SRV.9.3 says we must throw a FNFE
            throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
        }
        if (isError) {
            response.sendError(((Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).intValue());
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("defaultServlet.missingResource", requestUri));
        }
        return;
    }
    if (!resource.canRead()) {
        // Check if we're included so we can return the appropriate
        // missing resource name in the error
        String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
        if (requestUri == null) {
            requestUri = request.getRequestURI();
        } else {
            // reasonable
            throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
        }
        if (isError) {
            response.sendError(((Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).intValue());
        } else {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, requestUri);
        }
        return;
    }
    boolean included = false;
    // satisfied.
    if (resource.isFile()) {
        // Checking If headers
        included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
        if (!included && !isError && !checkIfHeaders(request, response, resource)) {
            return;
        }
    }
    // Find content type.
    String contentType = resource.getMimeType();
    if (contentType == null) {
        contentType = getServletContext().getMimeType(resource.getName());
        resource.setMimeType(contentType);
    }
    // These need to reflect the original resource, not the potentially
    // precompressed version of the resource so get them now if they are going to
    // be needed later
    String eTag = null;
    String lastModifiedHttp = null;
    if (resource.isFile() && !isError) {
        eTag = generateETag(resource);
        lastModifiedHttp = resource.getLastModifiedHttp();
    }
    // Serve a precompressed version of the file if present
    boolean usingPrecompressedVersion = false;
    if (compressionFormats.length > 0 && !included && resource.isFile() && !pathEndsWithCompressedExtension(path)) {
        List<PrecompressedResource> precompressedResources = getAvailablePrecompressedResources(path);
        if (!precompressedResources.isEmpty()) {
            ResponseUtil.addVaryFieldName(response, "accept-encoding");
            PrecompressedResource bestResource = getBestPrecompressedResource(request, precompressedResources);
            if (bestResource != null) {
                response.addHeader("Content-Encoding", bestResource.format.encoding);
                resource = bestResource.resource;
                usingPrecompressedVersion = true;
            }
        }
    }
    Ranges ranges = FULL;
    long contentLength = -1L;
    if (resource.isDirectory()) {
        if (!path.endsWith("/")) {
            doDirectoryRedirect(request, response);
            return;
        }
        // suppress them
        if (!listings) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("defaultServlet.missingResource", request.getRequestURI()));
            return;
        }
        contentType = "text/html;charset=UTF-8";
    } else {
        if (!isError) {
            if (useAcceptRanges) {
                // Accept ranges header
                response.setHeader("Accept-Ranges", "bytes");
            }
            // Parse range specifier
            ranges = parseRange(request, response, resource);
            if (ranges == null) {
                return;
            }
            // ETag header
            response.setHeader("ETag", eTag);
            // Last-Modified header
            response.setHeader("Last-Modified", lastModifiedHttp);
        }
        // Get content length
        contentLength = resource.getContentLength();
        // (silent) ISE when setting the output buffer size
        if (contentLength == 0L) {
            serveContent = false;
        }
    }
    ServletOutputStream ostream = null;
    PrintWriter writer = null;
    if (serveContent) {
        // Trying to retrieve the servlet output stream
        try {
            ostream = response.getOutputStream();
        } catch (IllegalStateException e) {
            // trying to serve a text file
            if (!usingPrecompressedVersion && isText(contentType)) {
                writer = response.getWriter();
                // Cannot reliably serve partial content with a Writer
                ranges = FULL;
            } else {
                throw e;
            }
        }
    }
    // Check to see if a Filter, Valve or wrapper has written some content.
    // If it has, disable range requests and setting of a content length
    // since neither can be done reliably.
    ServletResponse r = response;
    long contentWritten = 0;
    while (r instanceof ServletResponseWrapper) {
        r = ((ServletResponseWrapper) r).getResponse();
    }
    if (r instanceof ResponseFacade) {
        contentWritten = ((ResponseFacade) r).getContentWritten();
    }
    if (contentWritten > 0) {
        ranges = FULL;
    }
    String outputEncoding = response.getCharacterEncoding();
    Charset charset = B2CConverter.getCharset(outputEncoding);
    boolean conversionRequired;
    /*
         * The test below deliberately uses != to compare two Strings. This is
         * because the code is looking to see if the default character encoding
         * has been returned because no explicit character encoding has been
         * defined. There is no clean way of doing this via the Servlet API. It
         * would be possible to add a Tomcat specific API but that would require
         * quite a bit of code to get to the Tomcat specific request object that
         * may have been wrapped. The != test is a (slightly hacky) quick way of
         * doing this.
         */
    boolean outputEncodingSpecified = outputEncoding != org.apache.coyote.Constants.DEFAULT_BODY_CHARSET.name() && outputEncoding != resources.getContext().getResponseCharacterEncoding();
    if (!usingPrecompressedVersion && isText(contentType) && outputEncodingSpecified && !charset.equals(fileEncodingCharset)) {
        conversionRequired = true;
        // Conversion often results fewer/more/different bytes.
        // That does not play nicely with range requests.
        ranges = FULL;
    } else {
        conversionRequired = false;
    }
    if (resource.isDirectory() || isError || ranges == FULL) {
        // Set the appropriate output headers
        if (contentType != null) {
            if (debug > 0) {
                log("DefaultServlet.serveFile:  contentType='" + contentType + "'");
            }
            // Don't override a previously set content type
            if (response.getContentType() == null) {
                response.setContentType(contentType);
            }
        }
        if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null)) {
            if (debug > 0) {
                log("DefaultServlet.serveFile:  contentLength=" + contentLength);
            }
            // written to the response or if conversion will be taking place
            if (contentWritten == 0 && !conversionRequired) {
                response.setContentLengthLong(contentLength);
            }
        }
        if (serveContent) {
            try {
                response.setBufferSize(output);
            } catch (IllegalStateException e) {
            // Silent catch
            }
            InputStream renderResult = null;
            if (ostream == null) {
                // content directly.
                if (resource.isDirectory()) {
                    renderResult = render(request, getPathPrefix(request), resource, inputEncoding);
                } else {
                    renderResult = resource.getInputStream();
                    if (included) {
                        // Need to make sure any BOM is removed
                        if (!renderResult.markSupported()) {
                            renderResult = new BufferedInputStream(renderResult);
                        }
                        Charset bomCharset = processBom(renderResult, useBomIfPresent.stripBom);
                        if (bomCharset != null && useBomIfPresent.useBomEncoding) {
                            inputEncoding = bomCharset.name();
                        }
                    }
                }
                copy(renderResult, writer, inputEncoding);
            } else {
                // Output is via an OutputStream
                if (resource.isDirectory()) {
                    renderResult = render(request, getPathPrefix(request), resource, inputEncoding);
                } else {
                    // Check to see if conversion is required
                    if (conversionRequired || included) {
                        // When including a file, we need to check for a BOM
                        // to determine if a conversion is required, so we
                        // might as well always convert
                        InputStream source = resource.getInputStream();
                        if (!source.markSupported()) {
                            source = new BufferedInputStream(source);
                        }
                        Charset bomCharset = processBom(source, useBomIfPresent.stripBom);
                        if (bomCharset != null && useBomIfPresent.useBomEncoding) {
                            inputEncoding = bomCharset.name();
                        }
                        // specified
                        if (outputEncodingSpecified) {
                            OutputStreamWriter osw = new OutputStreamWriter(ostream, charset);
                            PrintWriter pw = new PrintWriter(osw);
                            copy(source, pw, inputEncoding);
                            pw.flush();
                        } else {
                            // Just included but no conversion
                            renderResult = source;
                        }
                    } else {
                        if (!checkSendfile(request, response, resource, contentLength, null)) {
                            // sendfile not possible so check if resource
                            // content is available directly via
                            // CachedResource. Do not want to call
                            // getContent() on other resource
                            // implementations as that could trigger loading
                            // the contents of a very large file into memory
                            byte[] resourceBody = null;
                            if (resource instanceof CachedResource) {
                                resourceBody = resource.getContent();
                            }
                            if (resourceBody == null) {
                                // Resource content not directly available,
                                // use InputStream
                                renderResult = resource.getInputStream();
                            } else {
                                // Use the resource content directly
                                ostream.write(resourceBody);
                            }
                        }
                    }
                }
                // the output (this method closes the stream)
                if (renderResult != null) {
                    copy(renderResult, ostream);
                }
            }
        }
    } else {
        if ((ranges == null) || (ranges.getEntries().isEmpty())) {
            return;
        }
        // Partial content response.
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        if (ranges.getEntries().size() == 1) {
            Ranges.Entry range = ranges.getEntries().get(0);
            long start = getStart(range, contentLength);
            long end = getEnd(range, contentLength);
            response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
            long length = end - start + 1;
            response.setContentLengthLong(length);
            if (contentType != null) {
                if (debug > 0) {
                    log("DefaultServlet.serveFile:  contentType='" + contentType + "'");
                }
                response.setContentType(contentType);
            }
            if (serveContent) {
                try {
                    response.setBufferSize(output);
                } catch (IllegalStateException e) {
                // Silent catch
                }
                if (ostream != null) {
                    if (!checkSendfile(request, response, resource, contentLength, range)) {
                        copy(resource, contentLength, ostream, range);
                    }
                } else {
                    // we should not get here
                    throw new IllegalStateException();
                }
            }
        } else {
            response.setContentType("multipart/byteranges; boundary=" + mimeSeparation);
            if (serveContent) {
                try {
                    response.setBufferSize(output);
                } catch (IllegalStateException e) {
                // Silent catch
                }
                if (ostream != null) {
                    copy(resource, contentLength, ostream, ranges, contentType);
                } else {
                    // we should not get here
                    throw new IllegalStateException();
                }
            }
        }
    }
}
Also used : Ranges(org.apache.tomcat.util.http.parser.Ranges) ServletResponse(jakarta.servlet.ServletResponse) HttpServletResponse(jakarta.servlet.http.HttpServletResponse) ServletOutputStream(jakarta.servlet.ServletOutputStream) BufferedInputStream(java.io.BufferedInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) FileNotFoundException(java.io.FileNotFoundException) WebResource(org.apache.catalina.WebResource) Charset(java.nio.charset.Charset) BufferedInputStream(java.io.BufferedInputStream) ResponseFacade(org.apache.catalina.connector.ResponseFacade) CachedResource(org.apache.catalina.webresources.CachedResource) OutputStreamWriter(java.io.OutputStreamWriter) ServletResponseWrapper(jakarta.servlet.ServletResponseWrapper) PrintWriter(java.io.PrintWriter)

Example 65 with HttpServletResponse

use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.

the class TestExpiresFilter method testExcludedResponseStatusCode.

@Test
public void testExcludedResponseStatusCode() throws Exception {
    HttpServlet servlet = new HttpServlet() {

        private static final long serialVersionUID = 1L;

        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            response.addHeader("ETag", "W/\"1934-1269208821000\"");
            response.addDateHeader("Date", System.currentTimeMillis());
        }
    };
    validate(servlet, null, HttpServletResponse.SC_NOT_MODIFIED);
}
Also used : HttpServletRequest(jakarta.servlet.http.HttpServletRequest) HttpServlet(jakarta.servlet.http.HttpServlet) HttpServletResponse(jakarta.servlet.http.HttpServletResponse) TomcatBaseTest(org.apache.catalina.startup.TomcatBaseTest) Test(org.junit.Test)

Aggregations

HttpServletResponse (jakarta.servlet.http.HttpServletResponse)118 HttpServletRequest (jakarta.servlet.http.HttpServletRequest)76 Test (org.junit.jupiter.api.Test)47 MockHttpServletResponse (org.springframework.web.testfixture.servlet.MockHttpServletResponse)34 MockHttpServletRequest (org.springframework.web.testfixture.servlet.MockHttpServletRequest)31 FilterChain (jakarta.servlet.FilterChain)22 Assertions.assertThat (org.assertj.core.api.Assertions.assertThat)18 MockHttpServletRequest (org.springframework.mock.web.MockHttpServletRequest)16 MockHttpServletResponse (org.springframework.mock.web.MockHttpServletResponse)15 ServletException (jakarta.servlet.ServletException)14 StandardCharsets (java.nio.charset.StandardCharsets)14 HttpServlet (jakarta.servlet.http.HttpServlet)13 IOException (java.io.IOException)12 HashMap (java.util.HashMap)12 TomcatBaseTest (org.apache.catalina.startup.TomcatBaseTest)10 Test (org.junit.Test)10 Authentication (org.springframework.security.core.Authentication)10 FileCopyUtils (org.springframework.util.FileCopyUtils)9 BeforeEach (org.junit.jupiter.api.BeforeEach)8 Collections (java.util.Collections)7