Skip to main content

webdav-rfc4918

webdav-rfc4918

A secure-by-default WebDAV client for Python, built on RFC 4918 and RFC 5689.
Filesystem-style API, the raw protocol when you need it, a dav command, and protection against known attacks.

Full documentation: webdav.readthedocs.io

PyPI Python versions Documentation Status License


webdav-rfc4918 is a WebDAV client for Python. WebDAV lets you read and write files on a server over HTTP, like a network drive reachable by URL.

  • Tested in CI on every commit against Nextcloud, Apache (mod_dav), nginx (dav-ext) and WsgiDAV. See Tested against four servers.
  • Secure defaults: TLS verification, same-origin redirects, size limits on buffered responses. See Security.
  • Works with pandas, dask and anything else built on fsspec. See fsspec.

Quick Start

Requires Python 3.11+. Built on requests.

pip install webdav-rfc4918

A single call, nothing to open or close:

import webdav

auth = ("user", "password")  # HTTP Basic auth

webdav.mkdir("https://webdav.example.org/Photos/", auth=auth)
webdav.upload_file("Gorilla.jpg", "https://webdav.example.org/Photos/Gorilla.jpg", auth=auth)
webdav.ls("https://webdav.example.org/Photos/", auth=auth)   # a list of Resource objects

Several calls to the same server: a FileSystem keeps the connection open.

with webdav.FileSystem("https://webdav.example.org", auth=auth) as fs:
    fs.upload_file("Gorilla.jpg", "Photos/Gorilla.jpg")
    print(fs.ls("Photos"))
    fs.download_file("Photos/Gorilla.jpg", "copy.jpg")

    with fs.open("Photos/Gorilla.jpg", "rb") as f:   # a file-like object
        image_bytes = f.read()

Need the raw protocol: status codes, headers, the multi-status body? Use a Session directly.

with webdav.Session("https://webdav.example.org", auth=auth) as session:
    response = session.propfind("/Photos/", depth=1)
    print(response.status_code, list(response.multistatus.responses))

A client certificate (mTLS) and a private CA:

with webdav.Session(
    "https://webdav.example.org",
    cert=("client.crt", "client.key"),
    verify="ca-bundle.pem",
) as session:
    session.propfind("/", depth=0)

Tested against four servers

Nextcloud, Apache mod_dav, and nginx dav-ext each get their own CI job, because each reads the RFC differently, and each is documented separately. WsgiDAV runs the rest of the test suite.

Server CI (main) Tests Docs
Nextcloud Nextcloud 40+ docs
Apache mod_dav Apache 100+ docs
nginx + dav-ext nginx 25+ docs
WsgiDAV WsgiDAV rest of the suite -

The test suite runs on every commit: 1500+ tests with over 90% code coverage. It includes:

  • fsspec's own conformance suite (130+ tests)
  • 130+ tests that each check one clause of RFC 4918
  • 70+ tests for the security defaults described below

Security

A WebDAV server, or a redirect to one, can be hostile. This is the complete list of defaults:

  • TLS verification is on. Turning it off (verify=False, or anything requests reads as false) emits and logs a TLSHardeningDisabledWarning that urllib3.disable_warnings() does not silence. So does a TLSOptions with a TLS version below 1.2 or with strict chain checking off.
  • REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE are ignored, so the environment cannot replace the CA you configured. ~/.netrc is ignored too: without auth=, no credentials are sent.
  • A URL with credentials in it (https://user:pw@host/) is refused. Pass auth= instead.
  • Credentials sent over plain http to a host other than localhost trigger an InsecureTransportWarning, once per host.
  • Only same-origin redirects are followed (RedirectPolicy.SAME_ORIGIN). Credentials and cookies are never sent to another origin, even a trusted one.
  • A redirect from https to http is never followed, under any policy.
  • Buffered responses, including multistatus XML, are size-capped, and so are redirect chains. Exact limits: Session reference.
  • A request that is not streamed has a deadline for the whole exchange (max_response_time, default 300 s): connecting, every redirect hop, headers and body. timeout only limits each single read.
  • A streamed download (stream=True, download_file) is bounded per read only. Neither max_response_size nor max_response_time applies to it.
  • XML from the server is parsed with the standard library's expat parser. External entities are never resolved, and expat 2.4.0 or newer rejects entity expansion attacks such as "billion laughs". A multistatus or lock response that tries either raises MalformedResponseError.
  • Credentials do not end up in exception messages, warnings or logs: the userinfo of a URL and the query of a signed URL are redacted.
  • download_file writes only to the path you give, through a temporary file, and refuses a symlink at that path.

Report a vulnerability: SECURITY.md.

fsspec

fsspec is the storage interface behind pandas, dask and most of the Python data ecosystem. This package adds a WebDAV backend, so those tools can read and write a WebDAV server like any other storage. It passes fsspec's own conformance suite (130+ tests).

pip install webdav-rfc4918[fsspec]
import fsspec
import pandas as pd

auth = ("user", "password")

df = pd.read_csv("webdavs://webdav.example.org/data.csv", storage_options={"auth": auth})

with fsspec.open("webdavs://webdav.example.org/Photos/Gorilla.jpg", auth=auth) as f:
    f.read()

Installing the package registers the webdav and webdavs schemes with fsspec. Paths start at the root of the server (/Photos/Gorilla.jpg). See fsspec for URL schemes, credentials and path semantics.

Locking

Lock a file while you edit it, so no one else can overwrite it (class 2 locking, RFC 4918 §7). The If header is handled for you:

import webdav

auth = ("user", "password")

with webdav.FileSystem("https://webdav.example.org", auth=auth) as fs:
    with fs.locked("Documents/report.docx") as lock:
        # writes to the locked path carry the lock token automatically
        fs.upload_file("report.docx", "Documents/report.docx", overwrite=True)
        fs.refresh_lock("Documents/report.docx", lock.token)

A lock times out, and nothing refreshes it for you: writes after that fail with 412. See Locking for the details.

Command line

The dav command is part of the package:

dav ls webdavs://webdav.example.org/Photos
dav get webdavs://webdav.example.org/report.pdf ./report.pdf
dav put ./report.pdf webdavs://webdav.example.org/report.pdf --overwrite

webdavs:// is WebDAV over HTTPS, webdav:// plain HTTP.

Also info, cat, mkdir, rm, mv and cp. Credentials via --user and --password, or $WEBDAV_USER and $WEBDAV_PASSWORD. See the CLI reference, or dav <command> --help.

More

The documentation has a quickstart, reference pages for sessions, TLS and redirects, and migration guides from webdav4, webdavclient3 and other WebDAV clients. Release history: CHANGELOG.md. Licensed under the MIT License.

Metadata

Release files for webdav-rfc4918 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for webdav-rfc4918 1.1.0
File Size Uploaded
webdav_rfc4918-1.1.0.tar.gz 324.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for webdav-rfc4918 1.1.0
File Interpreter ABI Platform
webdav_rfc4918-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 470.8 kB

Release files / webdav_rfc4918-1.1.0.tar.gz

Download URL webdav_rfc4918-1.1.0.tar.gz
Size 324.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7ff23069e8dff80257639aca5e9ab9bbc6ea898cc07f5e1f222d521f4cbbac33
BLAKE2b-256 checksum
How to use checksums
638927b8a6ca048c0b95831431c36c589be56b3dd1f0d04139926b8422042b4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / webdav_rfc4918-1.1.0-py3-none-any.whl

Download URL webdav_rfc4918-1.1.0-py3-none-any.whl
Size 146.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3ab6537f54eff2d4ef19c4e6c502d46686387c53fd0df424b855945fd1ca8b6e
BLAKE2b-256 checksum
How to use checksums
280579e443f08d5151732f9ad59124d94eaf6ef0b66447bef0bd56753786ec26
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page