Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
    * this work for additional information regarding copyright ownership.
    * The ASF licenses this file to You under the Apache License, Version 2.0
    * (the "License"); you may not use this file except in compliance with
    * the License.  You may obtain a copy of the License at
    *
    *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package org.apache.catalina.servlets;
  
  
  import static org.jboss.web.CatalinaMessages.MESSAGES;
  
  import java.io.File;
  import java.io.Reader;
  import java.util.Locale;
  
  
The default resource-serving servlet for most web applications, used to serve static resources such as HTML pages and images.

Author(s):
Craig R. McClanahan
Remy Maucherat
Version:
$Revision: 1781 $ $Date: 2011-07-13 18:31:38 +0200 (Wed, 13 Jul 2011) $
  
  
  public class DefaultServlet
      extends HttpServlet {
  
      private static final DocumentBuilderFactory factory;
 
     private static final SecureEntityResolver secureEntityResolver;
 
     // ----------------------------------------------------- Instance Variables
 

    
The debugging detail level for this servlet.
 
     protected int debug = 0;


    
The input buffer size to use when serving resources.
 
     protected int input = 2048;


    
Should we generate directory listings?
 
     protected boolean listings = false;


    
Read only flag. By default, it's set to true.
 
     protected boolean readOnly = true;


    
The output buffer size to use when serving resources.
 
     protected int output = 2048;


    
Array containing the safe characters set.
 
     protected static URLEncoder urlEncoder;


    
Allow customized directory listing per directory.
 
     protected String  localXsltFile = null;


    
Allow customized directory listing per context.
 
     protected String contextXsltFile = null;


    
Allow customized directory listing per instance.
 
     protected String  globalXsltFile = null;


    
Allow a readme file to be included.
 
     protected String readmeFile = null;


    
Proxy directory context.
 
     protected ProxyDirContext resources = null;


    
File encoding to be used when reading static files. If none is specified the platform default is used.
 
     protected String fileEncoding = null;
    
    
    
Minimum size for sendfile usage in bytes.
 
     protected int sendfileSize = 48 * 1024;
    
    
Should the Accept-Ranges: bytes header be send with static resources?
 
     protected boolean useAcceptRanges = true;

    
Full range marker.
 
     protected static ArrayList<RangeFULL = new ArrayList<Range>();
     
     
     // ----------------------------------------------------- Static Initializer
 

    
GMT timezone - all HTTP dates are on GMT
 
     static {
          = new URLEncoder();
         .addSafeCharacter('-');
         .addSafeCharacter('_');
         .addSafeCharacter('.');
         .addSafeCharacter('*');
         .addSafeCharacter('/');
         
         if (.) {
              = DocumentBuilderFactory.newInstance();
             .setNamespaceAware(true);
             .setValidating(false);
              = new SecureEntityResolver();
         } else {
              = null;
              = null;
         }
     }


    
MIME multipart separation string
 
     protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";


    
JNDI resources name.
 
     protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources";


    
Size of file transfer buffer in bytes.
 
     protected static final int BUFFER_SIZE = 4096;
 
 
     // --------------------------------------------------------- Public Methods
 

    
Finalize this servlet.
 
     public void destroy() {
     }


    
Initialize this servlet.
 
     public void init() throws ServletException {
 
         if (getServletConfig().getInitParameter("debug") != null)
              = Integer.parseInt(getServletConfig().getInitParameter("debug"));
 
         if (getServletConfig().getInitParameter("input") != null)
              = Integer.parseInt(getServletConfig().getInitParameter("input"));
 
         if (getServletConfig().getInitParameter("output") != null)
              = Integer.parseInt(getServletConfig().getInitParameter("output"));
 
          = Boolean.parseBoolean(getServletConfig().getInitParameter("listings"));
 
         if (getServletConfig().getInitParameter("readonly") != null)
              = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly"));
 
         if (getServletConfig().getInitParameter("sendfileSize") != null)
              = 
                 Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024;
 
          = getServletConfig().getInitParameter("fileEncoding");
 
          = getServletConfig().getInitParameter("globalXsltFile");
          = getServletConfig().getInitParameter("contextXsltFile");
          = getServletConfig().getInitParameter("localXsltFile");
          = getServletConfig().getInitParameter("readmeFile");
 
         if (getServletConfig().getInitParameter("useAcceptRanges") != null)
              = Boolean.parseBoolean(getServletConfig().getInitParameter("useAcceptRanges"));
 
         // Sanity check on the specified buffer sizes
         if ( < 256)
              = 256;
         if ( < 256)
              = 256;
 
         if ( > 0) {
             log("DefaultServlet.init:  input buffer size=" +  +
                 ", output buffer size=" + );
         }
 
         // Load the proxy dir context.
             .getAttribute(.);
         if ( == null) {
             try {
                  =
                     (ProxyDirContextnew InitialContext()
                     .lookup();
             } catch (NamingException e) {
                 // Failed
                 throw new ServletException("No resources"e);
             }
         }
 
         if ( == null) {
             throw new UnavailableException("No resources");
         }
 
     }
 
 
     // ------------------------------------------------------ Protected Methods
 

    
Return the relative path associated with this servlet.

Parameters:
request The servlet request we are processing
 
     protected String getRelativePath(HttpServletRequest request) {
 
         // Are we being processed by a RequestDispatcher.include()?
         if (request.getAttribute(.) != null) {
             String result = (Stringrequest.getAttribute(
                     .);
             if (result == null)
                 result = (Stringrequest.getAttribute(
                         .);
             if ((result == null) || (result.equals("")))
                 result = "/";
             return (result);
         }
 
         // No, extract the desired path directly from the request
         String result = request.getPathInfo();
         if (result == null) {
             result = request.getServletPath();
         }
         if ((result == null) || (result.equals(""))) {
             result = "/";
         }
         return (result);
 
     }


    
Process a GET request for the specified resource.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void doGet(HttpServletRequest request,
                          HttpServletResponse response)
         throws IOExceptionServletException {
 
         // Serve the requested resource, including the data content
         serveResource(requestresponsetrue);
 
     }


    
Process a HEAD request for the specified resource.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void doHead(HttpServletRequest request,
                           HttpServletResponse response)
         throws IOExceptionServletException {
 
         // Serve the requested resource, without the data content
         serveResource(requestresponsefalse);
 
     }


    
Process a POST request for the specified resource.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void doPost(HttpServletRequest request,
                           HttpServletResponse response)
         throws IOExceptionServletException {
         doGet(requestresponse);
     }


    
Process a POST request for the specified resource.

Parameters:
req The servlet request we are processing
resp The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void doPut(HttpServletRequest reqHttpServletResponse resp)
         throws ServletExceptionIOException {
 
         if () {
             resp.sendError(.);
             return;
         }
 
         String path = getRelativePath(req);
 
         boolean exists = true;
         try {
             .lookup(path);
         } catch (NamingException e) {
             exists = false;
         }
 
         boolean result = true;
 
         // Temp. content file used to support partial PUT
         File contentFile = null;
 
         Range range = parseContentRange(reqresp);
 
         InputStream resourceInputStream = null;
 
         // Append data specified in ranges to existing content for this
         // resource - create a temp. file on the local filesystem to
         // perform this operation
         // Assume just one range is specified for now
         if (range != null) {
             contentFile = executePartialPut(reqrangepath);
             resourceInputStream = new FileInputStream(contentFile);
         } else {
             resourceInputStream = req.getInputStream();
         }
 
         try {
             Resource newResource = new Resource(resourceInputStream);
             // FIXME: Add attributes
             if (exists) {
                 .rebind(pathnewResource);
             } else {
                 .bind(pathnewResource);
             }
         } catch(NamingException e) {
             result = false;
         }
 
         if (result) {
             if (exists) {
                 resp.setStatus(.);
             } else {
                 resp.setStatus(.);
             }
         } else {
             resp.sendError(.);
         }
 
     }


    
Handle a partial PUT. New content specified in request is appended to existing content in oldRevisionContent (if present). This code does not support simultaneous partial updates to the same resource.
 
     protected File executePartialPut(HttpServletRequest reqRange range,
                                      String path)
         throws IOException {
 
         // Append data specified in ranges to existing content for this
         // resource - create a temp. file on the local filesystem to
         // perform this operation
         File tempDir = (FilegetServletContext().getAttribute
             (.);
         // Convert all '/' characters to '.' in resourcePath
         String convertedResourcePath = path.replace('/''.');
         File contentFile = new File(tempDirconvertedResourcePath);
         if (contentFile.createNewFile()) {
             // Clean up contentFile when Tomcat is terminated
             contentFile.deleteOnExit();
         }
 
         RandomAccessFile randAccessContentFile =
             new RandomAccessFile(contentFile"rw");
 
         Resource oldResource = null;
         try {
             Object obj = .lookup(path);
             if (obj instanceof Resource)
                 oldResource = (Resourceobj;
         } catch (NamingException e) {
             // Ignore
         }
 
         // Copy data in oldRevisionContent to contentFile
         if (oldResource != null) {
             BufferedInputStream bufOldRevStream =
                 new BufferedInputStream(oldResource.streamContent(),
                                         );
 
             int numBytesRead;
             byte[] copyBuffer = new byte[];
             while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
                 randAccessContentFile.write(copyBuffer, 0, numBytesRead);
             }
 
             bufOldRevStream.close();
         }
 
         randAccessContentFile.setLength(range.length);
 
         // Append data in request input stream to contentFile
         randAccessContentFile.seek(range.start);
         int numBytesRead;
         byte[] transferBuffer = new byte[];
         BufferedInputStream requestBufInStream =
             new BufferedInputStream(req.getInputStream(), );
         while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
             randAccessContentFile.write(transferBuffer, 0, numBytesRead);
         }
         randAccessContentFile.close();
         requestBufInStream.close();
 
         return contentFile;
 
     }


    
Process a POST request for the specified resource.

Parameters:
req The servlet request we are processing
resp The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void doDelete(HttpServletRequest reqHttpServletResponse resp)
         throws ServletExceptionIOException {
 
         if () {
             resp.sendError(.);
             return;
         }
 
         String path = getRelativePath(req);
 
         boolean exists = true;
         try {
             .lookup(path);
         } catch (NamingException e) {
             exists = false;
         }
 
         if (exists) {
             boolean result = true;
             try {
                 .unbind(path);
             } catch (NamingException e) {
                 result = false;
             }
             if (result) {
                 resp.setStatus(.);
             } else {
                 resp.sendError(.);
             }
         } else {
             resp.sendError(.);
         }
 
     }


    
Check if the conditions specified in the optional If headers are satisfied.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
resourceAttributes The resource information
Returns:
boolean true if the resource meets all the specified conditions, and false if any of the conditions is not satisfied, in which case request processing is stopped
 
     protected boolean checkIfHeaders(HttpServletRequest request,
                                      HttpServletResponse response,
                                      ResourceAttributes resourceAttributes)
         throws IOException {
 
         return checkIfMatch(requestresponseresourceAttributes)
             && checkIfModifiedSince(requestresponseresourceAttributes)
             && checkIfNoneMatch(requestresponseresourceAttributes)
             && checkIfUnmodifiedSince(requestresponseresourceAttributes);
 
     }


    
URL rewriter.

Parameters:
path Path which has to be rewiten
 
     protected String rewriteUrl(String path) {
         return .encodepath );
     }


    
Display the size of a file.
 
     protected void displaySize(StringBuilder bufint filesize) {
 
         int leftside = filesize / 1024;
         int rightside = (filesize % 1024) / 103;  // makes 1 digit
         // To avoid 0.0 for non-zero file, we bump to 0.1
         if (leftside == 0 && rightside == 0 && filesize != 0)
             rightside = 1;
         buf.append(leftside).append(".").append(rightside);
         buf.append(" KB");
 
     }


    
Serve the specified resource, optionally including the data content.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
content Should the content be included?
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet-specified error occurs
 
     protected void serveResource(HttpServletRequest request,
                                  HttpServletResponse response,
                                  boolean content)
         throws IOExceptionServletException {
 
         // Identify the requested resource path
         String path = getRelativePath(request);
         if ( > 0) {
             if (content)
                 log("DefaultServlet.serveResource:  Serving resource '" +
                     path + "' headers and data");
             else
                 log("DefaultServlet.serveResource:  Serving resource '" +
                     path + "' headers only");
         }
 
         CacheEntry cacheEntry = .lookupCache(path);
 
         if (!cacheEntry.exists) {
             // Check if we're included so we can return the appropriate 
             // missing resource name in the error
             String requestUri = (Stringrequest.getAttribute(
                     .);
             if (requestUri == null) {
                 requestUri = request.getRequestURI();
             } else {
                 // We're included, and the response.sendError() below is going
                 // to be ignored by the resource that is including us.
                 // Therefore, throw an exception to notify the error.
                 throw new FileNotFoundException(.resourceNotAvailable(RequestUtil.filter(requestUri)));
             }
 
             response.sendError(.,
                                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 = (Stringrequest.getAttribute(
                         .);
                 if (requestUri == null) {
                     requestUri = request.getRequestURI();
                 }
                 response.sendError(.,
                                    requestUri);
                 return;
             }
         }
 
         // Check if the conditions specified in the optional If headers are
         // satisfied.
         if (cacheEntry.context == null) {
 
             // Checking If headers
             boolean included =
                 (request.getAttribute(.) != null);
             if (!included
                 && !checkIfHeaders(requestresponsecacheEntry.attributes)) {
                 return;
             }
 
         }
 
         // Find content type.
         String contentType = cacheEntry.attributes.getMimeType();
         if (contentType == null) {
             contentType = getServletContext().getMimeType(cacheEntry.name);
             cacheEntry.attributes.setMimeType(contentType);
         }
 
         ArrayList<Rangeranges = null;
         long contentLength = -1L;
 
         if (cacheEntry.context != null) {
 
             // Skip directory listings if we have been configured to
             // suppress them
             if (!) {
                 response.sendError(.,
                                    request.getRequestURI());
                 return;
             }
             contentType = "text/html;charset=UTF-8";
 
         } else {
             if () {
                 // Accept ranges header
                 response.setHeader("Accept-Ranges""bytes");
             }
 
             // Parse range specifier
             ranges = parseRange(requestresponsecacheEntry.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) {
                 content = false;
             }
 
         }
 
         ServletOutputStream ostream = null;
         PrintWriter writer = null;
 
         if (content) {
 
             // 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();
                 } else {
                     throw e;
                 }
             }
 
         }
 
         if ( (cacheEntry.context != null
                 || ( ((ranges == null) || (ranges.isEmpty()))
                         && (request.getHeader("Range") == null) )
                 || (ranges == ) ) {
 
             // Set the appropriate output headers
             if (contentType != null) {
                 if ( > 0)
                     log("DefaultServlet.serveFile:  contentType='" +
                         contentType + "'");
                 response.setContentType(contentType);
             }
             if ((cacheEntry.resource != null) && (contentLength >= 0)) {
                 if ( > 0)
                     log("DefaultServlet.serveFile:  contentLength=" +
                         contentLength);
                 if (contentLength < .) {
                     response.setContentLength((intcontentLength);
                 } 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 (content) {
                     // Serve the directory browser
                     renderResult =
                         render(request.getContextPath(), cacheEntry);
                 }
 
             }
 
             // Copy the input stream to our output stream (if requested)
             if (content) {
                 try {
                     response.setBufferSize();
                 } catch (IllegalStateException e) {
                     // Silent catch
                 }
                 if (ostream != null) {
                     if (!checkSendfile(requestresponsepathcacheEntrycontentLengthnull))
                         copy(cacheEntryrenderResultostream);
                 } else {
                     copy(cacheEntryrenderResultwriter);
                 }
             }
 
         } else {
 
             if ((ranges == null) || (ranges.isEmpty()))
                 return;
 
             // Partial content response.
 
             response.setStatus(.);
 
             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 < .) {
                     response.setContentLength((intlength);
                 } else {
                     // Set the content-length as String to be able to use a long
                     response.setHeader("content-length""" + length);
                 }
 
                 if (contentType != null) {
                     if ( > 0)
                         log("DefaultServlet.serveFile:  contentType='" +
                             contentType + "'");
                     response.setContentType(contentType);
                 }
 
                 if (content) {
                     try {
                         response.setBufferSize();
                     } catch (IllegalStateException e) {
                         // Silent catch
                     }
                     if (ostream != null) {
                         if (!checkSendfile(requestresponsepathcacheEntryrange.end - range.start + 1, range))
                             copy(cacheEntryostreamrange);
                     } else {
                         copy(cacheEntrywriterrange);
                     }
                 }
 
             } else {
 
                 response.setContentType("multipart/byteranges; boundary="
                                         + );
 
                 if (content) {
                     try {
                         response.setBufferSize();
                     } catch (IllegalStateException e) {
                         // Silent catch
                     }
                     if (ostream != null) {
                         copy(cacheEntryostreamranges.iterator(),
                              contentType);
                     } else {
                         copy(cacheEntrywriterranges.iterator(),
                              contentType);
                     }
                 }
 
             }
 
         }
 
     }


    
Parse the content-range header.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Returns:
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(.);
             return null;
         }
 
         rangeHeader = rangeHeader.substring(6).trim();
 
         int dashPos = rangeHeader.indexOf('-');
         int slashPos = rangeHeader.indexOf('/');
 
         if (dashPos == -1) {
             response.sendError(.);
             return null;
         }
 
         if (slashPos == -1) {
             response.sendError(.);
             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(.);
             return null;
         }
 
         if (!range.validate()) {
             response.sendError(.);
             return null;
         }
 
         return range;
 
     }


    
Parse the range header.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Returns:
Vector of ranges
 
     protected ArrayList<RangeparseRange(HttpServletRequest request,
             HttpServletResponse response,
             ResourceAttributes resourceAttributesthrows 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 ;
            } 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 ;
            }
        }
        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
            return null;
        }
        rangeHeader = rangeHeader.substring(6);
        // Vector which will contain all the ranges which are successfully
        // parsed.
        ArrayList<Rangeresult = 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
                    (.);
                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
                        (
                         .);
                    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
                        (
                         .);
                    return null;
                }
            }
            if (!currentRange.validate()) {
                response.addHeader("Content-Range""bytes */" + fileLength);
                response.sendError
                    (.);
                return null;
            }
            result.add(currentRange);
        }
        return result;
    }



    
Decide which way to render. HTML or XML.
    protected InputStream render(String contextPathCacheEntry cacheEntry)
            throws IOExceptionServletException {
        Source xsltSource = findXsltInputStream(cacheEntry.context);
        if (xsltSource == null) {
            return renderHtml(contextPathcacheEntry);
        }
        return renderXml(contextPathcacheEntryxsltSource);
    }

    
Return an InputStream to an HTML representation of the contents of this directory.

Parameters:
contextPath Context path to which our internal paths are relative
    protected InputStream renderXml(String contextPath,
                                    CacheEntry cacheEntry,
                                    Source xsltSource)
        throws IOExceptionServletException {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\"?>");
        sb.append("<listing ");
        sb.append(" contextPath='");
        sb.append(contextPath);
        sb.append("'");
        sb.append(" directory='");
        sb.append(cacheEntry.name);
        sb.append("' ");
        sb.append(" hasParent='").append(!cacheEntry.name.equals("/"));
        sb.append("'>");
        sb.append("<entries>");
        try {
            // Render the directory entries within this directory
            NamingEnumeration<NameClassPairenumeration =
                .list(cacheEntry.name);
            
            // rewriteUrl(contextPath) is expensive. cache result for later reuse
            String rewrittenContextPath =  rewriteUrl(contextPath);
            while (enumeration.hasMoreElements()) {
                NameClassPair ncPair = enumeration.nextElement();
                String resourceName = ncPair.getName();
                String trimmed = resourceName/*.substring(trim)*/;
                if (trimmed.equalsIgnoreCase("WEB-INF") ||
                    trimmed.equalsIgnoreCase("META-INF") ||
                    trimmed.equalsIgnoreCase())
                    continue;
                if ( != null
                        && (cacheEntry.name + trimmed).equals())
                    continue;
                CacheEntry childCacheEntry =
                    .lookupCache(cacheEntry.name + resourceName);
                if (!childCacheEntry.exists) {
                    continue;
                }
                sb.append("<entry");
                sb.append(" type='")
                  .append((childCacheEntry.context != null)?"dir":"file")
                  .append("'");
                sb.append(" urlPath='")
                  .append(rewrittenContextPath)
                  .append(rewriteUrl(cacheEntry.name + resourceName))
                  .append((childCacheEntry.context != null)?"/":"")
                  .append("'");
                if (childCacheEntry.resource != null) {
                    sb.append(" size='")
                      .append(renderSize(childCacheEntry.attributes.getContentLength()))
                      .append("'");
                }
                sb.append(" date='")
                  .append(childCacheEntry.attributes.getLastModifiedHttp())
                  .append("'");
                sb.append(">");
                sb.append(RequestUtil.filter(trimmed));
                if (childCacheEntry.context != null)
                    sb.append("/");
                sb.append("</entry>");
            }
        } catch (NamingException e) {
            // Something went wrong
            throw new ServletException(.resourceNotAvailable(cacheEntry.name), e);
        }
        sb.append("</entries>");
        String readme = getReadme(cacheEntry.context);
        if (readme!=null) {
            sb.append("<readme><![CDATA[");
            sb.append(readme);
            sb.append("]]></readme>");
        }
        sb.append("</listing>");
        // Prevent possible memory leak. Ensure Transformer and
        // TransformerFactory are not loaded from the web application.
        ClassLoader original;
        if (.) {
            PrivilegedGetTccl pa = new PrivilegedGetTccl();
            original = AccessController.doPrivileged(pa);
        } else {
            original = Thread.currentThread().getContextClassLoader();
        }
        try {
            if (.) {
                PrivilegedSetTccl pa =
                        new PrivilegedSetTccl(DefaultServlet.class.getClassLoader());
                AccessController.doPrivileged(pa);
            } else {
                Thread.currentThread().setContextClassLoader(
                        DefaultServlet.class.getClassLoader());
            }
            TransformerFactory tFactory = TransformerFactory.newInstance();
            Source xmlSource = new StreamSource(new StringReader(sb.toString()));
            Transformer transformer = tFactory.newTransformer(xsltSource);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            OutputStreamWriter osWriter = new OutputStreamWriter(stream"UTF8");
            StreamResult out = new StreamResult(osWriter);
            transformer.transform(xmlSourceout);
            osWriter.flush();
            return (new ByteArrayInputStream(stream.toByteArray()));
        } catch (TransformerException e) {
            throw new ServletException("XSL transformer error"e);
        } finally {
            if (.) {
                PrivilegedSetTccl pa = new PrivilegedSetTccl(original);
                AccessController.doPrivileged(pa);
            } else {
                Thread.currentThread().setContextClassLoader(original);
            }
        }
    }

    
Return an InputStream to an HTML representation of the contents of this directory.

Parameters:
contextPath Context path to which our internal paths are relative
    protected InputStream renderHtml(String contextPathCacheEntry cacheEntry)
        throws IOExceptionServletException {