A WebDAV server component for ESP-IDF, built on esp_http_server. It exposes
a mounted VFS directory (LittleFS, SPIFFS, FATFS, ...) as a WebDAV share, so
it can be mounted as a network drive on macOS (Finder, Mountain Duck,
Cyberduck), Windows (Explorer), or Linux (GVfs/davfs2).
GET/HEAD— download files, browse directories (serves a directory'sindex.htmlif present, otherwise renders a plain HTML index — for a regular web browser; WebDAV clients list directories viaPROPFINDinstead and are unaffected either way)PUT— upload/overwrite files, streamed to flash in chunks (no whole-file buffering)DELETE— recursive delete of files and directoriesMKCOL— create directoriesMOVE/COPY— rename/move and copy, including recursive directory copies andDepth/Overwriteheader handlingPROPFIND— directory listing metadata (Depth: 0,1,infinity), streamed so large directory trees don't need to fit in RAM at oncePROPPATCH,LOCK,UNLOCK— enough of RFC 4918's locking dance for clients that insist on it before they'll write a file; not a real lock manager (see Limitations)- Path sanitization against directory traversal (
..is rejected outright) - Optional read-only mode
- ESP-IDF >= 5.0
- A VFS-mounted filesystem to serve (LittleFS via
joltwallet/littlefsis what the example uses; SPIFFS/FATFS work too since this component only talks to the mount point through standard POSIX file calls)
Add it as a dependency via the ESP Component Registry:
idf.py add-dependency "erikmeinders/webdav^0.1.0"or add it to your project's idf_component.yml directly:
dependencies:
erikmeinders/webdav: "^0.1.0"For local development against an unpublished/modified copy, point
EXTRA_COMPONENT_DIRS at a checkout of this repo instead, or copy it into
your project's components/ directory.
Then:
#include "esp_webdav.h"
esp_webdav_config_t config = ESP_WEBDAV_CONFIG_DEFAULT();
config.root_path = "/littlefs"; // must already be mounted
// config.read_only = true; // optional: expose for download only
// config.server_port = 8080; // optional: default is 80
esp_webdav_handle_t webdav;
ESP_ERROR_CHECK(esp_webdav_start(&config, &webdav));
// ... later, if needed:
// esp_webdav_stop(webdav);See include/esp_webdav.h for the full config struct and
examples/littlefs_webdav for a complete, flashable project (Wi-Fi + LittleFS
- mDNS + WebDAV).
Run idf.py menuconfig → ESP WebDAV Server to adjust:
ESP_WEBDAV_MAX_PATH_LEN— stack buffer size for resolved filesystem paths (default 600)ESP_WEBDAV_IO_BUF_SIZE— chunk size for file transfers (default 4096)ESP_WEBDAV_ALLOW_DEPTH_INFINITY— whetherPROPFINDmay recurse an entire subtree in one request (default on)
- No authentication. Anyone who can reach the device on the network can read and write its filesystem. Put it behind a VPN or a network you control; don't expose it to the internet as-is.
- No TLS. Plain HTTP only (
esp_http_server, notesp_https_server). - LOCK/UNLOCK don't enforce anything. Every
LOCKrequest succeeds and hands back a token; there's no server-side lock table serializing access. This is normally fine for a device with one or a handful of trusted clients, but two clients editing the same file at once will race. PROPPATCHalways fails. There's nowhere on a plain filesystem to durably store arbitrary WebDAV dead properties, so custom property writes are rejected (403) rather than silently discarded on next boot.PROPFINDignores the requested property list and always returns the standard set (displayname,resourcetype,getcontentlength,getcontenttype,getetag,creationdate,getlastmodified). Extra properties in a response are harmless per RFC 4918 and every WebDAV client this was tested against (Finder, Mountain Duck, Cyberduck) is fine with it.- Designed for a handful of concurrent clients on an embedded device, not as
a general-purpose file server — there's no byte-range
GETsupport, no chunked-PUTsupport (requiresContent-Length), and directory listings are not paginated.
MIT — see LICENSE.