Skip to content

Error in get_props() with lighttpd #178

@RomainTT

Description

@RomainTT

Observations

When using lighttpd webdav module as a webdav server.
When using get_props on a resource (directory or file).
The following exception is raised:

    223 def get_response_for_path(self, hostname: str, path: str) -> Response:
    224     """Provides response for the resource with the specific href/path.
    225
    226     Args:
   (...)
    231             resource.
    232     """
--> 233     return self.responses[join_url_path(hostname, path)]

KeyError: 'path/to/my/file'

This is because propfind returns an empty content (the XML is valid, but with no data).

In[0]: client.propfind("./").content
Out[0]: '<?xml version="1.0" encoding="utf-8"?>\n<D:multistatus xmlns:D="DAV:" xmlns:ns0="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">\n</D:multistatus>\n'

Solution

After several tests I found out that propfind works well if the correct Depth header.

  • Depth: 1 as used by ls is listing files correctly.
  • Depth: 0 allows to get properties of a single filepath. Example below:
In[0]: client.propfind("path/to/file", headers={"Depth": "0"}).content
Out[0]: '<?xml version="1.0" encoding="utf-8"?>\n<D:multistatus xmlns:D="DAV:" xmlns:ns0="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">\n<D:response>\n<D:href>http://webdav-url/path/to/file</D:href>\n<D:propstat>\n<D:prop>\n<D:creationdate ns0:dt="dateTime.tz">2024-07-11T09:33:29Z</D:creationdate><D:getcontentlanguage>en</D:getcontentlanguage><D:getcontentlength>508</D:getcontentlength><D:getlastmodified ns0:dt="dateTime.rfc1123">Thu, 11 Jul 2024 09:33:29 GMT</D:getlastmodified></D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n</D:propstat>\n</D:response>\n</D:multistatus>\n'                                  

As get_props is meant to read properties of a single filepath, it seems relevant to add Depth: 0 to the headers in this method.

Here is a fix which is working for me:

    def get_props(
        self,
        path: str,
        name: Optional[str] = None,
        namespace: Optional[str] = None,
        data: Optional[str] = None,
    ) -> "DAVProperties":
        """Returns properties of a resource by doing a propfind request.

        Can also selectively request the properties by passing name or data.
        """
        data = data or prepare_propfind_request_data(name, namespace)
        headers = {"Content-Type": "application/xml"} if data else {}
        headers["Depth"] = "0"  # <-- This line enforce the Depth header
        result = self.propfind(path, headers=headers, data=data)
        response = result.get_response_for_path(self.base_url.path, path)
        return response.properties

But I am not sure of the all the consequences, maybe I’m missing the big picture. I did not test this with another webdav server like Nextcloud.

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions