WebDAV API

Ferro provides a fully compliant WebDAV server supporting Class 1 (PROPFIND), Class 2 (LOCK/UNLOCK), and Class 3 (PROPPATCH) operations.

Base URL

All WebDAV operations use the root path as the base collection:

http://localhost:8080/

Supported Methods

MethodDescriptionRFC
OPTIONSDiscover supported methods and DAV capabilitiesRFC 4918
PROPFINDRetrieve properties for one or more resourcesRFC 4918
GETRetrieve file contentRFC 7231
PUTCreate or update a fileRFC 7231
DELETERemove a resourceRFC 7231
MKCOLCreate a collection (directory)RFC 4918
COPYCopy a resource to a new locationRFC 4918
MOVEMove a resource to a new locationRFC 4918
LOCKLock a resourceRFC 4918
UNLOCKRelease a lockRFC 4918
PROPPATCHModify resource propertiesRFC 4918

Depth Header

The Depth header controls PROPFIND recursion:

ValueBehavior
0Only the requested resource (no children)
1The resource and its immediate children
infinityThe resource and all descendants (not fully supported)

Sync-Token Support

Ferro supports WebDAV sync-collection for incremental synchronization. Use the sync endpoint to get changes since a given sync token:

curl -X REPORT http://localhost:8080/ \
  -H "Content-Type: application/xml" \
  -d '<?xml version="1.0" encoding="utf-8"?>
       <D:sync-collection xmlns:D="DAV:">
         <D:sync-token>token-value</D:sync-token>
         <D:sync-level>1</D:sync-level>
       </D:sync-collection>'

Examples with curl

Create a directory

curl -X MKCOL http://localhost:8080/documents/

Upload a file

curl -X PUT http://localhost:8080/documents/report.pdf \
  -H "Content-Type: application/pdf" \
  --data-binary @report.pdf

List directory contents (PROPFIND Depth: 1)

curl -X PROPFIND http://localhost:8080/documents/ \
  -H "Depth: 1" \
  -H "Content-Type: application/xml" \
  -d '<?xml version="1.0" encoding="utf-8"?>
       <D:propfind xmlns:D="DAV:">
         <D:prop>
           <D:resourcetype/>
           <D:getcontentlength/>
           <D:getlastmodified/>
           <D:getetag/>
         </D:prop>
       </D:propfind>'

Response (207 Multi-Status):

<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
  <D:response>
    <D:href>/documents/</D:href>
    <D:propstat>
      <D:prop>
        <D:resourcetype><D:collection/></D:resourcetype>
        <D:getcontentlength>0</D:getcontentlength>
        <D:getlastmodified>Mon, 01 Jan 2024 00:00:00 GMT</D:getlastmodified>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
  <D:response>
    <D:href>/documents/report.pdf</D:href>
    <D:propstat>
      <D:prop>
        <D:resourcetype/>
        <D:getcontentlength>12345</D:getcontentlength>
        <D:getlastmodified>Mon, 01 Jan 2024 12:00:00 GMT</D:getlastmodified>
        <D:getetag>"abc123"</D:getetag>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
</D:multistatus>

Lock a file

curl -X LOCK http://localhost:8080/documents/report.pdf \
  -H "Content-Type: application/xml" \
  -H "Timeout: Second-3600" \
  -d '<?xml version="1.0" encoding="utf-8"?>
       <D:lockinfo xmlns:D="DAV:">
         <D:locktype><D:write/></D:locktype>
         <D:lockscope><D:exclusive/></D:lockscope>
         <D:owner>
           <D:href>mailto:user@example.com</D:href>
         </D:owner>
       </D:lockinfo>'

Unlock a file

curl -X UNLOCK http://localhost:8080/documents/report.pdf \
  -H "Lock-Token: opaquelocktoken:abc123"

Move a file

curl -X MOVE http://localhost:8080/documents/report.pdf \
  -H "Destination: http://localhost:8080/archive/report.pdf"

Copy a file

curl -X COPY http://localhost:8080/documents/report.pdf \
  -H "Destination: http://localhost:8080/backup/report.pdf"

Delete a file

curl -X DELETE http://localhost:8080/documents/report.pdf

Delete a directory

curl -X DELETE http://localhost:8080/documents/

Locking

Ferro supports WebDAV locking with the following lock types:

PropertyValue
Lock typeswrite
Lock scopesexclusive
Lock timeoutConfigurable (default: 3600 seconds)
Lock tokensOpaque token strings

Locks are tracked in-memory or in the SQLite database (when --data-dir is set). Expired locks are cleaned up periodically.

DAV Header

The DAV response header advertises server capabilities:

DAV: 1, 2, 3