Search in sources :

Example 11 with ServletResponseWrapper

use of javax.servlet.ServletResponseWrapper in project tomcat70 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?
 *
 * @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) 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;
    }
    CacheEntry cacheEntry = resources.lookupCache(path);
    boolean isError = DispatcherType.ERROR == request.getDispatcherType();
    if (!cacheEntry.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, requestUri);
        }
        return;
    }
    // satisfied.
    if (cacheEntry.context == null) {
        // Checking If headers
        boolean included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
        if (!included && !isError && !checkIfHeaders(request, response, cacheEntry.attributes)) {
            return;
        }
    }
    // Find content type.
    String contentType = cacheEntry.attributes.getMimeType();
    if (contentType == null) {
        contentType = getServletContext().getMimeType(cacheEntry.name);
        cacheEntry.attributes.setMimeType(contentType);
    }
    ArrayList<Range> ranges = null;
    long contentLength = -1L;
    if (cacheEntry.context != null) {
        if (!path.endsWith("/")) {
            doDirectoryRedirect(request, response);
            return;
        }
        // suppress them
        if (!listings) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, 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, cacheEntry.attributes);
            // ETag header
            response.setHeader("ETag", cacheEntry.attributes.getETag());
            // Last-Modified header
            response.setHeader("Last-Modified", cacheEntry.attributes.getLastModifiedHttp());
        }
        // Get content length
        contentLength = cacheEntry.attributes.getContentLength();
        // (silent) ISE when setting the output buffer size
        if (contentLength == 0L) {
            serveContent = false;
        }
    }
    ServletOutputStream ostream = null;
    PrintWriter writer = null;
    if (serveContent) {
        try {
            ostream = response.getOutputStream();
        } catch (IllegalStateException e) {
            // trying to serve a text file
            if ((contentType == null) || (contentType.startsWith("text")) || (contentType.endsWith("xml")) || (contentType.contains("/javascript"))) {
                writer = response.getWriter();
                // Cannot reliably serve partial content with a Writer
                ranges = FULL;
            } else {
                throw e;
            }
        }
    }
    // Check to see if a Filter, Valve of 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;
    }
    if ((cacheEntry.context != null) || isError || (((ranges == null) || (ranges.isEmpty())) && (request.getHeader("Range") == null)) || (ranges == FULL)) {
        // Set the appropriate output headers
        if (contentType != null) {
            if (debug > 0)
                log("DefaultServlet.serveFile:  contentType='" + contentType + "'");
            response.setContentType(contentType);
        }
        if ((cacheEntry.resource != null) && (contentLength >= 0) && (!serveContent || ostream != null)) {
            if (debug > 0)
                log("DefaultServlet.serveFile:  contentLength=" + contentLength);
            // written to the response.
            if (contentWritten == 0) {
                if (contentLength < Integer.MAX_VALUE) {
                    response.setContentLength((int) contentLength);
                } else {
                    // Set the content-length as String to be able to use a
                    // long
                    response.setHeader("content-length", "" + contentLength);
                }
            }
        }
        InputStream renderResult = null;
        if (cacheEntry.context != null) {
            if (serveContent) {
                // Serve the directory browser
                renderResult = render(getPathPrefix(request), cacheEntry);
            }
        }
        // Copy the input stream to our output stream (if requested)
        if (serveContent) {
            try {
                response.setBufferSize(output);
            } catch (IllegalStateException e) {
            // Silent catch
            }
            if (ostream != null) {
                if (!checkSendfile(request, response, cacheEntry, contentLength, null))
                    copy(cacheEntry, renderResult, ostream);
            } else {
                copy(cacheEntry, renderResult, writer);
            }
        }
    } else {
        if ((ranges == null) || (ranges.isEmpty()))
            return;
        // Partial content response.
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        if (ranges.size() == 1) {
            Range range = ranges.get(0);
            response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
            long length = range.end - range.start + 1;
            if (length < Integer.MAX_VALUE) {
                response.setContentLength((int) length);
            } else {
                // Set the content-length as String to be able to use a long
                response.setHeader("content-length", "" + 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, cacheEntry, range.end - range.start + 1, range))
                        copy(cacheEntry, 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(cacheEntry, ostream, ranges.iterator(), contentType);
                } else {
                    // we should not get here
                    throw new IllegalStateException();
                }
            }
        }
    }
}
Also used : ServletResponse(javax.servlet.ServletResponse) HttpServletResponse(javax.servlet.http.HttpServletResponse) ServletOutputStream(javax.servlet.ServletOutputStream) BufferedInputStream(java.io.BufferedInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) FileNotFoundException(java.io.FileNotFoundException) CacheEntry(org.apache.naming.resources.CacheEntry) ResponseFacade(org.apache.catalina.connector.ResponseFacade) ServletResponseWrapper(javax.servlet.ServletResponseWrapper) PrintWriter(java.io.PrintWriter)

Example 12 with ServletResponseWrapper

use of javax.servlet.ServletResponseWrapper in project mycore by MyCoRe-Org.

the class MCRServletContentHelper method serveContent.

/**
 * Serve the specified content, optionally including the data content.
 * This method handles both GET and HEAD requests.
 */
public static void serveContent(final MCRContent content, final HttpServletRequest request, final HttpServletResponse response, final ServletContext context, final Config config, final boolean withContent) throws IOException {
    boolean serveContent = withContent;
    final String path = getRequestPath(request);
    if (LOGGER.isDebugEnabled()) {
        if (serveContent) {
            LOGGER.debug("Serving '{}' headers and data", path);
        } else {
            LOGGER.debug("Serving '{}' headers only", path);
        }
    }
    if (response.isCommitted()) {
        // getContent has access to response
        return;
    }
    final boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;
    if (content == null && !isError) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI());
        return;
    }
    // Check if all conditional header validate
    if (!isError && !checkIfHeaders(request, response, content)) {
        return;
    }
    // Find content type.
    String contentType = content.getMimeType();
    final String filename = getFileName(request, content);
    if (contentType == null) {
        contentType = context.getMimeType(filename);
        content.setMimeType(contentType);
    }
    String enc = content.getEncoding();
    if (enc != null) {
        contentType = String.format(Locale.ROOT, "%s; charset=%s", contentType, enc);
    }
    String eTag = null;
    ArrayList<Range> ranges = null;
    if (!isError) {
        eTag = content.getETag();
        if (config.useAcceptRanges) {
            response.setHeader("Accept-Ranges", "bytes");
        }
        ranges = parseRange(request, response, content);
        response.setHeader("ETag", eTag);
        long lastModified = content.lastModified();
        if (lastModified >= 0) {
            response.setDateHeader("Last-Modified", lastModified);
        }
        if (serveContent) {
            String dispositionType = request.getParameter("dl") == null ? "inline" : "attachment";
            response.setHeader("Content-Disposition", dispositionType + ";filename=\"" + filename + "\"");
        }
    }
    final long contentLength = content.length();
    // No Content to serve?
    if (contentLength == 0) {
        serveContent = false;
    }
    if (content.isUsingSession()) {
        response.addHeader("Cache-Control", "private, max-age=0, must-revalidate");
        response.addHeader("Vary", "*");
    }
    try (ServletOutputStream out = serveContent ? response.getOutputStream() : null) {
        if (serveContent) {
            try {
                response.setBufferSize(config.outputBufferSize);
            } catch (final IllegalStateException e) {
            // does not matter if we fail
            }
        }
        if (response instanceof ServletResponseWrapper) {
            if (request.getHeader("Range") != null) {
                LOGGER.warn("Response is wrapped by ServletResponseWrapper, no 'Range' requests supported.");
            }
            ranges = FULL;
        }
        if (isError || (ranges == null || ranges.isEmpty()) && request.getHeader("Range") == null || ranges == FULL) {
            // No ranges
            if (contentType != null) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("contentType='{}'", contentType);
                }
                response.setContentType(contentType);
            }
            if (contentLength >= 0) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("contentLength={}", contentLength);
                }
                setContentLengthLong(response, contentLength);
            }
            if (serveContent) {
                copy(content, out, config.inputBufferSize, config.outputBufferSize);
            }
        } else {
            if (ranges == null || ranges.isEmpty()) {
                return;
            }
            // Partial content response.
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            if (ranges.size() == 1) {
                final Range range = ranges.get(0);
                response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
                final long length = range.end - range.start + 1;
                setContentLengthLong(response, length);
                if (contentType != null) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("contentType='{}'", contentType);
                    }
                    response.setContentType(contentType);
                }
                if (serveContent) {
                    copy(content, out, range, config.inputBufferSize, config.outputBufferSize);
                }
            } else {
                response.setContentType("multipart/byteranges; boundary=" + MIME_BOUNDARY);
                if (serveContent) {
                    copy(content, out, ranges.iterator(), contentType, config.inputBufferSize, config.outputBufferSize);
                }
            }
        }
    }
}
Also used : ServletOutputStream(javax.servlet.ServletOutputStream) ServletResponseWrapper(javax.servlet.ServletResponseWrapper)

Example 13 with ServletResponseWrapper

use of javax.servlet.ServletResponseWrapper in project undertow by undertow-io.

the class RequestDispatcherImpl method error.

private void error(ServletRequestContext servletRequestContext, final ServletRequest request, final ServletResponse response, final String servletName, final Throwable exception, final String message) throws ServletException, IOException {
    if (request.getDispatcherType() == DispatcherType.ERROR) {
        // we have already dispatched once with an error
        // if we dispatch again we run the risk of a stack overflow
        // so we just kill it, the user will just get the basic error page
        UndertowServletLogger.REQUEST_LOGGER.errorGeneratingErrorPage(servletRequestContext.getExchange().getRequestPath(), request.getAttribute(ERROR_EXCEPTION), servletRequestContext.getExchange().getStatusCode(), exception);
        servletRequestContext.getExchange().endExchange();
        return;
    }
    final HttpServletRequestImpl requestImpl = servletRequestContext.getOriginalRequest();
    final HttpServletResponseImpl responseImpl = servletRequestContext.getOriginalResponse();
    if (!servletContext.getDeployment().getDeploymentInfo().isAllowNonStandardWrappers()) {
        if (servletRequestContext.getOriginalRequest() != request) {
            if (!(request instanceof ServletRequestWrapper)) {
                throw UndertowServletMessages.MESSAGES.requestWasNotOriginalOrWrapper(request);
            }
        }
        if (servletRequestContext.getOriginalResponse() != response) {
            if (!(response instanceof ServletResponseWrapper)) {
                throw UndertowServletMessages.MESSAGES.responseWasNotOriginalOrWrapper(response);
            }
        }
    }
    final ServletRequest oldRequest = servletRequestContext.getServletRequest();
    final ServletResponse oldResponse = servletRequestContext.getServletResponse();
    servletRequestContext.setDispatcherType(DispatcherType.ERROR);
    // only update if this is the first forward, add forward attrs too
    if (request.getAttribute(FORWARD_REQUEST_URI) == null) {
        requestImpl.setAttribute(FORWARD_REQUEST_URI, requestImpl.getRequestURI());
        requestImpl.setAttribute(FORWARD_CONTEXT_PATH, requestImpl.getContextPath());
        requestImpl.setAttribute(FORWARD_SERVLET_PATH, requestImpl.getServletPath());
        requestImpl.setAttribute(FORWARD_PATH_INFO, requestImpl.getPathInfo());
        requestImpl.setAttribute(FORWARD_QUERY_STRING, requestImpl.getQueryString());
    }
    requestImpl.setAttribute(ERROR_REQUEST_URI, requestImpl.getRequestURI());
    requestImpl.setAttribute(ERROR_SERVLET_NAME, servletName);
    if (exception != null) {
        if (exception instanceof ServletException && ((ServletException) exception).getRootCause() != null) {
            requestImpl.setAttribute(ERROR_EXCEPTION, ((ServletException) exception).getRootCause());
            requestImpl.setAttribute(ERROR_EXCEPTION_TYPE, ((ServletException) exception).getRootCause().getClass());
        } else {
            requestImpl.setAttribute(ERROR_EXCEPTION, exception);
            requestImpl.setAttribute(ERROR_EXCEPTION_TYPE, exception.getClass());
        }
    }
    requestImpl.setAttribute(ERROR_MESSAGE, message);
    requestImpl.setAttribute(ERROR_STATUS_CODE, responseImpl.getStatus());
    int qsPos = path.indexOf("?");
    String newServletPath = path;
    if (qsPos != -1) {
        Map<String, Deque<String>> queryParameters = requestImpl.getQueryParameters();
        String newQueryString = newServletPath.substring(qsPos + 1);
        newServletPath = newServletPath.substring(0, qsPos);
        String encoding = QueryParameterUtils.getQueryParamEncoding(servletRequestContext.getExchange());
        Map<String, Deque<String>> newQueryParameters = QueryParameterUtils.mergeQueryParametersWithNewQueryString(queryParameters, newQueryString, encoding);
        requestImpl.getExchange().setQueryString(newQueryString);
        requestImpl.setQueryParameters(newQueryParameters);
    }
    String newRequestUri = servletContext.getContextPath() + newServletPath;
    requestImpl.getExchange().setRelativePath(newServletPath);
    requestImpl.getExchange().setRequestPath(newRequestUri);
    requestImpl.getExchange().setRequestURI(newRequestUri);
    requestImpl.getExchange().getAttachment(ServletRequestContext.ATTACHMENT_KEY).setServletPathMatch(pathMatch);
    requestImpl.setServletContext(servletContext);
    responseImpl.setServletContext(servletContext);
    try {
        try {
            servletRequestContext.setServletRequest(request);
            servletRequestContext.setServletResponse(response);
            servletContext.getDeployment().getServletDispatcher().dispatchToPath(requestImpl.getExchange(), pathMatch, DispatcherType.ERROR);
        } catch (ServletException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    } finally {
        AsyncContextImpl ac = servletRequestContext.getOriginalRequest().getAsyncContextInternal();
        if (ac != null) {
            ac.complete();
        }
        servletRequestContext.setServletRequest(oldRequest);
        servletRequestContext.setServletResponse(oldResponse);
    }
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletRequest(javax.servlet.ServletRequest) HttpServletResponse(javax.servlet.http.HttpServletResponse) ServletResponse(javax.servlet.ServletResponse) ServletRequestWrapper(javax.servlet.ServletRequestWrapper) IOException(java.io.IOException) Deque(java.util.Deque) ServletException(javax.servlet.ServletException) PrivilegedActionException(java.security.PrivilegedActionException) IOException(java.io.IOException) ServletException(javax.servlet.ServletException) ServletResponseWrapper(javax.servlet.ServletResponseWrapper)

Example 14 with ServletResponseWrapper

use of javax.servlet.ServletResponseWrapper in project undertow by undertow-io.

the class HttpServletRequestImpl method startAsync.

@Override
public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse) throws IllegalStateException {
    final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
    if (!servletContext.getDeployment().getDeploymentInfo().isAllowNonStandardWrappers()) {
        if (servletRequestContext.getOriginalRequest() != servletRequest) {
            if (!(servletRequest instanceof ServletRequestWrapper)) {
                throw UndertowServletMessages.MESSAGES.requestWasNotOriginalOrWrapper(servletRequest);
            }
        }
        if (servletRequestContext.getOriginalResponse() != servletResponse) {
            if (!(servletResponse instanceof ServletResponseWrapper)) {
                throw UndertowServletMessages.MESSAGES.responseWasNotOriginalOrWrapper(servletResponse);
            }
        }
    }
    if (!isAsyncSupported()) {
        throw UndertowServletMessages.MESSAGES.startAsyncNotAllowed();
    } else if (asyncStarted) {
        throw UndertowServletMessages.MESSAGES.asyncAlreadyStarted();
    }
    asyncStarted = true;
    servletRequestContext.setServletRequest(servletRequest);
    servletRequestContext.setServletResponse(servletResponse);
    return asyncContext = new AsyncContextImpl(exchange, servletRequest, servletResponse, servletRequestContext, true, asyncContext);
}
Also used : ServletRequestWrapper(javax.servlet.ServletRequestWrapper) ServletRequestContext(io.undertow.servlet.handlers.ServletRequestContext) ServletResponseWrapper(javax.servlet.ServletResponseWrapper)

Example 15 with ServletResponseWrapper

use of javax.servlet.ServletResponseWrapper in project tomee 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;
            }
        }
    }
    ArrayList<Range> 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, isStripBOM());
                        if (bomCharset != null && "true".equals(useBomIfPresent)) {
                            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, isStripBOM());
                        if (bomCharset != null && "true".equals(useBomIfPresent)) {
                            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.isEmpty()))
            return;
        // Partial content response.
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        if (ranges.size() == 1) {
            Range range = ranges.get(0);
            response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
            long length = range.end - range.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, range.end - range.start + 1, range))
                        copy(resource, 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, ostream, ranges.iterator(), contentType);
                } else {
                    // we should not get here
                    throw new IllegalStateException();
                }
            }
        }
    }
}
Also used : ServletResponse(javax.servlet.ServletResponse) HttpServletResponse(javax.servlet.http.HttpServletResponse) ServletOutputStream(javax.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) ContentRange(org.apache.tomcat.util.http.parser.ContentRange) BufferedInputStream(java.io.BufferedInputStream) ResponseFacade(org.apache.catalina.connector.ResponseFacade) CachedResource(org.apache.catalina.webresources.CachedResource) OutputStreamWriter(java.io.OutputStreamWriter) ServletResponseWrapper(javax.servlet.ServletResponseWrapper) PrintWriter(java.io.PrintWriter)

Aggregations

ServletResponseWrapper (javax.servlet.ServletResponseWrapper)15 ServletResponse (javax.servlet.ServletResponse)13 HttpServletResponse (javax.servlet.http.HttpServletResponse)13 PrintWriter (java.io.PrintWriter)6 ServletOutputStream (javax.servlet.ServletOutputStream)6 ServletRequestWrapper (javax.servlet.ServletRequestWrapper)6 ServletException (javax.servlet.ServletException)5 ServletRequest (javax.servlet.ServletRequest)5 HttpServletRequest (javax.servlet.http.HttpServletRequest)5 BufferedInputStream (java.io.BufferedInputStream)4 FileNotFoundException (java.io.FileNotFoundException)4 IOException (java.io.IOException)4 InputStream (java.io.InputStream)4 PrivilegedActionException (java.security.PrivilegedActionException)3 Deque (java.util.Deque)3 HttpServletResponseWrapper (javax.servlet.http.HttpServletResponseWrapper)3 ResponseFacade (org.apache.catalina.connector.ResponseFacade)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 FileInputStream (java.io.FileInputStream)2 OutputStreamWriter (java.io.OutputStreamWriter)2