pnever      2004/04/25 10:33:50

  Modified:    src/webdav/server/org/apache/slide/webdav/method
                        PutMethod.java GetMethod.java
                        AbstractWebdavMethod.java
  Log:
  FIXED BUG: If headers were not checked for PUT
  
  Revision  Changes    Path
  1.73      +25 -4     
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PutMethod.java
  
  Index: PutMethod.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PutMethod.java,v
  retrieving revision 1.72
  retrieving revision 1.73
  diff -u -r1.72 -r1.73
  --- PutMethod.java    24 Feb 2004 17:03:34 -0000      1.72
  +++ PutMethod.java    25 Apr 2004 17:33:50 -0000      1.73
  @@ -5,7 +5,7 @@
    *
    * ====================================================================
    *
  - * Copyright 1999-2002 The Apache Software Foundation 
  + * Copyright 1999-2002 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.
  @@ -192,6 +192,16 @@
                       revisionDescriptor.setContentLength(-1);
                   }
                   
  +                ResourceInfo resourceInfo =
  +                    new ResourceInfo(resourcePath, revisionDescriptor);
  +                
  +                // Checking If headers
  +                if (!checkIfHeaders(req, resp, resourceInfo)) {
  +                    int statusCode = WebdavStatus.SC_PRECONDITION_FAILED;
  +                    sendError( statusCode, "Check If Header failed" );
  +                    throw new WebdavException( statusCode );
  +                }
  +                
                   ResourceKind resourceKind = 
AbstractResourceKind.determineResourceKind(token, resourcePath, revisionDescriptor);
                   
                   versioningHelper.isWriteLocked(slideToken, revisionDescriptors);
  @@ -299,6 +309,17 @@
                   
                   NodeRevisionDescriptor revisionDescriptor =
                       new NodeRevisionDescriptor(req.getContentLength());
  +                
  +                ResourceInfo resourceInfo =
  +                    new ResourceInfo(resourcePath, revisionDescriptor);
  +                resourceInfo.exists = false;
  +                
  +                // Checking If headers
  +                if (!checkIfHeaders(req, resp, resourceInfo)) {
  +                    int statusCode = WebdavStatus.SC_PRECONDITION_FAILED;
  +                    sendError( statusCode, "Check If Header failed" );
  +                    throw new WebdavException( statusCode );
  +                }
                   
                   //NodeProperty property = null;
                   
  
  
  
  1.44      +4 -248    
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/GetMethod.java
  
  Index: GetMethod.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/GetMethod.java,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- GetMethod.java    24 Feb 2004 17:03:33 -0000      1.43
  +++ GetMethod.java    25 Apr 2004 17:33:50 -0000      1.44
  @@ -5,7 +5,7 @@
    *
    * ====================================================================
    *
  - * Copyright 1999-2002 The Apache Software Foundation 
  + * Copyright 1999-2002 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.
  @@ -27,10 +27,8 @@
   import java.io.IOException;
   import java.io.InputStream;
   import java.text.ParseException;
  -import java.text.SimpleDateFormat;
   import java.util.Date;
   import java.util.Enumeration;
  -import java.util.Locale;
   import java.util.StringTokenizer;
   import java.util.Vector;
   import javax.servlet.ServletOutputStream;
  @@ -73,15 +71,6 @@
       protected final int BUFFER_SIZE = 2048;
   
   
  -    /**
  -     * The set of SimpleDateFormat formats to use in getDateHeader().
  -     */
  -    protected static final SimpleDateFormat formats[] = {
  -        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
  -            new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
  -            new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
  -    };
  -
   
       /**
        * MIME multipart separation string
  @@ -343,186 +332,6 @@
       // -------------------------------------------------------- Private Methods
   
   
  -    /**
  -     * 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 resourceInfo File object
  -     * @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
  -     */
  -    private boolean checkIfHeaders(HttpServletRequest request,
  -                                   HttpServletResponse response,
  -                                   ResourceInfo resourceInfo)
  -        throws IOException {
  -
  -        String eTag = getETag(resourceInfo, true);
  -        long fileLength = resourceInfo.length;
  -        long lastModified = resourceInfo.date;
  -
  -        StringTokenizer commaTokenizer;
  -
  -        String headerValue;
  -
  -        // Checking If-Match
  -        headerValue = request.getHeader("If-Match");
  -        if (headerValue != null) {
  -            if (headerValue.indexOf("*") == -1) {
  -
  -                commaTokenizer = new StringTokenizer(headerValue, ",");
  -                boolean conditionSatisfied = false;
  -
  -                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
  -                    String currentToken = commaTokenizer.nextToken();
  -                    if (currentToken.trim().equals(eTag))
  -                        conditionSatisfied = true;
  -                }
  -
  -                // If none of the given ETags match, 412 Precodition failed is
  -                // sent back
  -                if (!conditionSatisfied) {
  -                    response.sendError
  -                        (HttpServletResponse.SC_PRECONDITION_FAILED);
  -                    return false;
  -                }
  -
  -            }
  -        }
  -
  -        // Checking If-Modified-Since
  -        headerValue = request.getHeader("If-Modified-Since");
  -        if (headerValue != null) {
  -
  -            // If an If-None-Match header has been specified, if modified since
  -            // is ignored.
  -            if (request.getHeader("If-None-Match") == null) {
  -
  -                Date date = null;
  -
  -                // Parsing the HTTP Date
  -                for (int i = 0; (date == null) && (i < formats.length); i++) {
  -                    try {
  -                        synchronized (formats[i]) {
  -                            date = formats[i].parse(headerValue);
  -                        }
  -                    } catch (ParseException e) {
  -                        ;
  -                    }
  -                }
  -
  -                if ((date != null)
  -                    && (lastModified <= (date.getTime() + 1000)) ) {
  -                    // The entity has not been modified since the date
  -                    // specified by the client. This is not an error case.
  -                    response.sendError
  -                        (HttpServletResponse.SC_NOT_MODIFIED);
  -                    return false;
  -                }
  -
  -            }
  -
  -        }
  -
  -        // Checking If-None-Match
  -        headerValue = request.getHeader("If-None-Match");
  -        if (headerValue != null) {
  -            if (headerValue.indexOf("*") == -1) {
  -
  -                commaTokenizer = new StringTokenizer(headerValue, ",");
  -                boolean conditionSatisfied = false;
  -
  -                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
  -                    String currentToken = commaTokenizer.nextToken();
  -                    if (currentToken.trim().equals(eTag))
  -                        conditionSatisfied = true;
  -                }
  -
  -                if (conditionSatisfied) {
  -
  -                    // For GET and HEAD, we should respond with
  -                    // 304 Not Modified.
  -                    // For every other method, 412 Precondition Failed is sent
  -                    // back.
  -                    if ( ("GET".equals(request.getMethod()))
  -                        || ("HEAD".equals(request.getMethod())) ) {
  -                        response.sendError
  -                            (HttpServletResponse.SC_NOT_MODIFIED);
  -                        return false;
  -                    } else {
  -                        response.sendError
  -                            (HttpServletResponse.SC_PRECONDITION_FAILED);
  -                        return false;
  -                    }
  -                }
  -
  -            } else {
  -                if (resourceInfo.exists()) {
  -
  -                }
  -            }
  -        }
  -
  -        // Checking If-Unmodified-Since
  -        headerValue = request.getHeader("If-Unmodified-Since");
  -        if (headerValue != null) {
  -
  -            Date date = null;
  -
  -            // Parsing the HTTP Date
  -            for (int i = 0; (date == null) && (i < formats.length); i++) {
  -                try {
  -                    synchronized (formats[i]) {
  -                        date = formats[i].parse(headerValue);
  -                    }
  -                } catch (ParseException e) {
  -                    ;
  -                }
  -            }
  -
  -            if ( (date != null) && (lastModified > date.getTime()) ) {
  -                // The entity has not been modified since the date
  -                // specified by the client. This is not an error case.
  -                response.sendError
  -                    (HttpServletResponse.SC_PRECONDITION_FAILED);
  -                return false;
  -            }
  -
  -        }
  -
  -        return true;
  -    }
  -
  -
  -    /**
  -     * Get the ETag value associated with a file.
  -     *
  -     * @param resourceInfo File object
  -     * @param strong True if we want a strong ETag, in which case a checksum
  -     * of the file has to be calculated
  -     */
  -    private String getETagValue(ResourceInfo resourceInfo, boolean strong) {
  -        // FIXME : Compute a strong ETag if requested, using an MD5 digest
  -        // of the file contents
  -        return resourceInfo.length + "-" + resourceInfo.date;
  -    }
  -
  -
  -    /**
  -     * Get the ETag associated with a file.
  -     *
  -     * @param resourceInfo File object
  -     * @param strong True if we want a strong ETag, in which case a checksum
  -     * of the file has to be calculated
  -     */
  -    private String getETag(ResourceInfo resourceInfo, boolean strong) {
  -        if (strong)
  -            return "\"" + getETagValue(resourceInfo, strong) + "\"";
  -        else
  -            return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
  -    }
   
   
       /**
  @@ -927,57 +736,4 @@
           }
   
       }
  -
  -
  -    // ----------------------------------------------  ResourceInfo Inner Class
  -
  -
  -    private class ResourceInfo {
  -
  -
  -        /**
  -         * Constructor.
  -         *
  -         * @param pathname Path name of the file
  -         */
  -        public ResourceInfo(String path, NodeRevisionDescriptor properties) {
  -
  -            this.path = path;
  -            this.exists = true;
  -            this.creationDate = properties.getCreationDateAsDate().getTime();
  -            this.date = properties.getLastModifiedAsDate().getTime();
  -            this.httpDate = properties.getLastModified();
  -            this.length = properties.getContentLength();
  -
  -        }
  -
  -
  -        public String path;
  -        public long creationDate;
  -        public String httpDate;
  -        public long date;
  -        public long length;
  -        //public boolean collection;
  -        public boolean exists;
  -
  -
  -        /**
  -         * Test if the associated resource exists.
  -         */
  -        public boolean exists() {
  -            return exists;
  -        }
  -
  -
  -        /**
  -         * String representation.
  -         */
  -        public String toString() {
  -            return path;
  -        }
  -
  -
  -    }
  -
  -
   }
  
  
  
  1.27      +368 -112  
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java
  
  Index: AbstractWebdavMethod.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- AbstractWebdavMethod.java 2 Apr 2004 07:30:28 -0000       1.26
  +++ AbstractWebdavMethod.java 25 Apr 2004 17:33:50 -0000      1.27
  @@ -5,7 +5,7 @@
    *
    * ====================================================================
    *
  - * Copyright 1999-2002 The Apache Software Foundation 
  + * Copyright 1999-2002 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.
  @@ -27,11 +27,18 @@
   import java.io.StringWriter;
   import java.security.MessageDigest;
   import java.security.NoSuchAlgorithmException;
  -import java.util.*;
  -
  +import java.text.ParseException;
  +import java.text.SimpleDateFormat;
  +import java.util.ArrayList;
  +import java.util.Collections;
  +import java.util.Date;
  +import java.util.Enumeration;
  +import java.util.Iterator;
  +import java.util.List;
  +import java.util.Locale;
  +import java.util.StringTokenizer;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
  -
   import org.apache.slide.common.Domain;
   import org.apache.slide.common.NamespaceAccessToken;
   import org.apache.slide.common.NestedSlideException;
  @@ -41,10 +48,10 @@
   import org.apache.slide.common.SlideTokenWrapper;
   import org.apache.slide.content.Content;
   import org.apache.slide.content.NodeProperty;
  +import org.apache.slide.content.NodeProperty.NamespaceCache;
   import org.apache.slide.content.NodeRevisionContent;
   import org.apache.slide.content.NodeRevisionDescriptor;
   import org.apache.slide.content.NodeRevisionDescriptors;
  -import org.apache.slide.content.NodeProperty.NamespaceCache;
   import org.apache.slide.lock.Lock;
   import org.apache.slide.lock.NodeLock;
   import org.apache.slide.lock.UnlockListener;
  @@ -60,7 +67,15 @@
   import org.apache.slide.webdav.WebdavException;
   import org.apache.slide.webdav.WebdavMethod;
   import org.apache.slide.webdav.WebdavServletConfig;
  -import org.apache.slide.webdav.util.*;
  +import org.apache.slide.webdav.util.BindConstants;
  +import org.apache.slide.webdav.util.DeltavConstants;
  +import org.apache.slide.webdav.util.NotificationConstants;
  +import org.apache.slide.webdav.util.PreconditionViolationException;
  +import org.apache.slide.webdav.util.TransactionConstants;
  +import org.apache.slide.webdav.util.UnlockListenerImpl;
  +import org.apache.slide.webdav.util.ViolatedPrecondition;
  +import org.apache.slide.webdav.util.WebdavConstants;
  +import org.apache.slide.webdav.util.WebdavUtils;
   import org.apache.util.MD5Encoder;
   import org.apache.util.WebdavStatus;
   import org.jdom.Document;
  @@ -122,6 +137,14 @@
       
       protected static final Namespace DNSP = NamespaceCache.DEFAULT_NAMESPACE;
       
  +    /**
  +     * The set of SimpleDateFormat formats to use in getDateHeader().
  +     */
  +    protected static final SimpleDateFormat formats[] = {
  +        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
  +            new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
  +            new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
  +    };
   
       // ----------------------------------------------------- Instance Variables
   
  @@ -243,11 +266,11 @@
               throw new IllegalStateException();
           }
       }
  -
  -
  +    
  +    
       // ----------------------------------------------------------- Constructors
  -
  -
  +    
  +    
       /**
        * Constructor.
        *
  @@ -256,10 +279,10 @@
        */
       public AbstractWebdavMethod(NamespaceAccessToken token,
                                   WebdavServletConfig config) {
  -
  +        
           this.config = config;
           this.token = token;
  -
  +        
           // initialize helpers
           structure = token.getStructureHelper();
           content = token.getContentHelper();
  @@ -267,11 +290,11 @@
           lock = token.getLockHelper();
           macro = token.getMacroHelper();
       }
  -
  -
  +    
  +    
       // -------------------------------------------- WebdavMethod Implementation
  -
  -
  +    
  +    
       /**
        * Exceute method.
        *
  @@ -279,13 +302,13 @@
        */
       public void run(HttpServletRequest req, HttpServletResponse resp)
           throws WebdavException {
  -
  +        
           this.req = req;
           this.resp = resp;
           this.slideToken = WebdavUtils.getSlideToken(req);
           this.requestUri = WebdavUtils.getRelativePath(req, config);
           parseRequestHeaders();
  -
  +        
           boolean transactionIsStarted = false;
           try {
               parseRequest();
  @@ -293,19 +316,19 @@
                   token.begin();
                   transactionIsStarted = true;
               }
  -
  +            
               // clear expired lock-tokens
               try {
                   UnlockListener listener =
                       new UnlockListenerImpl( slideToken, token, config, req, resp );
                   lock.clearExpiredLocks( slideToken, requestUri, listener );
  -
  +                
                   // if the URI has no more locks associated to it and is
                   // a lock-null resource, we must attempt to delete it
  -
  +                
                   Enumeration locks = lock.enumerateLocks(slideToken, requestUri);
                   if (!locks.hasMoreElements()) {
  -
  +                    
                       NodeRevisionDescriptors revisionDescriptors = 
content.retrieve(slideToken, requestUri);
                       NodeRevisionDescriptor revisionDescriptor = 
content.retrieve(slideToken, revisionDescriptors);
                       if (isLockNull(revisionDescriptor)) {
  @@ -318,7 +341,7 @@
   
               }
               catch (SlideException e) {}
  -
  +            
               executeRequest();
               if (methodNeedsTransactionSupport()) {
                   token.commit();
  @@ -375,11 +398,11 @@
       public String getSlidePath(String fullpath) {
           return WebdavUtils.getSlidePath(fullpath, req.getContextPath());
       }
  -
  -
  +    
  +    
       // ------------------------------------------------------ Protected Methods
  -
  -
  +    
  +    
       /**
        * Return true if the method needs transaction support.
        * Return true if the method needs transaction support, e.g.
  @@ -392,8 +415,8 @@
           // overwrite it to true, but PropFind creates a RevisionDescriptors
           // on the fly
       }
  -
  -
  +    
  +    
       /**
        * Read request contents.
        *
  @@ -401,12 +424,12 @@
        * @return char[] Array of char which contains the body of the request
        */
       protected void readRequestContent() {
  -
  +        
           if (req.getContentLength() == 0)
               return;
  -
  +        
           // TODO : Modify this and make it chunking aware
  -
  +        
           try {
               requestBody = new String(NodeRevisionContent.read(req.getInputStream()),
                                        getEncodingString(req.getCharacterEncoding()));
  @@ -415,9 +438,9 @@
               token.getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
           }
       }
  -
  -
  -
  +    
  +    
  +    
       /**
        * Translate the encoding string into a proper Java encoding String.
        */
  @@ -428,8 +451,8 @@
           if (result.endsWith("\""))   result = result.substring(0, 
result.length()-1);
           return result;
       }
  -
  -
  +    
  +    
       /**
        * Method parseHeaders
        *
  @@ -437,14 +460,14 @@
       private void parseRequestHeaders() throws WebdavException {
           requestHeaders.parse();
       }
  -
  +    
       /**
        * Test if a resource given by a path is a collection
        */
       protected boolean isCollection(String path) {
           return WebdavUtils.isCollection(token, slideToken, path);
       }
  -
  +    
       /**
        * Test whether the resource given by lowerNode is a descendant of the
        * resource given by upperNode
  @@ -463,7 +486,7 @@
           if (upperNode.hasBinding(lowerNode)) {
               return true;
           }
  -
  +        
           // use a non-blocking slide token.
           SlideToken stoken = readonlySlideToken();
           
  @@ -472,7 +495,7 @@
           try {
               lowerNrds = content.retrieve(stoken, lowerNode.getUri());
               lowerNrd = content.retrieve(stoken, lowerNrds);
  -
  +            
               NodeProperty psProp = lowerNrd.getProperty(P_PARENT_SET);
               XMLValue xv = new XMLValue( String.valueOf(psProp.getValue()) );
               Iterator i = xv.getList().iterator();
  @@ -486,11 +509,11 @@
           } catch (ServiceAccessException e) {
               throw e;
           } catch (Exception e) {}
  -
  +        
           return false;
       }
  -
  -
  +    
  +    
       /**
        * Parse WebDAV XML query.
        *
  @@ -498,9 +521,9 @@
        */
       protected abstract void parseRequest()
           throws WebdavException;
  -
  -
  -
  +    
  +    
  +    
       /**
        * Returns the request content (XML) Document.
        *
  @@ -509,9 +532,9 @@
       protected Document getRequestContent() {
           return requestContentDocument;
       }
  -
  +    
       //--
  -
  +    
       /**
        * precondition: sourceUri != null
        */
  @@ -532,12 +555,12 @@
               if ((hostName != null) && (uri.startsWith(hostName))) {
                   uri = uri.substring(hostName.length());
               }
  -
  +            
               int portIndex = uri.indexOf(":");
               if (portIndex >= 0) {
                   uri = uri.substring(portIndex);
               }
  -
  +            
               if (uri.startsWith(":")) {
                   int firstSeparator = uri.indexOf("/");
                   if (firstSeparator < 0) {
  @@ -547,16 +570,16 @@
                   }
               }
           }
  -
  +        
           // headers are "ISO-8859-1" encoded [not any more with TC 4.1.18
           // destinationUri = 
WebdavUtils.decodeURL(WebdavUtils.fixTomcatURL(destinationUri, "ISO-8859-1"));
           uri = WebdavUtils.decodeURL(uri);
  -
  +        
           String contextPath = req.getContextPath();
           if ((contextPath != null) && (uri.startsWith(contextPath))) {
               uri = uri.substring(contextPath.length());
           }
  -
  +        
           String pathInfo = req.getPathInfo();
           if (pathInfo != null) {
               String servletPath = req.getServletPath();
  @@ -565,14 +588,14 @@
               }
           }
           uri = getConfig().getScope() + uri;
  -
  +        
           return uri;
       }
  -
  +    
       protected Element parseRequestContent(String rootName) throws JDOMException, 
IOException {
           Document document;
           Element root;
  -
  +        
           document = parseRequestContent();
           if (document == null) {
               throw new JDOMException("Request content missing");
  @@ -584,7 +607,7 @@
           }
           return root;
       }
  -
  +    
       /**
        * Parses the request content (XML) Document.
        *
  @@ -594,15 +617,15 @@
        * @throws     JDOMException   if parsing the document failed.
        */
       protected Document parseRequestContent() throws JDOMException, IOException {
  -
  +        
           if (isRequestContentParsed) {
               return requestContentDocument;
           }
  -
  +        
           if (req.getContentLength() == 0) {
               return requestContentDocument;
           }
  -
  +        
           try {
               requestContentDocument = new SAXBuilder().build(req.getInputStream());
               isRequestContentParsed = true;
  @@ -615,11 +638,11 @@
                   throw e;
               }
           }
  -
  +        
           return requestContentDocument;
       }
  -
  -
  +    
  +    
       /**
        * Generate XML response.
        *
  @@ -627,8 +650,8 @@
        */
       protected abstract void executeRequest()
           throws WebdavException, IOException;
  -
  -
  +    
  +    
       /**
        * Simulate MS IIS5 ?
        *
  @@ -637,7 +660,7 @@
       protected boolean isMsProprietarySupport() {
           return (token.getNamespaceConfig().getParameter("ms") != null);
       }
  -
  +    
       /**
        * Sends a precondition vilolation response.
        *
  @@ -645,11 +668,11 @@
        *            precondition.
        */
       protected void sendPreconditionViolation(PreconditionViolationException pve) 
throws IOException {
  -
  +        
           if (pve != null) {
  -
  +            
               ViolatedPrecondition violatedPrecondition = 
pve.getViolatedPrecondition();
  -
  +            
               int statusCode = violatedPrecondition.getStatusCode();
               printStackTrace( pve, statusCode );
               String statusText = WebdavStatus.getStatusText(statusCode);
  @@ -678,18 +701,18 @@
        * @return   the absolute URL.
        */
       protected String getAbsoluteURL(String uri) {
  -
  +        
           StringBuffer buffer = new StringBuffer();
           buffer.append(HTTP_PROTOCOL);
           buffer.append(req.getServerName());
           buffer.append(":");
           buffer.append(req.getServerPort());
  -
  +        
           if ( ! req.getContextPath().startsWith("/") ) {
               buffer.append("/");
           }
           buffer.append(req.getContextPath());
  -
  +        
           if (uri != null) {
               if ( !req.getContextPath().endsWith("/") && !uri.startsWith("/") ) {
                   buffer.append("/");
  @@ -698,35 +721,35 @@
           }
           return buffer.toString();
       }
  -
  +    
       // -------------------------------------------------------- Private Methods
  -
  -
  +    
  +    
       /**
        * Get return status based on exception type.
        */
       protected int getErrorCode(Throwable ex) {
           return WebdavUtils.getErrorCode(ex);
       }
  -
  -
  +    
  +    
       /**
        * Get return status based on exception type.
        */
       protected int getErrorCode(SlideException ex) {
           return WebdavUtils.getErrorCode(ex);
       }
  -
  -
  -
  +    
  +    
  +    
       /**
        * Get return status based on exception type.
        */
       protected int getErrorCode(ServiceAccessException ex) {
           return WebdavUtils.getErrorCode(ex);
       }
  -
  -
  +    
  +    
       /**
        * Returns the value of a boolean init parameter of the servlet.
        * Default value: false.
  @@ -734,8 +757,8 @@
       protected boolean getBooleanInitParameter( String name ) {
           return "true".equalsIgnoreCase( getConfig().getInitParameter(name) );
       }
  -
  -
  +    
  +    
       /**
        * Returns the value of an integer init parameter of the servlet.
        * Default value: -1.
  @@ -748,14 +771,14 @@
           catch( NumberFormatException x ) {};
           return result;
       }
  -
  +    
       /**
        * Error handling routine
        */
       protected void sendError( int statusCode ) {
           try { resp.sendError( statusCode ); } catch( Throwable x ) {};
       }
  -
  +    
       /**
        * Error handling routine
        */
  @@ -767,7 +790,7 @@
                    : "");
           try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
       }
  -
  +    
       /**
        * Error handling routine
        */
  @@ -777,7 +800,7 @@
               Messages.format( message, args );
           try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
       }
  -
  +    
       /**
        * Error handling routine
        */
  @@ -791,7 +814,7 @@
               WebdavStatus.getStatusText(statusCode)+": "+explanation;
           try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
       }
  -
  +    
       /**
        * Prints the stack trace of the given exception if the specified status code
        * is greater-or-equal the value of the servlet init-parameter printStackTrace.
  @@ -805,8 +828,8 @@
           if( statusCode >= printStackTraceFrom )
               x.printStackTrace();
       }
  -
  -
  +    
  +    
       /**
        * Generate status text.
        *
  @@ -815,7 +838,7 @@
        * @param statusCode HTTP status code of the error
        */
       protected void generateStatusText(Element parentElement, String href, int 
statusCode) {
  -
  +        
           Element hrefElement = new Element(E_HREF, DNSP);
           parentElement.addContent(hrefElement);
           hrefElement.setText(getFullPath(href));
  @@ -824,7 +847,7 @@
           statusElement.setText("HTTP/1.1 " + statusCode + " "
                                     + WebdavStatus.getStatusText(statusCode));
       }
  -
  +    
       /**
        * Generate an XML error message.
        *
  @@ -833,13 +856,13 @@
        */
       protected String generateErrorMessage
           (NestedSlideException nestedException) {
  -
  +        
           Element multistatus = new Element(E_MULTISTATUS, DNSP);
  -
  +        
           Enumeration nestedExceptionsList =
               nestedException.enumerateExceptions();
           while (nestedExceptionsList.hasMoreElements()) {
  -
  +            
               Element response = new Element(E_RESPONSE, DNSP);
               multistatus.addContent(response);
               SlideException ex =
  @@ -849,9 +872,9 @@
               if (ex instanceof PreconditionViolationException) {
                   
response.addContent(MethodUtil.getPreconditionViolationResponseDescription((PreconditionViolationException)ex));
               }
  -
  +            
           }
  -
  +        
           StringWriter stringWriter = new StringWriter();
           try {
               new XMLOutputter().output(multistatus, stringWriter);
  @@ -860,13 +883,13 @@
               Domain.log(e);
           }
           return stringWriter.toString();
  -
  +        
       }
  -
  +    
       protected boolean exists( String uriStr ) throws SlideException {
           // use a non-blocking slide token.
           SlideToken stoken = readonlySlideToken();
  -
  +        
           boolean destinationExists = true;
           
           try {
  @@ -877,11 +900,11 @@
           }
           return destinationExists;
       }
  -
  +    
       protected boolean isLocked( String uriStr ) throws ServiceAccessException {
           // use a non-blocking slide token.
           SlideToken stoken = readonlySlideToken();
  -
  +        
           boolean isLocked = false;
           try {
               Enumeration locks = lock.enumerateLocks (stoken, uriStr, false);
  @@ -899,11 +922,11 @@
           }
           return isLocked;
       }
  -
  +    
       protected boolean isLockNull( String uriStr ) throws ServiceAccessException {
           // use a non-blocking slide token.
           SlideToken stoken = readonlySlideToken();
  -
  +        
           boolean isLockNull = false;
           try {
               NodeRevisionDescriptor nrd =
  @@ -918,11 +941,11 @@
           }
           return isLockNull;
       }
  -
  +    
       protected boolean isLockNull( NodeRevisionDescriptor nrd ) {
           return nrd.propertyValueContains(P_RESOURCETYPE, E_LOCKNULL);
       }
  -
  +    
       protected SlideToken readonlySlideToken() {
           SlideToken stoken = slideToken;
           if (stoken.isForceStoreEnlistment()) {
  @@ -930,7 +953,239 @@
           }
           return stoken;
       }
  -
  +    
  +    /**
  +     * 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 resourceInfo File object
  +     * @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,
  +                                     ResourceInfo resourceInfo)
  +        throws IOException {
  +        
  +        String eTag = getETag(resourceInfo, true);
  +        long fileLength = resourceInfo.length;
  +        long lastModified = resourceInfo.date;
  +        
  +        StringTokenizer commaTokenizer;
  +        
  +        String headerValue;
  +        
  +        // Checking If-Match
  +        headerValue = request.getHeader("If-Match");
  +        if (headerValue != null) {
  +            if (headerValue.indexOf("*") == -1) {
  +                
  +                commaTokenizer = new StringTokenizer(headerValue, ",");
  +                boolean conditionSatisfied = false;
  +                
  +                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
  +                    String currentToken = commaTokenizer.nextToken();
  +                    if (currentToken.trim().equals(eTag))
  +                        conditionSatisfied = true;
  +                }
  +                
  +                // If none of the given ETags match, 412 Precodition failed is
  +                // sent back
  +                if (!conditionSatisfied) {
  +                    response.sendError
  +                        (HttpServletResponse.SC_PRECONDITION_FAILED);
  +                    return false;
  +                }
  +                
  +            }
  +        }
  +        
  +        // Checking If-Modified-Since
  +        headerValue = request.getHeader("If-Modified-Since");
  +        if (headerValue != null) {
  +            
  +            // If an If-None-Match header has been specified, if modified since
  +            // is ignored.
  +            if (request.getHeader("If-None-Match") == null) {
  +                
  +                Date date = null;
  +                
  +                // Parsing the HTTP Date
  +                for (int i = 0; (date == null) && (i < formats.length); i++) {
  +                    try {
  +                        synchronized (formats[i]) {
  +                            date = formats[i].parse(headerValue);
  +                        }
  +                    } catch (ParseException e) {
  +                        ;
  +                    }
  +                }
  +                
  +                if ((date != null)
  +                    && (lastModified <= (date.getTime() + 1000)) ) {
  +                    // The entity has not been modified since the date
  +                    // specified by the client. This is not an error case.
  +                    response.sendError
  +                        (HttpServletResponse.SC_NOT_MODIFIED);
  +                    return false;
  +                }
  +                
  +            }
  +            
  +        }
  +        
  +        // Checking If-None-Match
  +        headerValue = request.getHeader("If-None-Match");
  +        if (headerValue != null) {
  +            if (headerValue.indexOf("*") == -1) {
  +                
  +                commaTokenizer = new StringTokenizer(headerValue, ",");
  +                boolean conditionSatisfied = true;
  +                
  +                while (conditionSatisfied && commaTokenizer.hasMoreTokens()) {
  +                    String currentToken = commaTokenizer.nextToken();
  +                    if (currentToken.trim().equals(eTag))
  +                        conditionSatisfied = false;
  +                }
  +                
  +                if (conditionSatisfied) {
  +                    
  +                    // For GET and HEAD, we should respond with
  +                    // 304 Not Modified.
  +                    // For every other method, 412 Precondition Failed is sent
  +                    // back.
  +                    if ( ("GET".equals(request.getMethod()))
  +                        || ("HEAD".equals(request.getMethod())) ) {
  +                        response.sendError
  +                            (HttpServletResponse.SC_NOT_MODIFIED);
  +                        return false;
  +                    } else {
  +                        response.sendError
  +                            (HttpServletResponse.SC_PRECONDITION_FAILED);
  +                        return false;
  +                    }
  +                }
  +                
  +            } else {
  +                if (resourceInfo.exists()) {
  +                    return false;
  +                }
  +            }
  +        }
  +        
  +        // Checking If-Unmodified-Since
  +        headerValue = request.getHeader("If-Unmodified-Since");
  +        if (headerValue != null) {
  +            
  +            Date date = null;
  +            
  +            // Parsing the HTTP Date
  +            for (int i = 0; (date == null) && (i < formats.length); i++) {
  +                try {
  +                    synchronized (formats[i]) {
  +                        date = formats[i].parse(headerValue);
  +                    }
  +                } catch (ParseException e) {
  +                    ;
  +                }
  +            }
  +            
  +            if ( (date != null) && (lastModified > date.getTime()) ) {
  +                // The entity has not been modified since the date
  +                // specified by the client. This is not an error case.
  +                response.sendError
  +                    (HttpServletResponse.SC_PRECONDITION_FAILED);
  +                return false;
  +            }
  +            
  +        }
  +        
  +        return true;
  +    }
  +    
  +    /**
  +     * Get the ETag value associated with a file.
  +     *
  +     * @param resourceInfo File object
  +     * @param strong True if we want a strong ETag, in which case a checksum
  +     * of the file has to be calculated
  +     */
  +    protected String getETagValue(ResourceInfo resourceInfo, boolean strong) {
  +        // FIXME : Compute a strong ETag if requested, using an MD5 digest
  +        // of the file contents
  +        if (resourceInfo.exists()) {
  +            return resourceInfo.etag;
  +        }
  +        else {
  +            return resourceInfo.length + "-" + resourceInfo.date;
  +        }
  +    }
  +    
  +    
  +    /**
  +     * Get the ETag associated with a file.
  +     *
  +     * @param resourceInfo File object
  +     * @param strong True if we want a strong ETag, in which case a checksum
  +     * of the file has to be calculated
  +     */
  +    protected String getETag(ResourceInfo resourceInfo, boolean strong) {
  +        if (strong)
  +            return "\"" + getETagValue(resourceInfo, strong) + "\"";
  +        else
  +            return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
  +    }
  +    
  +    protected class ResourceInfo {
  +        
  +        /**
  +         * Constructor.
  +         *
  +         * @param pathname Path name of the file
  +         */
  +        public ResourceInfo(String path, NodeRevisionDescriptor properties) {
  +            
  +            this.path = path;
  +            this.exists = true;
  +            this.creationDate = properties.getCreationDateAsDate().getTime();
  +            this.date = properties.getLastModifiedAsDate().getTime();
  +            this.httpDate = properties.getLastModified();
  +            this.length = properties.getContentLength();
  +            this.etag = properties.getETag();
  +            
  +        }
  +        
  +        
  +        public String path;
  +        public long creationDate;
  +        public String httpDate;
  +        public long date;
  +        public long length;
  +        public String etag;
  +        //public boolean collection;
  +        public boolean exists;
  +        
  +        
  +        /**
  +         * Test if the associated resource exists.
  +         */
  +        public boolean exists() {
  +            return exists;
  +        }
  +        
  +        
  +        /**
  +         * String representation.
  +         */
  +        public String toString() {
  +            return path;
  +        }
  +        
  +        
  +    }
       
       protected class RequestHeaders {
           private static final int
  @@ -1398,6 +1653,7 @@
           }
       }
   }
  +
   
   
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to