You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by re...@apache.org on 2001/02/11 21:39:26 UTC

cvs commit: jakarta-slide/src/webdav/server/org/apache/slide/webdav/method CopyMethod.java DeleteMethod.java GetMethod.java LockMethod.java MkcolMethod.java MoveMethod.java PropFindMethod.java PropPatchMethod.java PutMethod.java UnlockMethod.java WebdavMethod.java

remm        01/02/11 12:39:26

  Modified:    src/webdav/server/org/apache/slide/webdav/method
                        CopyMethod.java DeleteMethod.java GetMethod.java
                        LockMethod.java MkcolMethod.java MoveMethod.java
                        PropFindMethod.java PropPatchMethod.java
                        PutMethod.java UnlockMethod.java WebdavMethod.java
  Added:       src/webdav/server/org/apache/slide/webdav/common
                        RequestUtil.java
  Log:
  - Add proper URL encoding / decoding based on Catalina code.
  - The only supported char encoding is Unicode (UTF-8), but this will eventually be
    configurable.
  
  Revision  Changes    Path
  1.1                  jakarta-slide/src/webdav/server/org/apache/slide/webdav/common/RequestUtil.java
  
  Index: RequestUtil.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/common/RequestUtil.java,v 1.1 2001/02/11 20:39:24 remm Exp $
   * $Revision: 1.1 $
   * $Date: 2001/02/11 20:39:24 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.slide.webdav.common;
  
  import java.io.UnsupportedEncodingException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Map;
  import java.util.TimeZone;
  import javax.servlet.http.Cookie;
  
  
  /**
   * General purpose request parsing and encoding utility methods.
   *
   * @author Craig R. McClanahan
   * @author Tim Tye
   * @version $Revision: 1.1 $ $Date: 2001/02/11 20:39:24 $
   */
  
  public final class RequestUtil {
  
  
      /**
       * The DateFormat to use for generating readable dates in cookies.
       */
      private static SimpleDateFormat format =
          new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz");
  
      static {
          format.setTimeZone(TimeZone.getTimeZone("GMT"));
      }
  
  
      /**
       * Encode a cookie as per RFC 2109.  The resulting string can be used
       * as the value for a <code>Set-Cookie</code> header.
       *
       * @param cookie The cookie to encode.
       * @return A string following RFC 2109.
       */
      public static String encodeCookie(Cookie cookie) {
  
          StringBuffer buf = new StringBuffer( cookie.getName() );
          buf.append("=");
          buf.append(cookie.getValue());
  
  	if (cookie.getComment() != null) {
  	    buf.append("; Comment=\"");
  	    buf.append(cookie.getComment());
  	    buf.append("\"");
  	}
  
          if (cookie.getDomain() != null) {
              buf.append("; Domain=\"");
              buf.append(cookie.getDomain());
  	    buf.append("\"");
          }
  
          long age = cookie.getMaxAge();
  	if (cookie.getMaxAge() >= 0) {
  	    buf.append("; Max-Age=\"");
  	    buf.append(cookie.getMaxAge());
  	    buf.append("\"");
  	}
  
          if (cookie.getPath() != null) {
              buf.append("; Path=\"");
              buf.append(cookie.getPath());
  	    buf.append("\"");
          }
  
          if (cookie.getSecure()) {
              buf.append("; Secure");
          }
  
  	if (cookie.getVersion() > 0) {
  	    buf.append("; Version=\"");
  	    buf.append(cookie.getVersion());
  	    buf.append("\"");
  	}
  
          return (buf.toString());
      }
  
  
      /**
       * Parse the character encoding from the specified content type header.
       * If the content type is null, or there is no explicit character encoding,
       * <code>null</code> is returned.
       *
       * @param contentType a content type header
       */
      public static String parseCharacterEncoding(String contentType) {
  
  	if (contentType == null)
  	    return (null);
  	int start = contentType.indexOf("charset=");
  	if (start < 0)
  	    return (null);
  	String encoding = contentType.substring(start + 8);
  	int end = encoding.indexOf(";");
  	if (end >= 0)
  	    encoding = encoding.substring(0, end);
          encoding = encoding.trim();
          if ((encoding.length() > 2) && (encoding.startsWith("\"")) 
              && (encoding.endsWith("\"")))
              encoding = encoding.substring(1, encoding.length() - 1);
  	return (encoding.trim());
  
      }
  
  
      /**
       * Parse a cookie header into an array of cookies according to RFC 2109.
       *
       * @param header Value of an HTTP "Cookie" header
       */
      public static Cookie[] parseCookieHeader(String header) {
  
  	if ((header == null) || (header.length() < 1))
  	    return (new Cookie[0]);
  
          ArrayList cookies = new ArrayList();
          while (header.length() > 0) {
              int semicolon = header.indexOf(";");
              if (semicolon < 0)
                  semicolon = header.length();
              if (semicolon == 0)
                  break;
              String token = header.substring(0, semicolon);
              if (semicolon < header.length())
                  header = header.substring(semicolon + 1);
              else
                  header = "";
  	    try {
  		int equals = token.indexOf("=");
  		if (equals > 0) {
  		    String name = URLDecode(token.substring(0, equals).trim());
  		    String value = URLDecode(token.substring(equals+1).trim());
  		    cookies.add(new Cookie(name, value));
  		}
  	    } catch (Throwable e) {
  		;
  	    }
  	}
  
          return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
  
      }
  
  
      /**
       * Append request parameters from the specified String to the specified
       * Map.  It is presumed that the specified Map is not accessed from any
       * other thread, so no synchronization is performed.
       * <p>
       * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
       * individually on the parsed name and value elements, rather than on
       * the entire query string ahead of time, to properly deal with the case
       * where the name or value includes an encoded "=" or "&" character
       * that would otherwise be interpreted as a delimiter.
       *
       * @param map Map that accumulates the resulting parameters
       * @param data Input string containing request parameters
       * @param urlParameters true if we're parsing parameters on the URL
       *
       * @exception IllegalArgumentException if the data is malformed
       */
      public static void parseParameters(Map map, String data, String encoding) 
          throws UnsupportedEncodingException {
          
          if ((data != null) && (data.length() > 0)) {
              int len = data.length();
              byte[] bytes = new byte[len];
              data.getBytes(0, len, bytes, 0);
              parseParameters(map, bytes, encoding);
          }
          
      }
  
  
      /**
       * Decode and return the specified URL-encoded String.
       * When the byte array is converted to a string, the system default 
       * character encoding is used...  This may be different than some other
       * servers.
       *
       * @param str The url-encoded string
       *
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(String str) {
          
          return URLDecode(str, null);
          
      }
  
  
      /**
       * Decode and return the specified URL-encoded String.
       * 
       * @param str The url-encoded string
       * @param enc The encoding to use; if null, the default encoding is used
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(String str, String enc) {
          
          if (str == null)
              return (null);
          
          int len = str.length();
          byte[] bytes = new byte[len];
          str.getBytes(0, len, bytes, 0);
          
          return URLDecode(bytes, enc);
          
      }
  
  
      /**
       * Decode and return the specified URL-encoded byte array.
       * 
       * @param bytes The url-encoded byte array
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(byte[] bytes) {
          return URLDecode(bytes, null);
      }
  
  
      /**
       * Decode and return the specified URL-encoded byte array.
       * 
       * @param bytes The url-encoded byte array
       * @param enc The encoding to use; if null, the default encoding is used
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(byte[] bytes, String enc) {
          
          if (bytes == null)
              return (null);
          
          int len = bytes.length;
          int ix = 0;
          int ox = 0;
          while (ix < len) {
              byte b = bytes[ix++];     // Get byte to test
              if (b == '+') {
                  b = (byte)' ';
              } else if (b == '%') {
                  b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
                              + convertHexDigit(bytes[ix++]));
              } 
              bytes[ox++] = b;
          }
          if (enc != null) {
              try {
                  return new String(bytes, 0, ox, enc);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return new String(bytes, 0, ox);
          
      }
  
  
      /**
       * Convert a byte character value to hexidecimal digit value.
       *
       * @param b the character value byte
       */
      private static byte convertHexDigit( byte b ) {
          if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
          if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
          if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
          return 0;
      }
  
  
      /**
       * Put name value pair in map.
       *
       * @param b the character value byte
       *
       * Put name and value pair in map.  When name already exist, add value 
       * to array of values.
       */
      private static void putMapEntry( Map map, String name, String value) {
          String[] newValues = null;
          String[] oldValues = (String[]) map.get(name);
          if (oldValues == null) {
              newValues = new String[1];
              newValues[0] = value;
          } else {
              newValues = new String[oldValues.length + 1];
              System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
              newValues[oldValues.length] = value;
          }
          map.put(name, newValues);
      }
  
  
      /**
       * Append request parameters from the specified String to the specified
       * Map.  It is presumed that the specified Map is not accessed from any
       * other thread, so no synchronization is performed.
       * <p>
       * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
       * individually on the parsed name and value elements, rather than on
       * the entire query string ahead of time, to properly deal with the case
       * where the name or value includes an encoded "=" or "&" character
       * that would otherwise be interpreted as a delimiter.
       *
       * NOTE: byte array data is modified by this method.  Caller beware.
       *
       * @param map Map that accumulates the resulting parameters
       * @param data Input string containing request parameters
       * @param urlParameters true if we're parsing parameters on the URL
       *
       * @exception UnsupportedEncodingException if the data is malformed
       */
      public static void parseParameters(Map map, byte[] data, String encoding) 
          throws UnsupportedEncodingException {
  
          if (data != null && data.length > 0) {
              int    pos = 0;
              int    ix = 0;
              int    ox = 0;
              String key = null;
              String value = null;
              while (ix < data.length) {
                  byte c = data[ix++];
                  switch (c) {
                  case '&':
                      value = new String(data, 0, ox, encoding);
                      if (key != null) {
                          putMapEntry(map, key, value);
                          key = null;
                      }
                      ox = 0;
                      break;
                  case '=':
                      key = new String(data, 0, ox, encoding);
                      ox = 0;
                      break;
                  case '+':
                      data[ox++] = (byte)' ';
                      break;
                  case '%':
                      data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
                                      + convertHexDigit(data[ix++]));
                      break;
                  default:
                      data[ox++] = c;
                  }
              }
              //The last value does not end in '&'.  So save it now.
              if (key != null) {
                  value = new String(data, 0, ox, encoding);
                  putMapEntry(map, key, value);
              }
          }
  
      }
  
  
  
  }
  
  
  
  
  1.5       +4 -4      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/CopyMethod.java
  
  Index: CopyMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/CopyMethod.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- CopyMethod.java	2001/01/19 01:26:59	1.4
  +++ CopyMethod.java	2001/02/11 20:39:24	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/CopyMethod.java,v 1.4 2001/01/19 01:26:59 remm Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/01/19 01:26:59 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/CopyMethod.java,v 1.5 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -316,7 +316,7 @@
       protected void generateStatusText(WebdavXMLPrinter printer, String href,
                                         int statusCode) {
           printer.writeElement("d", "href", WebdavXMLPrinter.OPENING);
  -        printer.writeText(href);
  +        printer.writeText(URLEncode(href));
           printer.writeElement("d", "href", WebdavXMLPrinter.CLOSING);
           printer.writeElement("d", "status", WebdavXMLPrinter.OPENING);
           printer.writeText("HTTP/1.1 " + statusCode + " "
  
  
  
  1.4       +4 -4      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/DeleteMethod.java
  
  Index: DeleteMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/DeleteMethod.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- DeleteMethod.java	2001/01/17 16:48:59	1.3
  +++ DeleteMethod.java	2001/02/11 20:39:24	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/DeleteMethod.java,v 1.3 2001/01/17 16:48:59 juergen Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/01/17 16:48:59 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/DeleteMethod.java,v 1.4 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -233,7 +233,7 @@
       protected void generateStatusText(WebdavXMLPrinter printer, String href,
                                         int statusCode) {
           printer.writeElement("d", "href", WebdavXMLPrinter.OPENING);
  -        printer.writeText(href);
  +        printer.writeText(URLEncode(href));
           printer.writeElement("d", "href", WebdavXMLPrinter.CLOSING);
           printer.writeElement("d", "status", WebdavXMLPrinter.OPENING);
           printer.writeText("HTTP/1.1 " + statusCode + " "
  
  
  
  1.3       +5 -29     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.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- GetMethod.java	2000/11/25 01:36:09	1.2
  +++ GetMethod.java	2001/02/11 20:39:24	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/GetMethod.java,v 1.2 2000/11/25 01:36:09 remm Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/11/25 01:36:09 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/GetMethod.java,v 1.3 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -391,7 +391,7 @@
               String parent = name.substring(0, slash);
               writer.print("<tr><td colspan=\"5\" bgcolor=\"#ffffff\">\r\n");
               writer.print("<a href=\"");
  -            writer.print(rewriteUrl(contextPath));
  +            writer.print(URLEncode(contextPath));
               if (parent.equals(""))
                   parent = "/";
               writer.print(parent);
  @@ -507,8 +507,7 @@
               
               writer.print("<td align=\"left\" colspan=\"3\">&nbsp;&nbsp;\r\n");
               writer.print("<a href=\"");
  -            writer.print(rewriteUrl(contextPath));
  -            writer.print(rewriteUrl(currentResource));
  +            writer.print(URLEncode(contextPath + currentResource));
               writer.print("\"><tt>");
               writer.print(trimmed);
               if (isCollection(currentDescriptor)) {
  @@ -802,29 +801,6 @@
               rightSide = 1;
           
           return ("" + leftSide + "." + rightSide + " kb");
  -        
  -    }
  -    
  -    
  -    /**
  -     * URL rewriter.
  -     * 
  -     * @param path Path which has to be rewiten
  -     */
  -    private String rewriteUrl(String path) {
  -        
  -        String normalized = path;
  -        
  -        // Replace " " with "%20"
  -        while (true) {
  -            int index = normalized.indexOf(" ");
  -            if (index < 0)
  -                break;
  -            normalized = normalized.substring(0, index) + "%20"
  -                + normalized.substring(index + 1);
  -        }
  -        
  -        return normalized;
           
       }
       
  
  
  
  1.5       +7 -9      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java
  
  Index: LockMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- LockMethod.java	2001/01/29 12:18:04	1.4
  +++ LockMethod.java	2001/02/11 20:39:24	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java,v 1.4 2001/01/29 12:18:04 juergen Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/01/29 12:18:04 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java,v 1.5 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -678,11 +678,10 @@
           generatedXML.writeElement("d", null, "prop",
                                     WebdavXMLPrinter.CLOSING);
           
  +        
           try {
  -            System.out.println("Query result");
  -            
  -            System.out.println(generatedXML.toString());
  -            
  +            //System.out.println("Query result");
  +            //System.out.println(generatedXML.toString());
               Writer writer = resp.getWriter();
               writer.write(generatedXML.toString());
               writer.flush();
  @@ -691,17 +690,16 @@
               throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
           }
           
  +        
       }
      
       
  -    
       /**
        * Returns true
        */
       protected boolean methodNeedsTransactionSupport() {
           return true;
       }
  -    
       
      
   }
  
  
  
  1.5       +7 -9      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MkcolMethod.java
  
  Index: MkcolMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MkcolMethod.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- MkcolMethod.java	2001/01/17 16:49:01	1.4
  +++ MkcolMethod.java	2001/02/11 20:39:24	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MkcolMethod.java,v 1.4 2001/01/17 16:49:01 juergen Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/01/17 16:49:01 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MkcolMethod.java,v 1.5 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -257,16 +257,14 @@
   	// TODO : Initialize and create collection's properties.
   	
       }
  -   
  -	
  -	
  +    
  +    
       /**
        * Returns true
        */
  -	protected boolean methodNeedsTransactionSupport() {
  -		return true;
  +    protected boolean methodNeedsTransactionSupport() {
  +        return true;
       }
       
       
  -   
   }
  
  
  
  1.5       +8 -10     jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MoveMethod.java
  
  Index: MoveMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MoveMethod.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- MoveMethod.java	2001/01/19 01:27:00	1.4
  +++ MoveMethod.java	2001/02/11 20:39:24	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MoveMethod.java,v 1.4 2001/01/19 01:27:00 remm Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/01/19 01:27:00 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MoveMethod.java,v 1.5 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -318,23 +318,21 @@
       protected void generateStatusText(WebdavXMLPrinter printer, String href,
                                         int statusCode) {
           printer.writeElement("d", "href", WebdavXMLPrinter.OPENING);
  -        printer.writeText(href);
  +        printer.writeText(URLEncode(href));
           printer.writeElement("d", "href", WebdavXMLPrinter.CLOSING);
           printer.writeElement("d", "status", WebdavXMLPrinter.OPENING);
           printer.writeText("HTTP/1.1 " + statusCode + " "
                             + WebdavStatus.getStatusText(statusCode));
           printer.writeElement("d", "status", WebdavXMLPrinter.CLOSING);
       }
  -   
  -	
  -	
  +    
  +    
       /**
        * Returns true
        */
  -	protected boolean methodNeedsTransactionSupport() {
  -		return true;
  +    protected boolean methodNeedsTransactionSupport() {
  +        return true;
       }
  -    
       
      
   }
  
  
  
  1.6       +27 -46    jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropFindMethod.java
  
  Index: PropFindMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropFindMethod.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- PropFindMethod.java	2001/01/29 12:18:05	1.5
  +++ PropFindMethod.java	2001/02/11 20:39:24	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropFindMethod.java,v 1.5 2001/01/29 12:18:05 juergen Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/01/29 12:18:05 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropFindMethod.java,v 1.6 2001/02/11 20:39:24 remm Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/02/11 20:39:24 $
    *
    * ====================================================================
    *
  @@ -207,28 +207,24 @@
       
           msProprietarySupport = isMsProprietarySupport();
           
  -    String depthStr = req.getHeader("Depth");
  -    
  -    if (depthStr == null) {
  -        depth = INFINITY;
  -    } else {
  -        if (depthStr.equals("0")) {
  +        String depthStr = req.getHeader("Depth");
  +        
  +        if (depthStr == null) {
  +            depth = INFINITY;
  +        } else {
  +            if (depthStr.equals("0")) {
                   depth = 0;
  -        }
  -        if (depthStr.equals("1")) {
  +            }
  +            if (depthStr.equals("1")) {
                   depth = 1;
  -        }
  -        if (depthStr.equals("infinity")) {
  +            }
  +            if (depthStr.equals("infinity")) {
                   depth = INFINITY;
  +            }
           }
  -    }
  -        
  -    if (req.getContentLength() != 0) {
           
  -            //Propfind propfind = null;
  +        if (req.getContentLength() != 0) {
               
  -            // Workaround : Castor doesn't work, so I use DOM in the meantime
  -            
               Node propNode = null;
               
               try {
  @@ -287,8 +283,8 @@
                   
               }
               
  -    }
  -    
  +        }
  +        
       }
       
       
  @@ -311,8 +307,6 @@
           try {
               resource = structure.retrieve(slideToken, resourceUri);
           } catch (StructureException e) {
  -            // We silently catch that since we need to generate some XML ...
  -            e.printStackTrace();
               try {
                   resp.sendError
                       (WebdavStatus.SC_NOT_FOUND,
  @@ -393,20 +387,6 @@
           // Send remaining data
           generatedXML.sendData();
           
  -        /*
  -    try {
  -            //System.out.println("Query result");
  -            //System.out.println(generatedXML.toString());
  -            
  -        Writer writer = resp.getWriter();
  -            writer.write(generatedXML.toString());
  -        writer.flush();
  -    } catch (Exception e) {
  -            e.printStackTrace();
  -        throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  -    }
  -        */
  -        
       }
       
       
  @@ -460,7 +440,7 @@
                       }
                   }
                   
  -                generatedXML.writeText(absoluteUri + toAppend);
  +                generatedXML.writeText(URLEncode(absoluteUri + toAppend));
                   
               } catch (RevisionDescriptorNotFoundException e) {
                   
  @@ -483,7 +463,7 @@
                       }
                   }
                   
  -                generatedXML.writeText(absoluteUri + toAppend);
  +                generatedXML.writeText(URLEncode(absoluteUri + toAppend));
                   
               }
               
  @@ -575,9 +555,9 @@
               generatedXML.writeElement(null, "propstat",
                                         WebdavXMLPrinter.CLOSING);
               
  -        break;
  -    case FIND_PROPERTY_NAMES :
  -        // Show properties for current object.
  +            break;
  +        case FIND_PROPERTY_NAMES :
  +            // Show properties for current object.
               
               status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
                                   + " " + WebdavStatus.getStatusText
  @@ -616,9 +596,9 @@
               generatedXML.writeElement(null, "propstat",
                                         WebdavXMLPrinter.CLOSING);
               
  -        break;
  -    case FIND_BY_PROPERTY :
  -        // Show requested properties value.
  +            break;
  +        case FIND_BY_PROPERTY :
  +            // Show requested properties value.
               
               propertyList = propertyVector.elements();
               
  @@ -889,7 +869,8 @@
           
           generatedXML.writeElement(null, "owner", WebdavXMLPrinter.OPENING);
           generatedXML.writeElement(null, "href", WebdavXMLPrinter.OPENING);
  -        generatedXML.writeText(req.getServletPath() + token.getSubjectUri());
  +        generatedXML.writeText
  +            (URLEncode(req.getServletPath() + token.getSubjectUri()));
           generatedXML.writeElement(null, "href", WebdavXMLPrinter.CLOSING);
           generatedXML.writeElement(null, "owner", WebdavXMLPrinter.CLOSING);
           
  
  
  
  1.6       +4 -4      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMethod.java
  
  Index: PropPatchMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMethod.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- PropPatchMethod.java	2001/01/29 12:18:06	1.5
  +++ PropPatchMethod.java	2001/02/11 20:39:25	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMethod.java,v 1.5 2001/01/29 12:18:06 juergen Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/01/29 12:18:06 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMethod.java,v 1.6 2001/02/11 20:39:25 remm Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/02/11 20:39:25 $
    *
    * ====================================================================
    *
  @@ -494,7 +494,7 @@
           
           generatedXML.writeElement("d", null, "response",
                                     WebdavXMLPrinter.OPENING);
  -        generatedXML.writeProperty("d", null, "href", requestUri);
  +        generatedXML.writeProperty("d", null, "href", URLEncode(requestUri));
           
           
           
  
  
  
  1.6       +7 -9      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.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- PutMethod.java	2001/01/17 16:49:03	1.5
  +++ PutMethod.java	2001/02/11 20:39:25	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PutMethod.java,v 1.5 2001/01/17 16:49:03 juergen Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/01/17 16:49:03 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PutMethod.java,v 1.6 2001/02/11 20:39:25 remm Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/02/11 20:39:25 $
    *
    * ====================================================================
    *
  @@ -411,16 +411,14 @@
           
           
       }
  -  
  -	
  -	
  +    
  +    
       /**
        * Returns true
        */
  -	protected boolean methodNeedsTransactionSupport() {
  -		return true;
  +    protected boolean methodNeedsTransactionSupport() {
  +        return true;
       }
       
       
  -
   }
  
  
  
  1.4       +7 -9      jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UnlockMethod.java
  
  Index: UnlockMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UnlockMethod.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- UnlockMethod.java	2001/01/17 16:49:03	1.3
  +++ UnlockMethod.java	2001/02/11 20:39:25	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UnlockMethod.java,v 1.3 2001/01/17 16:49:03 juergen Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/01/17 16:49:03 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UnlockMethod.java,v 1.4 2001/02/11 20:39:25 remm Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/02/11 20:39:25 $
    *
    * ====================================================================
    *
  @@ -93,6 +93,7 @@
        */
       private String toUnlock;
       
  +    
       /**
        * Id.
        */
  @@ -187,17 +188,14 @@
           }
           
       }
  +    
       
  -   
  -	
  -	
       /**
        * Returns true
        */
  -	protected boolean methodNeedsTransactionSupport() {
  -		return true;
  +    protected boolean methodNeedsTransactionSupport() {
  +        return true;
       }
       
       
  -   
   }
  
  
  
  1.10      +155 -59   jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/WebdavMethod.java
  
  Index: WebdavMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/WebdavMethod.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- WebdavMethod.java	2001/02/08 08:02:00	1.9
  +++ WebdavMethod.java	2001/02/11 20:39:25	1.10
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/WebdavMethod.java,v 1.9 2001/02/08 08:02:00 remm Exp $
  - * $Revision: 1.9 $
  - * $Date: 2001/02/08 08:02:00 $
  + * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/WebdavMethod.java,v 1.10 2001/02/11 20:39:25 remm Exp $
  + * $Revision: 1.10 $
  + * $Date: 2001/02/11 20:39:25 $
    *
    * ====================================================================
    *
  @@ -233,6 +233,40 @@
       protected static String managerServletPath = "/manager/";
       
       
  +    /**
  +     * Array containing the safe characters set.
  +     */
  +    protected static BitSet safeCharacters;
  +
  +
  +    protected static final char[] hexadecimal = 
  +    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
  +     'A', 'B', 'C', 'D', 'E', 'F'};
  +
  +
  +    // ----------------------------------------------------- Static Initializer
  +
  +
  +    static {
  +	safeCharacters = new BitSet(256);
  +	int i;
  +	for (i = 'a'; i <= 'z'; i++) {
  +	    safeCharacters.set(i);
  +	}
  +	for (i = 'A'; i <= 'Z'; i++) {
  +	    safeCharacters.set(i);
  +	}
  +	for (i = '0'; i <= '9'; i++) {
  +	    safeCharacters.set(i);
  +	}
  +	safeCharacters.set('-');
  +	safeCharacters.set('_');
  +	safeCharacters.set('.');
  +	safeCharacters.set('*');
  +	safeCharacters.set('/');
  +    }
  +    
  +    
       // ----------------------------------------------------------- Constructors
       
       
  @@ -554,67 +588,129 @@
       
       
       /**
  -     * Decode and return the specified URL-encoded String.
  -     *
  -     * @param str The url-encoded string
  -     *
  -     * @exception IllegalArgumentException if a '%' character is not followed
  -     * by a valid 2-digit hexadecimal number
  -     */
  -    protected static String URLDecode(String str)
  -    throws IllegalArgumentException {
  +     * Return a context-relative path, beginning with a "/", that represents
  +     * the canonical version of the specified path after ".." and "." elements
  +     * are resolved out.  If the specified path attempts to go outside the
  +     * boundaries of the current context (i.e. too many ".." path elements
  +     * are present), return <code>null</code> instead.
  +     *
  +     * @param path Path to be normalized
  +     */
  +    protected static String URLDecode(String path) {
  +
  +        if (path == null)
  +            return null;
  +
  +	// Resolve encoded characters in the normalized path,
  +	// which also handles encoded spaces so we can skip that later.
  +	// Placed at the beginning of the chain so that encoded 
  +	// bad stuff(tm) can be caught by the later checks
  +        String normalized = path;
  +        if (normalized.indexOf('%') >= 0)
  +            // FIXME: Use configurable encoding here.
  +            normalized = RequestUtil.URLDecode(normalized, "UTF8");
  +        if (normalized == null)
  +            return (null);
  +        
  +	// Normalize the slashes and add leading slash if necessary
  +	if (normalized.indexOf('\\') >= 0)
  +	    normalized = normalized.replace('\\', '/');
  +	if (!normalized.startsWith("/"))
  +	    normalized = "/" + normalized;
  +
  +	// Resolve occurrences of "//" in the normalized path
  +	while (true) {
  +	    int index = normalized.indexOf("//");
  +	    if (index < 0)
  +		break;
  +	    normalized = normalized.substring(0, index) +
  +		normalized.substring(index + 1);
  +	}
  +
  +	// Resolve occurrences of "/./" in the normalized path
  +	while (true) {
  +	    int index = normalized.indexOf("/./");
  +	    if (index < 0)
  +		break;
  +	    normalized = normalized.substring(0, index) +
  +		normalized.substring(index + 2);
  +	}
  +
  +	// Resolve occurrences of "/../" in the normalized path
  +	while (true) {
  +	    int index = normalized.indexOf("/../");
  +	    if (index < 0)
  +		break;
  +	    if (index == 0)
  +		return (null);	// Trying to go outside our context
  +	    int index2 = normalized.lastIndexOf('/', index - 1);
  +	    normalized = normalized.substring(0, index2) +
  +		normalized.substring(index + 3);
  +	}
  +
  +	// Return the normalized path that we have completed
  +	return (normalized);
   
  -    if (str == null)
  -        return (null);
  +    }
   
  -    StringBuffer dec = new StringBuffer();
  -    int pos = 0;
  -    int len = str.length();
  -    dec.ensureCapacity(str.length());
  -
  -    while (pos < len) {
  -        int lookahead;  // Look-ahead position
  -
  -        // Look ahead to the next URLencoded metacharacter, if any
  -        for (lookahead = pos; lookahead < len; lookahead++) {
  -        char ch = str.charAt(lookahead);
  -        if ((ch == '+') || (ch == '%'))
  -            break;
  -        }
  -
  -        // If there were non-metacharacters, copy them as a block
  -        if (lookahead > pos) {
  -        dec.append(str.substring(pos, lookahead));
  -        pos = lookahead;
  -        }
  -
  -        // Shortcut out if we are at the end of the string
  -        if (pos >= len)
  -        break;
  -
  -        // Process the next metacharacter
  -        char meta = str.charAt(pos);
  -        if (meta == '+') {
  -        dec.append(' ');
  -        pos++;
  -        } else if (meta == '%') {
  +
  +    /**
  +     * URL rewriter.
  +     * 
  +     * @param path Path which has to be rewiten
  +     */
  +    protected static String URLEncode(String path) {
  +
  +        /**
  +         * Note: This code portion is very similar to URLEncoder.encode.
  +         * Unfortunately, there is no way to specify to the URLEncoder which
  +         * characters should be encoded. Here, ' ' should be encoded as "%20"
  +         * and '/' shouldn't be encoded.
  +         */
  +
  +	int maxBytesPerChar = 10;
  +        int caseDiff = ('a' - 'A');
  +        StringBuffer rewrittenPath = new StringBuffer(path.length());
  +	ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
  +        OutputStreamWriter writer = null;
           try {
  -            dec.append((char) Integer.parseInt
  -                   (str.substring(pos+1, pos+3), 16));
  -        } catch (NumberFormatException e) {
  -            throw new IllegalArgumentException
  -            ("Invalid hexadecimal '" + str.substring(pos+1, pos+3)
  -             + " in URLencoded string");
  -        } catch (StringIndexOutOfBoundsException e) {
  -            throw new IllegalArgumentException
  -            ("Invalid unescaped '%' in URLcoded string");
  -        }
  -        pos += 3;
  +            // FIXME: Use the same encoding as the one specified above
  +            writer = new OutputStreamWriter(buf, "UTF8");
  +        } catch (Exception e) {
  +            e.printStackTrace();
  +            writer = new OutputStreamWriter(buf);
           }
  -    }
  -    return (dec.toString());
   
  -    }
  +        for (int i = 0; i < path.length(); i++) {
  +            int c = (int) path.charAt(i);
  +            if (safeCharacters.get(c)) {
  +                rewrittenPath.append((char)c);
  +            } else {
  +                // convert to external encoding before hex conversion
  +                try {
  +                    writer.write(c);
  +                    writer.flush();
  +                } catch(IOException e) {
  +                    buf.reset();
  +                    continue;
  +                }
  +                byte[] ba = buf.toByteArray();
  +                for (int j = 0; j < ba.length; j++) {
  +                    // Converting each byte in the buffer
  +                    byte toEncode = ba[j];
  +                    rewrittenPath.append('%');
  +                    int low = (int) (toEncode & 0x0f);
  +                    int high = (int) ((toEncode & 0xf0) >> 4);
  +                    rewrittenPath.append(hexadecimal[high]);
  +                    rewrittenPath.append(hexadecimal[low]);
  +                }
  +                buf.reset();
  +            }
  +        }
   
  +        return rewrittenPath.toString();
   
  +    }
  +    
  +    
   }