Bug 32886 - client webdav lib doesn't return child collections using listwebdavresources
Summary: client webdav lib doesn't return child collections using listwebdavresources
Status: REOPENED
Alias: None
Product: Slide
Classification: Unclassified
Component: WebDAV client (show other bugs)
Version: 2.1
Hardware: PC Windows XP
: P2 critical with 9 votes (vote)
Target Milestone: ---
Assignee: Slide Developer List
URL:
Keywords:
: 22585 32470 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-12-30 11:07 UTC by canrull
Modified: 2006-10-06 05:26 UTC (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description canrull 2004-12-30 11:07:06 UTC
I have a mature application working with client webdavlib 2.0, with the webdav
server that comes with tomcat 5.0.28. Client webdavlib 2.1 seams to be broken.
Method listWebdavResources() doesn't return child collections, but the parent
collection itself.

This is the directory structure I tested:

parent/
	child1/
	child2/
	file1.txt
	file2.txt


This is my code:

HttpURL url = new HttpURL("http://localhost:8080/webdav/[some-url]");
url.setUserinfo("user", "pass");
WebdavResource wdResource = new WebdavResource(url);
WebdavResource[] webdavList = wdResource.listWebdavResources();

	System.out.println("Display Name: " + wdResource.getDisplayName());
	WebdavResource[] webdavList = null;
	webdavList = wdResource.listWebdavResources();
	System.out.println("Children returned: " + webdavList.length);

	for (int idx = 0; idx < webdavList.length; idx++) {
		System.out.println("\t" + webdavList[idx].getDisplayName());
		System.out.println("\t" + webdavList[idx].getHttpURL());
	}

This is the output:

Display Name: parent
Children returned: 3
	file1.txt
	http://localhost:8080/webdav/parent/file1.txt
	child2
	http://localhost:8080/webdav/parent/
	file2.txt
	http://localhost:8080/webdav/parent/file2.txt

The third result is the URL of the parent, with display name "child2"!
So nothing about child1, although it comes from the server (see trace).
And child2 URL is bad, because it shows parent URL.

In general, I see that collection childs are never shown.

And this is the http tracing I got. There are two requests involved, the first
using depth 0 and the second using depth 1.

FIRST REQUEST
===============

PROPFIND /webdav/parent HTTP/1.1
Authorization: Basic anVncmVnbzE6cGFkZW50cm8=
Content-Type: text/xml; charset=utf-8
User-Agent: Jakarta Commons-HttpClient/2.0final
Host: localhost:8080
Content-Length: 207
Depth: 0

<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:">
	<D:prop>
		<D:displayname/>
		<D:getcontentlength/>
		<D:getcontenttype/>
		<D:resourcetype/>
		<D:getlastmodified/>
		<D:lockdiscovery/>
	</D:prop>
</D:propfind>

FIRST RESPONSE
=================

HTTP/1.1 207 Multi-Estado
Content-Type: text/xml;charset=UTF-8
Content-Length: 436
Date: Thu, 30 Dec 2004 09:51:45 GMT
Server: Apache-Coyote/1.1

<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">
	<response>
		<href>/webdav/parent/</href>
		<propstat>
			<prop>
				<displayname><![CDATA[parent]]></displayname>
				<resourcetype>
					<collection/>
				</resourcetype>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<getcontentlength/>
				<getcontenttype/>
				<getlastmodified/>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
</multistatus>

SECOND REQUEST
================

PROPFIND /webdav/parent HTTP/1.1
Authorization: Basic anVncmVnbzE6cGFkZW50cm8=
Content-Type: text/xml; charset=utf-8
User-Agent: Jakarta Commons-HttpClient/2.0final
Host: localhost:8080
Content-Length: 207
Depth: 1

<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:">
	<D:prop>
		<D:displayname/>
		<D:getcontentlength/>
		<D:getcontenttype/>
		<D:resourcetype/>
		<D:getlastmodified/>
		<D:lockdiscovery/>
	</D:prop>
</D:propfind>

SECOND RESPONSE
=================

HTTP/1.1 207 Multi-Estado
Content-Type: text/xml;charset=UTF-8
Content-Length: 2028
Date: Thu, 30 Dec 2004 09:51:45 GMT
Server: Apache-Coyote/1.1

<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">
	<response>
		<href>/webdav/parent/</href>
		<propstat>
			<prop>
				<displayname><![CDATA[parent]]></displayname>
				<resourcetype>
					<collection/>
				</resourcetype>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<getcontentlength/>
				<getcontenttype/>
				<getlastmodified/>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
	<response>
		<href>/webdav/parent/file2.txt</href>
		<propstat>
			<prop>
				<displayname><![CDATA[file2.txt]]></displayname>
				<getcontentlength>10</getcontentlength>
				<getcontenttype>text/plain</getcontenttype>
				<resourcetype/>
				<getlastmodified>Mon, 27 Sep 2004 11:13:07 GMT</getlastmodified>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
	<response>
		<href>/webdav/parent/file1.txt</href>
		<propstat>
			<prop>
				<displayname><![CDATA[file1.txt]]></displayname>
				<getcontentlength>10</getcontentlength>
				<getcontenttype>text/plain</getcontenttype>
				<resourcetype/>
				<getlastmodified>Mon, 27 Sep 2004 11:13:07 GMT</getlastmodified>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
	<response>
		<href>/webdav/parent/child2/</href>
		<propstat>
			<prop>
				<displayname><![CDATA[child2]]></displayname>
				<resourcetype>
					<collection/>
				</resourcetype>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<getcontentlength/>
				<getcontenttype/>
				<getlastmodified/>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
	<response>
		<href>/webdav/parent/child1/</href>
		<propstat>
			<prop>
				<displayname><![CDATA[child1]]></displayname>
				<resourcetype>
					<collection/>
				</resourcetype>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
		<propstat>
			<prop>
				<getcontentlength/>
				<getcontenttype/>
				<getlastmodified/>
				<lockdiscovery/>
			</prop>
			<status>HTTP/1.1 404 Not Found</status>
		</propstat>
	</response>
</multistatus>

As you can see from the second response, all the resources are returned
correctly from the server.
Comment 1 Rob Leathley 2005-02-03 15:22:04 UTC
I have a very similar problem: when I listWebdavResources() on a collection,
only the first child collection is returned, and its path is wrong (it is the
path of the parent).  This worked with 2.0 but not in 2.1.

What is the status of this bug?  If it is genuine and not an error in usage, I
am suprised anyone can use this version.
Comment 2 canrull 2005-02-04 09:53:19 UTC
(In reply to comment #1)
> I have a very similar problem: when I listWebdavResources() on a collection,
> only the first child collection is returned, and its path is wrong (it is the
> path of the parent).  This worked with 2.0 but not in 2.1.
> 
> What is the status of this bug?  If it is genuine and not an error in usage, I
> am suprised anyone can use this version.


I am afraid few people use other WEBDAV servers than Slide. I guess this is not
a problem with Slide server...

Are you Rob using Slide server?

I'll patiently wait for a new release of this library, 2.1 is not usable for me.
Comment 3 Rob Leathley 2005-02-04 10:38:07 UTC
(In reply to comment #2)

No, I'm using the Apache webdav server.

2.1 isn't usable for me either.  I was hoping it may fix some problem with
escaped url's (bug #33136)
Comment 4 Zoran M. Djurisic 2005-02-08 03:07:06 UTC
(In reply to comment #3)
> (In reply to comment #2)
> No, I'm using the Apache webdav server.
> 2.1 isn't usable for me either.  I was hoping it may fix some problem with
> escaped url's (bug #33136)

I have the same problem accessing a DAV server running on IIS 5.1.

In addition, list() also returns the parent, rather than listing its contents
Comment 5 Daniel Hasler 2005-02-11 22:05:37 UTC
I experienced the same problem using the slide WebDAV client library against 
subversion 1.1.3.
Comment 6 Robert Sanders 2005-02-12 05:50:14 UTC
I think I had reported this too.  I traced this down to the following:

In WebdavResource, line 1086:  URIUtil.getName(href) is used to get the name of
the item; however as per the javadocs this method returns an empty string if
href ends with a slash.  At least with subversion, all hrefs to collections are
reported as ending with a slash; therefore no sub-collections are ever reported
by the WebdavResource.listWebdavResources() or associated methods.

My fix:  replace URIUtil.getName(href)  with  WebdavResource.getName(href)  this
seems to work fine for me; although as I said I am not sure what, if any,
implications this might have on other functionality. 
Comment 7 canrull 2005-02-14 12:05:22 UTC
(In reply to comment #6)

I tried this solution because I saw your post before reporting the bug.

It didn't solve my problem.
Comment 8 Philip MacIver 2005-03-15 06:19:13 UTC
(In reply to comment #6)
> I think I had reported this too.  I traced this down to the following:
> 
> In WebdavResource, line 1086:  URIUtil.getName(href) is used to get the name of
> the item; however as per the javadocs this method returns an empty string if
> href ends with a slash.  At least with subversion, all hrefs to collections are
> reported as ending with a slash; therefore no sub-collections are ever reported
> by the WebdavResource.listWebdavResources() or associated methods.
> 
> My fix:  replace URIUtil.getName(href)  with  WebdavResource.getName(href)  this
> seems to work fine for me; although as I said I am not sure what, if any,
> implications this might have on other functionality. 


Thanks for this suggestion. I too looked into the source code and found this to
be the problem. But the solution I used was to add the following lines

href = href.endsWith("/") ? href.substring(0,href.length() - 1) : href;
href=href.replaceAll("\\[","%5B");
href=href.replaceAll("\\]","%5D");
href=href.replaceAll("\\|","%7C");
href=href.replaceAll("\\^","%5E");
href=href.replaceAll("\\`","%60");

This I found to work perfectly. And the reason for the replaces statments is to
encode all special charaters that the exchange server might return. I suppose
that this would be better done with the URLEncoder.

This seems to be a long standing issue and because the fix is so simple I do not
know why it has not been implemented yet.

I will be using my modified class until the changes are implemented in the
official source code.
Comment 9 James Mason 2005-03-17 08:22:58 UTC
Fix committed to HEAD. If no one finds any problems with it I'll backport it to
the 2.1 branch.

I used Robert's fix, but I tweaked the getName() method a bit. It was decoding
the name which made anything with spaces in it invalid.
Comment 10 James Mason 2005-03-17 08:34:08 UTC
*** Bug 22585 has been marked as a duplicate of this bug. ***
Comment 11 James Mason 2005-03-17 08:43:43 UTC
*** Bug 32470 has been marked as a duplicate of this bug. ***
Comment 12 canrull 2005-03-17 11:31:17 UTC
Thanks indeed, 

today's cvs version of webdavclient runs smoothly (2.2pre1).

I think I'll wait for 2.2 to be released, instead of getting 2.1 patched (I'll
jump over it!)
 
regards,
canrull
Comment 13 Michael N. Christoff 2006-02-14 23:32:05 UTC
With regard to bug 32886

	http://issues.apache.org/bugzilla/show_bug.cgi?id=32886

I was wondering what version of the Slide client API the fix was put in, as I 
get the same error described in this bug with the 2.1 binary version I 
downloaded off the website today.  I assume I'd need to use a 2.2 beta or 
release candidate(?)

More info:

Folder structure is below ('+' denotes folder, '-' denotes file.  Note: these 
symbols are not part of the file name):

http://dav.biscu.com/

	+NewFolder1

		+A New Folder

			+SubSubFolder

				-MyDocsOnline.txt
				-TestFileUpload.txt

			-MyDocsOnline.txt
			-TestFileUpload.txt

		+NewFolder3

			-MyDocsOnline.txt
			-TestFileUpload.txt

		-MyDocsOnline.txt
		-TestFileUpload.txt

	+NewFolder

	-MyDocsOnline.txt
	-TestFileUpload.txt


The code I used to test is below:


    HttpURL url = new HttpURL("http://dav.Biscu.com/");
    url.setUserinfo("dmx_dawg@hotmail.com", "TUSu_618");
        
    WebdavResource wdr = new WebdavResource(url);
    recurseResources(wdr, 0);


    public void recurseResources(WebdavResource parent, int depth)
        throws Exception
    {
        int MAX_DEPTH = 3;
        
        if(depth > MAX_DEPTH || parent == null)
            return;
        
        WebdavResource[] wdrsArray = parent.listWebdavResources();
        
        for(WebdavResource r : wdrsArray)
        {            
            String s = r.isCollection() ? "[COLLECTION] " : "[FILE] ";
            System.out.println(repeat("\t", depth) + s + r.getDisplayName
());            
            
            if(r.isCollection())
                recurseResources(r, depth + 1);
        }
    }

    public String repeat(String s, int n)
    {
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < n; ++i)
            sb.append(s);
        return sb.toString();
    }

The output was:

[FILE] TestFileUpload.txt
[FILE] MyDocsOnline.txt
[COLLECTION] NewFolder2
        [FILE] TestFileUpload.txt
        [FILE] MyDocsOnline.txt
        [COLLECTION] NewFolder2
                [FILE] TestFileUpload.txt
                [FILE] MyDocsOnline.txt
                [COLLECTION] NewFolder2
                        [FILE] TestFileUpload.txt
                        [FILE] MyDocsOnline.txt
                        [COLLECTION] NewFolder2
Comment 14 Igor A. Karpov 2006-04-11 10:59:08 UTC
I bumped into the problem as well. 2.1 didn't work for me.
A solution was to change a part of WebdavResource.setWebdavProperties after

if (!itself) {
String myURI = httpURL.getEscapedURI();

...

to

if (!itself) {
                String myURI = httpURL.getEscapedURI();
                final String adjustedHref = href.endsWith("/") ?
href.substring(0, href.length() - 1) : href;
                final String name = URIUtil.getName(adjustedHref);
                char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
                                   + name).toCharArray();

the problem is that children's hrefs can end with '/' and in this case
URIUtil.getName returns empty string. Because of that childURI is the same as
myURI (bug!!!)
Comment 15 Igor A. Karpov 2006-04-11 10:59:34 UTC
I bumped into the problem as well. 2.1 didn't work for me.
A solution was to change a part of WebdavResource.setWebdavProperties after

if (!itself) {
String myURI = httpURL.getEscapedURI();

...

to

if (!itself) {
                String myURI = httpURL.getEscapedURI();
                final String adjustedHref = href.endsWith("/") ?
href.substring(0, href.length() - 1) : href;
                final String name = URIUtil.getName(adjustedHref);
                char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
                                   + name).toCharArray();

the problem is that children's hrefs can end with '/' and in this case
URIUtil.getName returns empty string. Because of that childURI is the same as
myURI (bug!!!)
Comment 16 Michael N. Christoff 2006-05-18 22:34:57 UTC
(In reply to comment #14)
> I bumped into the problem as well. 2.1 didn't work for me.
> A solution was to change a part of WebdavResource.setWebdavProperties after
> 
> if (!itself) {
> String myURI = httpURL.getEscapedURI();
> 
> ...
> 
> to
> 
> if (!itself) {
>                 String myURI = httpURL.getEscapedURI();
>                 final String adjustedHref = href.endsWith("/") ?
> href.substring(0, href.length() - 1) : href;
>                 final String name = URIUtil.getName(adjustedHref);
>                 char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
>                                    + name).toCharArray();
> 
> the problem is that children's hrefs can end with '/' and in this case
> URIUtil.getName returns empty string. Because of that childURI is the same as
> myURI (bug!!!)


Thanks Igor!  Everything works fine now.  Also thanks to Robert and Philip.  For
those who want a fast cut-and-paste solution, simply replace the entire

    protected void setWebdavProperties(Enumeration responses)

method in org.apache.webdav.lib.WebdavResource with the following code:

// START: FIX /////////////////////////////////////////////////////
    /**
     * Set WebDAV properties following to the given http URL.
     * This method is fundamental for getting information of a collection.
     *
     * @param responses An enumeration over {@link ResponseEntity} items, one
     * for each resource for which information was returned via PROPFIND.
     *
     * @exception HttpException
     * @exception IOException The socket error with a server.
     */
    protected void setWebdavProperties(Enumeration responses)
        throws HttpException, IOException {
    
        // Make the resources in the collection empty.
        childResources.removeAll();
        while (responses.hasMoreElements()) {
    
            ResponseEntity response =
                (ResponseEntity) responses.nextElement();
    
            boolean itself = false;
            String href = response.getHref();
            if (!href.startsWith("/"))
                href = URIUtil.getPath(href);
            href = decodeMarks(href);

            /*
             * Decode URIs to common (unescaped) format for comparison 
             * as HttpClient.URI.setPath() doesn't escape $ and : chars.
             */
            String httpURLPath = httpURL.getPath();
            String escapedHref = URIUtil.decode(href);
            
            // Normalize them to both have trailing slashes if they differ by
one in length.
            int lenDiff = escapedHref.length() - httpURLPath.length();
            int compareLen = 0;
            
            if ( lenDiff == -1 && !escapedHref.endsWith("/")) {
                compareLen = escapedHref.length();
                lenDiff = 0;
            }
            else
            if ( lenDiff == 1 && !httpURLPath.endsWith("/")) {
                compareLen = httpURLPath.length();
                lenDiff = 0;
            }

            // if they are the same length then compare them.
            if (lenDiff == 0) {
                if ((compareLen == 0 && httpURLPath.equals(escapedHref))
                    || httpURLPath.regionMatches(0, escapedHref, 0, compareLen))
                {
                    // escaped href and http path are the same
                    // Set the status code for this resource.
                    if (response.getStatusCode() > 0)
                        setStatusCode(response.getStatusCode());
                    setExistence(true);
                    itself = true;
                }
            }
    
            // Get to know each resource.
            WebdavResource workingResource = null;
            if (itself) {
                workingResource = this;
            }
            else {
                workingResource = createWebdavResource(client);
                workingResource.setDebug(debug);
            }
    
            // clear the current lock set
            workingResource.setLockDiscovery(null);
    
            // Process the resource's properties
            Enumeration properties = response.getProperties();
            while (properties.hasMoreElements()) {
    
                Property property = (Property) properties.nextElement();
    
                // ------------------------------  Checking WebDAV properties
                workingResource.processProperty(property);
            }
    
            String displayName = workingResource.getDisplayName();
    
            if (displayName == null || displayName.trim().equals("")) {
                displayName = getName(href);
            }

            /** BUGGY CODE
            if (!itself) {
                String myURI = httpURL.getEscapedURI();
                char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
                                   + URIUtil.getName(href)).toCharArray();
                HttpURL childURL = httpURL instanceof HttpsURL
                                   ? new HttpsURL(childURI)
                                   : new HttpURL(childURI);
                childURL.setRawAuthority(httpURL.getRawAuthority());
                workingResource.setHttpURL(childURL, NOACTION, defaultDepth);
                workingResource.setExistence(true);
                workingResource.setOverwrite(getOverwrite());
            }
            */
            
            /** FIX ********/
            if (!itself) {                
                String myURI = httpURL.getEscapedURI();
                
                /**
                	Checks if href contains trailing '/', and if so removes it.
                	This ensures URIUtil.getName does not return an empty
                	String when we don't want it to.
                	
                	See http://issues.apache.org/bugzilla/show_bug.cgi?id=32886
                	for more information.
                */
                String fixedHref = href.endsWith("/") ?
                    href.substring(0, href.length() - 1) : href;
                
                char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
                                   + URIUtil.getName(fixedHref)).toCharArray();
                
                HttpURL childURL = httpURL instanceof HttpsURL
                                   ? new HttpsURL(childURI)
                                   : new HttpURL(childURI);
                childURL.setRawAuthority(httpURL.getRawAuthority());
                workingResource.setHttpURL(childURL, NOACTION, defaultDepth);
                workingResource.setExistence(true);
                workingResource.setOverwrite(getOverwrite());
            }            
            /**************/
            
            
            workingResource.setDisplayName(displayName);
    
            if (!itself)
                childResources.addResource(workingResource);
        }
    }
// END: FIX /////////////////////////////////////////////////////

The code is based on Igor's solution and should work fine.  Please post here if
you stumble upon any issues the fix causes.  In the meantime however, its
working perfectly for me.

Cheers!

Mike N. Christoff
Comment 17 Elina 2006-10-06 05:26:49 UTC
I am still having problem with this solution. I now have deleted folders beeing
listed with the listWebdavResources call...

(In reply to comment #0)
> I have a mature application working with client webdavlib 2.0, with the webdav
> server that comes with tomcat 5.0.28. Client webdavlib 2.1 seams to be broken.
> Method listWebdavResources() doesn't return child collections, but the parent
> collection itself.
> 
> This is the directory structure I tested:
> 
> parent/
> 	child1/
> 	child2/
> 	file1.txt
> 	file2.txt
> 
> 
> This is my code:
> 
> HttpURL url = new HttpURL("http://localhost:8080/webdav/[some-url]");
> url.setUserinfo("user", "pass");
> WebdavResource wdResource = new WebdavResource(url);
> WebdavResource[] webdavList = wdResource.listWebdavResources();
> 
> 	System.out.println("Display Name: " + wdResource.getDisplayName());
> 	WebdavResource[] webdavList = null;
> 	webdavList = wdResource.listWebdavResources();
> 	System.out.println("Children returned: " + webdavList.length);
> 
> 	for (int idx = 0; idx < webdavList.length; idx++) {
> 		System.out.println("\t" + webdavList[idx].getDisplayName());
> 		System.out.println("\t" + webdavList[idx].getHttpURL());
> 	}
> 
> This is the output:
> 
> Display Name: parent
> Children returned: 3
> 	file1.txt
> 	http://localhost:8080/webdav/parent/file1.txt
> 	child2
> 	http://localhost:8080/webdav/parent/
> 	file2.txt
> 	http://localhost:8080/webdav/parent/file2.txt
> 
> The third result is the URL of the parent, with display name "child2"!
> So nothing about child1, although it comes from the server (see trace).
> And child2 URL is bad, because it shows parent URL.
> 
> In general, I see that collection childs are never shown.
> 
> And this is the http tracing I got. There are two requests involved, the first
> using depth 0 and the second using depth 1.
> 
> FIRST REQUEST
> ===============
> 
> PROPFIND /webdav/parent HTTP/1.1
> Authorization: Basic anVncmVnbzE6cGFkZW50cm8=
> Content-Type: text/xml; charset=utf-8
> User-Agent: Jakarta Commons-HttpClient/2.0final
> Host: localhost:8080
> Content-Length: 207
> Depth: 0
> 
> <?xml version="1.0" encoding="utf-8"?>
> <D:propfind xmlns:D="DAV:">
> 	<D:prop>
> 		<D:displayname/>
> 		<D:getcontentlength/>
> 		<D:getcontenttype/>
> 		<D:resourcetype/>
> 		<D:getlastmodified/>
> 		<D:lockdiscovery/>
> 	</D:prop>
> </D:propfind>
> 
> FIRST RESPONSE
> =================
> 
> HTTP/1.1 207 Multi-Estado
> Content-Type: text/xml;charset=UTF-8
> Content-Length: 436
> Date: Thu, 30 Dec 2004 09:51:45 GMT
> Server: Apache-Coyote/1.1
> 
> <?xml version="1.0" encoding="utf-8"?>
> <multistatus xmlns="DAV:">
> 	<response>
> 		<href>/webdav/parent/</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[parent]]></displayname>
> 				<resourcetype>
> 					<collection/>
> 				</resourcetype>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<getcontentlength/>
> 				<getcontenttype/>
> 				<getlastmodified/>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> </multistatus>
> 
> SECOND REQUEST
> ================
> 
> PROPFIND /webdav/parent HTTP/1.1
> Authorization: Basic anVncmVnbzE6cGFkZW50cm8=
> Content-Type: text/xml; charset=utf-8
> User-Agent: Jakarta Commons-HttpClient/2.0final
> Host: localhost:8080
> Content-Length: 207
> Depth: 1
> 
> <?xml version="1.0" encoding="utf-8"?>
> <D:propfind xmlns:D="DAV:">
> 	<D:prop>
> 		<D:displayname/>
> 		<D:getcontentlength/>
> 		<D:getcontenttype/>
> 		<D:resourcetype/>
> 		<D:getlastmodified/>
> 		<D:lockdiscovery/>
> 	</D:prop>
> </D:propfind>
> 
> SECOND RESPONSE
> =================
> 
> HTTP/1.1 207 Multi-Estado
> Content-Type: text/xml;charset=UTF-8
> Content-Length: 2028
> Date: Thu, 30 Dec 2004 09:51:45 GMT
> Server: Apache-Coyote/1.1
> 
> <?xml version="1.0" encoding="utf-8"?>
> <multistatus xmlns="DAV:">
> 	<response>
> 		<href>/webdav/parent/</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[parent]]></displayname>
> 				<resourcetype>
> 					<collection/>
> 				</resourcetype>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<getcontentlength/>
> 				<getcontenttype/>
> 				<getlastmodified/>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> 	<response>
> 		<href>/webdav/parent/file2.txt</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[file2.txt]]></displayname>
> 				<getcontentlength>10</getcontentlength>
> 				<getcontenttype>text/plain</getcontenttype>
> 				<resourcetype/>
> 				<getlastmodified>Mon, 27 Sep 2004 11:13:07 GMT</getlastmodified>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> 	<response>
> 		<href>/webdav/parent/file1.txt</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[file1.txt]]></displayname>
> 				<getcontentlength>10</getcontentlength>
> 				<getcontenttype>text/plain</getcontenttype>
> 				<resourcetype/>
> 				<getlastmodified>Mon, 27 Sep 2004 11:13:07 GMT</getlastmodified>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> 	<response>
> 		<href>/webdav/parent/child2/</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[child2]]></displayname>
> 				<resourcetype>
> 					<collection/>
> 				</resourcetype>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<getcontentlength/>
> 				<getcontenttype/>
> 				<getlastmodified/>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> 	<response>
> 		<href>/webdav/parent/child1/</href>
> 		<propstat>
> 			<prop>
> 				<displayname><![CDATA[child1]]></displayname>
> 				<resourcetype>
> 					<collection/>
> 				</resourcetype>
> 			</prop>
> 			<status>HTTP/1.1 200 OK</status>
> 		</propstat>
> 		<propstat>
> 			<prop>
> 				<getcontentlength/>
> 				<getcontenttype/>
> 				<getlastmodified/>
> 				<lockdiscovery/>
> 			</prop>
> 			<status>HTTP/1.1 404 Not Found</status>
> 		</propstat>
> 	</response>
> </multistatus>
> 
> As you can see from the second response, all the resources are returned
> correctly from the server.

(In reply to comment #16)
> (In reply to comment #14)
> > I bumped into the problem as well. 2.1 didn't work for me.
> > A solution was to change a part of WebdavResource.setWebdavProperties after
> > 
> > if (!itself) {
> > String myURI = httpURL.getEscapedURI();
> > 
> > ...
> > 
> > to
> > 
> > if (!itself) {
> >                 String myURI = httpURL.getEscapedURI();
> >                 final String adjustedHref = href.endsWith("/") ?
> > href.substring(0, href.length() - 1) : href;
> >                 final String name = URIUtil.getName(adjustedHref);
> >                 char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
> >                                    + name).toCharArray();
> > 
> > the problem is that children's hrefs can end with '/' and in this case
> > URIUtil.getName returns empty string. Because of that childURI is the same as
> > myURI (bug!!!)
> 
> 
> Thanks Igor!  Everything works fine now.  Also thanks to Robert and Philip.  For
> those who want a fast cut-and-paste solution, simply replace the entire
> 
>     protected void setWebdavProperties(Enumeration responses)
> 
> method in org.apache.webdav.lib.WebdavResource with the following code:
> 
> // START: FIX /////////////////////////////////////////////////////
>     /**
>      * Set WebDAV properties following to the given http URL.
>      * This method is fundamental for getting information of a collection.
>      *
>      * @param responses An enumeration over {@link ResponseEntity} items, one
>      * for each resource for which information was returned via PROPFIND.
>      *
>      * @exception HttpException
>      * @exception IOException The socket error with a server.
>      */
>     protected void setWebdavProperties(Enumeration responses)
>         throws HttpException, IOException {
>     
>         // Make the resources in the collection empty.
>         childResources.removeAll();
>         while (responses.hasMoreElements()) {
>     
>             ResponseEntity response =
>                 (ResponseEntity) responses.nextElement();
>     
>             boolean itself = false;
>             String href = response.getHref();
>             if (!href.startsWith("/"))
>                 href = URIUtil.getPath(href);
>             href = decodeMarks(href);
> 
>             /*
>              * Decode URIs to common (unescaped) format for comparison 
>              * as HttpClient.URI.setPath() doesn't escape $ and : chars.
>              */
>             String httpURLPath = httpURL.getPath();
>             String escapedHref = URIUtil.decode(href);
>             
>             // Normalize them to both have trailing slashes if they differ by
> one in length.
>             int lenDiff = escapedHref.length() - httpURLPath.length();
>             int compareLen = 0;
>             
>             if ( lenDiff == -1 && !escapedHref.endsWith("/")) {
>                 compareLen = escapedHref.length();
>                 lenDiff = 0;
>             }
>             else
>             if ( lenDiff == 1 && !httpURLPath.endsWith("/")) {
>                 compareLen = httpURLPath.length();
>                 lenDiff = 0;
>             }
> 
>             // if they are the same length then compare them.
>             if (lenDiff == 0) {
>                 if ((compareLen == 0 && httpURLPath.equals(escapedHref))
>                     || httpURLPath.regionMatches(0, escapedHref, 0, compareLen))
>                 {
>                     // escaped href and http path are the same
>                     // Set the status code for this resource.
>                     if (response.getStatusCode() > 0)
>                         setStatusCode(response.getStatusCode());
>                     setExistence(true);
>                     itself = true;
>                 }
>             }
>     
>             // Get to know each resource.
>             WebdavResource workingResource = null;
>             if (itself) {
>                 workingResource = this;
>             }
>             else {
>                 workingResource = createWebdavResource(client);
>                 workingResource.setDebug(debug);
>             }
>     
>             // clear the current lock set
>             workingResource.setLockDiscovery(null);
>     
>             // Process the resource's properties
>             Enumeration properties = response.getProperties();
>             while (properties.hasMoreElements()) {
>     
>                 Property property = (Property) properties.nextElement();
>     
>                 // ------------------------------  Checking WebDAV properties
>                 workingResource.processProperty(property);
>             }
>     
>             String displayName = workingResource.getDisplayName();
>     
>             if (displayName == null || displayName.trim().equals("")) {
>                 displayName = getName(href);
>             }
> 
>             /** BUGGY CODE
>             if (!itself) {
>                 String myURI = httpURL.getEscapedURI();
>                 char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
>                                    + URIUtil.getName(href)).toCharArray();
>                 HttpURL childURL = httpURL instanceof HttpsURL
>                                    ? new HttpsURL(childURI)
>                                    : new HttpURL(childURI);
>                 childURL.setRawAuthority(httpURL.getRawAuthority());
>                 workingResource.setHttpURL(childURL, NOACTION, defaultDepth);
>                 workingResource.setExistence(true);
>                 workingResource.setOverwrite(getOverwrite());
>             }
>             */
>             
>             /** FIX ********/
>             if (!itself) {                
>                 String myURI = httpURL.getEscapedURI();
>                 
>                 /**
>                 	Checks if href contains trailing '/', and if so removes it.
>                 	This ensures URIUtil.getName does not return an empty
>                 	String when we don't want it to.
>                 	
>                 	See http://issues.apache.org/bugzilla/show_bug.cgi?id=32886
>                 	for more information.
>                 */
>                 String fixedHref = href.endsWith("/") ?
>                     href.substring(0, href.length() - 1) : href;
>                 
>                 char[] childURI = (myURI + (myURI.endsWith("/") ? "" : "/")
>                                    + URIUtil.getName(fixedHref)).toCharArray();
>                 
>                 HttpURL childURL = httpURL instanceof HttpsURL
>                                    ? new HttpsURL(childURI)
>                                    : new HttpURL(childURI);
>                 childURL.setRawAuthority(httpURL.getRawAuthority());
>                 workingResource.setHttpURL(childURL, NOACTION, defaultDepth);
>                 workingResource.setExistence(true);
>                 workingResource.setOverwrite(getOverwrite());
>             }            
>             /**************/
>             
>             
>             workingResource.setDisplayName(displayName);
>     
>             if (!itself)
>                 childResources.addResource(workingResource);
>         }
>     }
> // END: FIX /////////////////////////////////////////////////////
> 
> The code is based on Igor's solution and should work fine.  Please post here if
> you stumble upon any issues the fix causes.  In the meantime however, its
> working perfectly for me.
> 
> Cheers!
> 
> Mike N. Christoff