Source Code Cross Referenced for DefaultServlet.java in  » Web-Server » Rimfaxe-Web-Server » com » rimfaxe » webserver » servletapi » 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 » Web Server » Rimfaxe Web Server » com.rimfaxe.webserver.servletapi 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * The Apache Software License, Version 1.1
0003:         *
0004:         * Copyright (c) 1999 The Apache Software Foundation.  All rights
0005:         * reserved.
0006:         *
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met:
0010:         *
0011:         * 1. Redistributions of source code must retain the above copyright
0012:         *    notice, this list of conditions and the following disclaimer.
0013:         *
0014:         * 2. Redistributions in binary form must reproduce the above copyright
0015:         *    notice, this list of conditions and the following disclaimer in
0016:         *    the documentation and/or other materials provided with the
0017:         *    distribution.
0018:         *
0019:         * 3. The end-user documentation included with the redistribution, if
0020:         *    any, must include the following acknowlegement:
0021:         *       "This product includes software developed by the
0022:         *        Apache Software Foundation (http://www.apache.org/)."
0023:         *    Alternately, this acknowlegement may appear in the software itself,
0024:         *    if and wherever such third-party acknowlegements normally appear.
0025:         *
0026:         * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0027:         *    Foundation" must not be used to endorse or promote products derived
0028:         *    from this software without prior written permission. For written
0029:         *    permission, please contact apache@apache.org.
0030:         *
0031:         * 5. Products derived from this software may not be called "Apache"
0032:         *    nor may "Apache" appear in their names without prior written
0033:         *    permission of the Apache Group.
0034:         *
0035:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0036:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0037:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0038:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0039:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0042:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0043:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0044:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0045:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0046:         * SUCH DAMAGE.
0047:         * ====================================================================
0048:         *
0049:         * This software consists of voluntary contributions made by many
0050:         * individuals on behalf of the Apache Software Foundation.  For more
0051:         * information on the Apache Software Foundation, please see
0052:         * <http://www.apache.org/>.
0053:         *
0054:         * [Additional notices, if required by prior licensing conditions]
0055:         *
0056:         */
0057:
0058:        package com.rimfaxe.webserver.servletapi;
0059:
0060:        import java.io.BufferedInputStream;
0061:        import java.io.ByteArrayOutputStream;
0062:        import java.io.ByteArrayInputStream;
0063:        import java.io.File;
0064:        import java.io.FileInputStream;
0065:        import java.io.InputStream;
0066:        import java.io.IOException;
0067:        import java.io.PrintWriter;
0068:        import java.io.RandomAccessFile;
0069:        import java.io.Reader;
0070:        import java.io.InputStreamReader;
0071:        import java.io.Writer;
0072:        import java.io.OutputStreamWriter;
0073:        import java.net.MalformedURLException;
0074:        import java.net.URL;
0075:        import java.sql.Timestamp;
0076:        import java.util.Date;
0077:        import java.util.Enumeration;
0078:        import java.util.Vector;
0079:        import java.util.StringTokenizer;
0080:        import java.util.Locale;
0081:        import java.util.TimeZone;
0082:        import java.util.Hashtable;
0083:        import java.text.ParseException;
0084:        import java.text.SimpleDateFormat;
0085:        import java.security.MessageDigest;
0086:        import java.security.NoSuchAlgorithmException;
0087:        import javax.servlet.RequestDispatcher;
0088:        import javax.servlet.ServletException;
0089:        import javax.servlet.ServletContext;
0090:        import javax.servlet.ServletOutputStream;
0091:        import javax.servlet.http.HttpServlet;
0092:        import javax.servlet.http.HttpServletRequest;
0093:        import javax.servlet.http.HttpServletResponse;
0094:        import javax.naming.NamingException;
0095:        import javax.naming.InitialContext;
0096:        import javax.naming.Context;
0097:        import javax.naming.NamingEnumeration;
0098:        import javax.naming.NameClassPair;
0099:        import javax.naming.directory.DirContext;
0100:        import javax.naming.directory.Attribute;
0101:        import javax.naming.directory.Attributes;
0102:
0103:        import org.apache.naming.resources.Resource;
0104:        import org.apache.naming.resources.ResourceAttributes;
0105:
0106:        import com.rimfaxe.webserver.servletapi.util.URLEncoder;
0107:
0108:        /**
0109:         * The default resource-serving servlet for most web applications,
0110:         * used to serve static resources such as HTML pages and images.
0111:         *
0112:         * @author Craig R. McClanahan
0113:         * @author Remy Maucherat
0114:         * @author Lars Andersen
0115:         */
0116:
0117:        public class DefaultServlet extends HttpServlet {
0118:
0119:            // ----------------------------------------------------- Instance Variables
0120:
0121:            /**
0122:             * The debugging detail level for this servlet.
0123:             */
0124:            protected int debug = 0;
0125:
0126:            /**
0127:             * The input buffer size to use when serving resources.
0128:             */
0129:            protected int input = 2048;
0130:
0131:            /**
0132:             * Should we generate directory listings when no welcome file is present?
0133:             */
0134:            protected boolean listings = true;
0135:
0136:            /**
0137:             * Read only flag. By default, it's set to true.
0138:             */
0139:            protected boolean readOnly = true;
0140:
0141:            /**
0142:             * The output buffer size to use when serving resources.
0143:             */
0144:            protected int output = 2048;
0145:
0146:            /**
0147:             * The set of welcome files for this web application
0148:             */
0149:            protected String welcomes[] = new String[0];
0150:
0151:            /**
0152:             * MD5 message digest provider.
0153:             */
0154:            protected static MessageDigest md5Helper;
0155:
0156:            /**
0157:             * The MD5 helper object for this class.
0158:             */
0159:            //protected static final MD5Encoder md5Encoder = new MD5Encoder();
0160:
0161:            /**
0162:             * The set of SimpleDateFormat formats to use in getDateHeader().
0163:             */
0164:            protected static final SimpleDateFormat formats[] = {
0165:                    new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
0166:                            Locale.US),
0167:                    new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
0168:                            Locale.US),
0169:                    new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
0170:
0171:            protected final static TimeZone gmtZone = TimeZone
0172:                    .getTimeZone("GMT");
0173:
0174:            /**
0175:             * Array containing the safe characters set.
0176:             */
0177:            protected static URLEncoder urlEncoder;
0178:
0179:            /**
0180:             * GMT timezone - all HTTP dates are on GMT
0181:             */
0182:            // ----------------------------------------------------- Static Initializer
0183:            static {
0184:                formats[0].setTimeZone(gmtZone);
0185:                formats[1].setTimeZone(gmtZone);
0186:                formats[2].setTimeZone(gmtZone);
0187:
0188:                urlEncoder = new URLEncoder();
0189:                urlEncoder.addSafeCharacter('-');
0190:                urlEncoder.addSafeCharacter('_');
0191:                urlEncoder.addSafeCharacter('.');
0192:                urlEncoder.addSafeCharacter('*');
0193:                urlEncoder.addSafeCharacter('/');
0194:            }
0195:
0196:            /**
0197:             * MIME multipart separation string
0198:             */
0199:            protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
0200:
0201:            /**
0202:             * JNDI resources name.
0203:             */
0204:            protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources";
0205:
0206:            /**
0207:             * The string manager for this package.
0208:             */
0209:            //protected static StringManager sm = StringManager.getManager(Constants.Package);
0210:
0211:            /**
0212:             * Size of file transfer buffer in bytes.
0213:             */
0214:            private static final int BUFFER_SIZE = 4096;
0215:
0216:            // --------------------------------------------------------- Public Methods
0217:
0218:            /**
0219:             * Finalize this servlet.
0220:             */
0221:            public void destroy() {
0222:
0223:                ; // No actions necessary
0224:
0225:            }
0226:
0227:            /**
0228:             * Initialize this servlet.
0229:             */
0230:            public void init() throws ServletException {
0231:
0232:                //log("DefaultServlet.init: start");
0233:                // Set our properties from the initialization parameters
0234:                String value = null;
0235:                try {
0236:                    value = getServletConfig().getInitParameter("debug");
0237:                    debug = Integer.parseInt(value);
0238:                } catch (Throwable t) {
0239:                    ;
0240:                }
0241:                try {
0242:                    value = getServletConfig().getInitParameter("input");
0243:                    input = Integer.parseInt(value);
0244:                } catch (Throwable t) {
0245:                    ;
0246:                }
0247:                try {
0248:                    value = getServletConfig().getInitParameter("listings");
0249:                    listings = (new Boolean(value)).booleanValue();
0250:                } catch (Throwable t) {
0251:                    ;
0252:                }
0253:                //System.out.println("Listings set to "+listings);
0254:                try {
0255:                    value = getServletConfig().getInitParameter("readonly");
0256:                    if (value != null)
0257:                        readOnly = (new Boolean(value)).booleanValue();
0258:                } catch (Throwable t) {
0259:                    ;
0260:                }
0261:                try {
0262:                    value = getServletConfig().getInitParameter("output");
0263:                    output = Integer.parseInt(value);
0264:                } catch (Throwable t) {
0265:                    ;
0266:                }
0267:
0268:                // Sanity check on the specified buffer sizes
0269:                if (input < 256)
0270:                    input = 256;
0271:                if (output < 256)
0272:                    output = 256;
0273:
0274:                // Initialize the set of welcome files for this application
0275:                welcomes = (String[]) getServletContext().getAttribute(
0276:                        "com.rimfaxe.webserver.WELCOME_FILES");
0277:
0278:                if (welcomes == null)
0279:                    welcomes = new String[0];
0280:
0281:                if (debug > 0) {
0282:                    log("DefaultServlet.init:  input buffer size=" + input
0283:                            + ", output buffer size=" + output);
0284:                    for (int i = 0; i < welcomes.length; i++) {
0285:                        log("DefaultServlet.init:  welcome file=" + welcomes[i]);
0286:                    }
0287:                }
0288:
0289:                // Load the MD5 helper used to calculate signatures.
0290:                try {
0291:                    md5Helper = MessageDigest.getInstance("MD5");
0292:                    //System.out.println("MD5 provider -> "+md5Helper.getProvider().getName() );
0293:                } catch (NoSuchAlgorithmException e) {
0294:
0295:                    throw new IllegalStateException("No such Algoritm : MD5");
0296:                }
0297:
0298:                //log("DefaultServlet.init: done!");
0299:            }
0300:
0301:            // ------------------------------------------------------ Protected Methods
0302:
0303:            /**
0304:             * Get resources. This method will try to retrieve the resources through
0305:             * JNDI first, then in the servlet context if JNDI has failed (it could be
0306:             * disabled). It will return null.
0307:             *
0308:             * @return A JNDI DirContext, or null.
0309:             */
0310:            protected DirContext getResources() {
0311:
0312:                DirContext result = null;
0313:
0314:                // Try the servlet context
0315:                try {
0316:                    result = (DirContext) getServletContext().getAttribute(
0317:                            "com.rimfaxe.webserver.resources");
0318:                } catch (ClassCastException e) {
0319:                    // Failed : Not the right type
0320:                }
0321:
0322:                if (result != null)
0323:                    return result;
0324:
0325:                // Try JNDI
0326:                try {
0327:                    result = (DirContext) new InitialContext()
0328:                            .lookup(RESOURCES_JNDI_NAME);
0329:                } catch (NamingException e) {
0330:                    // Failed
0331:                } catch (ClassCastException e) {
0332:                    // Failed : Not the right type
0333:                }
0334:
0335:                return result;
0336:
0337:            }
0338:
0339:            /**
0340:             * Show HTTP header information.
0341:             */
0342:            protected void showRequestInfo(HttpServletRequest req) {
0343:
0344:                System.out.println();
0345:                System.out.println("SlideDAV Request Info");
0346:                System.out.println();
0347:
0348:                // Show generic info
0349:                System.out.println("Encoding : " + req.getCharacterEncoding());
0350:                System.out.println("Length : " + req.getContentLength());
0351:                System.out.println("Type : " + req.getContentType());
0352:
0353:                System.out.println();
0354:                System.out.println("Parameters");
0355:
0356:                Enumeration parameters = req.getParameterNames();
0357:
0358:                while (parameters.hasMoreElements()) {
0359:                    String paramName = (String) parameters.nextElement();
0360:                    String[] values = req.getParameterValues(paramName);
0361:                    System.out.print(paramName + " : ");
0362:                    for (int i = 0; i < values.length; i++) {
0363:                        System.out.print(values[i] + ", ");
0364:                    }
0365:                    System.out.println();
0366:                }
0367:
0368:                System.out.println();
0369:
0370:                System.out.println("Protocol : " + req.getProtocol());
0371:                System.out.println("Address : " + req.getRemoteAddr());
0372:                System.out.println("Host : " + req.getRemoteHost());
0373:                System.out.println("Scheme : " + req.getScheme());
0374:                System.out.println("Server Name : " + req.getServerName());
0375:                System.out.println("Server Port : " + req.getServerPort());
0376:
0377:                System.out.println();
0378:                System.out.println("Attributes");
0379:
0380:                Enumeration attributes = req.getAttributeNames();
0381:
0382:                while (attributes.hasMoreElements()) {
0383:                    String attributeName = (String) attributes.nextElement();
0384:                    System.out.print(attributeName + " : ");
0385:                    System.out.println(req.getAttribute(attributeName)
0386:                            .toString());
0387:                }
0388:
0389:                System.out.println();
0390:
0391:                // Show HTTP info
0392:                System.out.println();
0393:                System.out.println("HTTP Header Info");
0394:                System.out.println();
0395:
0396:                System.out
0397:                        .println("Authentication Type : " + req.getAuthType());
0398:                System.out.println("HTTP Method : " + req.getMethod());
0399:                System.out.println("Path Info : " + req.getPathInfo());
0400:                System.out.println("Path translated : "
0401:                        + req.getPathTranslated());
0402:                System.out.println("Query string : " + req.getQueryString());
0403:                System.out.println("Remote user : " + req.getRemoteUser());
0404:                System.out.println("Requested session id : "
0405:                        + req.getRequestedSessionId());
0406:                System.out.println("Request URI : " + req.getRequestURI());
0407:                System.out.println("Context path : " + req.getContextPath());
0408:                System.out.println("Servlet path : " + req.getServletPath());
0409:                System.out
0410:                        .println("User principal : " + req.getUserPrincipal());
0411:
0412:                System.out.println();
0413:                System.out.println("Headers : ");
0414:
0415:                Enumeration headers = req.getHeaderNames();
0416:
0417:                while (headers.hasMoreElements()) {
0418:                    String headerName = (String) headers.nextElement();
0419:                    System.out.print(headerName + " : ");
0420:                    System.out.println(req.getHeader(headerName));
0421:                }
0422:
0423:                System.out.println();
0424:                System.out.println();
0425:
0426:            }
0427:
0428:            /**
0429:             * Return the relative path associated with this servlet.
0430:             *
0431:             * @param request The servlet request we are processing
0432:             */
0433:            protected String getRelativePath(HttpServletRequest request) {
0434:
0435:                // Are we being processed by a RequestDispatcher.include()?
0436:                if (request.getAttribute("javax.servlet.include.request_uri") != null) {
0437:                    String result = (String) request
0438:                            .getAttribute("javax.servlet.include.path_info");
0439:                    if (result == null) {
0440:                        result = (String) request
0441:                                .getAttribute("javax.servlet.include.servlet_path");
0442:                    }
0443:                    if ((result == null) || (result.equals(""))) {
0444:                        result = "/";
0445:                    }
0446:                    return (result);
0447:                }
0448:
0449:                // No, extract the desired path directly from the request
0450:                String result = request.getPathInfo();
0451:                if (result == null) {
0452:                    result = request.getServletPath();
0453:                }
0454:                if ((result == null) || (result.equals(""))) {
0455:                    result = "/";
0456:                }
0457:                return normalize(result);
0458:
0459:            }
0460:
0461:            /**
0462:             * Process a GET request for the specified resource.
0463:             *
0464:             * @param request The servlet request we are processing
0465:             * @param response The servlet response we are creating
0466:             *
0467:             * @exception IOException if an input/output error occurs
0468:             * @exception ServletException if a servlet-specified error occurs
0469:             */
0470:            protected void doGet(HttpServletRequest request,
0471:                    HttpServletResponse response) throws IOException,
0472:                    ServletException {
0473:
0474:                if (debug > 999)
0475:                    showRequestInfo(request);
0476:
0477:                // Serve the requested resource, including the data content
0478:
0479:                serveResource(request, response, true);
0480:
0481:            }
0482:
0483:            /**
0484:             * Process a HEAD request for the specified resource.
0485:             *
0486:             * @param request The servlet request we are processing
0487:             * @param response The servlet response we are creating
0488:             *
0489:             * @exception IOException if an input/output error occurs
0490:             * @exception ServletException if a servlet-specified error occurs
0491:             */
0492:            protected void doHead(HttpServletRequest request,
0493:                    HttpServletResponse response) throws IOException,
0494:                    ServletException {
0495:
0496:                // Serve the requested resource, without the data content
0497:                serveResource(request, response, false);
0498:
0499:            }
0500:
0501:            /**
0502:             * Process a POST request for the specified resource.
0503:             *
0504:             * @param request The servlet request we are processing
0505:             * @param response The servlet response we are creating
0506:             *
0507:             * @exception IOException if an input/output error occurs
0508:             * @exception ServletException if a servlet-specified error occurs
0509:             */
0510:            protected void doPost(HttpServletRequest request,
0511:                    HttpServletResponse response) throws IOException,
0512:                    ServletException {
0513:                doGet(request, response);
0514:            }
0515:
0516:            /**
0517:             * Process a POST request for the specified resource.
0518:             *
0519:             * @param request The servlet request we are processing
0520:             * @param response The servlet response we are creating
0521:             *
0522:             * @exception IOException if an input/output error occurs
0523:             * @exception ServletException if a servlet-specified error occurs
0524:             */
0525:            protected void doPut(HttpServletRequest req,
0526:                    HttpServletResponse resp) throws ServletException,
0527:                    IOException {
0528:
0529:                if (readOnly) {
0530:                    resp.sendError(HttpServletResponse.SC_FORBIDDEN);
0531:                    return;
0532:                }
0533:
0534:                String path = getRelativePath(req);
0535:
0536:                // Retrieve the resources
0537:                DirContext resources = getResources();
0538:
0539:                if (resources == null) {
0540:                    resp
0541:                            .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
0542:                    return;
0543:                }
0544:
0545:                boolean exists = true;
0546:                try {
0547:                    resources.lookup(path);
0548:                } catch (NamingException e) {
0549:                    exists = false;
0550:                }
0551:
0552:                boolean result = true;
0553:
0554:                // Temp. content file used to support partial PUT
0555:                File contentFile = null;
0556:
0557:                // Input stream for temp. content file used to support partial PUT
0558:                FileInputStream contentFileInStream = null;
0559:
0560:                ResourceInfo resourceInfo = new ResourceInfo(path, resources);
0561:                Range range = parseContentRange(req, resp);
0562:
0563:                InputStream resourceInputStream = null;
0564:
0565:                // Append data specified in ranges to existing content for this
0566:                // resource - create a temp. file on the local filesystem to
0567:                // perform this operation
0568:                // Assume just one range is specified for now
0569:                if (range != null) {
0570:                    contentFile = executePartialPut(req, range, path);
0571:                    resourceInputStream = new FileInputStream(contentFile);
0572:                } else {
0573:                    resourceInputStream = req.getInputStream();
0574:                }
0575:
0576:                try {
0577:                    Resource newResource = new Resource(resourceInputStream);
0578:                    // FIXME: Add attributes
0579:                    if (exists) {
0580:                        resources.rebind(path, newResource);
0581:                    } else {
0582:                        resources.bind(path, newResource);
0583:                    }
0584:                } catch (NamingException e) {
0585:                    result = false;
0586:                }
0587:
0588:                if (result) {
0589:                    if (exists) {
0590:                        resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
0591:                    } else {
0592:                        resp.setStatus(HttpServletResponse.SC_CREATED);
0593:                    }
0594:                } else {
0595:                    resp.sendError(HttpServletResponse.SC_CONFLICT);
0596:                }
0597:
0598:            }
0599:
0600:            /**
0601:             * Handle a partial PUT.  New content specified in request is appended to 
0602:             * existing content in oldRevisionContent (if present). This code does 
0603:             * not support simultaneous partial updates to the same resource.
0604:             */
0605:            protected File executePartialPut(HttpServletRequest req,
0606:                    Range range, String path) throws IOException {
0607:
0608:                // Append data specified in ranges to existing content for this
0609:                // resource - create a temp. file on the local filesystem to
0610:                // perform this operation
0611:                File tempDir = (File) getServletContext().getAttribute(
0612:                        "javax.servlet.context.tempdir");
0613:                // Convert all '/' characters to '.' in resourcePath
0614:                String convertedResourcePath = path.replace('/', '.');
0615:                File contentFile = new File(tempDir, convertedResourcePath);
0616:                if (contentFile.createNewFile()) {
0617:                    // Clean up contentFile when Tomcat is terminated
0618:                    contentFile.deleteOnExit();
0619:                }
0620:
0621:                RandomAccessFile randAccessContentFile = new RandomAccessFile(
0622:                        contentFile, "rw");
0623:
0624:                Resource oldResource = null;
0625:                try {
0626:                    Object obj = getResources().lookup(path);
0627:                    if (obj instanceof  Resource)
0628:                        oldResource = (Resource) obj;
0629:                } catch (NamingException e) {
0630:                }
0631:
0632:                // Copy data in oldRevisionContent to contentFile
0633:                if (oldResource != null) {
0634:                    BufferedInputStream bufOldRevStream = new BufferedInputStream(
0635:                            oldResource.streamContent(), BUFFER_SIZE);
0636:
0637:                    int numBytesRead;
0638:                    byte[] copyBuffer = new byte[BUFFER_SIZE];
0639:                    while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
0640:                        randAccessContentFile
0641:                                .write(copyBuffer, 0, numBytesRead);
0642:                    }
0643:
0644:                    bufOldRevStream.close();
0645:                }
0646:
0647:                randAccessContentFile.setLength(range.length);
0648:
0649:                // Append data in request input stream to contentFile
0650:                randAccessContentFile.seek(range.start);
0651:                int numBytesRead;
0652:                byte[] transferBuffer = new byte[BUFFER_SIZE];
0653:                BufferedInputStream requestBufInStream = new BufferedInputStream(
0654:                        req.getInputStream(), BUFFER_SIZE);
0655:                while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
0656:                    randAccessContentFile
0657:                            .write(transferBuffer, 0, numBytesRead);
0658:                }
0659:                randAccessContentFile.close();
0660:                requestBufInStream.close();
0661:
0662:                return contentFile;
0663:
0664:            }
0665:
0666:            /**
0667:             * Process a POST request for the specified resource.
0668:             *
0669:             * @param request The servlet request we are processing
0670:             * @param response The servlet response we are creating
0671:             *
0672:             * @exception IOException if an input/output error occurs
0673:             * @exception ServletException if a servlet-specified error occurs
0674:             */
0675:            protected void doDelete(HttpServletRequest req,
0676:                    HttpServletResponse resp) throws ServletException,
0677:                    IOException {
0678:
0679:                if (readOnly) {
0680:                    resp.sendError(HttpServletResponse.SC_FORBIDDEN);
0681:                    return;
0682:                }
0683:
0684:                String path = getRelativePath(req);
0685:
0686:                // Retrieve the Catalina context
0687:                // Retrieve the resources
0688:                DirContext resources = getResources();
0689:
0690:                if (resources == null) {
0691:                    resp
0692:                            .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
0693:                    return;
0694:                }
0695:
0696:                boolean exists = true;
0697:                try {
0698:                    resources.lookup(path);
0699:                } catch (NamingException e) {
0700:                    exists = false;
0701:                }
0702:
0703:                if (exists) {
0704:                    boolean result = true;
0705:                    try {
0706:                        resources.unbind(path);
0707:                    } catch (NamingException e) {
0708:                        result = false;
0709:                    }
0710:                    if (result) {
0711:                        resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
0712:                    } else {
0713:                        resp
0714:                                .sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
0715:                    }
0716:                } else {
0717:                    resp.sendError(HttpServletResponse.SC_NOT_FOUND);
0718:                }
0719:
0720:            }
0721:
0722:            /**
0723:             * Check if the conditions specified in the optional If headers are
0724:             * satisfied.
0725:             *
0726:             * @param request The servlet request we are processing
0727:             * @param response The servlet response we are creating
0728:             * @param resourceInfo File object
0729:             * @return boolean true if the resource meets all the specified conditions,
0730:             * and false if any of the conditions is not satisfied, in which case
0731:             * request processing is stopped
0732:             */
0733:            protected boolean checkIfHeaders(HttpServletRequest request,
0734:                    HttpServletResponse response, ResourceInfo resourceInfo)
0735:                    throws IOException {
0736:
0737:                return checkIfMatch(request, response, resourceInfo)
0738:                        && checkIfModifiedSince(request, response, resourceInfo)
0739:                        && checkIfNoneMatch(request, response, resourceInfo)
0740:                        && checkIfUnmodifiedSince(request, response,
0741:                                resourceInfo);
0742:
0743:            }
0744:
0745:            /**
0746:             * Get the ETag associated with a file.
0747:             *
0748:             * @param resourceInfo File object
0749:             * @param strong True if we want a strong ETag, in which case a checksum
0750:             * of the file has to be calculated
0751:             */
0752:            protected String getETag(ResourceInfo resourceInfo) {
0753:                if (resourceInfo.strongETag != null) {
0754:                    return resourceInfo.strongETag;
0755:                } else if (resourceInfo.weakETag != null) {
0756:                    return resourceInfo.weakETag;
0757:                } else {
0758:                    return "W/\"" + resourceInfo.length + "-"
0759:                            + resourceInfo.date + "\"";
0760:                }
0761:            }
0762:
0763:            /**
0764:             * Return a context-relative path, beginning with a "/", that represents
0765:             * the canonical version of the specified path after ".." and "." elements
0766:             * are resolved out.  If the specified path attempts to go outside the
0767:             * boundaries of the current context (i.e. too many ".." path elements
0768:             * are present), return <code>null</code> instead.
0769:             *
0770:             * @param path Path to be normalized
0771:             */
0772:            protected String normalize(String path) {
0773:
0774:                if (path == null)
0775:                    return null;
0776:
0777:                // Create a place for the normalized path
0778:                String normalized = path;
0779:
0780:                /*
0781:                 * Commented out -- already URL-decoded in StandardContextMapper
0782:                 * Decoding twice leaves the container vulnerable to %25 --> '%'
0783:                 * attacks.
0784:                 *
0785:                 * if (normalized.indexOf('%') >= 0)
0786:                 *     normalized = RequestUtil.URLDecode(normalized, "UTF8");
0787:                 */
0788:
0789:                if (normalized == null)
0790:                    return (null);
0791:
0792:                if (normalized.equals("/."))
0793:                    return "/";
0794:
0795:                // Normalize the slashes and add leading slash if necessary
0796:                if (normalized.indexOf('\\') >= 0)
0797:                    normalized = normalized.replace('\\', '/');
0798:                if (!normalized.startsWith("/"))
0799:                    normalized = "/" + normalized;
0800:
0801:                // Resolve occurrences of "//" in the normalized path
0802:                while (true) {
0803:                    int index = normalized.indexOf("//");
0804:                    if (index < 0)
0805:                        break;
0806:                    normalized = normalized.substring(0, index)
0807:                            + normalized.substring(index + 1);
0808:                }
0809:
0810:                // Resolve occurrences of "/./" in the normalized path
0811:                while (true) {
0812:                    int index = normalized.indexOf("/./");
0813:                    if (index < 0)
0814:                        break;
0815:                    normalized = normalized.substring(0, index)
0816:                            + normalized.substring(index + 2);
0817:                }
0818:
0819:                // Resolve occurrences of "/../" in the normalized path
0820:                while (true) {
0821:                    int index = normalized.indexOf("/../");
0822:                    if (index < 0)
0823:                        break;
0824:                    if (index == 0)
0825:                        return (null); // Trying to go outside our context
0826:                    int index2 = normalized.lastIndexOf('/', index - 1);
0827:                    normalized = normalized.substring(0, index2)
0828:                            + normalized.substring(index + 3);
0829:                }
0830:
0831:                // Return the normalized path that we have completed
0832:                return (normalized);
0833:
0834:            }
0835:
0836:            /**
0837:             * URL rewriter.
0838:             *
0839:             * @param path Path which has to be rewiten
0840:             */
0841:            protected String rewriteUrl(String path) {
0842:                return urlEncoder.encode(path);
0843:            }
0844:
0845:            /**
0846:             * Display the size of a file.
0847:             */
0848:            protected void displaySize(StringBuffer buf, int filesize) {
0849:
0850:                int leftside = filesize / 1024;
0851:                int rightside = (filesize % 1024) / 103; // makes 1 digit
0852:                // To avoid 0.0 for non-zero file, we bump to 0.1
0853:                if (leftside == 0 && rightside == 0 && filesize != 0)
0854:                    rightside = 1;
0855:                buf.append(leftside).append(".").append(rightside);
0856:                buf.append(" KB");
0857:
0858:            }
0859:
0860:            /**
0861:             * Serve the specified resource, optionally including the data content.
0862:             *
0863:             * @param request The servlet request we are processing
0864:             * @param response The servlet response we are creating
0865:             * @param content Should the content be included?
0866:             *
0867:             * @exception IOException if an input/output error occurs
0868:             * @exception ServletException if a servlet-specified error occurs
0869:             */
0870:            protected void serveResource(HttpServletRequest request,
0871:                    HttpServletResponse response, boolean content)
0872:                    throws IOException, ServletException {
0873:
0874:                // Identify the requested resource path
0875:                String path = getRelativePath(request);
0876:
0877:                //log("1");
0878:
0879:                if (debug > 0) {
0880:                    if (content)
0881:                        log("DefaultServlet.serveResource:  Serving resource '"
0882:                                + path + "' headers and data");
0883:                    else
0884:                        log("DefaultServlet.serveResource:  Serving resource '"
0885:                                + path + "' headers only");
0886:
0887:                }
0888:
0889:                // Retrieve the Catalina context and Resources implementation
0890:                DirContext resources = getResources();
0891:                ResourceInfo resourceInfo = new ResourceInfo(path, resources);
0892:
0893:                //System.out.println("Is it a collection? -> "+resourceInfo.collection);
0894:
0895:                //System.out.println("Does resource info exist? -> "+resourceInfo.exists);
0896:                if (!resourceInfo.exists) {
0897:                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
0898:                            request.getRequestURI());
0899:                    return;
0900:                }
0901:
0902:                // If the resource is not a collection, and the resource path
0903:                // ends with "/" or "\", return NOT FOUND
0904:                //System.out.println("if the resource is not a collection, and the resource path ends with / return NOT FOUND");
0905:                if (!resourceInfo.collection) {
0906:                    if (path.endsWith("/") || (path.endsWith("\\"))) {
0907:                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
0908:                                request.getRequestURI());
0909:                        return;
0910:                    }
0911:                }
0912:
0913:                // If the resource is a collection (aka a directory), we check
0914:                // the welcome files list.
0915:                if (resourceInfo.collection) {
0916:                    System.out
0917:                            .println("It is a collection, lookup in welcome files.\nDefaultServlet Request URI = "
0918:                                    + request.getRequestURI());
0919:
0920:                    if (!request.getRequestURI().endsWith("/")) {
0921:                        String redirectPath = path;
0922:                        String contextPath = request.getContextPath();
0923:                        if ((contextPath != null) && (!contextPath.equals("/"))) {
0924:                            redirectPath = contextPath + redirectPath;
0925:                        }
0926:                        if (!(redirectPath.endsWith("/")))
0927:                            redirectPath = redirectPath + "/";
0928:                        redirectPath = appendParameters(request, redirectPath);
0929:                        response.sendRedirect(redirectPath);
0930:                        return;
0931:                    }
0932:
0933:                    ResourceInfo welcomeFileInfo = checkWelcomeFiles(path,
0934:                            resources);
0935:                    if (welcomeFileInfo != null) {
0936:                        String redirectPath = welcomeFileInfo.path;
0937:                        String contextPath = request.getContextPath();
0938:
0939:                        if ((contextPath != null) && (!contextPath.equals("/"))) {
0940:                            redirectPath = contextPath + redirectPath;
0941:                        }
0942:                        redirectPath = appendParameters(request, redirectPath);
0943:                        response.sendRedirect(redirectPath);
0944:                        return;
0945:                    }
0946:
0947:                } else {
0948:
0949:                    // Checking If headers
0950:                    //System.out.println("Checking If headers");
0951:                    boolean included = (request
0952:                            .getAttribute("javax.servlet.include.context_path") != null);
0953:                    if (!included
0954:                            && !checkIfHeaders(request, response, resourceInfo)) {
0955:
0956:                        return;
0957:                    }
0958:
0959:                }
0960:
0961:                // Find content type.
0962:                //System.out.println("Find content type.");
0963:                String contentType = getServletContext().getMimeType(
0964:                        resourceInfo.path);
0965:
0966:                Vector ranges = null;
0967:
0968:                if (resourceInfo.collection) {
0969:                    // Skip directory listings if we have been configured to
0970:                    // suppress them
0971:                    if (!listings) {
0972:                        //System.out.println("Listings is OFF");
0973:                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
0974:                                request.getRequestURI());
0975:                        return;
0976:                    }
0977:                    contentType = "text/html;charset=UTF-8";
0978:
0979:                } else {
0980:
0981:                    // Parse range specifier
0982:
0983:                    ranges = parseRange(request, response, resourceInfo);
0984:
0985:                    // ETag header
0986:                    response.setHeader("ETag", getETag(resourceInfo));
0987:
0988:                    // Last-Modified header
0989:                    if (debug > 0)
0990:                        log("DefaultServlet.serveFile:  lastModified='"
0991:                                + (new Timestamp(resourceInfo.date)).toString()
0992:                                + "'");
0993:                    response.setHeader("Last-Modified", resourceInfo.httpDate);
0994:
0995:                    //response.setHeader("Date", resourceInfo.httpDate);
0996:
0997:                }
0998:
0999:                ServletOutputStream ostream = null;
1000:                PrintWriter writer = null;
1001:
1002:                if (content) {
1003:
1004:                    // Trying to retrieve the servlet output stream
1005:
1006:                    try {
1007:                        ostream = response.getOutputStream();
1008:                    } catch (IllegalStateException e) {
1009:                        // If it fails, we try to get a Writer instead if we're
1010:                        // trying to serve a text file
1011:                        if ((contentType != null)
1012:                                && (contentType.startsWith("text"))) {
1013:                            writer = response.getWriter();
1014:                        } else {
1015:                            throw e;
1016:                        }
1017:                    }
1018:
1019:                }
1020:
1021:                if ((resourceInfo.collection)
1022:                        || (((ranges == null) || (ranges.isEmpty())) && (request
1023:                                .getHeader("Range") == null))) {
1024:
1025:                    // Set the appropriate output headers
1026:                    if (contentType != null) {
1027:                        if (debug > 0)
1028:                            log("DefaultServlet.serveFile:  contentType='"
1029:                                    + contentType + "'");
1030:                        response.setContentType(contentType);
1031:                    }
1032:                    long contentLength = resourceInfo.length;
1033:                    if ((!resourceInfo.collection) && (contentLength >= 0)) {
1034:                        if (debug > 0)
1035:                            log("DefaultServlet.serveFile:  contentLength="
1036:                                    + contentLength);
1037:                        if (request
1038:                                .getAttribute("javax.servlet.include.context_path") == null) {
1039:                            //System.out.println("DefaultServlet : set content length");  
1040:                            response.setContentLength((int) contentLength);
1041:                        } else {
1042:                            //System.out.println("DefaultServlet : DO NOT set content length! This is an include!");   
1043:                        }
1044:                    }
1045:
1046:                    if (resourceInfo.collection) {
1047:
1048:                        if (content) {
1049:                            // Serve the directory browser
1050:                            if (request.getRequestURI().startsWith("/WEB-INF")) {
1051:                                response.sendError(
1052:                                        HttpServletResponse.SC_NOT_FOUND,
1053:                                        request.getRequestURI());
1054:                                return;
1055:                            }
1056:
1057:                            if (!resourceInfo.exists()) {
1058:                                response.sendError(
1059:                                        HttpServletResponse.SC_NOT_FOUND,
1060:                                        request.getRequestURI());
1061:                                return;
1062:                            }
1063:
1064:                            resourceInfo.setStream(render(request
1065:                                    .getContextPath(), resourceInfo));
1066:                        }
1067:
1068:                    }
1069:
1070:                    // Copy the input stream to our output stream (if requested)
1071:                    if (content) {
1072:                        try {
1073:                            response.setBufferSize(output);
1074:                        } catch (IllegalStateException e) {
1075:                            // Silent catch
1076:                        }
1077:                        if (ostream != null) {
1078:                            copy(resourceInfo, ostream);
1079:                        } else {
1080:                            copy(resourceInfo, writer);
1081:                        }
1082:                    }
1083:
1084:                } else {
1085:
1086:                    if ((ranges == null) || (ranges.isEmpty()))
1087:                        return;
1088:
1089:                    // Partial content response.
1090:
1091:                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
1092:
1093:                    if (ranges.size() == 1) {
1094:
1095:                        Range range = (Range) ranges.elementAt(0);
1096:                        response.addHeader("Content-Range", "bytes "
1097:                                + range.start + "-" + range.end + "/"
1098:                                + range.length);
1099:
1100:                        if (request
1101:                                .getAttribute("javax.servlet.include.context_path") == null) {
1102:                            //System.out.println("DefaultServlet : set content length");  
1103:                            response.setContentLength((int) (range.end
1104:                                    - range.start + 1));
1105:                        } else {
1106:                            //System.out.println("DefaultServlet : DO NOT set content length! This is an include!");   
1107:                        }
1108:
1109:                        if (contentType != null) {
1110:                            if (debug > 0)
1111:                                log("DefaultServlet.serveFile:  contentType='"
1112:                                        + contentType + "'");
1113:                            response.setContentType(contentType);
1114:                        }
1115:
1116:                        if (content) {
1117:                            try {
1118:                                response.setBufferSize(output);
1119:                            } catch (IllegalStateException e) {
1120:                                // Silent catch
1121:                            }
1122:                            if (ostream != null) {
1123:                                copy(resourceInfo, ostream, range);
1124:                            } else {
1125:                                copy(resourceInfo, writer, range);
1126:                            }
1127:                        }
1128:
1129:                    } else {
1130:
1131:                        response
1132:                                .setContentType("multipart/byteranges; boundary="
1133:                                        + mimeSeparation);
1134:
1135:                        if (content) {
1136:                            try {
1137:                                response.setBufferSize(output);
1138:                            } catch (IllegalStateException e) {
1139:                                // Silent catch
1140:                            }
1141:                            if (ostream != null) {
1142:                                copy(resourceInfo, ostream, ranges.elements(),
1143:                                        contentType);
1144:                            } else {
1145:                                copy(resourceInfo, writer, ranges.elements(),
1146:                                        contentType);
1147:                            }
1148:                        }
1149:
1150:                    }
1151:
1152:                }
1153:
1154:            }
1155:
1156:            /**
1157:             * Parse the content-range header.
1158:             *
1159:             * @param request The servlet request we are processing
1160:             * @param response The servlet response we are creating
1161:             * @return Range
1162:             */
1163:            protected Range parseContentRange(HttpServletRequest request,
1164:                    HttpServletResponse response) throws IOException {
1165:
1166:                // Retrieving the content-range header (if any is specified
1167:                String rangeHeader = request.getHeader("Content-Range");
1168:
1169:                if (rangeHeader == null)
1170:                    return null;
1171:
1172:                // bytes is the only range unit supported
1173:                if (!rangeHeader.startsWith("bytes")) {
1174:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
1175:                    return null;
1176:                }
1177:
1178:                rangeHeader = rangeHeader.substring(6).trim();
1179:
1180:                int dashPos = rangeHeader.indexOf('-');
1181:                int slashPos = rangeHeader.indexOf('/');
1182:
1183:                if (dashPos == -1) {
1184:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
1185:                    return null;
1186:                }
1187:
1188:                if (slashPos == -1) {
1189:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
1190:                    return null;
1191:                }
1192:
1193:                Range range = new Range();
1194:
1195:                try {
1196:                    range.start = Long.parseLong(rangeHeader.substring(0,
1197:                            dashPos));
1198:                    range.end = Long.parseLong(rangeHeader.substring(
1199:                            dashPos + 1, slashPos));
1200:                    range.length = Long.parseLong(rangeHeader.substring(
1201:                            slashPos + 1, rangeHeader.length()));
1202:                } catch (NumberFormatException e) {
1203:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
1204:                    return null;
1205:                }
1206:
1207:                if (!range.validate()) {
1208:                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
1209:                    return null;
1210:                }
1211:
1212:                return range;
1213:
1214:            }
1215:
1216:            /**
1217:             * Parse the range header.
1218:             *
1219:             * @param request The servlet request we are processing
1220:             * @param response The servlet response we are creating
1221:             * @return Vector of ranges
1222:             */
1223:            protected Vector parseRange(HttpServletRequest request,
1224:                    HttpServletResponse response, ResourceInfo resourceInfo)
1225:                    throws IOException {
1226:
1227:                // Checking If-Range
1228:                String headerValue = request.getHeader("If-Range");
1229:                if (headerValue != null) {
1230:
1231:                    String eTag = getETag(resourceInfo);
1232:                    long lastModified = resourceInfo.date;
1233:
1234:                    Date date = null;
1235:
1236:                    // Parsing the HTTP Date
1237:                    for (int i = 0; (date == null) && (i < formats.length); i++) {
1238:                        try {
1239:                            date = formats[i].parse(headerValue);
1240:                        } catch (ParseException e) {
1241:                            ;
1242:                        }
1243:                    }
1244:
1245:                    if (date == null) {
1246:
1247:                        // If the ETag the client gave does not match the entity
1248:                        // etag, then the entire entity is returned.
1249:                        if (!eTag.equals(headerValue.trim()))
1250:                            return null;
1251:
1252:                    } else {
1253:
1254:                        // If the timestamp of the entity the client got is older than
1255:                        // the last modification date of the entity, the entire entity
1256:                        // is returned.
1257:                        if (lastModified > (date.getTime() + 1000))
1258:                            return null;
1259:
1260:                    }
1261:
1262:                }
1263:
1264:                long fileLength = resourceInfo.length;
1265:
1266:                if (fileLength == 0)
1267:                    return null;
1268:
1269:                // Retrieving the range header (if any is specified
1270:                String rangeHeader = request.getHeader("Range");
1271:
1272:                if (rangeHeader == null)
1273:                    return null;
1274:                // bytes is the only range unit supported (and I don't see the point
1275:                // of adding new ones).
1276:                if (!rangeHeader.startsWith("bytes")) {
1277:                    response
1278:                            .addHeader("Content-Range", "bytes */" + fileLength);
1279:                    response
1280:                            .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1281:                    return null;
1282:                }
1283:
1284:                rangeHeader = rangeHeader.substring(6);
1285:
1286:                // Vector which will contain all the ranges which are successfully
1287:                // parsed.
1288:                Vector result = new Vector();
1289:                StringTokenizer commaTokenizer = new StringTokenizer(
1290:                        rangeHeader, ",");
1291:
1292:                // Parsing the range list
1293:                while (commaTokenizer.hasMoreTokens()) {
1294:                    String rangeDefinition = commaTokenizer.nextToken();
1295:
1296:                    Range currentRange = new Range();
1297:                    currentRange.length = fileLength;
1298:
1299:                    int dashPos = rangeDefinition.indexOf('-');
1300:
1301:                    if (dashPos == -1) {
1302:                        response.addHeader("Content-Range", "bytes */"
1303:                                + fileLength);
1304:                        response
1305:                                .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1306:                        return null;
1307:                    }
1308:
1309:                    if (dashPos == 0) {
1310:
1311:                        try {
1312:                            long offset = Long.parseLong(rangeDefinition);
1313:                            currentRange.start = fileLength + offset;
1314:                            currentRange.end = fileLength - 1;
1315:                        } catch (NumberFormatException e) {
1316:                            response.addHeader("Content-Range", "bytes */"
1317:                                    + fileLength);
1318:                            response
1319:                                    .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1320:                            return null;
1321:                        }
1322:
1323:                    } else {
1324:
1325:                        try {
1326:                            currentRange.start = Long.parseLong(rangeDefinition
1327:                                    .substring(0, dashPos));
1328:                            if (dashPos < rangeDefinition.length() - 1)
1329:                                currentRange.end = Long
1330:                                        .parseLong(rangeDefinition.substring(
1331:                                                dashPos + 1, rangeDefinition
1332:                                                        .length()));
1333:                            else
1334:                                currentRange.end = fileLength - 1;
1335:                        } catch (NumberFormatException e) {
1336:                            response.addHeader("Content-Range", "bytes */"
1337:                                    + fileLength);
1338:                            response
1339:                                    .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1340:                            return null;
1341:                        }
1342:
1343:                    }
1344:
1345:                    if (!currentRange.validate()) {
1346:                        response.addHeader("Content-Range", "bytes */"
1347:                                + fileLength);
1348:                        response
1349:                                .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
1350:                        return null;
1351:                    }
1352:
1353:                    result.addElement(currentRange);
1354:                }
1355:
1356:                return result;
1357:            }
1358:
1359:            /**
1360:             * Append the request parameters to the redirection string before calling
1361:             * sendRedirect.
1362:             */
1363:            protected String appendParameters(HttpServletRequest request,
1364:                    String redirectPath) {
1365:
1366:                StringBuffer result = new StringBuffer(rewriteUrl(redirectPath));
1367:
1368:                String query = request.getQueryString();
1369:                if (query != null)
1370:                    result.append("?").append(query);
1371:
1372:                return result.toString();
1373:
1374:            }
1375:
1376:            /**
1377:             * Return an InputStream to an HTML representation of the contents
1378:             * of this directory.
1379:             *
1380:             * @param contextPath Context path to which our internal paths are
1381:             *  relative
1382:             */
1383:            protected InputStream render(String contextPath, ResourceInfo resourceInfo) 
1384:    {
1385:
1386:        String name = resourceInfo.path;
1387:
1388:        // Number of characters to trim from the beginnings of filenames
1389:        int trim = name.length();
1390:        if (!name.endsWith("/"))
1391:            trim += 1;
1392:        if (name.equals("/"))
1393:            trim = 1;
1394:
1395:        // Prepare a writer to a buffered area
1396:        ByteArrayOutputStream stream = new ByteArrayOutputStream();
1397:        OutputStreamWriter osWriter = null;
1398:        try {
1399:            osWriter = new OutputStreamWriter(stream, "UTF8");
1400:        } catch (Exception e) {
1401:            // Should never happen
1402:            osWriter = new OutputStreamWriter(stream);
1403:        }
1404:        PrintWriter writer = new PrintWriter(osWriter);
1405:
1406:        StringBuffer sb = new StringBuffer();
1407:
1408:        // Render the page header
1409:        sb.append("<html>");
1410:        sb.append("<head>"); 
1411:        sb.append("  <title>");
1412:        sb.append("    [ "+name+" ] Directory Listing");
1413:        sb.append("  </title>\r\n");
1414:        sb.append("</head>");
1415:        
1416:        sb.append("<body>"); 
1417:        
1418:        
1419:        sb.append("<p align=\"center\" style=\"color: #676a77; margin-left: 10px; margin-right: 10px; font-weight: bold; font-size: 20pt\">");
1420:        sb.append("Directory Listing");
1421:        sb.append("</p>");
1422:        
1423:        
1424:        sb.append("  <table align=\"center\" border=\"0\" width=\"92%\">");
1425:        sb.append("  <tr>");
1426:        sb.append("    <td>");
1427:        sb.append("      <p align=\"left\" style=\"font-weight: normal; font-size: 12pt\">");
1428:        sb.append("        Browse directory <b>"+name+"</b> <br><br>");
1429:        sb.append("        For more information on how to configure the Rimfaxe Web Server, please visit");
1430:        sb.append("        <a href=\"http://www.rimfaxe.com\"><b>www.rimfaxe.com</b></a>. <br>");
1431:        sb.append("      </p>");
1432:        sb.append("    </td>");
1433:        sb.append("  </tr>");
1434:        sb.append("  <tr>  <td> &nbsp;  </td> </tr>");
1435:        
1436:        
1437:        
1438:        sb.append("  <tr>");
1439:        sb.append("    <td>");
1440:        sb.append("      <p align=\"left\" style=\"font-weight: normal; font-size: 12pt\">");
1441:        sb.append("        <b>[ "+name+" ]</b> ");
1442:        
1443:        // Render the link to our parent (if required)
1444:        String parentDirectory = name;
1445:        if (parentDirectory.endsWith("/")) {
1446:            parentDirectory =
1447:                parentDirectory.substring(0, parentDirectory.length() - 1);
1448:        }
1449:        int slash = parentDirectory.lastIndexOf('/');
1450:        if (slash >= 0) 
1451:        {
1452:            String parent = name.substring(0, slash);
1453:            sb.append("&nbsp;&nbsp;&nbsp;  <a href=\"");
1454:            sb.append(rewriteUrl(contextPath));
1455:            if (parent.equals(""))
1456:                parent = "/";
1457:            sb.append(rewriteUrl(parent));
1458:            if (!parent.endsWith("/"))
1459:                sb.append("/");
1460:            sb.append("\">");
1461:            sb.append("<b>[ ");
1462:            sb.append(parent);
1463:            sb.append(" ]</b>");
1464:            sb.append("</a>");
1465:        }
1466:        
1467:        sb.append("      </p>");
1468:        sb.append("    </td>");
1469:        sb.append("  </tr>");
1470:        
1471:        sb.append("  <tr>  <td> &nbsp;  </td> </tr>");
1472:        
1473:        sb.append("  <tr>");
1474:        sb.append("    <td>");
1475:        sb.append("        <table border=\"0\" width=\"100%\" cellspacing=\"2\" cellpadding=\"3\" align=\"center\">");
1476:        sb.append("        <tr bgcolor=\"#90a1b3\">");
1477:        sb.append("          <td align=\"left\">");
1478:        sb.append("            <p align=\"left\" style=\"margin-left: 5px; margin-right: 5px; font-weight: bold; font-size: 12pt\">Filename</p>");
1479:        sb.append("          </td>");
1480:        sb.append("          <td align=\"right\">");
1481:        sb.append("            <p align=\"right\" style=\"margin-left: 5px; margin-right: 5px; font-weight: bold; font-size: 12pt\">Size</p>");
1482:        sb.append("          </td>");
1483:        sb.append("          <td align=\"right\">");
1484:        sb.append("            <p align=\"right\" style=\"margin-left: 5px; margin-right: 5px; font-weight: bold; font-size: 12pt\">Last Modified</p>");
1485:        sb.append("          </td>");
1486:        sb.append("        </tr>");
1487:        
1488:        
1489:       
1490:
1491:        try 
1492:        {
1493:
1494:            // Render the directory entries within this directory
1495:            DirContext directory = resourceInfo.directory;
1496:            NamingEnumeration enum = resourceInfo.resources.list(resourceInfo.path);
1497:            boolean shade = false;
1498:            while (enum.hasMoreElements()) 
1499:            {
1500:
1501:                NameClassPair ncPair = (NameClassPair) enum.nextElement();
1502:                String resourceName = ncPair.getName();
1503:                ResourceInfo childResourceInfo = new ResourceInfo(resourceName, directory);
1504:
1505:                String trimmed = resourceName/*.substring(trim)*/;
1506:                if (trimmed.equalsIgnoreCase("WEB-INF") || trimmed.equalsIgnoreCase("META-INF"))
1507:                    continue;
1508:
1509:                sb.append("<tr");
1510:                
1511:                if (shade)
1512:                    sb.append(" bgcolor=\"c7d0d9\"");
1513:                else
1514:                    sb.append(" bgcolor=\"c7d0d9\"");
1515:                
1516:                sb.append(">\r\n");
1517:                shade = !shade;
1518:
1519:                sb.append("<td align=\"left\">&nbsp;&nbsp;\r\n");
1520:                sb.append("<a href=\"");
1521:                sb.append(rewriteUrl(contextPath));
1522:                resourceName = rewriteUrl(name + resourceName);
1523:                sb.append(resourceName);
1524:                if (childResourceInfo.collection)
1525:                    sb.append("/");
1526:                sb.append("\"><tt>");
1527:                sb.append(trimmed);
1528:                if (childResourceInfo.collection)
1529:                    sb.append("/");
1530:                sb.append("</tt></a></td>\r\n");
1531:
1532:                sb.append("<td align=\"right\"><tt>");
1533:                if (childResourceInfo.collection)
1534:                    sb.append("&nbsp;");
1535:                else
1536:                    sb.append(renderSize(childResourceInfo.length));
1537:                sb.append("</tt></td>\r\n");
1538:
1539:                sb.append("<td align=\"right\"><tt>");
1540:                sb.append(childResourceInfo.httpDate);
1541:                sb.append("</tt></td>\r\n");
1542:
1543:                sb.append("</tr>\r\n");
1544:            }
1545:
1546:        } 
1547:        catch (NamingException e) 
1548:        {
1549:           // Appropiate action? TODO 
1550:        }
1551:
1552:        // Render the page footer
1553:        sb.append("</table>\r\n");
1554:
1555:        sb.append("</td>");
1556:        sb.append("</tr>");
1557:        
1558:        sb.append("<tr>  <td> &nbsp;  </td> </tr>");
1559:        
1560:        
1561:        sb.append("  <tr>");
1562:        sb.append("    <td height=\"15\">");
1563:        
1564:        
1565:        sb.append("      <p style=\"margin-left: 10px; font-size: 10pt\">");
1566:        sb.append("        <b>"+com.rimfaxe.webserver.ObjectStore.getConfiguration().getBanner()+"</b> &nbsp;&nbsp; - <a href=\"http://www.rimfaxe.com\">Rimfaxe Software</a>");
1567:        sb.append("      </p>");
1568:        sb.append("    </td>");
1569:        sb.append("  </tr>");
1570:        
1571:        
1572:        sb.append("  </table>");
1573:        sb.append("</body>");
1574:        sb.append("</html>");
1575:        
1576:        
1577:
1578:        // Return an input stream to the underlying bytes
1579:        writer.write(sb.toString());
1580:        writer.flush();
1581:        return (new ByteArrayInputStream(stream.toByteArray()));
1582:
1583:    }
1584:
1585:            /**
1586:             * Render the specified file size (in bytes).
1587:             *
1588:             * @param size File size (in bytes)
1589:             */
1590:            protected String renderSize(long size) {
1591:
1592:                long leftSide = size / 1024;
1593:                long rightSide = (size % 1024) / 103; // Makes 1 digit
1594:                if ((leftSide == 0) && (rightSide == 0) && (size > 0))
1595:                    rightSide = 1;
1596:
1597:                return ("" + leftSide + "." + rightSide + " kb");
1598:
1599:            }
1600:
1601:            // -------------------------------------------------------- Private Methods
1602:
1603:            /**
1604:             * Check if the if-match condition is satisfied.
1605:             *
1606:             * @param request The servlet request we are processing
1607:             * @param response The servlet response we are creating
1608:             * @param resourceInfo File object
1609:             * @return boolean true if the resource meets the specified condition,
1610:             * and false if the condition is not satisfied, in which case request 
1611:             * processing is stopped
1612:             */
1613:            private boolean checkIfMatch(HttpServletRequest request,
1614:                    HttpServletResponse response, ResourceInfo resourceInfo)
1615:                    throws IOException {
1616:
1617:                String eTag = getETag(resourceInfo);
1618:                String headerValue = request.getHeader("If-Match");
1619:                if (headerValue != null) {
1620:                    if (headerValue.indexOf('*') == -1) {
1621:
1622:                        StringTokenizer commaTokenizer = new StringTokenizer(
1623:                                headerValue, ",");
1624:                        boolean conditionSatisfied = false;
1625:
1626:                        while (!conditionSatisfied
1627:                                && commaTokenizer.hasMoreTokens()) {
1628:                            String currentToken = commaTokenizer.nextToken();
1629:                            if (currentToken.trim().equals(eTag))
1630:                                conditionSatisfied = true;
1631:                        }
1632:
1633:                        // If none of the given ETags match, 412 Precodition failed is
1634:                        // sent back
1635:                        if (!conditionSatisfied) {
1636:                            response
1637:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1638:                            return false;
1639:                        }
1640:
1641:                    }
1642:                }
1643:                return true;
1644:
1645:            }
1646:
1647:            /**
1648:             * Check if the if-modified-since condition is satisfied.
1649:             *
1650:             * @param request The servlet request we are processing
1651:             * @param response The servlet response we are creating
1652:             * @param resourceInfo File object
1653:             * @return boolean true if the resource meets the specified condition,
1654:             * and false if the condition is not satisfied, in which case request 
1655:             * processing is stopped
1656:             */
1657:            private boolean checkIfModifiedSince(HttpServletRequest request,
1658:                    HttpServletResponse response, ResourceInfo resourceInfo)
1659:                    throws IOException {
1660:
1661:                try {
1662:                    long headerValue = request
1663:                            .getDateHeader("If-Modified-Since");
1664:                    long lastModified = resourceInfo.date;
1665:                    if (headerValue != -1) {
1666:
1667:                        // If an If-None-Match header has been specified, if modified since
1668:                        // is ignored.
1669:                        if ((request.getHeader("If-None-Match") == null)
1670:                                && (lastModified <= headerValue + 1000)) {
1671:                            // The entity has not been modified since the date
1672:                            // specified by the client. This is not an error case.
1673:                            response
1674:                                    .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
1675:                            return false;
1676:                        }
1677:                    }
1678:                } catch (IllegalArgumentException illegalArgument) {
1679:                    return false;
1680:                }
1681:
1682:                return true;
1683:
1684:            }
1685:
1686:            /**
1687:             * Check if the if-none-match condition is satisfied.
1688:             *
1689:             * @param request The servlet request we are processing
1690:             * @param response The servlet response we are creating
1691:             * @param resourceInfo File object
1692:             * @return boolean true if the resource meets the specified condition,
1693:             * and false if the condition is not satisfied, in which case request 
1694:             * processing is stopped
1695:             */
1696:            private boolean checkIfNoneMatch(HttpServletRequest request,
1697:                    HttpServletResponse response, ResourceInfo resourceInfo)
1698:                    throws IOException {
1699:
1700:                String eTag = getETag(resourceInfo);
1701:                String headerValue = request.getHeader("If-None-Match");
1702:                if (headerValue != null) {
1703:
1704:                    boolean conditionSatisfied = false;
1705:
1706:                    if (!headerValue.equals("*")) {
1707:
1708:                        StringTokenizer commaTokenizer = new StringTokenizer(
1709:                                headerValue, ",");
1710:
1711:                        while (!conditionSatisfied
1712:                                && commaTokenizer.hasMoreTokens()) {
1713:                            String currentToken = commaTokenizer.nextToken();
1714:                            if (currentToken.trim().equals(eTag))
1715:                                conditionSatisfied = true;
1716:                        }
1717:
1718:                    } else {
1719:                        conditionSatisfied = true;
1720:                    }
1721:
1722:                    if (conditionSatisfied) {
1723:
1724:                        // For GET and HEAD, we should respond with
1725:                        // 304 Not Modified.
1726:                        // For every other method, 412 Precondition Failed is sent
1727:                        // back.
1728:                        if (("GET".equals(request.getMethod()))
1729:                                || ("HEAD".equals(request.getMethod()))) {
1730:                            response
1731:                                    .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
1732:                            return false;
1733:                        } else {
1734:                            response
1735:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1736:                            return false;
1737:                        }
1738:                    }
1739:                }
1740:                return true;
1741:
1742:            }
1743:
1744:            /**
1745:             * Check if the if-unmodified-since condition is satisfied.
1746:             *
1747:             * @param request The servlet request we are processing
1748:             * @param response The servlet response we are creating
1749:             * @param resourceInfo File object
1750:             * @return boolean true if the resource meets the specified condition,
1751:             * and false if the condition is not satisfied, in which case request 
1752:             * processing is stopped
1753:             */
1754:            private boolean checkIfUnmodifiedSince(HttpServletRequest request,
1755:                    HttpServletResponse response, ResourceInfo resourceInfo)
1756:                    throws IOException {
1757:                try {
1758:                    long lastModified = resourceInfo.date;
1759:                    long headerValue = request
1760:                            .getDateHeader("If-Unmodified-Since");
1761:                    if (headerValue != -1) {
1762:                        if (lastModified > headerValue) {
1763:                            // The entity has not been modified since the date
1764:                            // specified by the client. This is not an error case.
1765:                            response
1766:                                    .sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1767:                            return false;
1768:                        }
1769:                    }
1770:                } catch (IllegalArgumentException illegalArgument) {
1771:                    return false;
1772:                }
1773:                return true;
1774:
1775:            }
1776:
1777:            /**
1778:             * Copy the contents of the specified input stream to the specified
1779:             * output stream, and ensure that both streams are closed before returning
1780:             * (even in the face of an exception).
1781:             *
1782:             * @param istream The input stream to read from
1783:             * @param ostream The output stream to write to
1784:             *
1785:             * @exception IOException if an input/output error occurs
1786:             */
1787:            private void copy(ResourceInfo resourceInfo,
1788:                    ServletOutputStream ostream) throws IOException {
1789:
1790:                IOException exception = null;
1791:
1792:                // FIXME : i18n ?
1793:                InputStream resourceInputStream = resourceInfo.getStream();
1794:                InputStream istream = new BufferedInputStream(
1795:                        resourceInputStream, input);
1796:
1797:                // Copy the input stream to the output stream
1798:                exception = copyRange(istream, ostream);
1799:
1800:                // Clean up the input stream
1801:                try {
1802:                    istream.close();
1803:                } catch (Throwable t) {
1804:                    ;
1805:                }
1806:
1807:                // Rethrow any exception that has occurred
1808:                if (exception != null)
1809:                    throw exception;
1810:
1811:            }
1812:
1813:            /**
1814:             * Copy the contents of the specified input stream to the specified
1815:             * output stream, and ensure that both streams are closed before returning
1816:             * (even in the face of an exception).
1817:             *
1818:             * @param istream The input stream to read from
1819:             * @param writer The writer to write to
1820:             *
1821:             * @exception IOException if an input/output error occurs
1822:             */
1823:            private void copy(ResourceInfo resourceInfo, PrintWriter writer)
1824:                    throws IOException {
1825:
1826:                IOException exception = null;
1827:
1828:                InputStream resourceInputStream = resourceInfo.getStream();
1829:                // FIXME : i18n ?
1830:                Reader reader = new InputStreamReader(resourceInputStream);
1831:
1832:                // Copy the input stream to the output stream
1833:                exception = copyRange(reader, writer);
1834:
1835:                // Clean up the reader
1836:                try {
1837:                    reader.close();
1838:                } catch (Throwable t) {
1839:                    ;
1840:                }
1841:
1842:                // Rethrow any exception that has occurred
1843:                if (exception != null)
1844:                    throw exception;
1845:
1846:            }
1847:
1848:            /**
1849:             * Copy the contents of the specified input stream to the specified
1850:             * output stream, and ensure that both streams are closed before returning
1851:             * (even in the face of an exception).
1852:             *
1853:             * @param resourceInfo The ResourceInfo object
1854:             * @param ostream The output stream to write to
1855:             * @param range Range the client wanted to retrieve
1856:             * @exception IOException if an input/output error occurs
1857:             */
1858:            private void copy(ResourceInfo resourceInfo,
1859:                    ServletOutputStream ostream, Range range)
1860:                    throws IOException {
1861:
1862:                IOException exception = null;
1863:
1864:                InputStream resourceInputStream = resourceInfo.getStream();
1865:                InputStream istream = new BufferedInputStream(
1866:                        resourceInputStream, input);
1867:                exception = copyRange(istream, ostream, range.start, range.end);
1868:
1869:                // Clean up the input stream
1870:                try {
1871:                    istream.close();
1872:                } catch (Throwable t) {
1873:                    ;
1874:                }
1875:
1876:                // Rethrow any exception that has occurred
1877:                if (exception != null)
1878:                    throw exception;
1879:
1880:            }
1881:
1882:            /**
1883:             * Copy the contents of the specified input stream to the specified
1884:             * output stream, and ensure that both streams are closed before returning
1885:             * (even in the face of an exception).
1886:             *
1887:             * @param resourceInfo The ResourceInfo object
1888:             * @param writer The writer to write to
1889:             * @param range Range the client wanted to retrieve
1890:             * @exception IOException if an input/output error occurs
1891:             */
1892:            private void copy(ResourceInfo resourceInfo, PrintWriter writer,
1893:                    Range range) throws IOException {
1894:
1895:                IOException exception = null;
1896:
1897:                InputStream resourceInputStream = resourceInfo.getStream();
1898:                Reader reader = new InputStreamReader(resourceInputStream);
1899:                exception = copyRange(reader, writer, range.start, range.end);
1900:
1901:                // Clean up the input stream
1902:                try {
1903:                    reader.close();
1904:                } catch (Throwable t) {
1905:                    ;
1906:                }
1907:
1908:                // Rethrow any exception that has occurred
1909:                if (exception != null)
1910:                    throw exception;
1911:
1912:            }
1913:
1914:            /**
1915:             * Copy the contents of the specified input stream to the specified
1916:             * output stream, and ensure that both streams are closed before returning
1917:             * (even in the face of an exception).
1918:             *
1919:             * @param resourceInfo The ResourceInfo object
1920:             * @param ostream The output stream to write to
1921:             * @param ranges Enumeration of the ranges the client wanted to retrieve
1922:             * @param contentType Content type of the resource
1923:             * @exception IOException if an input/output error occurs
1924:             */
1925:            private void copy(ResourceInfo resourceInfo,
1926:                    ServletOutputStream ostream, Enumeration ranges,
1927:                    String contentType) throws IOException {
1928:
1929:                IOException exception = null;
1930:
1931:                while ((exception == null) && (ranges.hasMoreElements())) {
1932:
1933:                    InputStream resourceInputStream = resourceInfo.getStream();
1934:                    InputStream istream = // FIXME: internationalization???????
1935:                    new BufferedInputStream(resourceInputStream, input);
1936:
1937:                    Range currentRange = (Range) ranges.nextElement();
1938:
1939:                    // Writing MIME header.
1940:                    ostream.println("--" + mimeSeparation);
1941:                    if (contentType != null)
1942:                        ostream.println("Content-Type: " + contentType);
1943:                    ostream.println("Content-Range: bytes "
1944:                            + currentRange.start + "-" + currentRange.end + "/"
1945:                            + currentRange.length);
1946:                    ostream.println();
1947:
1948:                    // Printing content
1949:                    exception = copyRange(istream, ostream, currentRange.start,
1950:                            currentRange.end);
1951:
1952:                    try {
1953:                        istream.close();
1954:                    } catch (Throwable t) {
1955:                        ;
1956:                    }
1957:
1958:                }
1959:
1960:                ostream.print("--" + mimeSeparation + "--");
1961:
1962:                // Rethrow any exception that has occurred
1963:                if (exception != null)
1964:                    throw exception;
1965:
1966:            }
1967:
1968:            /**
1969:             * Copy the contents of the specified input stream to the specified
1970:             * output stream, and ensure that both streams are closed before returning
1971:             * (even in the face of an exception).
1972:             *
1973:             * @param resourceInfo The ResourceInfo object
1974:             * @param writer The writer to write to
1975:             * @param ranges Enumeration of the ranges the client wanted to retrieve
1976:             * @param contentType Content type of the resource
1977:             * @exception IOException if an input/output error occurs
1978:             */
1979:            private void copy(ResourceInfo resourceInfo, PrintWriter writer,
1980:                    Enumeration ranges, String contentType) throws IOException {
1981:
1982:                IOException exception = null;
1983:
1984:                while ((exception == null) && (ranges.hasMoreElements())) {
1985:
1986:                    InputStream resourceInputStream = resourceInfo.getStream();
1987:                    Reader reader = new InputStreamReader(resourceInputStream);
1988:
1989:                    Range currentRange = (Range) ranges.nextElement();
1990:
1991:                    // Writing MIME header.
1992:                    writer.println("--" + mimeSeparation);
1993:                    if (contentType != null)
1994:                        writer.println("Content-Type: " + contentType);
1995:                    writer.println("Content-Range: bytes " + currentRange.start
1996:                            + "-" + currentRange.end + "/"
1997:                            + currentRange.length);
1998:                    writer.println();
1999:
2000:                    // Printing content
2001:                    exception = copyRange(reader, writer, currentRange.start,
2002:                            currentRange.end);
2003:
2004:                    try {
2005:                        reader.close();
2006:                    } catch (Throwable t) {
2007:                        ;
2008:                    }
2009:
2010:                }
2011:
2012:                writer.print("--" + mimeSeparation + "--");
2013:
2014:                // Rethrow any exception that has occurred
2015:                if (exception != null)
2016:                    throw exception;
2017:
2018:            }
2019:
2020:            /**
2021:             * Copy the contents of the specified input stream to the specified
2022:             * output stream, and ensure that both streams are closed before returning
2023:             * (even in the face of an exception).
2024:             *
2025:             * @param istream The input stream to read from
2026:             * @param ostream The output stream to write to
2027:             * @return Exception which occurred during processing
2028:             */
2029:            private IOException copyRange(InputStream istream,
2030:                    ServletOutputStream ostream) {
2031:
2032:                // Copy the input stream to the output stream
2033:                IOException exception = null;
2034:                byte buffer[] = new byte[input];
2035:                int len = buffer.length;
2036:                while (true) {
2037:                    try {
2038:                        len = istream.read(buffer);
2039:                        if (len == -1)
2040:                            break;
2041:                        ostream.write(buffer, 0, len);
2042:                    } catch (IOException e) {
2043:                        exception = e;
2044:                        len = -1;
2045:                        break;
2046:                    }
2047:                }
2048:                return exception;
2049:
2050:            }
2051:
2052:            /**
2053:             * Copy the contents of the specified input stream to the specified
2054:             * output stream, and ensure that both streams are closed before returning
2055:             * (even in the face of an exception).
2056:             *
2057:             * @param reader The reader to read from
2058:             * @param writer The writer to write to
2059:             * @return Exception which occurred during processing
2060:             */
2061:            private IOException copyRange(Reader reader, PrintWriter writer) {
2062:
2063:                // Copy the input stream to the output stream
2064:                IOException exception = null;
2065:                char buffer[] = new char[input];
2066:                int len = buffer.length;
2067:                while (true) {
2068:                    try {
2069:                        len = reader.read(buffer);
2070:                        if (len == -1)
2071:                            break;
2072:                        writer.write(buffer, 0, len);
2073:                    } catch (IOException e) {
2074:                        exception = e;
2075:                        len = -1;
2076:                        break;
2077:                    }
2078:                }
2079:                return exception;
2080:
2081:            }
2082:
2083:            /**
2084:             * Copy the contents of the specified input stream to the specified
2085:             * output stream, and ensure that both streams are closed before returning
2086:             * (even in the face of an exception).
2087:             *
2088:             * @param istream The input stream to read from
2089:             * @param ostream The output stream to write to
2090:             * @param start Start of the range which will be copied
2091:             * @param end End of the range which will be copied
2092:             * @return Exception which occurred during processing
2093:             */
2094:            private IOException copyRange(InputStream istream,
2095:                    ServletOutputStream ostream, long start, long end) {
2096:
2097:                if (debug > 10)
2098:                    System.out.println("Serving bytes:" + start + "-" + end);
2099:
2100:                try {
2101:                    istream.skip(start);
2102:                } catch (IOException e) {
2103:                    return e;
2104:                }
2105:
2106:                IOException exception = null;
2107:                long bytesToRead = end - start + 1;
2108:
2109:                byte buffer[] = new byte[input];
2110:                int len = buffer.length;
2111:                while ((bytesToRead > 0) && (len >= buffer.length)) {
2112:                    try {
2113:                        len = istream.read(buffer);
2114:                        if (bytesToRead >= len) {
2115:                            ostream.write(buffer, 0, len);
2116:                            bytesToRead -= len;
2117:                        } else {
2118:                            ostream.write(buffer, 0, (int) bytesToRead);
2119:                            bytesToRead = 0;
2120:                        }
2121:                    } catch (IOException e) {
2122:                        exception = e;
2123:                        len = -1;
2124:                    }
2125:                    if (len < buffer.length)
2126:                        break;
2127:                }
2128:
2129:                return exception;
2130:
2131:            }
2132:
2133:            /**
2134:             * Copy the contents of the specified input stream to the specified
2135:             * output stream, and ensure that both streams are closed before returning
2136:             * (even in the face of an exception).
2137:             *
2138:             * @param reader The reader to read from
2139:             * @param writer The writer to write to
2140:             * @param start Start of the range which will be copied
2141:             * @param end End of the range which will be copied
2142:             * @return Exception which occurred during processing
2143:             */
2144:            private IOException copyRange(Reader reader, PrintWriter writer,
2145:                    long start, long end) {
2146:
2147:                try {
2148:                    reader.skip(start);
2149:                } catch (IOException e) {
2150:                    return e;
2151:                }
2152:
2153:                IOException exception = null;
2154:                long bytesToRead = end - start + 1;
2155:
2156:                char buffer[] = new char[input];
2157:                int len = buffer.length;
2158:                while ((bytesToRead > 0) && (len >= buffer.length)) {
2159:                    try {
2160:                        len = reader.read(buffer);
2161:                        if (bytesToRead >= len) {
2162:                            writer.write(buffer, 0, len);
2163:                            bytesToRead -= len;
2164:                        } else {
2165:                            writer.write(buffer, 0, (int) bytesToRead);
2166:                            bytesToRead = 0;
2167:                        }
2168:                    } catch (IOException e) {
2169:                        exception = e;
2170:                        len = -1;
2171:                    }
2172:                    if (len < buffer.length)
2173:                        break;
2174:                }
2175:
2176:                return exception;
2177:
2178:            }
2179:
2180:            /**
2181:             * Check to see if a default page exists.
2182:             *
2183:             * @param pathname Pathname of the file to be served
2184:             */
2185:            private ResourceInfo checkWelcomeFiles(String pathname,
2186:                    DirContext resources) {
2187:
2188:                String collectionName = pathname;
2189:                if (!pathname.endsWith("/")) {
2190:                    collectionName += "/";
2191:                }
2192:
2193:                // Refresh our currently defined set of welcome files
2194:                synchronized (welcomes) {
2195:                    welcomes = (String[]) getServletContext().getAttribute(
2196:                            "com.rimfaxe.webserver.WELCOME_FILES");
2197:                    if (welcomes == null)
2198:                        welcomes = new String[0];
2199:                }
2200:
2201:                // Serve a welcome resource or file if one exists
2202:                for (int i = 0; i < welcomes.length; i++) {
2203:
2204:                    // Does the specified resource exist?
2205:                    String resourceName = collectionName + welcomes[i];
2206:                    ResourceInfo resourceInfo = new ResourceInfo(resourceName,
2207:                            resources);
2208:                    if (resourceInfo.exists()) {
2209:                        return resourceInfo;
2210:                    }
2211:
2212:                }
2213:
2214:                return null;
2215:
2216:            }
2217:
2218:            // ------------------------------------------------------ Range Inner Class
2219:
2220:            private class Range {
2221:
2222:                public long start;
2223:                public long end;
2224:                public long length;
2225:
2226:                /**
2227:                 * Validate range.
2228:                 */
2229:                public boolean validate() {
2230:                    if (end >= length)
2231:                        end = length - 1;
2232:                    return ((start >= 0) && (end >= 0) && (start <= end) && (length > 0));
2233:                }
2234:
2235:                public void recycle() {
2236:                    start = 0;
2237:                    end = 0;
2238:                    length = 0;
2239:                }
2240:
2241:            }
2242:
2243:            // ----------------------------------------------  ResourceInfo Inner Class
2244:
2245:            protected class ResourceInfo {
2246:
2247:                /**
2248:                 * Constructor.
2249:                 *
2250:                 * @param pathname Path name of the file
2251:                 */
2252:                public ResourceInfo(String path, DirContext resources) {
2253:                    set(path, resources);
2254:                }
2255:
2256:                public Object object;
2257:                public DirContext directory;
2258:                public Resource file;
2259:                public Attributes attributes;
2260:                public String path;
2261:                public long creationDate;
2262:                public String httpDate;
2263:                public long date;
2264:                public long length;
2265:                public boolean collection;
2266:                public String weakETag;
2267:                public String strongETag;
2268:                public boolean exists;
2269:                public DirContext resources;
2270:                protected InputStream is;
2271:
2272:                public void recycle() {
2273:                    object = null;
2274:                    directory = null;
2275:                    file = null;
2276:                    attributes = null;
2277:                    path = null;
2278:                    creationDate = 0;
2279:                    httpDate = null;
2280:                    date = 0;
2281:                    length = -1;
2282:                    collection = true;
2283:                    weakETag = null;
2284:                    strongETag = null;
2285:                    exists = false;
2286:                    resources = null;
2287:                    is = null;
2288:                }
2289:
2290:                public void set(String path, DirContext resources) {
2291:
2292:                    recycle();
2293:
2294:                    this .path = path;
2295:                    this .resources = resources;
2296:                    exists = true;
2297:                    try {
2298:                        object = resources.lookup(path);
2299:                        if (object instanceof  Resource) {
2300:                            file = (Resource) object;
2301:                            collection = false;
2302:                        } else if (object instanceof  DirContext) {
2303:                            directory = (DirContext) object;
2304:                            collection = true;
2305:                        } else {
2306:                            // Don't know how to serve another object type
2307:                            exists = false;
2308:                        }
2309:                    } catch (NamingException e) {
2310:                        exists = false;
2311:                    }
2312:                    if (exists) {
2313:                        try {
2314:                            attributes = resources.getAttributes(path);
2315:                            if (attributes instanceof  ResourceAttributes) {
2316:                                ResourceAttributes tempAttrs = (ResourceAttributes) attributes;
2317:                                Date tempDate = tempAttrs.getCreationDate();
2318:                                if (tempDate != null)
2319:                                    creationDate = tempDate.getTime();
2320:                                tempDate = tempAttrs.getLastModifiedDate();
2321:
2322:                                if (tempDate != null) {
2323:                                    com.rimfaxe.util.Calendar tempCal = new com.rimfaxe.util.Calendar(
2324:                                            tempDate);
2325:                                    httpDate = tempCal.getHttpDate();
2326:
2327:                                    //httpDate = FastHttpDateFormat.getDate(tempDate);
2328:                                    date = tempDate.getTime();
2329:                                } else {
2330:                                    com.rimfaxe.util.Calendar tempCal = new com.rimfaxe.util.Calendar();
2331:                                    httpDate = tempCal.getHttpDate();
2332:
2333:                                    //httpDate = FastHttpDateFormat.getCurrentDate();
2334:                                }
2335:                                weakETag = tempAttrs.getETag();
2336:                                strongETag = tempAttrs.getETag(true);
2337:                                length = tempAttrs.getContentLength();
2338:                            }
2339:                        } catch (NamingException e) {
2340:                            // Shouldn't happen, the implementation of the DirContext
2341:                            // is probably broken
2342:                            exists = false;
2343:                        }
2344:                    }
2345:
2346:                }
2347:
2348:                /**
2349:                 * Test if the associated resource exists.
2350:                 */
2351:                public boolean exists() {
2352:                    return exists;
2353:                }
2354:
2355:                /**
2356:                 * String representation.
2357:                 */
2358:                public String toString() {
2359:                    return path;
2360:                }
2361:
2362:                /**
2363:                 * Set IS.
2364:                 */
2365:                public void setStream(InputStream is) {
2366:                    this .is = is;
2367:                }
2368:
2369:                /**
2370:                 * Get IS from resource.
2371:                 */
2372:                public InputStream getStream() throws IOException {
2373:                    if (is != null)
2374:                        return is;
2375:                    if (file != null)
2376:                        return (file.streamContent());
2377:                    else
2378:                        return null;
2379:                }
2380:
2381:            }
2382:
2383:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.