Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in get_props() with lighttpd #178

Open
RomainTT opened this issue Jul 12, 2024 · 1 comment
Open

Error in get_props() with lighttpd #178

RomainTT opened this issue Jul 12, 2024 · 1 comment

Comments

@RomainTT
Copy link

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?

@gstrauss
Copy link

The WebDAV RFC was published June 2007 (which is 17 years ago)
https://www.rfc-editor.org/rfc/rfc4918#section-9.1

A client MUST submit a Depth header with a value of "0", "1", or
"infinity" with a PROPFIND request. Servers MUST support "0" and "1"
depth requests on WebDAV-compliant resources and SHOULD support
"infinity" requests. In practice, support for infinite-depth
requests MAY be disabled, due to the performance and security
concerns associated with this behavior. Servers SHOULD treat a
request without a Depth header as if a "Depth: infinity" header was
included.

get_props() should most definitely be updated to send an appropriate Depth header.


Note: not all servers support Depth: infinity.

lighttpd supports Depth: infinity, but disables PROPFIND Depth: infinity by default, unless explicitly configured in lighttpd.conf: webdav.opts += ("propfind-depth-infinity" => "enable")

Therefore, if you send Depth: infinity, you should be prepared to fall back to multiple PROPFIND requests with Depth: 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants