您的位置:首页 > 运维架构 > Tomcat

DefaultServlet int Tomcat

2015-09-30 15:16 567 查看
转载 :http://blog.csdn.net/zdhcumt/article/details/6867264

附上部分源码:

package org.apache.catalina.servlets;

import ....

/**

 * <p>The default resource-serving servlet for most web applications,

 * used to serve static resources such as HTML pages and images.

 * This servlet is intended to be mapped to <em>/</em> e.g.:

 * </p>

 * <pre>

 *   <servlet-mapping>

 *       <servlet-name>default</servlet-name>

 *       <url-pattern>/</url-pattern>

 *   </servlet-mapping>

 * </pre>

 * <p>It can be mapped to sub-paths, however in all cases resources are served

 * from the web appplication resource root using the full path from the root

 * of the web application context.

 * <br/>e.g. given a web application structure:

 *</p>

 * <pre>

 * /context

 *   /images

 *     tomcat2.jpg

 *   /static

 *     /images

 *       tomcat.jpg

 * </pre>

 * <p>

 * ... and a servlet mapping that maps only <code>/static/*</code> to the default servlet:

 * </p>

 * <pre>

 *   <servlet-mapping>

 *       <servlet-name>default</servlet-name>

 *       <url-pattern>/static/*</url-pattern>

 *   </servlet-mapping>

 * </pre>

 * <p>

 * Then a request to <code>/context/static/images/tomcat.jpg</code> will succeed

 * while a request to <code>/context/images/tomcat2.jpg</code> will fail.

 * </p>

 * @author Craig R. McClanahan

 * @author Remy Maucherat

 * @version $Id: DefaultServlet.java 1086995 2011-03-30 15:50:28Z markt $

 */

public class DefaultServlet extends HttpServlet {

    /**

     * The output buffer size to use when serving resources.

     */

    protected int output = 2048;

    /**

     * Size of file transfer buffer in bytes.

     */

    protected static final int BUFFER_SIZE = 4096;

   

    protected void doGet(HttpServletRequest request,

                         HttpServletResponse response)

        throws IOException, ServletException {

        // Serve the requested resource, including the data content

        serveResource(request, response, true);

    }

    /**

     * 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);

        if (debug > 0) {

            if (serveContent)

                log("DefaultServlet.serveResource:  Serving resource '" +

                    path + "' headers and data");

            else

                log("DefaultServlet.serveResource:  Serving resource '" +

                    path + "' headers only");

        }

        CacheEntry cacheEntry = resources.lookupCache(path);

        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 {

                // We're included

                // SRV.9.3 says we must throw a FNFE

                throw new FileNotFoundException(

                        sm.getString("defaultServlet.missingResource",

                    requestUri));

            }

            response.sendError(HttpServletResponse.SC_NOT_FOUND,

                               requestUri);

            return;

        }

        // If the resource is not a collection, and the resource path

        // ends with "/" or "\", return NOT FOUND

        if (cacheEntry.context == null) {

            if (path.endsWith("/") || (path.endsWith("\\"))) {

                // 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();

                }

                response.sendError(HttpServletResponse.SC_NOT_FOUND,

                                   requestUri);

                return;

            }

        }

        boolean isError =

            response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;

        // Check if the conditions specified in the optional If headers are

        // 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) {

            // Skip directory listings if we have been configured to

            // 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();

            // Special case for zero length files, which would cause a

            // (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) {

                // If it fails, we try to get a Writer instead if we're

                // trying to serve a text file

                if ( (contentType == null)

                        || (contentType.startsWith("text"))

                        || (contentType.endsWith("xml")) ) {

                    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);

                // Don't set a content length if something else has already

                // 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();

                    }

                }

            }

        }

    }

    /**

     * Parse the content-range header.

     *

     * @param request The servlet request we are processing

     * @param response The servlet response we are creating

     * @return Range

     */

    protected Range parseContentRange(HttpServletRequest request,

                                      HttpServletResponse response)

        throws IOException {

        // Retrieving the content-range header (if any is specified

        String rangeHeader = request.getHeader("Content-Range");

        if (rangeHeader == null)

            return null;

        // bytes is the only range unit supported

        if (!rangeHeader.startsWith("bytes")) {

            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return null;

        }

        rangeHeader = rangeHeader.substring(6).trim();

        int dashPos = rangeHeader.indexOf('-');

        int slashPos = rangeHeader.indexOf('/');

        if (dashPos == -1) {

            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return null;

        }

        if (slashPos == -1) {

            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return null;

        }

        Range range = new Range();

        try {

            range.start = Long.parseLong(rangeHeader.substring(0, dashPos));

            range.end =

                Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos));

            range.length = Long.parseLong

                (rangeHeader.substring(slashPos + 1, rangeHeader.length()));

        } catch (NumberFormatException e) {

            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return null;

        }

        if (!range.validate()) {

            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return null;

        }

        return range;

    }

    /**

     * Parse the range header.

     *

     * @param request The servlet request we are processing

     * @param response The servlet response we are creating

     * @return Vector of ranges

     */

    protected ArrayList<Range> parseRange(HttpServletRequest request,

            HttpServletResponse response,

            ResourceAttributes resourceAttributes) throws IOException {

        // Checking If-Range

        String headerValue = request.getHeader("If-Range");

        if (headerValue != null) {

            long headerValueTime = (-1L);

            try {

                headerValueTime = request.getDateHeader("If-Range");

            } catch (IllegalArgumentException e) {

                // Ignore

            }

            String eTag = resourceAttributes.getETag();

            long lastModified = resourceAttributes.getLastModified();

            if (headerValueTime == (-1L)) {

                // If the ETag the client gave does not match the entity

                // etag, then the entire entity is returned.

                if (!eTag.equals(headerValue.trim()))

                    return FULL;

            } else {

                // If the timestamp of the entity the client got is older than

                // the last modification date of the entity, the entire entity

                // is returned.

                if (lastModified > (headerValueTime + 1000))

                    return FULL;

            }

        }

        long fileLength = resourceAttributes.getContentLength();

        if (fileLength == 0)

            return null;

        // Retrieving the range header (if any is specified

        String rangeHeader = request.getHeader("Range");

        if (rangeHeader == null)

            return null;

        // bytes is the only range unit supported (and I don't see the point

        // of adding new ones).

        if (!rangeHeader.startsWith("bytes")) {

            response.addHeader("Content-Range", "bytes */" + fileLength);

            response.sendError

                (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);

            return null;

        }

        rangeHeader = rangeHeader.substring(6);

        // Vector which will contain all the ranges which are successfully

        // parsed.

        ArrayList<Range> result = new ArrayList<Range>();

        StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");

        // Parsing the range list

        while (commaTokenizer.hasMoreTokens()) {

            String rangeDefinition = commaTokenizer.nextToken().trim();

            Range currentRange = new Range();

            currentRange.length = fileLength;

            int dashPos = rangeDefinition.indexOf('-');

            if (dashPos == -1) {

                response.addHeader("Content-Range", "bytes */" + fileLength);

                response.sendError

                    (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);

                return null;

            }

            if (dashPos == 0) {

                try {

                    long offset = Long.parseLong(rangeDefinition);

                    currentRange.start = fileLength + offset;

                    currentRange.end = fileLength - 1;

                } catch (NumberFormatException e) {

                    response.addHeader("Content-Range",

                                       "bytes */" + fileLength);

                    response.sendError

                        (HttpServletResponse

                         .SC_REQUESTED_RANGE_NOT_SATISFIABLE);

                    return null;

                }

            } else {

                try {

                    currentRange.start = Long.parseLong

                        (rangeDefinition.substring(0, dashPos));

                    if (dashPos < rangeDefinition.length() - 1)

                        currentRange.end = Long.parseLong

                            (rangeDefinition.substring

                             (dashPos + 1, rangeDefinition.length()));

                    else

                        currentRange.end = fileLength - 1;

                } catch (NumberFormatException e) {

                    response.addHeader("Content-Range",

                                       "bytes */" + fileLength);

                    response.sendError

                        (HttpServletResponse

                         .SC_REQUESTED_RANGE_NOT_SATISFIABLE);

                    return null;

                }

            }

            if (!currentRange.validate()) {

                response.addHeader("Content-Range", "bytes */" + fileLength);

                response.sendError

                    (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);

                return null;

            }

            result.add(currentRange);

        }

        return result;

    }

    protected static class Range {

        public long start;

        public long end;

        public long length;

        /**

         * Validate range.

         */

        public boolean validate() {

            if (end >= length)

                end = length - 1;

            return (start >= 0) && (end >= 0) && (start <= end) && (length > 0);

        }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tomcat defaultservle