You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/07/10 20:42:41 UTC

svn commit: r420610 [2/3] - in /tomcat/sandbox: ./ bin/ java/org/apache/commons/logging/ java/org/apache/coyote/servlet/ java/org/apache/coyote/servlet/servlets/ java/org/apache/coyote/servlet/util/ java/org/apache/tomcat/servlets/file/ java/org/apache...

Added: tomcat/sandbox/java/org/apache/tomcat/servlets/file/WebdavServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/servlets/file/WebdavServlet.java?rev=420610&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/servlets/file/WebdavServlet.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/servlets/file/WebdavServlet.java Mon Jul 10 11:42:39 2006
@@ -0,0 +1,1822 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.tomcat.servlets.file;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.tomcat.servlets.util.RequestUtil;
+import org.apache.tomcat.servlets.util.XMLWriter;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+
+/**
+ * Servlet which adds support for WebDAV level 1. All the basic HTTP requests
+ * are handled by the DefaultServlet. 
+ * 
+ * Based on Catalina WebdavServlet, with following changes:
+ *  - removed the JNDI abstraction, use File instead
+ *  - removed WebDAV 2 support ( moved to Webdav2Servlet ) - i.e. no locks
+ *    supported
+ *  - simplified and cleaned up the code
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class WebdavServlet extends DefaultServlet {
+
+
+    // -------------------------------------------------------------- Constants
+
+    //protected static final String METHOD_HEAD = "HEAD";
+    protected static final String METHOD_PROPFIND = "PROPFIND";
+    protected static final String METHOD_PROPPATCH = "PROPPATCH";
+    protected static final String METHOD_MKCOL = "MKCOL";
+    protected static final String METHOD_COPY = "COPY";
+    protected static final String METHOD_DELETE = "DELETE";
+    protected static final String METHOD_MOVE = "MOVE";
+    protected static final String METHOD_LOCK = "LOCK";
+    protected static final String METHOD_UNLOCK = "UNLOCK";
+
+
+    /**
+     * Default depth is infite.
+     */
+    protected static final int INFINITY = 3; // To limit tree browsing a bit
+
+
+    /**
+     * PROPFIND - Specify a property mask.
+     */
+    protected static final int FIND_BY_PROPERTY = 0;
+
+
+    /**
+     * PROPFIND - Display all properties.
+     */
+    protected static final int FIND_ALL_PROP = 1;
+
+
+    /**
+     * PROPFIND - Return property names.
+     */
+    protected static final int FIND_PROPERTY_NAMES = 2;
+
+    /**
+     * Default namespace.
+     */
+    protected static final String DEFAULT_NAMESPACE = "DAV:";
+
+
+    /**
+     * Simple date format for the creation date ISO representation (partial).
+     * TODO: ThreadLocal
+     */
+    protected static final SimpleDateFormat creationDateFormat =
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+
+
+    static {
+        creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+    }
+
+    // TODO: replace it with writeRole - who is enabled to write
+    protected boolean readOnly = false;
+
+    /**
+     * Repository of the lock-null resources.
+     * <p>
+     * Key : path of the collection containing the lock-null resource<br>
+     * Value : Vector of lock-null resource which are members of the
+     * collection. Each element of the Vector is the path associated with
+     * the lock-null resource.
+     */
+    protected Hashtable lockNullResources = new Hashtable();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init()
+        throws ServletException {
+
+        super.init();
+
+        try {
+            String value = getServletConfig().getInitParameter("readonly");
+            if (value != null)
+                readOnly = (new Boolean(value)).booleanValue();
+        } catch (Throwable t) {
+            ;
+        }
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+    /**
+     * Handles the special WebDAV methods.
+     */
+    protected void service(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        String method = req.getMethod();
+
+        if (method.equals(METHOD_PROPFIND)) {
+            doPropfind(req, resp);
+        } else if (method.equals(METHOD_PROPPATCH)) {
+            doProppatch(req, resp);
+        } else if (method.equals(METHOD_MKCOL)) {
+            doMkcol(req, resp);
+        } else if (method.equals(METHOD_COPY)) {
+            doCopy(req, resp);
+        } else if (method.equals(METHOD_MOVE)) {
+            doMove(req, resp);
+        } else if (method.equals(METHOD_LOCK)) {
+            doLock(req, resp);
+        } else if (method.equals(METHOD_UNLOCK)) {
+            doUnlock(req, resp);
+        } else if (method.equals(METHOD_DELETE)) {
+            doDelete(req, resp);
+        } else {
+            // DefaultServlet processing
+            super.service(req, resp);
+        }
+
+    }
+
+    /**
+     * Check if the conditions specified in the optional If headers are
+     * satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceAttributes The resource information
+     * @return boolean true if the resource meets all the specified conditions,
+     * and false if any of the conditions is not satisfied, in which case
+     * request processing is stopped
+     */
+    protected boolean checkIfHeaders(HttpServletRequest request,
+                                     HttpServletResponse response,
+                                     File resourceAttributes)
+        throws IOException {
+
+        if (!super.checkIfHeaders(request, response, resourceAttributes))
+            return false;
+
+        // TODO : Checking the WebDAV If header
+        return true;
+
+    }
+
+
+    /**
+     * OPTIONS Method.
+     *
+     * @param req The request
+     * @param resp The response
+     * @throws ServletException If an error occurs
+     * @throws IOException If an IO error occurs
+     */
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.addHeader("DAV", "1"); // And not: ,2");
+
+        StringBuffer methodsAllowed = determineMethodsAllowed(basePath,
+                                                              req);
+        resp.addHeader("Allow", methodsAllowed.toString());
+        resp.addHeader("MS-Author-Via", "DAV");
+    }
+
+    // ------------------ PROPFIND --------------------
+
+    /**
+     * PROPFIND Method.
+     */
+    protected void doPropfind(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        String path = getRelativePath(req);
+        if (path.endsWith("/"))
+            path = path.substring(0, path.length() - 1);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        // Propfind depth
+        int depth = getDepth(req);
+
+        File object = new File(basePath, path);
+
+        if (!object.exists()) {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
+            return;
+        }
+
+        // Properties which are to be displayed.
+        Vector properties = new Vector();
+        int type = getPropfindType(req, properties);
+
+        resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
+        resp.setContentType("text/xml; charset=UTF-8");
+
+        // Create multistatus object
+        XMLWriter generatedXML = new XMLWriter(resp.getWriter());
+        generatedXML.writeXMLHeader();
+
+        generatedXML.writeElement(null, "multistatus"
+                                  + generateNamespaceDeclarations(),
+                                  XMLWriter.OPENING);
+
+        if (depth == 0) {
+            parseProperties(req, generatedXML, path, type,
+                            properties);
+        } else {
+            propfindRecurse(req, path, depth, properties, 
+                    type, generatedXML);
+        }
+
+        generatedXML.writeElement(null, "multistatus",
+                                  XMLWriter.CLOSING);
+        generatedXML.sendData();
+    }
+
+
+    private void propfindRecurse(HttpServletRequest req, String path, int depth, Vector properties, int type, XMLWriter generatedXML) throws IOException {
+        File object;
+        // The stack always contains the object of the current level
+        Stack stack = new Stack();
+        stack.push(path);
+
+        // Stack of the objects one level below
+        Stack stackBelow = new Stack();
+
+        while ((!stack.isEmpty()) && (depth >= 0)) {
+            String currentPath = (String) stack.pop();
+            parseProperties(req, generatedXML, currentPath,
+                            type, properties);
+
+            object = new File(basePath,currentPath);
+            if (!object.exists()) {
+                continue;
+            }
+
+            if ((object.isDirectory()) && (depth > 0)) {
+
+                File[] files = object.listFiles();
+                for (int i=0; i < files.length; i++) {
+                    String newPath = currentPath;
+                    if (!(newPath.endsWith("/")))
+                        newPath += "/";
+                    newPath += files[i].getName();
+                    stackBelow.push(newPath);
+                }
+            }
+
+            if (stack.isEmpty()) {
+                depth--;
+                stack = stackBelow;
+                stackBelow = new Stack();
+            }
+
+            generatedXML.sendData();
+        }
+    }
+
+
+    private int getPropfindType(HttpServletRequest req, Vector properties) throws ServletException {
+        // Propfind type
+        int type = FIND_ALL_PROP;
+
+        DocumentBuilder documentBuilder = getDocumentBuilder();
+        try {
+            Document document = documentBuilder.parse
+                (new InputSource(req.getInputStream()));
+            // Get the root element of the document
+            Element rootElement = document.getDocumentElement();
+            NodeList childList = rootElement.getChildNodes();
+
+            for (int i=0; i < childList.getLength(); i++) {
+                Node currentNode = childList.item(i);
+                switch (currentNode.getNodeType()) {
+                case Node.TEXT_NODE:
+                    break;
+                case Node.ELEMENT_NODE:
+                    if (currentNode.getNodeName().endsWith("prop")) {
+                        type = FIND_BY_PROPERTY;
+                        Node propNode = currentNode;
+                        NodeList childListPN = propNode.getChildNodes();
+                        for (int iPN=0; iPN < childListPN.getLength(); iPN++) {
+                            Node currentNodePN = childListPN.item(iPN);
+                            switch (currentNodePN.getNodeType()) {
+                            case Node.TEXT_NODE:
+                                break;
+                            case Node.ELEMENT_NODE:
+                                String nodeName = currentNodePN.getNodeName();
+                                String propertyName = null;
+                                if (nodeName.indexOf(':') != -1) {
+                                    propertyName = nodeName.substring
+                                        (nodeName.indexOf(':') + 1);
+                                } else {
+                                    propertyName = nodeName;
+                                }
+                                // href is a live property which is handled differently
+                                properties.addElement(propertyName);
+                                break;
+                            }
+                        }
+                    }
+                    if (currentNode.getNodeName().endsWith("propname")) {
+                        type = FIND_PROPERTY_NAMES;
+                    }
+                    if (currentNode.getNodeName().endsWith("allprop")) {
+                        type = FIND_ALL_PROP;
+                    }
+                    break;
+                }
+            }
+        } catch(Exception e) {
+            // Most likely there was no content : we use the defaults.
+            // TODO : Enhance that !
+        }
+        return type;
+    }
+
+
+    private int getDepth(HttpServletRequest req) {
+        int depth = INFINITY;
+        String depthStr = req.getHeader("Depth");
+
+        if (depthStr == null) {
+            depth = INFINITY;
+        } else {
+            if (depthStr.equals("0")) {
+                depth = 0;
+            } else if (depthStr.equals("1")) {
+                depth = 1;
+            } else if (depthStr.equals("infinity")) {
+                depth = INFINITY;
+            }
+        }
+        return depth;
+    }
+
+
+    /**
+     * Propfind helper method.
+     *
+     * @param req The servlet request
+     * @param resources Resources object associated with this context
+     * @param out XML response to the Propfind request
+     * @param path Path of the current resource
+     * @param type Propfind type
+     * @param propertiesVector If the propfind type is find properties by
+     * name, then this Vector contains those properties
+     */
+    protected void parseProperties(HttpServletRequest req,
+                                 XMLWriter out,
+                                 String path, int type,
+                                 Vector propertiesVector) {
+
+        // Exclude any resource in the /WEB-INF and /META-INF subdirectories
+        // (the "toUpperCase()" avoids problems on Windows systems)
+        if (path.toUpperCase().startsWith("/WEB-INF") ||
+            path.toUpperCase().startsWith("/META-INF"))
+            return;
+
+        File cacheEntry = new File(basePath, path);
+
+        out.writeElement(null, "response", XMLWriter.OPENING);
+        String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+                                   + WebdavStatus.getStatusText
+                                   (WebdavStatus.SC_OK));
+
+        // Generating href element
+        out.writeElement(null, "href", XMLWriter.OPENING);
+
+        String href = req.getContextPath();// + req.getServletPath() + 
+        //  req.getPathInfo();
+        
+        // ??? 
+        if ((href.endsWith("/")) && (path.startsWith("/")))
+            href += path.substring(1);
+        else
+            href += path;
+        if ((cacheEntry.isDirectory()) && (!href.endsWith("/")))
+            href += "/";
+
+        out.writeText(rewriteUrl(href));
+
+        out.writeElement(null, "href", XMLWriter.CLOSING);
+
+        String resourceName = path;
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash != -1)
+            resourceName = resourceName.substring(lastSlash + 1);
+
+        switch (type) {
+
+        case FIND_ALL_PROP :
+
+            out.writeElement(null, "propstat", XMLWriter.OPENING);
+            out.writeElement(null, "prop", XMLWriter.OPENING);
+
+            out.writeProperty
+                (null, "creationdate",
+                 getISOCreationDate(cacheEntry.lastModified()));
+            out.writeElement(null, "displayname", XMLWriter.OPENING);
+            out.writeData(resourceName);
+            out.writeElement(null, "displayname", XMLWriter.CLOSING);
+            if (!cacheEntry.isDirectory()) {
+                out.writeProperty(null, "getlastmodified", 
+                        FastHttpDateFormat.formatDate(cacheEntry.lastModified(), 
+                                null));
+                out.writeProperty(null, "getcontentlength",  
+                        String.valueOf(cacheEntry.length()));
+                String contentType = 
+                    getServletContext().getMimeType(cacheEntry.getName());
+                if (contentType != null) {
+                    out.writeProperty(null, "getcontenttype",  contentType);
+                }
+                out.writeProperty(null, "getetag",  getETag(cacheEntry));
+                out.writeElement(null, "resourcetype", XMLWriter.NO_CONTENT);
+            } else {
+                out.writeElement(null, "resourcetype", XMLWriter.OPENING);
+                out.writeElement(null, "collection", XMLWriter.NO_CONTENT);
+                out.writeElement(null, "resourcetype", XMLWriter.CLOSING);
+            }
+
+            out.writeProperty(null, "source", "");
+            out.writeElement(null, "prop", XMLWriter.CLOSING);
+            out.writeElement(null, "status", XMLWriter.OPENING);
+            out.writeText(status);
+            out.writeElement(null, "status", XMLWriter.CLOSING);
+            out.writeElement(null, "propstat", XMLWriter.CLOSING);
+            break;
+
+        case FIND_PROPERTY_NAMES :
+            out.writeElement(null, "propstat", XMLWriter.OPENING);
+            out.writeElement(null, "prop", XMLWriter.OPENING);
+            out.writeElement(null, "creationdate",  XMLWriter.NO_CONTENT);
+            out.writeElement(null, "displayname", XMLWriter.NO_CONTENT);
+            if (! cacheEntry.isDirectory()) {
+                out.writeElement(null, "getcontentlanguage",
+                                          XMLWriter.NO_CONTENT);
+                out.writeElement(null, "getcontentlength",
+                                          XMLWriter.NO_CONTENT);
+                out.writeElement(null, "getcontenttype",
+                                          XMLWriter.NO_CONTENT);
+                out.writeElement(null, "getetag",
+                                          XMLWriter.NO_CONTENT);
+                out.writeElement(null, "getlastmodified",
+                                          XMLWriter.NO_CONTENT);
+            }
+            out.writeElement(null, "resourcetype", XMLWriter.NO_CONTENT);
+            out.writeElement(null, "source", XMLWriter.NO_CONTENT);
+            out.writeElement(null, "lockdiscovery", XMLWriter.NO_CONTENT);
+
+            out.writeElement(null, "prop", XMLWriter.CLOSING);
+            out.writeElement(null, "status", XMLWriter.OPENING);
+            out.writeText(status);
+            out.writeElement(null, "status", XMLWriter.CLOSING);
+            out.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            break;
+
+        case FIND_BY_PROPERTY :
+
+            Vector propertiesNotFound = new Vector();
+
+            // Parse the list of properties
+            out.writeElement(null, "propstat", XMLWriter.OPENING);
+            out.writeElement(null, "prop", XMLWriter.OPENING);
+
+            genPropertiesFound(out, propertiesVector, cacheEntry, 
+                    resourceName, propertiesNotFound);
+
+            out.writeElement(null, "prop", XMLWriter.CLOSING);
+            out.writeElement(null, "status", XMLWriter.OPENING);
+            out.writeText(status);
+            out.writeElement(null, "status", XMLWriter.CLOSING);
+            out.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            Enumeration propertiesNotFoundList = propertiesNotFound.elements();
+
+            if (propertiesNotFoundList.hasMoreElements()) {
+                status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+                                    + " " + WebdavStatus.getStatusText
+                                    (WebdavStatus.SC_NOT_FOUND));
+
+                out.writeElement(null, "propstat", XMLWriter.OPENING);
+                out.writeElement(null, "prop", XMLWriter.OPENING);
+                while (propertiesNotFoundList.hasMoreElements()) {
+                    out.writeElement
+                        (null, (String) propertiesNotFoundList.nextElement(),
+                         XMLWriter.NO_CONTENT);
+                }
+                out.writeElement(null, "prop", XMLWriter.CLOSING);
+                out.writeElement(null, "status", XMLWriter.OPENING);
+                out.writeText(status);
+                out.writeElement(null, "status", XMLWriter.CLOSING);
+                out.writeElement(null, "propstat", XMLWriter.CLOSING);
+            }
+            break;
+
+        }
+
+        out.writeElement(null, "response", XMLWriter.CLOSING);
+    }
+
+
+    private void genPropertiesFound(XMLWriter out, Vector propertiesVector, 
+                                    File cacheEntry, String resourceName, 
+                                    Vector propertiesNotFound) {
+        Enumeration properties = propertiesVector.elements();
+
+        while (properties.hasMoreElements()) {
+            String property = (String) properties.nextElement();
+            if (property.equals("creationdate")) {
+                out.writeProperty(null, "creationdate",
+                     getISOCreationDate(cacheEntry.lastModified()));
+            } else if (property.equals("displayname")) {
+                out.writeElement(null, "displayname", XMLWriter.OPENING);
+                out.writeData(resourceName);
+                out.writeElement(null, "displayname", XMLWriter.CLOSING);
+            } else if (property.equals("getcontentlanguage")) {
+                if (cacheEntry.isDirectory()) {
+                    propertiesNotFound.addElement(property);
+                } else {
+                    out.writeElement(null, "getcontentlanguage",
+                            XMLWriter.NO_CONTENT);
+                }
+            } else if (property.equals("getcontentlength")) {
+                if (cacheEntry.isDirectory()) {
+                    propertiesNotFound.addElement(property);
+                } else {
+                    out.writeProperty(null, "getcontentlength",
+                         (String.valueOf(cacheEntry.length())));
+                }
+            } else if (property.equals("getcontenttype")) {
+                if (cacheEntry.isDirectory()) {
+                    propertiesNotFound.addElement(property);
+                } else {
+                    out.writeProperty(null, "getcontenttype",
+                         getServletContext().getMimeType(cacheEntry.getName()));
+                }
+            } else if (property.equals("getetag")) {
+                if (cacheEntry.isDirectory()) {
+                    propertiesNotFound.addElement(property);
+                } else {
+                    out.writeProperty(null, "getetag", getETag(cacheEntry));
+                }
+            } else if (property.equals("getlastmodified")) {
+                if (cacheEntry.isDirectory()) {
+                    propertiesNotFound.addElement(property);
+                } else {
+                    out.writeProperty(null, "getlastmodified", 
+                            FastHttpDateFormat
+                            .formatDate(cacheEntry.lastModified(), null));
+                }
+            } else if (property.equals("resourcetype")) {
+                if (cacheEntry.isDirectory()) {
+                    out.writeElement(null, "resourcetype",
+                                              XMLWriter.OPENING);
+                    out.writeElement(null, "collection",
+                                              XMLWriter.NO_CONTENT);
+                    out.writeElement(null, "resourcetype",
+                                              XMLWriter.CLOSING);
+                } else {
+                    out.writeElement(null, "resourcetype",
+                                              XMLWriter.NO_CONTENT);
+                }
+            } else if (property.equals("source")) {
+                out.writeProperty(null, "source", "");
+            } else if (property.equals("supportedlock")) {
+                // TODO: hook for Webdav2
+                propertiesNotFound.addElement(property);
+            } else if (property.equals("lockdiscovery")) {
+                propertiesNotFound.addElement(property);
+            } else {
+                propertiesNotFound.addElement(property);
+            }
+
+        }
+    }
+
+    // ------------------ PROPPATCH --------------------
+    
+    /**
+     * PROPPATCH Method.
+     */
+    protected void doProppatch(HttpServletRequest req,
+                               HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.sendError(WebdavStatus.SC_FORBIDDEN);
+    }
+
+    // ------------------ MKCOL --------------------
+
+    /**
+     * MKCOL Method.
+     */
+    protected void doMkcol(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        File object = new File(basePath,path);
+        
+        // Can't create a collection if a resource already exists at the given
+        // path
+        if (object.exists()) {
+            // Get allowed methods
+            StringBuffer methodsAllowed = determineMethodsAllowed(basePath,
+                                                                  req);
+
+            resp.addHeader("Allow", methodsAllowed.toString());
+
+            resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+
+        if (req.getInputStream().available() > 0) {
+            DocumentBuilder documentBuilder = getDocumentBuilder();
+            try {
+                Document document = documentBuilder.parse
+                    (new InputSource(req.getInputStream()));
+                // TODO : Process this request body
+                resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED);
+                return;
+
+            } catch(SAXException saxe) {
+                // Parse error - assume invalid content
+                resp.sendError(WebdavStatus.SC_BAD_REQUEST);
+                return;
+            }
+        }
+
+        boolean result = true;
+        
+        File newDir = new File(basePath, path);
+        result = newDir.mkdir();
+
+        if (!result) {
+            resp.sendError(WebdavStatus.SC_CONFLICT,
+                           WebdavStatus.getStatusText
+                           (WebdavStatus.SC_CONFLICT));
+        } else {
+            resp.setStatus(WebdavStatus.SC_CREATED);
+            // Removing any lock-null resource which would be present
+            lockNullResources.remove(path);
+        }
+
+    }
+
+    /**
+     * DELETE Method.
+     */
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        deleteResource(req, resp);
+
+    }
+
+
+    /**
+     * This is not part of DefaultServlet - all PUT and write operations
+     * should be handled by webdav servlet, which allows more control
+     */
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        if (readOnly) {
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        if (path.indexOf("..") >= 0) {
+            // not supported, too dangerous
+            // what else to escape ?
+            resp.setStatus(404);
+            return;
+        }
+
+        File resFile = new File(basePath, path);
+        boolean exists = resFile.exists();
+        
+        // extra check
+        if (!resFile.getCanonicalPath().startsWith(basePathName)) {
+            //log.info("File outside basedir " + basePathS + " " + f);
+            resp.setStatus(404);
+            return;
+        }
+
+
+        boolean result = true;
+
+        // Temp. content file used to support partial PUT
+        //File contentFile = null;
+
+        Range range = parseContentRange(req, resp);
+
+        InputStream resourceInputStream = null;
+
+        // Append data specified in ranges to existing content for this
+        // resource - create a temp. file on the local filesystem to
+        // perform this operation
+        // Assume just one range is specified for now
+        if (range != null) {
+            //contentFile = executePartialPut(req, range, path);
+            //resourceInputStream = new FileInputStream(contentFile);
+            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
+            return;
+        } else {
+            resourceInputStream = req.getInputStream();
+        }
+
+        try {
+            // will override 
+            FileOutputStream fos = new FileOutputStream(resFile);
+            copy(resourceInputStream, fos);
+        } catch(IOException e) {
+            result = false;
+        }
+
+        if (result) {
+            if (exists) {
+                resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
+            } else {
+                resp.setStatus(HttpServletResponse.SC_CREATED);
+            }
+        } else {
+            resp.sendError(HttpServletResponse.SC_CONFLICT);
+        }
+
+        // Removing any lock-null resource which would be present
+        lockNullResources.remove(path);
+    }
+
+
+    /**
+     * Handle a partial PUT.  New content specified in request is appended to
+     * existing content in oldRevisionContent (if present). This code does
+     * not support simultaneous partial updates to the same resource.
+     */
+//    protected File executePartialPut(HttpServletRequest req, Range range,
+//                                     String path)
+//        throws IOException {
+//
+//        // Append data specified in ranges to existing content for this
+//        // resource - create a temp. file on the local filesystem to
+//        // perform this operation
+//        File tempDir = (File) getServletContext().getAttribute
+//            ("javax.servlet.context.tempdir");
+//        // Convert all '/' characters to '.' in resourcePath
+//        String convertedResourcePath = path.replace('/', '.');
+//        File contentFile = new File(tempDir, convertedResourcePath);
+//        if (contentFile.createNewFile()) {
+//            // Clean up contentFile when Tomcat is terminated
+//            contentFile.deleteOnExit();
+//        }
+//
+//        RandomAccessFile randAccessContentFile =
+//            new RandomAccessFile(contentFile, "rw");
+//
+//        Resource oldResource = null;
+//        try {
+//            Object obj = resources.lookup(path);
+//            if (obj instanceof Resource)
+//                oldResource = (Resource) obj;
+//        } catch (NamingException e) {
+//        }
+//
+//        // Copy data in oldRevisionContent to contentFile
+//        if (oldResource != null) {
+//            BufferedInputStream bufOldRevStream =
+//                new BufferedInputStream(oldResource.streamContent(),
+//                                        BUFFER_SIZE);
+//
+//            int numBytesRead;
+//            byte[] copyBuffer = new byte[BUFFER_SIZE];
+//            while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
+//                randAccessContentFile.write(copyBuffer, 0, numBytesRead);
+//            }
+//
+//            bufOldRevStream.close();
+//        }
+//
+//        randAccessContentFile.setLength(range.length);
+//
+//        // Append data in request input stream to contentFile
+//        randAccessContentFile.seek(range.start);
+//        int numBytesRead;
+//        byte[] transferBuffer = new byte[BUFFER_SIZE];
+//        BufferedInputStream requestBufInStream =
+//            new BufferedInputStream(req.getInputStream(), BUFFER_SIZE);
+//        while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
+//            randAccessContentFile.write(transferBuffer, 0, numBytesRead);
+//        }
+//        randAccessContentFile.close();
+//        requestBufInStream.close();
+//
+//        return contentFile;
+//
+//    }
+
+
+    /**
+     * COPY Method.
+     */
+    protected void doCopy(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        copyResource(req, resp);
+    }
+
+
+    /**
+     * MOVE Method.
+     */
+    protected void doMove(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        if (copyResource(req, resp)) {
+            deleteResource(path, req, resp, false);
+        }
+
+    }
+
+
+    /**
+     * LOCK Method.
+     */
+    protected void doLock(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED);
+    }
+
+    /**
+     * UNLOCK Method.
+     */
+    protected void doUnlock(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED);
+    }
+
+    // -------------------------------------------------------- protected Methods
+
+    /**
+     * Generate the namespace declarations.
+     */
+    protected String generateNamespaceDeclarations() {
+        return " xmlns=\"" + DEFAULT_NAMESPACE + "\"";
+    }
+
+
+    /**
+     * Check to see if a resource is currently write locked. The method
+     * will look at the "If" header to make sure the client
+     * has give the appropriate lock tokens.
+     *
+     * @param req Servlet request
+     * @return boolean true if the resource is locked (and no appropriate
+     * lock token has been found for at least one of the non-shared locks which
+     * are present on the resource).
+     */
+    protected boolean isLocked(HttpServletRequest req) {
+        return false;
+    }
+
+    /**
+     * Check to see if a resource is currently write locked.
+     *
+     * @param path Path of the resource
+     * @param ifHeader "If" HTTP header which was included in the request
+     * @return boolean true if the resource is locked (and no appropriate
+     * lock token has been found for at least one of the non-shared locks which
+     * are present on the resource).
+     */
+    protected boolean isLocked(String path, String ifHeader) {
+        return false;
+    }
+
+
+    /**
+     * Copy a resource.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @return boolean true if the copy is successful
+     */
+    protected boolean copyResource(HttpServletRequest req,
+                                 HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        // Parsing destination header
+
+        String destinationPath = req.getHeader("Destination");
+
+        if (destinationPath == null) {
+            resp.sendError(WebdavStatus.SC_BAD_REQUEST);
+            return false;
+        }
+
+        // Remove url encoding from destination
+        destinationPath = RequestUtil.URLDecode(destinationPath, "UTF8");
+
+        destinationPath = removeDestinationPrefix(req, destinationPath);
+
+        // Normalise destination path (remove '.' and '..')
+        destinationPath = normalize(destinationPath);
+
+        String contextPath = req.getContextPath();
+        if ((contextPath != null) &&
+            (destinationPath.startsWith(contextPath))) {
+            destinationPath = destinationPath.substring(contextPath.length());
+        }
+
+        String pathInfo = req.getPathInfo();
+        if (pathInfo != null) {
+            String servletPath = req.getServletPath();
+            if ((servletPath != null) &&
+                (destinationPath.startsWith(servletPath))) {
+                destinationPath = destinationPath.substring(servletPath.length());
+            }
+        }
+
+
+        if ((destinationPath.toUpperCase().startsWith("/WEB-INF")) ||
+            (destinationPath.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        String path = getRelativePath(req);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        if (destinationPath.equals(path)) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        // Parsing overwrite header
+
+        boolean overwrite = true;
+        String overwriteHeader = req.getHeader("Overwrite");
+
+        if (overwriteHeader != null) {
+            if (overwriteHeader.equalsIgnoreCase("T")) {
+                overwrite = true;
+            } else {
+                overwrite = false;
+            }
+        }
+
+        // Overwriting the destination
+
+        boolean exists = true;
+        File f1 = new File(basePath, destinationPath);
+        if (!f1.exists()) {
+            exists = false;
+        }
+
+        if (overwrite) {
+            // Delete destination resource, if it exists
+            if (exists) {
+                if (!deleteResource(destinationPath, req, resp, true)) {
+                    return false;
+                }
+            } else {
+                resp.setStatus(WebdavStatus.SC_CREATED);
+            }
+        } else {
+            // If the destination exists, then it's a conflict
+            if (exists) {
+                resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
+                return false;
+            }
+        }
+
+        // Copying source to destination
+
+        Hashtable errorList = new Hashtable();
+
+        boolean result = copyResource(basePath, errorList,
+                                      path, destinationPath);
+
+        if ((!result) || (!errorList.isEmpty())) {
+            sendReport(req, resp, errorList);
+            return false;
+        }
+
+        // Removing any lock-null resource which would be present at
+        // the destination path
+        lockNullResources.remove(destinationPath);
+        return true;
+
+    }
+
+
+    private String removeDestinationPrefix(HttpServletRequest req, 
+                                           String destinationPath) {
+        int protocolIndex = destinationPath.indexOf("://");
+        if (protocolIndex >= 0) {
+            // if the Destination URL contains the protocol, we can safely
+            // trim everything upto the first "/" character after "://"
+            int firstSeparator =
+                destinationPath.indexOf("/", protocolIndex + 4);
+            if (firstSeparator < 0) {
+                destinationPath = "/";
+            } else {
+                destinationPath = destinationPath.substring(firstSeparator);
+            }
+        } else {
+            String hostName = req.getServerName();
+            if ((hostName != null) && (destinationPath.startsWith(hostName))) {
+                destinationPath = destinationPath.substring(hostName.length());
+            }
+
+            int portIndex = destinationPath.indexOf(":");
+            if (portIndex >= 0) {
+                destinationPath = destinationPath.substring(portIndex);
+            }
+
+            if (destinationPath.startsWith(":")) {
+                int firstSeparator = destinationPath.indexOf("/");
+                if (firstSeparator < 0) {
+                    destinationPath = "/";
+                } else {
+                    destinationPath =
+                        destinationPath.substring(firstSeparator);
+                }
+            }
+        }
+        return destinationPath;
+    }
+
+
+    /**
+     * Copy a collection.
+     *
+     * @param resources Resources implementation to be used
+     * @param errorList Hashtable containing the list of errors which occurred
+     * during the copy operation
+     * @param source Path of the resource to be copied
+     * @param dest Destination path
+     */
+    protected boolean copyResource(File resources, Hashtable errorList,
+                                   String source, String dest) {
+
+        File object = new File(basePath, source);
+        File destF = new File(basePath, dest);
+        
+        if (object.isDirectory()) {
+
+            boolean done = destF.mkdirs();
+            if (!done) {
+                errorList.put
+                    (dest, new Integer(WebdavStatus.SC_CONFLICT));
+                return false;
+            }
+
+            File[] enumeration = object.listFiles();
+            for (int i=0; i<enumeration.length; i++) {
+                String childDest = dest;
+                if (!childDest.equals("/"))
+                    childDest += "/";
+                childDest += enumeration[i].getName();
+                String childSrc = source;
+                if (!childSrc.equals("/"))
+                    childSrc += "/";
+                childSrc += enumeration[i].getName();
+                copyResource(resources, errorList, childSrc, childDest);
+            }
+
+        } else {
+
+            try {
+                super.copy( new FileInputStream(object), 
+                    new FileOutputStream(dest));
+            } catch(IOException ex ) {
+                errorList.put
+                (source,
+                        new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                return false;
+            }
+
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Delete a resource.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @return boolean true if the copy is successful
+     */
+    protected boolean deleteResource(HttpServletRequest req,
+                                   HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        String path = getRelativePath(req);
+
+        return deleteResource(path, req, resp, true);
+
+    }
+
+
+    /**
+     * Delete a resource.
+     *
+     * @param path Path of the resource which is to be deleted
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @param setStatus Should the response status be set on successful
+     *                  completion
+     */
+    protected boolean deleteResource(String path, HttpServletRequest req,
+                                   HttpServletResponse resp, boolean setStatus)
+        throws ServletException, IOException {
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        String ifHeader = req.getHeader("If");
+        if (ifHeader == null)
+            ifHeader = "";
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        if (isLocked(path, ifHeader + lockTokenHeader)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return false;
+        }
+
+        boolean exists = true;
+        File object = new File(basePath, path);
+        if (!object.exists()) {
+            exists = false;
+        }
+
+        if (!exists) {
+            resp.sendError(WebdavStatus.SC_NOT_FOUND);
+            return false;
+        }
+
+        boolean collection = object.isDirectory();
+
+        if (!collection) {
+            boolean deleted = object.delete();
+            if (!deleted) {
+                resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
+                return false;
+            }
+        } else {
+
+            Hashtable errorList = new Hashtable();
+
+            deleteCollection(req, basePath, path, errorList);
+            boolean deleted = object.delete();
+            if (!deleted) {
+                errorList.put(path, new Integer
+                    (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+            }
+
+            if (!errorList.isEmpty()) {
+
+                sendReport(req, resp, errorList);
+                return false;
+
+            }
+
+        }
+        if (setStatus) {
+            resp.setStatus(WebdavStatus.SC_NO_CONTENT);
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Deletes a collection.
+     *
+     * @param resources Resources implementation associated with the context
+     * @param path Path to the collection to be deleted
+     * @param errorList Contains the list of the errors which occurred
+     */
+    protected void deleteCollection(HttpServletRequest req,
+                                  File resources,
+                                  String path, Hashtable errorList) {
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN));
+            return;
+        }
+
+        String ifHeader = req.getHeader("If");
+        if (ifHeader == null)
+            ifHeader = "";
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        File f = new File(basePath, path);
+        File[] enumeration = f.listFiles();
+
+        for (int i=0; i<enumeration.length; i++) {
+            String childName = path;
+            if (!childName.equals("/"))
+                childName += "/";
+            
+            childName += enumeration[i].getName();
+
+            if (isLocked(childName, ifHeader + lockTokenHeader)) {
+
+                errorList.put(childName, new Integer(WebdavStatus.SC_LOCKED));
+
+            } else {
+                File object = enumeration[i];
+                if (object.isDirectory()) {
+                    deleteCollection(req, resources, childName, errorList);
+                }
+                
+                boolean deleted = object.delete();
+                if (!deleted) {
+                    if (!(object.isDirectory())) {
+                        // If it's not a collection, then it's an unknown
+                        // error
+                        errorList.put
+                        (childName, new Integer
+                                (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                    }
+                }
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Send a multistatus element containing a complete error report to the
+     * client.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @param errorList List of error to be displayed
+     */
+    protected void sendReport(HttpServletRequest req, HttpServletResponse resp,
+                            Hashtable errorList)
+        throws ServletException, IOException {
+
+        resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
+
+        String absoluteUri = req.getRequestURI();
+        String relativePath = getRelativePath(req);
+
+        XMLWriter generatedXML = new XMLWriter();
+        generatedXML.writeXMLHeader();
+
+        generatedXML.writeElement(null, "multistatus"
+                                  + generateNamespaceDeclarations(),
+                                  XMLWriter.OPENING);
+
+        Enumeration pathList = errorList.keys();
+        while (pathList.hasMoreElements()) {
+
+            String errorPath = (String) pathList.nextElement();
+            int errorCode = ((Integer) errorList.get(errorPath)).intValue();
+
+            generatedXML.writeElement(null, "response", XMLWriter.OPENING);
+
+            generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+            String toAppend = errorPath.substring(relativePath.length());
+            if (!toAppend.startsWith("/"))
+                toAppend = "/" + toAppend;
+            generatedXML.writeText(absoluteUri + toAppend);
+            generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML
+                .writeText("HTTP/1.1 " + errorCode + " "
+                           + WebdavStatus.getStatusText(errorCode));
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
+
+        }
+
+        generatedXML.writeElement(null, "multistatus", XMLWriter.CLOSING);
+
+        Writer writer = resp.getWriter();
+        writer.write(generatedXML.toString());
+        writer.close();
+
+    }
+
+
+
+
+    /**
+     * Return JAXP document builder instance.
+     */
+    protected DocumentBuilder getDocumentBuilder()
+        throws ServletException {
+        DocumentBuilder documentBuilder = null;
+        DocumentBuilderFactory documentBuilderFactory = null;
+        try {
+            documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            documentBuilderFactory.setNamespaceAware(true);
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch(ParserConfigurationException e) {
+            throw new ServletException
+                (sm.getString("webdavservlet.jaxpfailed"));
+        }
+        return documentBuilder;
+    }
+
+
+
+    /**
+     * Get creation date in ISO format.
+     */
+    protected String getISOCreationDate(long creationDate) {
+        StringBuffer creationDateValue = new StringBuffer
+            (creationDateFormat.format
+             (new Date(creationDate)));
+        /*
+        int offset = Calendar.getInstance().getTimeZone().getRawOffset()
+            / 3600000; // FIXME ?
+        if (offset < 0) {
+            creationDateValue.append("-");
+            offset = -offset;
+        } else if (offset > 0) {
+            creationDateValue.append("+");
+        }
+        if (offset != 0) {
+            if (offset < 10)
+                creationDateValue.append("0");
+            creationDateValue.append(offset + ":00");
+        } else {
+            creationDateValue.append("Z");
+        }
+        */
+        return creationDateValue.toString();
+    }
+
+    /**
+     * Determines the methods normally allowed for the resource.
+     *
+     */
+    protected StringBuffer determineMethodsAllowed(File basePath,
+                                                   HttpServletRequest req) {
+
+        StringBuffer methodsAllowed = new StringBuffer();
+        String path = getRelativePath(req);
+        File object = new File(basePath, path);
+        if (!object.exists()) {
+            methodsAllowed.append("OPTIONS, MKCOL, PUT");
+            return methodsAllowed;
+        }
+        methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE");
+        methodsAllowed.append(", PROPPATCH, COPY, MOVE, PROPFIND");
+
+        if (object.isDirectory()) {
+            methodsAllowed.append(", PUT");
+        }
+
+        return methodsAllowed;
+    }
+}
+
+
+// --------------------------------------------------------  WebdavStatus Class
+
+
+/**
+ * Wraps the HttpServletResponse class to abstract the
+ * specific protocol used.  To support other protocols
+ * we would only need to modify this class and the
+ * WebDavRetCode classes.
+ *
+ * @author              Marc Eaddy
+ * @version             1.0, 16 Nov 1997
+ */
+class WebdavStatus {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * This Hashtable contains the mapping of HTTP and WebDAV
+     * status codes to descriptive text.  This is a static
+     * variable.
+     */
+    protected static Hashtable mapStatusCodes = new Hashtable();
+
+
+    // ------------------------------------------------------ HTTP Status Codes
+
+
+    /**
+     * Status code (200) indicating the request succeeded normally.
+     */
+    public static final int SC_OK = HttpServletResponse.SC_OK;
+
+
+    /**
+     * Status code (201) indicating the request succeeded and created
+     * a new resource on the server.
+     */
+    public static final int SC_CREATED = HttpServletResponse.SC_CREATED;
+
+
+    /**
+     * Status code (202) indicating that a request was accepted for
+     * processing, but was not completed.
+     */
+    public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED;
+
+
+    /**
+     * Status code (204) indicating that the request succeeded but that
+     * there was no new information to return.
+     */
+    public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT;
+
+
+    /**
+     * Status code (301) indicating that the resource has permanently
+     * moved to a new location, and that future references should use a
+     * new URI with their requests.
+     */
+    public static final int SC_MOVED_PERMANENTLY =
+        HttpServletResponse.SC_MOVED_PERMANENTLY;
+
+
+    /**
+     * Status code (302) indicating that the resource has temporarily
+     * moved to another location, but that future references should
+     * still use the original URI to access the resource.
+     */
+    public static final int SC_MOVED_TEMPORARILY =
+        HttpServletResponse.SC_MOVED_TEMPORARILY;
+
+
+    /**
+     * Status code (304) indicating that a conditional GET operation
+     * found that the resource was available and not modified.
+     */
+    public static final int SC_NOT_MODIFIED =
+        HttpServletResponse.SC_NOT_MODIFIED;
+
+
+    /**
+     * Status code (400) indicating the request sent by the client was
+     * syntactically incorrect.
+     */
+    public static final int SC_BAD_REQUEST =
+        HttpServletResponse.SC_BAD_REQUEST;
+
+
+    /**
+     * Status code (401) indicating that the request requires HTTP
+     * authentication.
+     */
+    public static final int SC_UNAUTHORIZED =
+        HttpServletResponse.SC_UNAUTHORIZED;
+
+
+    /**
+     * Status code (403) indicating the server understood the request
+     * but refused to fulfill it.
+     */
+    public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN;
+
+
+    /**
+     * Status code (404) indicating that the requested resource is not
+     * available.
+     */
+    public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND;
+
+
+    /**
+     * Status code (500) indicating an error inside the HTTP service
+     * which prevented it from fulfilling the request.
+     */
+    public static final int SC_INTERNAL_SERVER_ERROR =
+        HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+
+
+    /**
+     * Status code (501) indicating the HTTP service does not support
+     * the functionality needed to fulfill the request.
+     */
+    public static final int SC_NOT_IMPLEMENTED =
+        HttpServletResponse.SC_NOT_IMPLEMENTED;
+
+
+    /**
+     * Status code (502) indicating that the HTTP server received an
+     * invalid response from a server it consulted when acting as a
+     * proxy or gateway.
+     */
+    public static final int SC_BAD_GATEWAY =
+        HttpServletResponse.SC_BAD_GATEWAY;
+
+
+    /**
+     * Status code (503) indicating that the HTTP service is
+     * temporarily overloaded, and unable to handle the request.
+     */
+    public static final int SC_SERVICE_UNAVAILABLE =
+        HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+
+
+    /**
+     * Status code (100) indicating the client may continue with
+     * its request.  This interim response is used to inform the
+     * client that the initial part of the request has been
+     * received and has not yet been rejected by the server.
+     */
+    public static final int SC_CONTINUE = 100;
+
+
+    /**
+     * Status code (405) indicating the method specified is not
+     * allowed for the resource.
+     */
+    public static final int SC_METHOD_NOT_ALLOWED = 405;
+
+
+    /**
+     * Status code (409) indicating that the request could not be
+     * completed due to a conflict with the current state of the
+     * resource.
+     */
+    public static final int SC_CONFLICT = 409;
+
+
+    /**
+     * Status code (412) indicating the precondition given in one
+     * or more of the request-header fields evaluated to false
+     * when it was tested on the server.
+     */
+    public static final int SC_PRECONDITION_FAILED = 412;
+
+
+    /**
+     * Status code (413) indicating the server is refusing to
+     * process a request because the request entity is larger
+     * than the server is willing or able to process.
+     */
+    public static final int SC_REQUEST_TOO_LONG = 413;
+
+
+    /**
+     * Status code (415) indicating the server is refusing to service
+     * the request because the entity of the request is in a format
+     * not supported by the requested resource for the requested
+     * method.
+     */
+    public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
+
+
+    // -------------------------------------------- Extended WebDav status code
+
+
+    /**
+     * Status code (207) indicating that the response requires
+     * providing status for multiple independent operations.
+     */
+    public static final int SC_MULTI_STATUS = 207;
+    // This one colides with HTTP 1.1
+    // "207 Parital Update OK"
+
+
+    /**
+     * Status code (418) indicating the entity body submitted with
+     * the PATCH method was not understood by the resource.
+     */
+    public static final int SC_UNPROCESSABLE_ENTITY = 418;
+    // This one colides with HTTP 1.1
+    // "418 Reauthentication Required"
+
+
+    /**
+     * Status code (419) indicating that the resource does not have
+     * sufficient space to record the state of the resource after the
+     * execution of this method.
+     */
+    public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
+    // This one colides with HTTP 1.1
+    // "419 Proxy Reauthentication Required"
+
+
+    /**
+     * Status code (420) indicating the method was not executed on
+     * a particular resource within its scope because some part of
+     * the method's execution failed causing the entire method to be
+     * aborted.
+     */
+    public static final int SC_METHOD_FAILURE = 420;
+
+
+    /**
+     * Status code (423) indicating the destination resource of a
+     * method is locked, and either the request did not contain a
+     * valid Lock-Info header, or the Lock-Info header identifies
+     * a lock held by another principal.
+     */
+    public static final int SC_LOCKED = 423;
+
+
+    // ------------------------------------------------------------ Initializer
+
+
+    static {
+        // HTTP 1.0 tatus Code
+        addStatusCodeMap(SC_OK, "OK");
+        addStatusCodeMap(SC_CREATED, "Created");
+        addStatusCodeMap(SC_ACCEPTED, "Accepted");
+        addStatusCodeMap(SC_NO_CONTENT, "No Content");
+        addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently");
+        addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily");
+        addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified");
+        addStatusCodeMap(SC_BAD_REQUEST, "Bad Request");
+        addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized");
+        addStatusCodeMap(SC_FORBIDDEN, "Forbidden");
+        addStatusCodeMap(SC_NOT_FOUND, "Not Found");
+        addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
+        addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented");
+        addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway");
+        addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable");
+        addStatusCodeMap(SC_CONTINUE, "Continue");
+        addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed");
+        addStatusCodeMap(SC_CONFLICT, "Conflict");
+        addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed");
+        addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long");
+        addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
+        // WebDav Status Codes
+        addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status");
+        addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity");
+        addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE,
+                         "Insufficient Space On Resource");
+        addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure");
+        addStatusCodeMap(SC_LOCKED, "Locked");
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Returns the HTTP status text for the HTTP or WebDav status code
+     * specified by looking it up in the static mapping.  This is a
+     * static function.
+     *
+     * @param   nHttpStatusCode [IN] HTTP or WebDAV status code
+     * @return  A string with a short descriptive phrase for the
+     *                  HTTP status code (e.g., "OK").
+     */
+    public static String getStatusText(int nHttpStatusCode) {
+        Integer intKey = new Integer(nHttpStatusCode);
+
+        if (!mapStatusCodes.containsKey(intKey)) {
+            return "";
+        } else {
+            return (String) mapStatusCodes.get(intKey);
+        }
+    }
+
+
+    // -------------------------------------------------------- protected Methods
+
+
+    /**
+     * Adds a new status code -> status text mapping.  This is a static
+     * method because the mapping is a static variable.
+     *
+     * @param   nKey    [IN] HTTP or WebDAV status code
+     * @param   strVal  [IN] HTTP status text
+     */
+    protected static void addStatusCodeMap(int nKey, String strVal) {
+        mapStatusCodes.put(new Integer(nKey), strVal);
+    }
+
+};
+

Added: tomcat/sandbox/java/org/apache/tomcat/servlets/sec/IPFilter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/servlets/sec/IPFilter.java?rev=420610&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/servlets/sec/IPFilter.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/servlets/sec/IPFilter.java Mon Jul 10 11:42:39 2006
@@ -0,0 +1,119 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.tomcat.servlets.sec;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Reimplementation of catalina IP valve.
+ * 
+ * @author Costin Manolache
+ */
+public class IPFilter implements Filter {
+    /**
+     * The set of <code>allow</code> regular expressions we will evaluate.
+     */
+    protected Pattern allows[] = new Pattern[0];
+
+
+    /**
+     * The set of <code>deny</code> regular expressions we will evaluate.
+     */
+    protected Pattern denies[] = new Pattern[0];
+
+    // --------------------------------------------------------- Public Methods
+
+    public void setAllows(String pattern) {
+        allows = getPatterns(pattern);
+    }
+    
+    public void setDenies(String pattern) {
+        denies = getPatterns(pattern);
+    }
+    
+    private Pattern[] getPatterns(String pattern) {
+        String[] patSplit = pattern.split(",");
+        ArrayList allowsAL = new ArrayList();
+        for( int i=0; i<patSplit.length; i++) {
+            patSplit[i] = patSplit[i].trim();
+            if (!patSplit[i].equals("")) {
+                allowsAL.add(Pattern.compile(patSplit[i]));
+            }
+        }
+        // TODO
+        Pattern[] result = new Pattern[allowsAL.size()];
+        allowsAL.toArray(result);
+        return result;
+    }
+    
+    public void destroy() {
+    }
+
+
+    public void doFilter(ServletRequest request, 
+                         ServletResponse servletResponse, 
+                         FilterChain chain) 
+            throws IOException, ServletException {
+        
+        HttpServletResponse response = (HttpServletResponse)servletResponse;
+        String property = request.getRemoteAddr();
+        
+        // Check the deny patterns, if any
+        for (int i = 0; i < denies.length; i++) {
+            if (denies[i].matcher(property).matches()) {
+                response.sendError(HttpServletResponse.SC_FORBIDDEN);
+                return;
+            }
+        }
+
+        // Check the allow patterns, if any
+        for (int i = 0; i < allows.length; i++) {
+            if (allows[i].matcher(property).matches()) {
+                chain.doFilter(request, response);
+                return;
+            }
+        }
+
+        // Allow if denies specified but not allows
+        if ((denies.length > 0) && (allows.length == 0)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        // Deny this request
+        response.sendError(HttpServletResponse.SC_FORBIDDEN);
+    }
+
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+
+}

Added: tomcat/sandbox/java/org/apache/tomcat/servlets/sec/SimpleIPFilter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/servlets/sec/SimpleIPFilter.java?rev=420610&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/servlets/sec/SimpleIPFilter.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/servlets/sec/SimpleIPFilter.java Mon Jul 10 11:42:39 2006
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.tomcat.servlets.sec;
+
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Simpler IP filter - no regexp, patterns, etc.
+ * 
+ * Allows only localhost or a specified address
+ * 
+ * @author Costin Manolache
+ */
+public class SimpleIPFilter implements Filter {
+   
+    
+    // --------------------------------------------------------- Public Methods
+    public SimpleIPFilter() {
+        
+    }
+    
+    public void setAddress(String addr) {
+    }
+        
+    public void destroy() {
+    }
+
+
+    public void doFilter(ServletRequest request, 
+                         ServletResponse servletResponse, 
+                         FilterChain chain) 
+            throws IOException, ServletException {
+        
+        HttpServletResponse response = (HttpServletResponse)servletResponse;
+        String property = request.getRemoteAddr();
+        
+        // Allow if denies specified but not allows
+        if ("127.0.0.1".equals(property)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        // Deny this request
+        response.sendError(HttpServletResponse.SC_FORBIDDEN);
+    }
+
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+
+}

Copied: tomcat/sandbox/java/org/apache/tomcat/servlets/util/URLEncoder.java (from r415842, tomcat/sandbox/java/org/apache/tomcat/servlets/file/URLEncoder.java)
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/servlets/util/URLEncoder.java?p2=tomcat/sandbox/java/org/apache/tomcat/servlets/util/URLEncoder.java&p1=tomcat/sandbox/java/org/apache/tomcat/servlets/file/URLEncoder.java&r1=415842&r2=420610&rev=420610&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/servlets/file/URLEncoder.java (original)
+++ tomcat/sandbox/java/org/apache/tomcat/servlets/util/URLEncoder.java Mon Jul 10 11:42:39 2006
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.tomcat.servlets.file;
+package org.apache.tomcat.servlets.util;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;

Modified: tomcat/sandbox/java/org/apache/tomcat/standalone/ETomcat.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/standalone/ETomcat.java?rev=420610&r1=420609&r2=420610&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/standalone/ETomcat.java (original)
+++ tomcat/sandbox/java/org/apache/tomcat/standalone/ETomcat.java Mon Jul 10 11:42:39 2006
@@ -4,6 +4,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Hashtable;
 
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
@@ -21,35 +22,26 @@
 import org.apache.catalina.core.StandardWrapper;
 import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.session.StandardManager;
+import org.apache.tomcat.util.IntrospectionUtils;
 
 /**
  * Minimal tomcat starter for embedding. 
  * 
  * Tomcat supports multiple styles of configuration. 
  * 
- * 1. Classical server.xml, web.xml - see the Tomcat superclass.
- * 2. Minimal tomcat, programatically configured, using regular webapps and web.xml
- * 3. For apps that only need basic servlets, or have their own deployment mechanism -
- *  you can start tomcat without using web.xml
- *  
- *  Before people start screaming 'violation of the spec' - please read again the
- *  spec, web.xml is a mechanism for _deployment_. If you ship or deploy a webapp, it
- *  must have web.xml and all the war format. However the spec doesn't require the
- *  container to store the files in the same format or use the web.xml file - they
- *  added a lot of pain to the spec to make sure files could be stored in a database
- *  for example. 
- *  
- *  In particular, storing the web.xml in a pre-parsed form, like a .ser file or 
- *  a generated java class is (IMO) perfectly fine. One particular case of this is 
- *  a hand-generated configurator - which is a good fit for apps that want to 
- *  provide a HTTP interface and use servlets, but don't need all dynamic deployment
- *  and reconfiguration.
- *  
- *  In fact - if you don't use jsps or use precompiled jsps, you can leave most of the 
- *  xml parsing overhead out of your app, and have a more minimal http server.
- * 
- * This is provided as a base class and as an example - you can extend it, or just 
- * cut&paste or reuse methods.
+ * 1. Classical server.xml-based. 
+ *  Use org.apache.catalina.startup.Bootstrap as main class 
+ * 2. No server.xml, deploy hosts using HostConfig
+ *  Args: -hostbase BASE_HOST_PATH   
+ * 3. No server.xml, load individual webapps using ContextConfig
+ *  Args: -ctxbase BASE_WEBAPP_PATH  
+ * 4. Single webapp, load individual servlets from current classpath ( no
+ *   web.xml or other configuration ) for specific cases. This assumes 
+ *   web.xml has been translated to method calls or args. Use method calls 
+ *   to do this.
+ *        
+ * This is provided as a base class and as an example - you can extend it, or 
+ * just cut&paste or reuse methods.
  * 
  * @author Costin Manolache
  */
@@ -58,32 +50,13 @@
     protected StandardServer server;
     protected StandardService service;
     protected StandardEngine eng;
-    protected StandardHost host;
-    protected StandardContext ctx;
 
-    /** Example main. You should extend ETomcat and call start() your own way.
-     */
-    public static void main( String args[] ) {
-        try {
-            ETomcat etomcat = new ETomcat();
-            
-            etomcat.initServer(null);
-            etomcat.initConnector(8000);
-            etomcat.initHost("localhost");
-            etomcat.initWebapp("/", ".");
-            etomcat.initWebappDefaults();
-            
-            etomcat.start();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-    
-    public void start() throws Exception {
-        server.initialize();
-        server.start();
+    public StandardEngine getEngine() {
+        return eng;
     }
     
+    /** First call - need to initialize tomcat objects.
+     */
     public StandardServer initServer(String baseDir) {
         initHome(baseDir);
         System.setProperty("catalina.useNaming", "false");
@@ -91,14 +64,16 @@
         server = new StandardServer();
         server.setPort( -1 );
         
-        //ServerLifecycleListener jmxLoader = new ServerLifecycleListener();
-        //server.addLifecycleListener(jmxLoader);
-        
         service = new StandardService();
         server.addService( service );
         return server;
     }
 
+    public void start() throws Exception {
+        server.initialize();
+        server.start();
+    }
+
     /** Add a default http connector.
      * 
      * Alternatively, you can construct a Connector and set any params,
@@ -115,24 +90,6 @@
         service.addConnector( connector );
     }
     
-    /** Create a host. First host will be the default.
-     */
-    public StandardHost initHost(String hostname) {
-        if(eng == null ) {
-            eng = new StandardEngine();
-            eng.setName( "default" );
-            eng.setDefaultHost(hostname);
-            service.setContainer(eng);
-        }
-
-        
-        host = new StandardHost();
-        host.setName(hostname);
-
-        eng.addChild( host );
-        return host;
-    }
-
     /** Initialize a webapp.
      * 
      * You can customize the return value to support different web.xml features:
@@ -150,8 +107,10 @@
      * ctx.addMimeMapping("ext", "type");
      *  
      */
-    public StandardContext initWebapp(String path, String dir) {
-        ctx = new StandardContext();
+    public StandardContext initWebappSimple(StandardHost host, 
+                                            String path, 
+                                            String dir) {
+        StandardContext ctx = new StandardContext();
         ctx.setPath( path );
         ctx.setDocBase(dir);
 
@@ -161,24 +120,18 @@
         return ctx;
     }
     
-    public void addWebapp(StandardContext ctx) {
-        this.ctx = ctx;
-        
-        ctx.addLifecycleListener(new FixContextListener());
-
-        host.addChild(ctx);
-        
-    }
-
-    public void initWebappDefaults() {
+    /** Init default servlets for the context. 
+     */
+    public void initWebappDefaults(StandardContext ctx) {
         // Default servlet 
         StandardWrapper defaultServletW = 
-            initServlet("default", "org.apache.catalina.servlets.DefaultServlet");
+            initServlet(ctx, "default", 
+                    "org.apache.catalina.servlets.DefaultServlet");
         defaultServletW.addInitParameter("listings", "true");
 
-        initServlet("invoker", "org.apache.catalina.servlets.InvokerServlet");
+        initServlet(ctx, "invoker", "org.apache.catalina.servlets.InvokerServlet");
 
-        initServlet("jsp", "org.apache.tomcat.servlets.jsp.JspProxyServlet");
+        initServlet(ctx, "jsp", "org.apache.tomcat.servlets.jsp.JspProxyServlet");
         
         ctx.addServletMapping("/", "default");
         ctx.addServletMapping("*.jsp", "jsp");
@@ -204,7 +157,9 @@
      * 
      *    wrapper.addInitParameter("name", "value");
      */
-    public StandardWrapper initServlet(String servletName, String servletClass) {
+    public StandardWrapper initServlet(StandardContext ctx, 
+                                       String servletName, 
+                                       String servletClass) {
         // will do class for name and set init params
         StandardWrapper sw = (StandardWrapper)ctx.createWrapper();
         sw.setServletClass(servletClass);
@@ -215,9 +170,11 @@
     }
 
     /** Use an existing servlet, no class.forName or initialization will be 
-     * performed
+     *  performed
      */
-    public StandardWrapper initServlet(String servletName, Servlet servlet) {
+    public StandardWrapper initServlet(StandardContext ctx,
+                                       String servletName, 
+                                       Servlet servlet) {
         // will do class for name and set init params
         StandardWrapper sw = new ExistingStandardWrapper(servlet);
         sw.setName(servletName);
@@ -225,7 +182,80 @@
         
         return sw;
     }
+    
+    /** Create a host. First host will be the default.
+     */
+    public StandardHost initHostSimple(String hostname) {
+        if(eng == null ) {
+            eng = new StandardEngine();
+            eng.setName( "default" );
+            eng.setDefaultHost(hostname);
+            service.setContainer(eng);
+        }
+
+        
+        StandardHost host = new StandardHost();
+        host.setName(hostname);
+
+        eng.addChild( host );
+        return host;
+    }
+
+
+    /** Init a host, using HostConfig. All webapps under webappsBase will be 
+     * loaded
+     */
+    public StandardHost initHost(String hostName, 
+                                 String webappsBase) 
+        throws ServletException
+    {
+        StandardHost host = new StandardHost();
+        host.setName(hostName);
+        
+        
+        //HostConfig hconfig = new HostConfig();
+        //host.addLifecycleListener( hconfig );
+        try {
+            Class c = Class.forName("org.apache.catalina.startup.HostConfig");
+            LifecycleListener hconfig = (LifecycleListener) c.newInstance();
+            host.addLifecycleListener(hconfig);
+        } catch(Throwable t) {
+            throw new ServletException(t);
+        }
+
+        host.setAppBase(webappsBase);
+
+        getEngine().addChild(host);
+        return host;
+    }
+
+    /** Init a webapp, using ContextConfig.
+     */
+    public StandardContext initWebapp(StandardHost host, 
+                                      String url, String path) 
+        throws ServletException
+    {
+        StandardContext ctx = new StandardContext();
+        ctx.setPath( url );
+        ctx.setDocBase(path);
+
+        // web.xml reader
+        try {
+            Class c = Class.forName("org.apache.catalina.startup.ContextConfig");
+            LifecycleListener hconfig = (LifecycleListener) c.newInstance();
+            ctx.addLifecycleListener(hconfig);
+        } catch(Throwable t) {
+            throw new ServletException(t);
+        }
+        //  ContextConfig ctxCfg = new ContextConfig();
+        //  ctx.addLifecycleListener( ctxCfg );
+        
+        host.addChild(ctx);
+        return ctx;
+    }
 
+    // ---------- Helper methods and classes -------------------
+    
     /** Init expected tomcat env. This is used as a base for the work directory.
      * TODO: disable work dir if not needed ( no jsp, etc ).
      * 
@@ -299,4 +329,41 @@
             return false;       
         }
     }
+
+    // ---------------- Command line processing -----------------------------
+
+    
+    StandardHost currentHost;
+    StandardContext currentContext;
+    
+    public void setHost(String hostname) {
+        currentHost = initHostSimple(hostname); 
+    }
+    
+    
+    /** Example main. You should extend ETomcat and call start() your own way.
+     */
+    public static void main( String args[] ) {
+        try {
+            ETomcat etomcat = new ETomcat();
+            etomcat.initServer(null);
+            
+            IntrospectionUtils.processArgs(etomcat, args, 
+                    new String[] {}, null, new Hashtable());
+
+            etomcat.initConnector(8000);
+            
+            // 
+            StandardHost host = etomcat.initHostSimple("localhost");
+            StandardContext ctx = etomcat.initWebappSimple(host, "/", ".");
+            // 
+            etomcat.initWebappDefaults(ctx);
+            
+            etomcat.start();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+
 }

Modified: tomcat/sandbox/java/org/apache/tomcat/util/buf/ByteChunk.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/buf/ByteChunk.java?rev=420610&r1=420609&r2=420610&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/buf/ByteChunk.java (original)
+++ tomcat/sandbox/java/org/apache/tomcat/util/buf/ByteChunk.java Mon Jul 10 11:42:39 2006
@@ -264,7 +264,7 @@
         isSet=true;
         if( mode > 1 ) {
             System.err.println("Old mode: " + mode);
-            new Throwable().printStackTrace();
+            //new Throwable().printStackTrace();
         }
         mode = 1;
     }
@@ -536,7 +536,7 @@
                 System.err.println("Mode 2 buffer");
                 mode = 2;
             } else { // mode change
-                new Throwable().printStackTrace();
+               // new Throwable().printStackTrace();
             }
         }        
     }

Modified: tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Processor.java?rev=420610&r1=420609&r2=420610&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Processor.java (original)
+++ tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Processor.java Mon Jul 10 11:42:39 2006
@@ -50,7 +50,6 @@
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.http.MimeHeaders;
-import org.apache.tomcat.util.net.JIoEndpoint;
 import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.net.simple.SimpleEndpoint;
 import org.apache.tomcat.util.res.StringManager;

Modified: tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Protocol.java?rev=420610&r1=420609&r2=420610&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Protocol.java (original)
+++ tomcat/sandbox/java/org/apache/tomcat/util/net/http11/Http11Protocol.java Mon Jul 10 11:42:39 2006
@@ -96,7 +96,7 @@
     // *
 
 
-    protected HashMap<String, Object> attributes = new HashMap<String, Object>();
+    protected HashMap attributes = new HashMap();
 
     
     /**
@@ -150,9 +150,9 @@
         */
 
         if (socketFactory!=null) {
-            Iterator<String> attE = attributes.keySet().iterator();
+            Iterator attE = attributes.keySet().iterator();
             while( attE.hasNext() ) {
-                String key = attE.next();
+                String key = (String)attE.next();
                 Object v=attributes.get(key);
                 socketFactory.setAttribute(key, v);
             }
@@ -499,7 +499,7 @@
         protected Http11Protocol protocol;
         protected static int count = 0;
         protected RequestGroupInfo global = new RequestGroupInfo();
-        protected ThreadLocal<Http11Processor> localProcessor = new ThreadLocal<Http11Processor>();
+        protected ThreadLocal localProcessor = new ThreadLocal();
 
         Http11ConnectionHandler(Http11Protocol proto) {
             this.protocol = proto;
@@ -508,7 +508,7 @@
         public boolean process(Socket socket) {
             Http11Processor processor = null;
             try {
-                processor = localProcessor.get();
+                processor = (Http11Processor)localProcessor.get();
                 if (processor == null) {
                     processor =
                         new Http11Processor(protocol.maxHttpHeaderSize, protocol.endpoint);



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org