Source Code Cross Referenced for DefaultServlet.java in  » Sevlet-Container » apache-tomcat-6.0.14 » org » apache » catalina » servlets » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » apache tomcat 6.0.14 » org.apache.catalina.servlets 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.catalina.servlets;
0019:
0020:        import java.io.BufferedInputStream;
0021:        import java.io.ByteArrayInputStream;
0022:        import java.io.ByteArrayOutputStream;
0023:        import java.io.File;
0024:        import java.io.FileInputStream;
0025:        import java.io.IOException;
0026:        import java.io.InputStream;
0027:        import java.io.InputStreamReader;
0028:        import java.io.OutputStreamWriter;
0029:        import java.io.PrintWriter;
0030:        import java.io.RandomAccessFile;
0031:        import java.io.Reader;
0032:        import java.io.StringReader;
0033:        import java.io.StringWriter;
0034:        import java.util.ArrayList;
0035:        import java.util.Iterator;
0036:        import java.util.StringTokenizer;
0037:
0038:        import javax.naming.InitialContext;
0039:        import javax.naming.NameClassPair;
0040:        import javax.naming.NamingEnumeration;
0041:        import javax.naming.NamingException;
0042:        import javax.naming.directory.DirContext;
0043:        import javax.servlet.ServletException;
0044:        import javax.servlet.ServletOutputStream;
0045:        import javax.servlet.UnavailableException;
0046:        import javax.servlet.http.HttpServlet;
0047:        import javax.servlet.http.HttpServletRequest;
0048:        import javax.servlet.http.HttpServletResponse;
0049:        import javax.xml.transform.Source;
0050:        import javax.xml.transform.Transformer;
0051:        import javax.xml.transform.TransformerException;
0052:        import javax.xml.transform.TransformerFactory;
0053:        import javax.xml.transform.stream.StreamResult;
0054:        import javax.xml.transform.stream.StreamSource;
0055:
0056:        import org.apache.catalina.Globals;
0057:        import org.apache.catalina.util.RequestUtil;
0058:        import org.apache.catalina.util.ServerInfo;
0059:        import org.apache.catalina.util.StringManager;
0060:        import org.apache.catalina.util.URLEncoder;
0061:        import org.apache.naming.resources.CacheEntry;
0062:        import org.apache.naming.resources.ProxyDirContext;
0063:        import org.apache.naming.resources.Resource;
0064:        import org.apache.naming.resources.ResourceAttributes;
0065:
0066:        /**
0067:         * The default resource-serving servlet for most web applications,
0068:         * used to serve static resources such as HTML pages and images.
0069:         *
0070:         * @author Craig R. McClanahan
0071:         * @author Remy Maucherat
0072:         * @version $Revision: 543680 $ $Date: 2007-06-02 02:42:36 +0200 (sam., 02 juin 2007) $
0073:         */
0074:
0075:        public class DefaultServlet extends HttpServlet {
0076:
0077:            // ----------------------------------------------------- Instance Variables
0078:
0079:            /**
0080:             * The debugging detail level for this servlet.
0081:             */
0082:            protected int debug = 0;
0083:
0084:            /**
0085:             * The input buffer size to use when serving resources.
0086:             */
0087:            protected int input = 2048;
0088:
0089:            /**
0090:             * Should we generate directory listings?
0091:             */
0092:            protected boolean listings = false;
0093:
0094:            /**
0095:             * Read only flag. By default, it's set to true.
0096:             */
0097:            protected boolean readOnly = true;
0098:
0099:            /**
0100:             * The output buffer size to use when serving resources.
0101:             */
0102:            protected int output = 2048;
0103:
0104:            /**
0105:             * Array containing the safe characters set.
0106:             */
0107:            protected static URLEncoder urlEncoder;
0108:
0109:            /**
0110:             * Allow customized directory listing per directory.
0111:             */
0112:            protected String localXsltFile = null;
0113:
0114:            /**
0115:             * Allow customized directory listing per instance.
0116:             */
0117:            protected String globalXsltFile = null;
0118:
0119:            /**
0120:             * Allow a readme file to be included.
0121:             */
0122:            protected String readmeFile = null;
0123:
0124:            /**
0125:             * Proxy directory context.
0126:             */
0127:            protected ProxyDirContext resources = null;
0128:
0129:            /**
0130:             * File encoding to be used when reading static files. If none is specified
0131:             * the platform default is used.
0132:             */
0133:            protected String fileEncoding = null;
0134:
0135:            /**
0136:             * Minimum size for sendfile usage in bytes.
0137:             */
0138:            protected int sendfileSize = 48 * 1024;
0139:
0140:            /**
0141:             * Full range marker.
0142:             */
0143:            protected static ArrayList FULL = new ArrayList();
0144:
0145:            // ----------------------------------------------------- Static Initializer
0146:
0147:            /**
0148:             * GMT timezone - all HTTP dates are on GMT
0149:             */
0150:            static {
0151:                urlEncoder = new URLEncoder();
0152:                urlEncoder.addSafeCharacter('-');
0153:                urlEncoder.addSafeCharacter('_');
0154:                urlEncoder.addSafeCharacter('.');
0155:                urlEncoder.addSafeCharacter('*');
0156:                urlEncoder.addSafeCharacter('/');
0157:            }
0158:
0159:            /**
0160:             * MIME multipart separation string
0161:             */
0162:            protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
0163:
0164:            /**
0165:             * JNDI resources name.
0166:             */
0167:            protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources";
0168:
0169:            /**
0170:             * The string manager for this package.
0171:             */
0172:            protected static StringManager sm = StringManager
0173:                    .getManager(Constants.Package);
0174:
0175:            /**
0176:             * Size of file transfer buffer in bytes.
0177:             */
0178:            protected static final int BUFFER_SIZE = 4096;
0179:
0180:            // --------------------------------------------------------- Public Methods
0181:
0182:            /**
0183:             * Finalize this servlet.
0184:             */
0185:            public void destroy() {
0186:            }
0187:
0188:            /**
0189:             * Initialize this servlet.
0190:             */
0191:            public void init() throws ServletException {
0192:
0193:                if (getServletConfig().getInitParameter("debug") != null)
0194:                    debug = Integer.parseInt(getServletConfig()
0195:                            .getInitParameter("debug"));
0196:
0197:                if (getServletConfig().getInitParameter("input") != null)
0198:                    input = Integer.parseInt(getServletConfig()
0199:                            .getInitParameter("input"));
0200:
0201:                if (getServletConfig().getInitParameter("output") != null)
0202:                    output = Integer.parseInt(getServletConfig()
0203:                            .getInitParameter("output"));
0204:
0205:                listings = Boolean.parseBoolean(getServletConfig()
0206:                        .getInitParameter("listings"));
0207:
0208:                if (getServletConfig().getInitParameter("readonly") != null)
0209:                    readOnly = Boolean.parseBoolean(getServletConfig()
0210:                            .getInitParameter("readonly"));
0211:
0212:                if (getServletConfig().getInitParameter("sendfileSize") != null)
0213:                    sendfileSize = Integer.parseInt(getServletConfig()
0214:                            .getInitParameter("sendfileSize")) * 1024;
0215:
0216:                fileEncoding = getServletConfig().getInitParameter(
0217:                        "fileEncoding");
0218:
0219:                globalXsltFile = getServletConfig().getInitParameter(
0220:                        "globalXsltFile");
0221:                localXsltFile = getServletConfig().getInitParameter(
0222:                        "localXsltFile");
0223:                readmeFile = getServletConfig().getInitParameter("readmeFile");
0224:
0225:                // Sanity check on the specified buffer sizes
0226:                if (input < 256)
0227:                    input = 256;
0228:                if (output < 256)
0229:                    output = 256;
0230:
0231:                if (debug > 0) {
0232:                    log("DefaultServlet.init:  input buffer size=" + input
0233:                            + ", output buffer size=" + output);
0234:                }
0235:
0236:                // Load the proxy dir context.
0237:                resources = (ProxyDirContext) getServletContext().getAttribute(
0238:                        Globals.RESOURCES_ATTR);
0239:                if (resources == null) {
0240:                    try {
0241:                        resources = (ProxyDirContext) new InitialContext()
0242:                                .lookup(RESOURCES_JNDI_NAME);
0243:                    } catch (NamingException e) {
0244:                        // Failed
0245:                        throw new ServletException("No resources", e);
0246:                    }
0247:                }
0248:
0249:                if (resources == null) {
0250:                    throw new UnavailableException("No resources");
0251:                }
0252:
0253:            }
0254:
0255:            // ------------------------------------------------------ Protected Methods
0256:
0257:            /**
0258:             * Return the relative path associated with this servlet.
0259:             *
0260:             * @param request The servlet request we are processing
0261:             */
0262:            protected String getRelativePath(HttpServletRequest request) {
0263:
0264:                // Are we being processed by a RequestDispatcher.include()?
0265:                if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) {
0266:                    String result = (String) request
0267:                            .getAttribute(Globals.INCLUDE_PATH_INFO_ATTR);
0268:                    if (result == null)
0269:                        result = (String) request
0270:                                .getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
0271:                    if ((result == null) || (result.equals("")))
0272:                        result = "/";
0273:                    return (result);
0274:                }
0275:
0276:                // No, extract the desired path directly from the request
0277:                String result = request.getPathInfo();
0278:                if (result == null) {
0279:                    result = request.getServletPath();
0280:                }
0281:                if ((result == null) || (result.equals(""))) {
0282:                    result = "/";
0283:                }
0284:                return (result);
0285:
0286:            }
0287:
0288:            /**
0289:             * Process a GET request for the specified resource.
0290:             *
0291:             * @param request The servlet request we are processing
0292:             * @param response The servlet response we are creating
0293:             *
0294:             * @exception IOException if an input/output error occurs
0295:             * @exception ServletException if a servlet-specified error occurs
0296:             */
0297:            protected void doGet(HttpServletRequest request,
0298:                    HttpServletResponse response) throws IOException,
0299:                    ServletException {
0300:
0301:                // Serve the requested resource, including the data content
0302:                serveResource(request, response, true);
0303:
0304:            }
0305:
0306:            /**
0307:             * Process a HEAD request for the specified resource.
0308:             *
0309:             * @param request The servlet request we are processing
0310:             * @param response The servlet response we are creating
0311:             *
0312:             * @exception IOException if an input/output error occurs
0313:             * @exception ServletException if a servlet-specified error occurs
0314:             */
0315:            protected void doHead(HttpServletRequest request,
0316:                    HttpServletResponse response) throws IOException,
0317:                    ServletException {
0318:
0319:                // Serve the requested resource, without the data content
0320:                serveResource(request, response, false);
0321:
0322:            }
0323:
0324:            /**
0325:             * Process a POST request for the specified resource.
0326:             *
0327:             * @param request The servlet request we are processing
0328:             * @param response The servlet response we are creating
0329:             *
0330:             * @exception IOException if an input/output error occurs
0331:             * @exception ServletException if a servlet-specified error occurs
0332:             */
0333:            protected void doPost(HttpServletRequest request,
0334:                    HttpServletResponse response) throws IOException,
0335:                    ServletException {
0336:                doGet(request, response);
0337:            }
0338:
0339:            /**
0340:             * Process a POST request for the specified resource.
0341:             *
0342:             * @param req The servlet request we are processing
0343:             * @param resp The servlet response we are creating
0344:             *
0345:             * @exception IOException if an input/output error occurs
0346:             * @exception ServletException if a servlet-specified error occurs
0347:             */
0348:            protected void doPut(HttpServletRequest req,
0349:                    HttpServletResponse resp) throws ServletException,
0350:                    IOException {
0351:
0352:                if (readOnly) {
0353:                    resp.sendError(HttpServletResponse.SC_FORBIDDEN);
0354:                    return;
0355:                }
0356:
0357:                String path = getRelativePath(req);
0358:
0359:                boolean exists = true;
0360:                try {
0361:                    resources.lookup(path);
0362:                } catch (NamingException e) {
0363:                    exists = false;
0364:                }
0365:
0366:                boolean result = true;
0367:
0368:                // Temp. content file used to support partial PUT
0369:                File contentFile = null;
0370:
0371:                Range range = parseContentRange(req, resp);
0372:
0373:                InputStream resourceInputStream = null;
0374:
0375:                // Append data specified in ranges to existing content for this
0376:                // resource - create a temp. file on the local filesystem to
0377:                // perform this operation
0378:                // Assume just one range is specified for now
0379:                if (range != null) {
0380:                    contentFile = executePartialPut(req, range, path);
0381:                    resourceInputStream = new FileInputStream(contentFile);
0382:                } else {
0383:                    resourceInputStream = req.getInputStream();
0384:                }
0385:
0386:                try {
0387:                    Resource newResource = new Resource(resourceInputStream);
0388:                    // FIXME: Add attributes
0389:                    if (exists) {
0390:                        resources.rebind(path, newResource);
0391:                    } else {
0392:                        resources.bind(path, newResource);
0393:                    }
0394:                } catch (NamingException e) {
0395:                    result = false;
0396:                }
0397:
0398:                if (result) {
0399:                    if (exists) {
0400:                        resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
0401:                    } else {
0402:                        resp.setStatus(HttpServletResponse.SC_CREATED);
0403:                    }
0404:                } else {
0405:                    resp.sendError(HttpServletResponse.SC_CONFLICT);
0406:                }
0407:
0408:            }
0409:
0410:            /**
0411:             * Handle a partial PUT.  New content specified in request is appended to
0412:             * existing content in oldRevisionContent (if present). This code does
0413:             * not support simultaneous partial updates to the same resource.
0414:             */
0415:            protected File executePartialPut(HttpServletRequest req,
0416:                    Range range, String path) throws IOException {
0417:
0418:                // Append data specified in ranges to existing content for this
0419:                // resource - create a temp. file on the local filesystem to
0420:                // perform this operation
0421:                File tempDir = (File) getServletContext().getAttribute(
0422:                        "javax.servlet.context.tempdir");
0423:                // Convert all '/' characters to '.' in resourcePath
0424:                String convertedResourcePath = path.replace('/', '.');
0425:                File contentFile = new File(tempDir, convertedResourcePath);
0426:                if (contentFile.createNewFile()) {
0427:                    // Clean up contentFile when Tomcat is terminated
0428:                    contentFile.deleteOnExit();
0429:                }
0430:
0431:                RandomAccessFile randAccessContentFile = new RandomAccessFile(
0432:                        contentFile, "rw");
0433:
0434:                Resource oldResource = null;
0435:                try {
0436:                    Object obj = resources.lookup(path);
0437:                    if (obj instanceof  Resource)
0438:                        oldResource = (Resource) obj;
0439:                } catch (NamingException e) {
0440:                    ;
0441:                }
0442:
0443:                // Copy data in oldRevisionContent to contentFile
0444:                if (oldResource != null) {
0445:                    BufferedInputStream bufOldRevStream = new BufferedInputStream(
0446:                            oldResource.streamContent(), BUFFER_SIZE);
0447:
0448:                    int numBytesRead;
0449:                    byte[] copyBuffer = new byte[BUFFER_SIZE];
0450:                    while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
0451:                        randAccessContentFile
0452:                                .write(copyBuffer, 0, numBytesRead);
0453:                    }
0454:
0455:                    bufOldRevStream.close();
0456:                }
0457:
0458:                randAccessContentFile.setLength(range.length);
0459:
0460:                // Append data in request input stream to contentFile
0461:                randAccessContentFile.seek(range.start);
0462:                int numBytesRead;
0463:                byte[] transferBuffer = new byte[BUFFER_SIZE];
0464:                BufferedInputStream requestBufInStream = new BufferedInputStream(
0465:                        req.getInputStream(), BUFFER_SIZE);
0466:                while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
0467:                    randAccessContentFile
0468:                            .write(transferBuffer, 0, numBytesRead);
0469:                }
0470:                randAccessContentFile.close();
0471:                requestBufInStream.close();
0472:
0473:                return contentFile;
0474:
0475:            }
0476:
0477:            /**
0478:             * Process a POST request for the specified resource.
0479:             *
0480:             * @param req The servlet request we are processing
0481:             * @param resp The servlet response we are creating
0482:             *
0483:             * @exception IOException if an input/output error occurs
0484:             * @exception ServletException if a servlet-specified error occurs
0485:             */
0486:            protected void doDelete(HttpServletRequest req,
0487:                    HttpServletResponse resp) throws ServletException,
0488:                    IOException {
0489:
0490:                if (readOnly) {
0491:                    resp.sendError(HttpServletResponse.SC_FORBIDDEN);
0492:                    return;
0493:                }
0494:
0495:                String path = getRelativePath(req);
0496:
0497:                boolean exists = true;
0498:                try {
0499:                    resources.lookup(path);
0500:                } catch (NamingException e) {
0501:                    exists = false;
0502:                }
0503:
0504:                if (exists) {
0505:                    boolean result = true;
0506:                    try {
0507:                        resources.unbind(path);
0508:                    } catch (NamingException e) {
0509:                        result = false;
0510:                    }
0511:                    if (result) {
0512:                        resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
0513:                    } else {
0514:                        resp
0515:                                .sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
0516:                    }
0517:                } else {
0518:                    resp.sendError(HttpServletResponse.SC_NOT_FOUND);
0519:                }
0520:
0521:            }
0522:
0523:            /**
0524:             * Check if the conditions specified in the optional If headers are
0525:             * satisfied.
0526:             *
0527:             * @param request The servlet request we are processing
0528:             * @param response The servlet response we are creating
0529:             * @param resourceAttributes The resource information
0530:             * @return boolean true if the resource meets all the specified conditions,
0531:             * and false if any of the conditions is not satisfied, in which case
0532:             * request processing is stopped
0533:             */
0534:            protected boolean checkIfHeaders(HttpServletRequest request,
0535:                    HttpServletResponse response,
0536:                    ResourceAttributes resourceAttributes) throws IOException {
0537:
0538:                return checkIfMatch(request, response, resourceAttributes)
0539:                        && checkIfModifiedSince(request, response,
0540:                                resourceAttributes)
0541:                        && checkIfNoneMatch(request, response,
0542:                                resourceAttributes)
0543:                        && checkIfUnmodifiedSince(request, response,
0544:                                resourceAttributes);
0545:
0546:            }
0547:
0548:            /**
0549:             * Get the ETag associated with a file.
0550:             *
0551:             * @param resourceAttributes The resource information
0552:             */
0553:            protected String getETag(ResourceAttributes resourceAttributes) {
0554:                String result = null;
0555:                if ((result = resourceAttributes.getETag(true)) != null) {
0556:                    return result;
0557:                } else if ((result = resourceAttributes.getETag()) != null) {
0558:                    return result;
0559:                } else {
0560:                    return "W/\"" + resourceAttributes.getContentLength() + "-"
0561:                            + resourceAttributes.getLastModified() + "\"";
0562:                }
0563:            }
0564:
0565:            /**
0566:             * URL rewriter.
0567:             *
0568:             * @param path Path which has to be rewiten
0569:             */
0570:            protected String rewriteUrl(String path) {
0571:                return urlEncoder.encode(path);
0572:            }
0573:
0574:            /**
0575:             * Display the size of a file.
0576:             */
0577:            protected void displaySize(StringBuffer buf, int filesize) {
0578:
0579:                int leftside = filesize / 1024;
0580:                int rightside = (filesize % 1024) / 103; // makes 1 digit
0581:                // To avoid 0.0 for non-zero file, we bump to 0.1
0582:                if (leftside == 0 && rightside == 0 && filesize != 0)
0583:                    rightside = 1;
0584:                buf.append(leftside).append(".").append(rightside);
0585:                buf.append(" KB");
0586:
0587:            }
0588:
0589:            /**
0590:             * Serve the specified resource, optionally including the data content.
0591:             *
0592:             * @param request The servlet request we are processing
0593:             * @param response The servlet response we are creating
0594:             * @param content Should the content be included?
0595:             *
0596:             * @exception IOException if an input/output error occurs
0597:             * @exception ServletException if a servlet-specified error occurs
0598:             */
0599:            protected void serveResource(HttpServletRequest request,
0600:                    HttpServletResponse response, boolean content)
0601:                    throws IOException, ServletException {
0602:
0603:                // Identify the requested resource path
0604:                String path = getRelativePath(request);
0605:                if (debug > 0) {
0606:                    if (content)
0607:                        log("DefaultServlet.serveResource:  Serving resource '"
0608:                                + path + "' headers and data");
0609:                    else
0610:                        log("DefaultServlet.serveResource:  Serving resource '"
0611:                                + path + "' headers only");
0612:                }
0613:
0614:                CacheEntry cacheEntry = resources.lookupCache(path);
0615:
0616:                if (!cacheEntry.exists) {
0617:                    // Check if we're included so we can return the appropriate 
0618:                    // missing resource name in the error
0619:                    String requestUri = (String) request
0620:                            .getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR);
0621:                    if (requestUri == null) {
0622:                        requestUri = request.getRequestURI();
0623:                    } else {
0624:                        // We're included, and the response.sendError() below is going
0625:                        // to be ignored by the resource that is including us.
0626:                        // Therefore, the only way we can let the including resource
0627:                        // know is by including warning message in response
0628:                        response.getWriter().write(
0629:                                sm.getString("defaultServlet.missingResource",
0630:                                        requestUri));
0631:                    }
0632:
0633:                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
0634:                            requestUri);
0635:                    return;
0636:                }
0637:
0638:                // If the resource is not a collection, and the resource path
0639:                // ends with "/" or "\", return NOT FOUND
0640:                if (cacheEntry.context == null) {
0641:                    if (path.endsWith("/") || (path.endsWith("\\"))) {
0642:                        // Check if we're included so we can return the appropriate 
0643:                        // missing resource name in the error
0644:                        String requestUri = (String) request
0645:                                .getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR);
0646:                        if (requestUri == null) {
0647:                            requestUri = request.getRequestURI();
0648:                        }
0649:                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
0650:                                requestUri);
0651:                        return;
0652:                    }
0653:                }
0654:
0655:                // Check if the conditions specified in the optional If headers are
0656:                // satisfied.
0657:                if (cacheEntry.context == null) {
0658:
0659:                    // Checking If headers
0660:                    boolean included = (request
0661:                            .getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null);
0662:                    if (!included
0663:                            && !checkIfHeaders(request, response,
0664:                                    cacheEntry.attributes)) {
0665:                        return;
0666:                    }
0667:
0668:                }
0669:
0670:                // Find content type.
0671:                String contentType = cacheEntry.attributes.getMimeType();
0672:                if (contentType == null) {
0673:                    contentType = getServletContext().getMimeType(
0674:                            cacheEntry.name);
0675:                    cacheEntry.attributes.setMimeType(contentType);
0676:                }
0677:
0678:                ArrayList ranges = null;
0679:                long contentLength = -1L;
0680:
0681:                if (cacheEntry.context != null) {
0682:
0683:                    // Skip directory listings if we have been configured to
0684:                    // suppress them
0685:                    if (!listings) {
0686:                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
0687:                                request.getRequestURI());
0688:                        return;
0689:                    }
0690:                    contentType = "text/html;charset=UTF-8";
0691:
0692:                } else {
0693:
0694:                    // Parse range specifier
0695:
0696:                    ranges = parseRange(request, response,
0697:                            cacheEntry.attributes);
0698:
0699:                    // ETag header
0700:                    response.setHeader("ETag", getETag(cacheEntry.attributes));
0701:
0702:                    // Last-Modified header
0703:                    response.setHeader("Last-Modified", cacheEntry.attributes
0704:                            .getLastModifiedHttp());
0705:
0706:                    // Get content length
0707:                    contentLength = cacheEntry.attributes.getContentLength();
0708:                    // Special case for zero length files, which would cause a
0709:                    // (silent) ISE when setting the output buffer size
0710:                    if (contentLength == 0L) {
0711:                        content = false;
0712:                    }
0713:
0714:                }
0715:
0716:                ServletOutputStream ostream = null;
0717:                PrintWriter writer = null;
0718:
0719:                if (content) {
0720:
0721:                    // Trying to retrieve the servlet output stream
0722:
0723:                    try {
0724:                        ostream = response.getOutputStream();
0725:                    } catch (IllegalStateException e) {
0726:                        // If it fails, we try to get a Writer instead if we're
0727:                        // trying to serve a text file
0728:                        if ((contentType == null)
0729:                                || (contentType.startsWith("text"))
0730:                                || (contentType.endsWith("xml"))) {
0731:                            writer = response.getWriter();
0732:                        } else {
0733:                            throw e;
0734:                        }
0735:                    }
0736:
0737:                }
0738:
0739:                if ((cacheEntry.context != null)
0740:                        || (((ranges == null) || (ranges.isEmpty())) && (request
0741:                                .getHeader("Range") == null))
0742:                        || (ranges == FULL)) {
0743:
0744:                    // Set the appropriate output headers
0745:                    if (contentType != null) {
0746:                        if (debug > 0)
0747:                            log("DefaultServlet.serveFile:  contentType='"
0748:                                    + contentType + "'");
0749:                        response.setContentType(contentType);
0750:                    }
0751:                    if ((cacheEntry.resource != null) && (contentLength >= 0)) {
0752:                        if (debug > 0)
0753:                            log("DefaultServlet.serveFile:  contentLength="
0754:                                    + contentLength);
0755:                        if (contentLength < Integer.MAX_VALUE) {
0756:                            response.setContentLength((int) contentLength);
0757:                        } else {
0758:                            // Set the content-length as String to be able to use a long
0759:                            response.setHeader("content-length", ""
0760:                                    + contentLength);
0761:                        }
0762:                    }
0763:
0764:                    InputStream renderResult = null;
0765:                    if (cacheEntry.context != null) {
0766:
0767:                        if (content) {
0768:                            // Serve the directory browser
0769:                            renderResult = render(request.getContextPath(),
0770:                                    cacheEntry);
0771:                        }
0772:
0773:                    }
0774:
0775:                    // Copy the input stream to our output stream (if requested)
0776:                    if (content) {
0777:                        try {
0778:                            response.setBufferSize(output);
0779:                        } catch (IllegalStateException e) {
0780:                            // Silent catch
0781:                        }
0782:                        if (ostream != null) {
0783:                            if (!checkSendfile(request, response, cacheEntry,
0784:                                    contentLength, null))
0785:                                copy(cacheEntry, renderResult, ostream);
0786:                        } else {
0787:                            copy(cacheEntry, renderResult, writer);
0788:                        }
0789:                    }
0790:
0791:                } else {
0792:
0793:                    if ((ranges == null) || (ranges.isEmpty()))
0794:                        return;
0795:
0796:                    // Partial content response.
0797:
0798:                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
0799:
0800:                    if (ranges.size() == 1) {
0801:
0802:                        Range range = (Range) ranges.get(0);
0803:                        response.addHeader("Content-Range", "bytes "
0804:                                + range.start + "-" + range.end + "/"
0805:                                + range.length);
0806:                        long length = range.end - range.start + 1;
0807:                        if (length < Integer.MAX_VALUE) {
0808:                            response.setContentLength((int) length);
0809:                        } else {
0810:                            // Set the content-length as String to be able to use a long
0811:                            response.setHeader("content-length", "" + length);
0812:                        }
0813:
0814:                        if (contentType != null) {
0815:                            if (debug > 0)
0816:                                log("DefaultServlet.serveFile:  contentType='"
0817:                                        + contentType + "'");
0818:                            response.setContentType(contentType);
0819:                        }
0820:
0821:                        if (content) {
0822:                            try {
0823:                                response.setBufferSize(output);
0824:                            } catch (IllegalStateException e) {
0825:                                // Silent catch
0826:                            }
0827:                            if (ostream != null) {
0828:                                if (!checkSendfile(request, response,
0829:                                        cacheEntry,
0830:                                        range.end - range.start + 1, range))
0831:                                    copy(cacheEntry, ostream, range);
0832:                            } else {
0833:                                copy(cacheEntry, writer, range);
0834:                            }
0835:                        }
0836:
0837:                    } else {
0838:
0839:                        response
0840:                                .setContentType("multipart/byteranges; boundary="
0841:                                        + mimeSeparation);
0842:
0843:                        if (content) {
0844:                            try {
0845:                                response.setBufferSize(output);
0846:                            } catch (IllegalStateException e) {
0847:                                // Silent catch
0848:                            }
0849:                            if (ostream != null) {
0850:                                copy(cacheEntry, ostream, ranges.iterator(),
0851:                                        contentType);
0852:                            } else {
0853:                                copy(cacheEntry, writer, ranges.iterator(),
0854:                                        contentType);
0855:                            }
0856:                        }
0857:
0858:                    }
0859:
0860:                }
0861:
0862:            }
0863:
0864:            /**
0865:             * Parse the content-range header.
0866:             *
0867:             * @param request The servlet request we are processing
0868:             * @param response The servlet response we are creating
0869:             * @return Range
0870:             */
0871:            protected Range parseContentRange(HttpServletRequest request,
0872:                    HttpServletResponse response) throws IOException {
0873:
0874:                // Retrieving the content-range header (if any is specified
0875:                String rangeHeader = request.getHeader("Content-Range");
0876:
0877:                if (rangeHeader == null)
0878:                    return null;
0879:
0880:                // bytes is the only range unit supported
0881:                if (!rangeHeader.startsWith("bytes")) {
0882:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
0883:                    return null;
0884:                }
0885:
0886:                rangeHeader = rangeHeader.substring(6).trim();
0887:
0888:                int dashPos = rangeHeader.indexOf('-');
0889:                int slashPos = rangeHeader.indexOf('/');
0890:
0891:                if (dashPos == -1) {
0892:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
0893:                    return null;
0894:                }
0895:
0896:                if (slashPos == -1) {
0897:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
0898:                    return null;
0899:                }
0900:
0901:                Range range = new Range();
0902:
0903:                try {
0904:                    range.start = Long.parseLong(rangeHeader.substring(0,
0905:                            dashPos));
0906:                    range.end = Long.parseLong(rangeHeader.substring(
0907:                            dashPos + 1, slashPos));
0908:                    range.length = Long.parseLong(rangeHeader.substring(
0909:                            slashPos + 1, rangeHeader.length()));
0910:                } catch (NumberFormatException e) {
0911:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
0912:                    return null;
0913:                }
0914:
0915:                if (!range.validate()) {
0916:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
0917:                    return null;
0918:                }
0919:
0920:                return range;
0921:
0922:            }
0923:
0924:            /**
0925:             * Parse the range header.
0926:             *
0927:             * @param request The servlet request we are processing
0928:             * @param response The servlet response we are creating
0929:             * @return Vector of ranges
0930:             */
0931:            protected ArrayList parseRange(HttpServletRequest request,
0932:                    HttpServletResponse response,
0933:                    ResourceAttributes resourceAttributes) throws IOException {
0934:
0935:                // Checking If-Range
0936:                String headerValue = request.getHeader("If-Range");
0937:
0938:                if (headerValue != null) {
0939:
0940:                    long headerValueTime = (-1L);
0941:                    try {
0942:                        headerValueTime = request.getDateHeader("If-Range");
0943:                    } catch (IllegalArgumentException e) {
0944:                        ;
0945:                    }
0946:
0947:                    String eTag = getETag(resourceAttributes);
0948:                    long lastModified = resourceAttributes.getLastModified();
0949:
0950:                    if (headerValueTime == (-1L)) {
0951:
0952:                        // If the ETag the client gave does not match the entity
0953:                        // etag, then the entire entity is returned.
0954:                        if (!eTag.equals(headerValue.trim()))
0955:                            return FULL;
0956:
0957:                    } else {
0958:
0959:                        // If the timestamp of the entity the client got is older than
0960:                        // the last modification date of the entity, the entire entity
0961:                        // is returned.
0962:                        if (lastModified > (headerValueTime + 1000))
0963:                            return FULL;
0964:
0965:                    }
0966:
0967:                }
0968:
0969:                long fileLength = resourceAttributes.getContentLength();
0970:
0971:                if (fileLength == 0)
0972:                    return null;
0973:
0974:                // Retrieving the range header (if any is specified
0975:                String rangeHeader = request.getHeader("Range");
0976:
0977:                if (rangeHeader == null)
0978:                    return null;
0979:                // bytes is the only range unit supported (and I don't see the point
0980:                // of adding new ones).
0981:                if (!rangeHeader.startsWith("bytes")) {
0982:                    response
0983:                            .addHeader("Content-Range", "bytes */" + fileLength);
0984:                    response
0985:                            .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
0986:                    return null;
0987:                }
0988:
0989:                rangeHeader = rangeHeader.substring(6);
0990:
0991:                // Vector which will contain all the ranges which are successfully
0992:                // parsed.
0993:                ArrayList<Range> result = new ArrayList<Range>();
0994:                StringTokenizer commaTokenizer = new StringTokenizer(
0995:                        rangeHeader, ",");
0996:
0997:                // Parsing the range list
0998:                while (commaTokenizer.hasMoreTokens()) {
0999:                    String rangeDefinition = commaTokenizer.nextToken().trim();
1000:
1001:                    Range currentRange = new Range();
1002:                    currentRange.length = fileLength;
1003:
1004:                    int dashPos = rangeDefinition.indexOf('-');
1005:
1006:                    if (dashPos == -1) {
1007:                        response.addHeader("Content-Range", "bytes */"
1008:                                + fileLength);
1009:                        response
1010:                                .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1011:                        return null;
1012:                    }
1013:
1014:                    if (dashPos == 0) {
1015:
1016:                        try {
1017:                            long offset = Long.parseLong(rangeDefinition);
1018:                            currentRange.start = fileLength + offset;
1019:                            currentRange.end = fileLength - 1;
1020:                        } catch (NumberFormatException e) {
1021:                            response.addHeader("Content-Range", "bytes */"
1022:                                    + fileLength);
1023:                            response
1024:                                    .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1025:                            return null;
1026:                        }
1027:
1028:                    } else {
1029:
1030:                        try {
1031:                            currentRange.start = Long.parseLong(rangeDefinition
1032:                                    .substring(0, dashPos));
1033:                            if (dashPos < rangeDefinition.length() - 1)
1034:                                currentRange.end = Long
1035:                                        .parseLong(rangeDefinition.substring(
1036:                                                dashPos + 1, rangeDefinition
1037:                                                        .length()));
1038:                            else
1039:                                currentRange.end = fileLength - 1;
1040:                        } catch (NumberFormatException e) {
1041:                            response.addHeader("Content-Range", "bytes */"
1042:                                    + fileLength);
1043:                            response
1044:                                    .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1045:                            return null;
1046:                        }
1047:
1048:                    }
1049:
1050:                    if (!currentRange.validate()) {
1051:                        response.addHeader("Content-Range", "bytes */"
1052:                                + fileLength);
1053:                        response
1054:                                .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1055:                        return null;
1056:                    }
1057:
1058:                    result.add(currentRange);
1059:                }
1060:
1061:                return result;
1062:            }
1063:
1064:            /**
1065:             *  Decide which way to render. HTML or XML.
1066:             */
1067:            protected InputStream render(String contextPath,
1068:                    CacheEntry cacheEntry) throws IOException, ServletException {
1069:
1070:                InputStream xsltInputStream = findXsltInputStream(cacheEntry.context);
1071:
1072:                if (xsltInputStream == null) {
1073:                    return renderHtml(contextPath, cacheEntry);
1074:                } else {
1075:                    return renderXml(contextPath, cacheEntry, xsltInputStream);
1076:                }
1077:
1078:            }
1079:
1080:            /**
1081:             * Return an InputStream to an HTML representation of the contents
1082:             * of this directory.
1083:             *
1084:             * @param contextPath Context path to which our internal paths are
1085:             *  relative
1086:             */
1087:            protected InputStream renderXml(String contextPath,
1088:                    CacheEntry cacheEntry, InputStream xsltInputStream)
1089:                    throws IOException, ServletException {
1090:
1091:                StringBuffer sb = new StringBuffer();
1092:
1093:                sb.append("<?xml version=\"1.0\"?>");
1094:                sb.append("<listing ");
1095:                sb.append(" contextPath='");
1096:                sb.append(contextPath);
1097:                sb.append("'");
1098:                sb.append(" directory='");
1099:                sb.append(cacheEntry.name);
1100:                sb.append("' ");
1101:                sb.append(" hasParent='").append(!cacheEntry.name.equals("/"));
1102:                sb.append("'>");
1103:
1104:                sb.append("<entries>");
1105:
1106:                try {
1107:
1108:                    // Render the directory entries within this directory
1109:                    NamingEnumeration enumeration = resources
1110:                            .list(cacheEntry.name);
1111:
1112:                    // rewriteUrl(contextPath) is expensive. cache result for later reuse
1113:                    String rewrittenContextPath = rewriteUrl(contextPath);
1114:
1115:                    while (enumeration.hasMoreElements()) {
1116:
1117:                        NameClassPair ncPair = (NameClassPair) enumeration
1118:                                .nextElement();
1119:                        String resourceName = ncPair.getName();
1120:                        String trimmed = resourceName/*.substring(trim)*/;
1121:                        if (trimmed.equalsIgnoreCase("WEB-INF")
1122:                                || trimmed.equalsIgnoreCase("META-INF")
1123:                                || trimmed.equalsIgnoreCase(localXsltFile))
1124:                            continue;
1125:
1126:                        CacheEntry childCacheEntry = resources
1127:                                .lookupCache(cacheEntry.name + resourceName);
1128:                        if (!childCacheEntry.exists) {
1129:                            continue;
1130:                        }
1131:
1132:                        sb.append("<entry");
1133:                        sb.append(" type='").append(
1134:                                (childCacheEntry.context != null) ? "dir"
1135:                                        : "file").append("'");
1136:                        sb.append(" urlPath='").append(rewrittenContextPath)
1137:                                .append(
1138:                                        rewriteUrl(cacheEntry.name
1139:                                                + resourceName)).append(
1140:                                        (childCacheEntry.context != null) ? "/"
1141:                                                : "").append("'");
1142:                        if (childCacheEntry.resource != null) {
1143:                            sb.append(" size='").append(
1144:                                    renderSize(childCacheEntry.attributes
1145:                                            .getContentLength())).append("'");
1146:                        }
1147:                        sb.append(" date='").append(
1148:                                childCacheEntry.attributes
1149:                                        .getLastModifiedHttp()).append("'");
1150:
1151:                        sb.append(">");
1152:                        sb.append(RequestUtil.filter(trimmed));
1153:                        if (childCacheEntry.context != null)
1154:                            sb.append("/");
1155:                        sb.append("</entry>");
1156:
1157:                    }
1158:
1159:                } catch (NamingException e) {
1160:                    // Something went wrong
1161:                    throw new ServletException("Error accessing resource", e);
1162:                }
1163:
1164:                sb.append("</entries>");
1165:
1166:                String readme = getReadme(cacheEntry.context);
1167:
1168:                if (readme != null) {
1169:                    sb.append("<readme><![CDATA[");
1170:                    sb.append(readme);
1171:                    sb.append("]]></readme>");
1172:                }
1173:
1174:                sb.append("</listing>");
1175:
1176:                try {
1177:                    TransformerFactory tFactory = TransformerFactory
1178:                            .newInstance();
1179:                    Source xmlSource = new StreamSource(new StringReader(sb
1180:                            .toString()));
1181:                    Source xslSource = new StreamSource(xsltInputStream);
1182:                    Transformer transformer = tFactory
1183:                            .newTransformer(xslSource);
1184:
1185:                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
1186:                    OutputStreamWriter osWriter = new OutputStreamWriter(
1187:                            stream, "UTF8");
1188:                    StreamResult out = new StreamResult(osWriter);
1189:                    transformer.transform(xmlSource, out);
1190:                    osWriter.flush();
1191:                    return (new ByteArrayInputStream(stream.toByteArray()));
1192:                } catch (TransformerException e) {
1193:                    throw new ServletException("XSL transformer error", e);
1194:                }
1195:            }
1196:
1197:            /**
1198:             * Return an InputStream to an HTML representation of the contents
1199:             * of this directory.
1200:             *
1201:             * @param contextPath Context path to which our internal paths are
1202:             *  relative
1203:             */
1204:            protected InputStream renderHtml(String contextPath,
1205:                    CacheEntry cacheEntry) throws IOException, ServletException {
1206:
1207:                String name = cacheEntry.name;
1208:
1209:                // Number of characters to trim from the beginnings of filenames
1210:                int trim = name.length();
1211:                if (!name.endsWith("/"))
1212:                    trim += 1;
1213:                if (name.equals("/"))
1214:                    trim = 1;
1215:
1216:                // Prepare a writer to a buffered area
1217:                ByteArrayOutputStream stream = new ByteArrayOutputStream();
1218:                OutputStreamWriter osWriter = new OutputStreamWriter(stream,
1219:                        "UTF8");
1220:                PrintWriter writer = new PrintWriter(osWriter);
1221:
1222:                StringBuffer sb = new StringBuffer();
1223:
1224:                // rewriteUrl(contextPath) is expensive. cache result for later reuse
1225:                String rewrittenContextPath = rewriteUrl(contextPath);
1226:
1227:                // Render the page header
1228:                sb.append("<html>\r\n");
1229:                sb.append("<head>\r\n");
1230:                sb.append("<title>");
1231:                sb.append(sm.getString("directory.title", name));
1232:                sb.append("</title>\r\n");
1233:                sb.append("<STYLE><!--");
1234:                sb.append(org.apache.catalina.util.TomcatCSS.TOMCAT_CSS);
1235:                sb.append("--></STYLE> ");
1236:                sb.append("</head>\r\n");
1237:                sb.append("<body>");
1238:                sb.append("<h1>");
1239:                sb.append(sm.getString("directory.title", name));
1240:
1241:                // Render the link to our parent (if required)
1242:                String parentDirectory = name;
1243:                if (parentDirectory.endsWith("/")) {
1244:                    parentDirectory = parentDirectory.substring(0,
1245:                            parentDirectory.length() - 1);
1246:                }
1247:                int slash = parentDirectory.lastIndexOf('/');
1248:                if (slash >= 0) {
1249:                    String parent = name.substring(0, slash);
1250:                    sb.append(" - <a href=\"");
1251:                    sb.append(rewrittenContextPath);
1252:                    if (parent.equals(""))
1253:                        parent = "/";
1254:                    sb.append(rewriteUrl(parent));
1255:                    if (!parent.endsWith("/"))
1256:                        sb.append("/");
1257:                    sb.append("\">");
1258:                    sb.append("<b>");
1259:                    sb.append(sm.getString("directory.parent", parent));
1260:                    sb.append("</b>");
1261:                    sb.append("</a>");
1262:                }
1263:
1264:                sb.append("</h1>");
1265:                sb.append("<HR size=\"1\" noshade=\"noshade\">");
1266:
1267:                sb.append("<table width=\"100%\" cellspacing=\"0\""
1268:                        + " cellpadding=\"5\" align=\"center\">\r\n");
1269:
1270:                // Render the column headings
1271:                sb.append("<tr>\r\n");
1272:                sb.append("<td align=\"left\"><font size=\"+1\"><strong>");
1273:                sb.append(sm.getString("directory.filename"));
1274:                sb.append("</strong></font></td>\r\n");
1275:                sb.append("<td align=\"center\"><font size=\"+1\"><strong>");
1276:                sb.append(sm.getString("directory.size"));
1277:                sb.append("</strong></font></td>\r\n");
1278:                sb.append("<td align=\"right\"><font size=\"+1\"><strong>");
1279:                sb.append(sm.getString("directory.lastModified"));
1280:                sb.append("</strong></font></td>\r\n");
1281:                sb.append("</tr>");
1282:
1283:                try {
1284:
1285:                    // Render the directory entries within this directory
1286:                    NamingEnumeration enumeration = resources
1287:                            .list(cacheEntry.name);
1288:                    boolean shade = false;
1289:                    while (enumeration.hasMoreElements()) {
1290:
1291:                        NameClassPair ncPair = (NameClassPair) enumeration
1292:                                .nextElement();
1293:                        String resourceName = ncPair.getName();
1294:                        String trimmed = resourceName/*.substring(trim)*/;
1295:                        if (trimmed.equalsIgnoreCase("WEB-INF")
1296:                                || trimmed.equalsIgnoreCase("META-INF"))
1297:                            continue;
1298:
1299:                        CacheEntry childCacheEntry = resources
1300:                                .lookupCache(cacheEntry.name + resourceName);
1301:                        if (!childCacheEntry.exists) {
1302:                            continue;
1303:                        }
1304:
1305:                        sb.append("<tr");
1306:                        if (shade)
1307:                            sb.append(" bgcolor=\"#eeeeee\"");
1308:                        sb.append(">\r\n");
1309:                        shade = !shade;
1310:
1311:                        sb.append("<td align=\"left\">&nbsp;&nbsp;\r\n");
1312:                        sb.append("<a href=\"");
1313:                        sb.append(rewrittenContextPath);
1314:                        resourceName = rewriteUrl(name + resourceName);
1315:                        sb.append(resourceName);
1316:                        if (childCacheEntry.context != null)
1317:                            sb.append("/");
1318:                        sb.append("\"><tt>");
1319:                        sb.append(RequestUtil.filter(trimmed));
1320:                        if (childCacheEntry.context != null)
1321:                            sb.append("/");
1322:                        sb.append("</tt></a></td>\r\n");
1323:
1324:                        sb.append("<td align=\"right\"><tt>");
1325:                        if (childCacheEntry.context != null)
1326:                            sb.append("&nbsp;");
1327:                        else
1328:                            sb.append(renderSize(childCacheEntry.attributes
1329:                                    .getContentLength()));
1330:                        sb.append("</tt></td>\r\n");
1331:
1332:                        sb.append("<td align=\"right\"><tt>");
1333:                        sb.append(childCacheEntry.attributes
1334:                                .getLastModifiedHttp());
1335:                        sb.append("</tt></td>\r\n");
1336:
1337:                        sb.append("</tr>\r\n");
1338:                    }
1339:
1340:                } catch (NamingException e) {
1341:                    // Something went wrong
1342:                    throw new ServletException("Error accessing resource", e);
1343:                }
1344:
1345:                // Render the page footer
1346:                sb.append("</table>\r\n");
1347:
1348:                sb.append("<HR size=\"1\" noshade=\"noshade\">");
1349:
1350:                String readme = getReadme(cacheEntry.context);
1351:                if (readme != null) {
1352:                    sb.append(readme);
1353:                    sb.append("<HR size=\"1\" noshade=\"noshade\">");
1354:                }
1355:
1356:                sb.append("<h3>").append(ServerInfo.getServerInfo()).append(
1357:                        "</h3>");
1358:                sb.append("</body>\r\n");
1359:                sb.append("</html>\r\n");
1360:
1361:                // Return an input stream to the underlying bytes
1362:                writer.write(sb.toString());
1363:                writer.flush();
1364:                return (new ByteArrayInputStream(stream.toByteArray()));
1365:
1366:            }
1367:
1368:            /**
1369:             * Render the specified file size (in bytes).
1370:             *
1371:             * @param size File size (in bytes)
1372:             */
1373:            protected String renderSize(long size) {
1374:
1375:                long leftSide = size / 1024;
1376:                long rightSide = (size % 1024) / 103; // Makes 1 digit
1377:                if ((leftSide == 0) && (rightSide == 0) && (size > 0))
1378:                    rightSide = 1;
1379:
1380:                return ("" + leftSide + "." + rightSide + " kb");
1381:
1382:            }
1383:
1384:            /**
1385:             * Get the readme file as a string.
1386:             */
1387:            protected String getReadme(DirContext directory)
1388:                    throws IOException, ServletException {
1389:
1390:                if (readmeFile != null) {
1391:                    try {
1392:                        Object obj = directory.lookup(readmeFile);
1393:                        if ((obj != null) && (obj instanceof  Resource)) {
1394:                            StringWriter buffer = new StringWriter();
1395:                            InputStream is = ((Resource) obj).streamContent();
1396:                            copyRange(new InputStreamReader(is),
1397:                                    new PrintWriter(buffer));
1398:                            return buffer.toString();
1399:                        }
1400:                    } catch (NamingException e) {
1401:                        throw new ServletException(
1402:                                "Error opening readme resource", e);
1403:                    }
1404:                }
1405:
1406:                return null;
1407:            }
1408:
1409:            /**
1410:             * Return the xsl template inputstream (if possible)
1411:             */
1412:            protected InputStream findXsltInputStream(DirContext directory)
1413:                    throws IOException, ServletException {
1414:
1415:                if (localXsltFile != null) {
1416:                    try {
1417:                        Object obj = directory.lookup(localXsltFile);
1418:                        if ((obj != null) && (obj instanceof  Resource)) {
1419:                            InputStream is = ((Resource) obj).streamContent();
1420:                            if (is != null)
1421:                                return is;
1422:                        }
1423:                    } catch (NamingException e) {
1424:                        throw new ServletException(
1425:                                "Error opening XSLT resource", e);
1426:                    }
1427:                }
1428:
1429:                /*  Open and read in file in one fell swoop to reduce chance
1430:                 *  chance of leaving handle open.
1431:                 */
1432:                if (globalXsltFile != null) {
1433:                    FileInputStream fis = null;
1434:
1435:                    try {
1436:                        File f = new File(globalXsltFile);
1437:                        if (f.exists()) {
1438:                            fis = new FileInputStream(f);
1439:                            byte b[] = new byte[(int) f.length()]; /* danger! */
1440:                            fis.read(b);
1441:                            return new ByteArrayInputStream(b);
1442:                        }
1443:                    } finally {
1444:                        if (fis != null)
1445:                            fis.close();
1446:                    }
1447:                }
1448:
1449:                return null;
1450:
1451:            }
1452:
1453:            // -------------------------------------------------------- protected Methods
1454:
1455:            /**
1456:             * Check if sendfile can be used.
1457:             */
1458:            protected boolean checkSendfile(HttpServletRequest request,
1459:                    HttpServletResponse response, CacheEntry entry,
1460:                    long length, Range range) {
1461:                if ((sendfileSize > 0)
1462:                        && (entry.resource != null)
1463:                        && ((length > sendfileSize) || (entry.resource
1464:                                .getContent() == null))
1465:                        && (entry.attributes.getCanonicalPath() != null)
1466:                        && (Boolean.TRUE == request
1467:                                .getAttribute("org.apache.tomcat.sendfile.support"))
1468:                        && (request.getClass().getName()
1469:                                .equals("org.apache.catalina.connector.RequestFacade"))
1470:                        && (response.getClass().getName()
1471:                                .equals("org.apache.catalina.connector.ResponseFacade"))) {
1472:                    request.setAttribute("org.apache.tomcat.sendfile.filename",
1473:                            entry.attributes.getCanonicalPath());
1474:                    if (range == null) {
1475:                        request.setAttribute(
1476:                                "org.apache.tomcat.sendfile.start",
1477:                                new Long(0L));
1478:                        request.setAttribute("org.apache.tomcat.sendfile.end",
1479:                                new Long(length));
1480:                    } else {
1481:                        request.setAttribute(
1482:                                "org.apache.tomcat.sendfile.start", new Long(
1483:                                        range.start));
1484:                        request.setAttribute("org.apache.tomcat.sendfile.end",
1485:                                new Long(range.end + 1));
1486:                    }
1487:                    request.setAttribute("org.apache.tomcat.sendfile.token",
1488:                            this );
1489:                    return true;
1490:                } else {
1491:                    return false;
1492:                }
1493:            }
1494:
1495:            /**
1496:             * Check if the if-match condition is satisfied.
1497:             *
1498:             * @param request The servlet request we are processing
1499:             * @param response The servlet response we are creating
1500:             * @param resourceInfo File object
1501:             * @return boolean true if the resource meets the specified condition,
1502:             * and false if the condition is not satisfied, in which case request
1503:             * processing is stopped
1504:             */
1505:            protected boolean checkIfMatch(HttpServletRequest request,
1506:                    HttpServletResponse response,
1507:                    ResourceAttributes resourceAttributes) throws IOException {
1508:
1509:                String eTag = getETag(resourceAttributes);
1510:                String headerValue = request.getHeader("If-Match");
1511:                if (headerValue != null) {
1512:                    if (headerValue.indexOf('*') == -1) {
1513:
1514:                        StringTokenizer commaTokenizer = new StringTokenizer(
1515:                                headerValue, ",");
1516:                        boolean conditionSatisfied = false;
1517:
1518:                        while (!conditionSatisfied
1519:                                && commaTokenizer.hasMoreTokens()) {
1520:                            String currentToken = commaTokenizer.nextToken();
1521:                            if (currentToken.trim().equals(eTag))
1522:                                conditionSatisfied = true;
1523:                        }
1524:
1525:                        // If none of the given ETags match, 412 Precodition failed is
1526:                        // sent back
1527:                        if (!conditionSatisfied) {
1528:                            response
1529:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1530:                            return false;
1531:                        }
1532:
1533:                    }
1534:                }
1535:                return true;
1536:
1537:            }
1538:
1539:            /**
1540:             * Check if the if-modified-since condition is satisfied.
1541:             *
1542:             * @param request The servlet request we are processing
1543:             * @param response The servlet response we are creating
1544:             * @param resourceInfo File object
1545:             * @return boolean true if the resource meets the specified condition,
1546:             * and false if the condition is not satisfied, in which case request
1547:             * processing is stopped
1548:             */
1549:            protected boolean checkIfModifiedSince(HttpServletRequest request,
1550:                    HttpServletResponse response,
1551:                    ResourceAttributes resourceAttributes) throws IOException {
1552:                try {
1553:                    long headerValue = request
1554:                            .getDateHeader("If-Modified-Since");
1555:                    long lastModified = resourceAttributes.getLastModified();
1556:                    if (headerValue != -1) {
1557:
1558:                        // If an If-None-Match header has been specified, if modified since
1559:                        // is ignored.
1560:                        if ((request.getHeader("If-None-Match") == null)
1561:                                && (lastModified < headerValue + 1000)) {
1562:                            // The entity has not been modified since the date
1563:                            // specified by the client. This is not an error case.
1564:                            response
1565:                                    .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
1566:                            response.setHeader("ETag",
1567:                                    getETag(resourceAttributes));
1568:
1569:                            return false;
1570:                        }
1571:                    }
1572:                } catch (IllegalArgumentException illegalArgument) {
1573:                    return true;
1574:                }
1575:                return true;
1576:
1577:            }
1578:
1579:            /**
1580:             * Check if the if-none-match condition is satisfied.
1581:             *
1582:             * @param request The servlet request we are processing
1583:             * @param response The servlet response we are creating
1584:             * @param resourceInfo File object
1585:             * @return boolean true if the resource meets the specified condition,
1586:             * and false if the condition is not satisfied, in which case request
1587:             * processing is stopped
1588:             */
1589:            protected boolean checkIfNoneMatch(HttpServletRequest request,
1590:                    HttpServletResponse response,
1591:                    ResourceAttributes resourceAttributes) throws IOException {
1592:
1593:                String eTag = getETag(resourceAttributes);
1594:                String headerValue = request.getHeader("If-None-Match");
1595:                if (headerValue != null) {
1596:
1597:                    boolean conditionSatisfied = false;
1598:
1599:                    if (!headerValue.equals("*")) {
1600:
1601:                        StringTokenizer commaTokenizer = new StringTokenizer(
1602:                                headerValue, ",");
1603:
1604:                        while (!conditionSatisfied
1605:                                && commaTokenizer.hasMoreTokens()) {
1606:                            String currentToken = commaTokenizer.nextToken();
1607:                            if (currentToken.trim().equals(eTag))
1608:                                conditionSatisfied = true;
1609:                        }
1610:
1611:                    } else {
1612:                        conditionSatisfied = true;
1613:                    }
1614:
1615:                    if (conditionSatisfied) {
1616:
1617:                        // For GET and HEAD, we should respond with
1618:                        // 304 Not Modified.
1619:                        // For every other method, 412 Precondition Failed is sent
1620:                        // back.
1621:                        if (("GET".equals(request.getMethod()))
1622:                                || ("HEAD".equals(request.getMethod()))) {
1623:                            response
1624:                                    .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
1625:                            response.setHeader("ETag",
1626:                                    getETag(resourceAttributes));
1627:
1628:                            return false;
1629:                        } else {
1630:                            response
1631:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1632:                            return false;
1633:                        }
1634:                    }
1635:                }
1636:                return true;
1637:
1638:            }
1639:
1640:            /**
1641:             * Check if the if-unmodified-since condition is satisfied.
1642:             *
1643:             * @param request The servlet request we are processing
1644:             * @param response The servlet response we are creating
1645:             * @param resourceInfo File object
1646:             * @return boolean true if the resource meets the specified condition,
1647:             * and false if the condition is not satisfied, in which case request
1648:             * processing is stopped
1649:             */
1650:            protected boolean checkIfUnmodifiedSince(
1651:                    HttpServletRequest request, HttpServletResponse response,
1652:                    ResourceAttributes resourceAttributes) throws IOException {
1653:                try {
1654:                    long lastModified = resourceAttributes.getLastModified();
1655:                    long headerValue = request
1656:                            .getDateHeader("If-Unmodified-Since");
1657:                    if (headerValue != -1) {
1658:                        if (lastModified >= (headerValue + 1000)) {
1659:                            // The entity has not been modified since the date
1660:                            // specified by the client. This is not an error case.
1661:                            response
1662:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1663:                            return false;
1664:                        }
1665:                    }
1666:                } catch (IllegalArgumentException illegalArgument) {
1667:                    return true;
1668:                }
1669:                return true;
1670:
1671:            }
1672:
1673:            /**
1674:             * Copy the contents of the specified input stream to the specified
1675:             * output stream, and ensure that both streams are closed before returning
1676:             * (even in the face of an exception).
1677:             *
1678:             * @param resourceInfo The resource information
1679:             * @param ostream The output stream to write to
1680:             *
1681:             * @exception IOException if an input/output error occurs
1682:             */
1683:            protected void copy(CacheEntry cacheEntry, InputStream is,
1684:                    ServletOutputStream ostream) throws IOException {
1685:
1686:                IOException exception = null;
1687:                InputStream resourceInputStream = null;
1688:
1689:                // Optimization: If the binary content has already been loaded, send
1690:                // it directly
1691:                if (cacheEntry.resource != null) {
1692:                    byte buffer[] = cacheEntry.resource.getContent();
1693:                    if (buffer != null) {
1694:                        ostream.write(buffer, 0, buffer.length);
1695:                        return;
1696:                    }
1697:                    resourceInputStream = cacheEntry.resource.streamContent();
1698:                } else {
1699:                    resourceInputStream = is;
1700:                }
1701:
1702:                InputStream istream = new BufferedInputStream(
1703:                        resourceInputStream, input);
1704:
1705:                // Copy the input stream to the output stream
1706:                exception = copyRange(istream, ostream);
1707:
1708:                // Clean up the input stream
1709:                istream.close();
1710:
1711:                // Rethrow any exception that has occurred
1712:                if (exception != null)
1713:                    throw exception;
1714:
1715:            }
1716:
1717:            /**
1718:             * Copy the contents of the specified input stream to the specified
1719:             * output stream, and ensure that both streams are closed before returning
1720:             * (even in the face of an exception).
1721:             *
1722:             * @param resourceInfo The resource info
1723:             * @param writer The writer to write to
1724:             *
1725:             * @exception IOException if an input/output error occurs
1726:             */
1727:            protected void copy(CacheEntry cacheEntry, InputStream is,
1728:                    PrintWriter writer) throws IOException {
1729:
1730:                IOException exception = null;
1731:
1732:                InputStream resourceInputStream = null;
1733:                if (cacheEntry.resource != null) {
1734:                    resourceInputStream = cacheEntry.resource.streamContent();
1735:                } else {
1736:                    resourceInputStream = is;
1737:                }
1738:
1739:                Reader reader;
1740:                if (fileEncoding == null) {
1741:                    reader = new InputStreamReader(resourceInputStream);
1742:                } else {
1743:                    reader = new InputStreamReader(resourceInputStream,
1744:                            fileEncoding);
1745:                }
1746:
1747:                // Copy the input stream to the output stream
1748:                exception = copyRange(reader, writer);
1749:
1750:                // Clean up the reader
1751:                reader.close();
1752:
1753:                // Rethrow any exception that has occurred
1754:                if (exception != null)
1755:                    throw exception;
1756:
1757:            }
1758:
1759:            /**
1760:             * Copy the contents of the specified input stream to the specified
1761:             * output stream, and ensure that both streams are closed before returning
1762:             * (even in the face of an exception).
1763:             *
1764:             * @param resourceInfo The ResourceInfo object
1765:             * @param ostream The output stream to write to
1766:             * @param range Range the client wanted to retrieve
1767:             * @exception IOException if an input/output error occurs
1768:             */
1769:            protected void copy(CacheEntry cacheEntry,
1770:                    ServletOutputStream ostream, Range range)
1771:                    throws IOException {
1772:
1773:                IOException exception = null;
1774:
1775:                InputStream resourceInputStream = cacheEntry.resource
1776:                        .streamContent();
1777:                InputStream istream = new BufferedInputStream(
1778:                        resourceInputStream, input);
1779:                exception = copyRange(istream, ostream, range.start, range.end);
1780:
1781:                // Clean up the input stream
1782:                istream.close();
1783:
1784:                // Rethrow any exception that has occurred
1785:                if (exception != null)
1786:                    throw exception;
1787:
1788:            }
1789:
1790:            /**
1791:             * Copy the contents of the specified input stream to the specified
1792:             * output stream, and ensure that both streams are closed before returning
1793:             * (even in the face of an exception).
1794:             *
1795:             * @param resourceInfo The ResourceInfo object
1796:             * @param writer The writer to write to
1797:             * @param range Range the client wanted to retrieve
1798:             * @exception IOException if an input/output error occurs
1799:             */
1800:            protected void copy(CacheEntry cacheEntry, PrintWriter writer,
1801:                    Range range) throws IOException {
1802:
1803:                IOException exception = null;
1804:
1805:                InputStream resourceInputStream = cacheEntry.resource
1806:                        .streamContent();
1807:
1808:                Reader reader;
1809:                if (fileEncoding == null) {
1810:                    reader = new InputStreamReader(resourceInputStream);
1811:                } else {
1812:                    reader = new InputStreamReader(resourceInputStream,
1813:                            fileEncoding);
1814:                }
1815:
1816:                exception = copyRange(reader, writer, range.start, range.end);
1817:
1818:                // Clean up the input stream
1819:                reader.close();
1820:
1821:                // Rethrow any exception that has occurred
1822:                if (exception != null)
1823:                    throw exception;
1824:
1825:            }
1826:
1827:            /**
1828:             * Copy the contents of the specified input stream to the specified
1829:             * output stream, and ensure that both streams are closed before returning
1830:             * (even in the face of an exception).
1831:             *
1832:             * @param resourceInfo The ResourceInfo object
1833:             * @param ostream The output stream to write to
1834:             * @param ranges Enumeration of the ranges the client wanted to retrieve
1835:             * @param contentType Content type of the resource
1836:             * @exception IOException if an input/output error occurs
1837:             */
1838:            protected void copy(CacheEntry cacheEntry,
1839:                    ServletOutputStream ostream, Iterator ranges,
1840:                    String contentType) throws IOException {
1841:
1842:                IOException exception = null;
1843:
1844:                while ((exception == null) && (ranges.hasNext())) {
1845:
1846:                    InputStream resourceInputStream = cacheEntry.resource
1847:                            .streamContent();
1848:                    InputStream istream = new BufferedInputStream(
1849:                            resourceInputStream, input);
1850:
1851:                    Range currentRange = (Range) ranges.next();
1852:
1853:                    // Writing MIME header.
1854:                    ostream.println();
1855:                    ostream.println("--" + mimeSeparation);
1856:                    if (contentType != null)
1857:                        ostream.println("Content-Type: " + contentType);
1858:                    ostream.println("Content-Range: bytes "
1859:                            + currentRange.start + "-" + currentRange.end + "/"
1860:                            + currentRange.length);
1861:                    ostream.println();
1862:
1863:                    // Printing content
1864:                    exception = copyRange(istream, ostream, currentRange.start,
1865:                            currentRange.end);
1866:
1867:                    istream.close();
1868:
1869:                }
1870:
1871:                ostream.println();
1872:                ostream.print("--" + mimeSeparation + "--");
1873:
1874:                // Rethrow any exception that has occurred
1875:                if (exception != null)
1876:                    throw exception;
1877:
1878:            }
1879:
1880:            /**
1881:             * Copy the contents of the specified input stream to the specified
1882:             * output stream, and ensure that both streams are closed before returning
1883:             * (even in the face of an exception).
1884:             *
1885:             * @param resourceInfo The ResourceInfo object
1886:             * @param writer The writer to write to
1887:             * @param ranges Enumeration of the ranges the client wanted to retrieve
1888:             * @param contentType Content type of the resource
1889:             * @exception IOException if an input/output error occurs
1890:             */
1891:            protected void copy(CacheEntry cacheEntry, PrintWriter writer,
1892:                    Iterator ranges, String contentType) throws IOException {
1893:
1894:                IOException exception = null;
1895:
1896:                while ((exception == null) && (ranges.hasNext())) {
1897:
1898:                    InputStream resourceInputStream = cacheEntry.resource
1899:                            .streamContent();
1900:
1901:                    Reader reader;
1902:                    if (fileEncoding == null) {
1903:                        reader = new InputStreamReader(resourceInputStream);
1904:                    } else {
1905:                        reader = new InputStreamReader(resourceInputStream,
1906:                                fileEncoding);
1907:                    }
1908:
1909:                    Range currentRange = (Range) ranges.next();
1910:
1911:                    // Writing MIME header.
1912:                    writer.println();
1913:                    writer.println("--" + mimeSeparation);
1914:                    if (contentType != null)
1915:                        writer.println("Content-Type: " + contentType);
1916:                    writer.println("Content-Range: bytes " + currentRange.start
1917:                            + "-" + currentRange.end + "/"
1918:                            + currentRange.length);
1919:                    writer.println();
1920:
1921:                    // Printing content
1922:                    exception = copyRange(reader, writer, currentRange.start,
1923:                            currentRange.end);
1924:
1925:                    reader.close();
1926:
1927:                }
1928:
1929:                writer.println();
1930:                writer.print("--" + mimeSeparation + "--");
1931:
1932:                // Rethrow any exception that has occurred
1933:                if (exception != null)
1934:                    throw exception;
1935:
1936:            }
1937:
1938:            /**
1939:             * Copy the contents of the specified input stream to the specified
1940:             * output stream, and ensure that both streams are closed before returning
1941:             * (even in the face of an exception).
1942:             *
1943:             * @param istream The input stream to read from
1944:             * @param ostream The output stream to write to
1945:             * @return Exception which occurred during processing
1946:             */
1947:            protected IOException copyRange(InputStream istream,
1948:                    ServletOutputStream ostream) {
1949:
1950:                // Copy the input stream to the output stream
1951:                IOException exception = null;
1952:                byte buffer[] = new byte[input];
1953:                int len = buffer.length;
1954:                while (true) {
1955:                    try {
1956:                        len = istream.read(buffer);
1957:                        if (len == -1)
1958:                            break;
1959:                        ostream.write(buffer, 0, len);
1960:                    } catch (IOException e) {
1961:                        exception = e;
1962:                        len = -1;
1963:                        break;
1964:                    }
1965:                }
1966:                return exception;
1967:
1968:            }
1969:
1970:            /**
1971:             * Copy the contents of the specified input stream to the specified
1972:             * output stream, and ensure that both streams are closed before returning
1973:             * (even in the face of an exception).
1974:             *
1975:             * @param reader The reader to read from
1976:             * @param writer The writer to write to
1977:             * @return Exception which occurred during processing
1978:             */
1979:            protected IOException copyRange(Reader reader, PrintWriter writer) {
1980:
1981:                // Copy the input stream to the output stream
1982:                IOException exception = null;
1983:                char buffer[] = new char[input];
1984:                int len = buffer.length;
1985:                while (true) {
1986:                    try {
1987:                        len = reader.read(buffer);
1988:                        if (len == -1)
1989:                            break;
1990:                        writer.write(buffer, 0, len);
1991:                    } catch (IOException e) {
1992:                        exception = e;
1993:                        len = -1;
1994:                        break;
1995:                    }
1996:                }
1997:                return exception;
1998:
1999:            }
2000:
2001:            /**
2002:             * Copy the contents of the specified input stream to the specified
2003:             * output stream, and ensure that both streams are closed before returning
2004:             * (even in the face of an exception).
2005:             *
2006:             * @param istream The input stream to read from
2007:             * @param ostream The output stream to write to
2008:             * @param start Start of the range which will be copied
2009:             * @param end End of the range which will be copied
2010:             * @return Exception which occurred during processing
2011:             */
2012:            protected IOException copyRange(InputStream istream,
2013:                    ServletOutputStream ostream, long start, long end) {
2014:
2015:                if (debug > 10)
2016:                    log("Serving bytes:" + start + "-" + end);
2017:
2018:                try {
2019:                    istream.skip(start);
2020:                } catch (IOException e) {
2021:                    return e;
2022:                }
2023:
2024:                IOException exception = null;
2025:                long bytesToRead = end - start + 1;
2026:
2027:                byte buffer[] = new byte[input];
2028:                int len = buffer.length;
2029:                while ((bytesToRead > 0) && (len >= buffer.length)) {
2030:                    try {
2031:                        len = istream.read(buffer);
2032:                        if (bytesToRead >= len) {
2033:                            ostream.write(buffer, 0, len);
2034:                            bytesToRead -= len;
2035:                        } else {
2036:                            ostream.write(buffer, 0, (int) bytesToRead);
2037:                            bytesToRead = 0;
2038:                        }
2039:                    } catch (IOException e) {
2040:                        exception = e;
2041:                        len = -1;
2042:                    }
2043:                    if (len < buffer.length)
2044:                        break;
2045:                }
2046:
2047:                return exception;
2048:
2049:            }
2050:
2051:            /**
2052:             * Copy the contents of the specified input stream to the specified
2053:             * output stream, and ensure that both streams are closed before returning
2054:             * (even in the face of an exception).
2055:             *
2056:             * @param reader The reader to read from
2057:             * @param writer The writer to write to
2058:             * @param start Start of the range which will be copied
2059:             * @param end End of the range which will be copied
2060:             * @return Exception which occurred during processing
2061:             */
2062:            protected IOException copyRange(Reader reader, PrintWriter writer,
2063:                    long start, long end) {
2064:
2065:                try {
2066:                    reader.skip(start);
2067:                } catch (IOException e) {
2068:                    return e;
2069:                }
2070:
2071:                IOException exception = null;
2072:                long bytesToRead = end - start + 1;
2073:
2074:                char buffer[] = new char[input];
2075:                int len = buffer.length;
2076:                while ((bytesToRead > 0) && (len >= buffer.length)) {
2077:                    try {
2078:                        len = reader.read(buffer);
2079:                        if (bytesToRead >= len) {
2080:                            writer.write(buffer, 0, len);
2081:                            bytesToRead -= len;
2082:                        } else {
2083:                            writer.write(buffer, 0, (int) bytesToRead);
2084:                            bytesToRead = 0;
2085:                        }
2086:                    } catch (IOException e) {
2087:                        exception = e;
2088:                        len = -1;
2089:                    }
2090:                    if (len < buffer.length)
2091:                        break;
2092:                }
2093:
2094:                return exception;
2095:
2096:            }
2097:
2098:            // ------------------------------------------------------ Range Inner Class
2099:
2100:            protected class Range {
2101:
2102:                public long start;
2103:                public long end;
2104:                public long length;
2105:
2106:                /**
2107:                 * Validate range.
2108:                 */
2109:                public boolean validate() {
2110:                    if (end >= length)
2111:                        end = length - 1;
2112:                    return ((start >= 0) && (end >= 0) && (start <= end) && (length > 0));
2113:                }
2114:
2115:                public void recycle() {
2116:                    start = 0;
2117:                    end = 0;
2118:                    length = 0;
2119:                }
2120:
2121:            }
2122:
2123:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.