Gumdrop

Gumdrop File Server & WebDAV

The WebDAVService is a complete, production-ready HTTP file service built on the Gumdrop framework. It serves static files from a filesystem directory with high performance, and optionally provides full WebDAV (RFC 2518) distributed authoring support. Because it is an HTTP service, it can be configured with any combination of HTTP/3, HTTP/2, and HTTP/1.1 listeners.

Contents

File Server

Features

Configuration

<service id="files" class="org.bluezoo.gumdrop.webdav.WebDAVService">
  <property name="root-path">/var/www/html</property>
  <property name="welcome-file">index.html</property>
  <property name="allow-write">false</property>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">8080</property>
  </listener>
</service>

Properties:

Security

The file server validates all paths to ensure they remain within the configured root directory. Symbolic links are resolved to their real paths before access checks. The root path must be a readable directory; if write operations are enabled, the server logs a warning if the directory is not writable.

Performance

File transfers use Java NIO's FileChannel.transferTo() where possible, enabling zero-copy transfers directly from the filesystem to the socket. This minimises memory allocation and CPU usage for large file transfers.

For HTTP/3 and HTTP/2 connections, the file server benefits from stream multiplexing when serving mixed content (HTML, CSS, JavaScript, images).

HTTP/3 Support

To serve files over HTTP/3 as well as HTTP/2 and HTTP/1.1, add both an HTTPListener and an HTTP3Listener:

<service id="files" class="org.bluezoo.gumdrop.webdav.WebDAVService">
  <property name="root-path">/var/www/html</property>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">443</property>
    <property name="secure">true</property>
    <property name="keystore-file">keystore.p12</property>
    <property name="keystore-pass">changeit</property>
  </listener>
  <listener class="org.bluezoo.gumdrop.http.h3.HTTP3Listener">
    <property name="port">443</property>
    <property name="cert-file">cert.pem</property>
    <property name="key-file">key.pem</property>
  </listener>
</service>

The service automatically advertises HTTP/3 availability via the Alt-Svc response header on TCP connections.

WebDAV Support

The file server supports WebDAV (RFC 2518) distributed authoring when enabled via the webdavEnabled property. This allows WebDAV clients such as Windows Explorer, macOS Finder, or dedicated clients like Cyberduck to access the file server as a network drive.

Enabling WebDAV

<service id="webdav" class="org.bluezoo.gumdrop.webdav.WebDAVService">
  <property name="root-path">/var/www/dav</property>
  <property name="allow-write">true</property>
  <property name="webdav-enabled">true</property>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">8080</property>
  </listener>
</service>

When WebDAV is enabled, the server advertises DAV: 1,2 in OPTIONS responses and supports the following additional HTTP methods:

WebDAV Methods

Live Properties

The following live properties are computed from the filesystem and returned by PROPFIND requests:

Dead Properties

Dead (custom) properties are arbitrary name/value pairs stored on resources by WebDAV clients via PROPPATCH. Gumdrop persists dead properties using a dual-strategy backend:

Configuration

The dead property storage mode is configurable:

<service id="webdav" class="org.bluezoo.gumdrop.webdav.WebDAVService">
  <property name="root-path">/var/www/dav</property>
  <property name="allow-write">true</property>
  <property name="webdav-enabled">true</property>
  <property name="dead-property-storage">auto</property>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">8080</property>
  </listener>
</service>
ValueBehaviour
autoUse xattr when available, fall back to sidecar (default)
xattrExtended attributes only; fails if unsupported
sidecarSidecar files only
noneDead properties disabled (PROPPATCH returns 403)

Sidecar files are hidden from PROPFIND responses, HTML directory listings, and direct GET requests. They are automatically copied, moved, and deleted alongside their parent resource.

Locking

WebDAV locks prevent conflicting modifications when multiple clients access the same resource. Locks are:

When a resource is locked, modifying operations (PUT, DELETE, MOVE, PROPPATCH) require a valid lock token in the If or Lock-Token header.

Collection DELETE (RFC 4918 §9.6.1)

DELETE on a collection (directory) recursively deletes all member resources depth-first. If all deletions succeed, 204 No Content is returned. If any individual deletion fails, a 207 Multi-Status response lists the failed resources:

DELETE /documents/old-project/ HTTP/1.1
Host: example.com

HTTP/1.1 207 Multi-Status
Content-Type: application/xml

<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
  <D:response>
    <D:href>/documents/old-project/locked-file.txt</D:href>
    <D:status>HTTP/1.1 403 Forbidden</D:status>
  </D:response>
</D:multistatus>

If Header (RFC 4918 §10.4)

The If header supports the full grammar defined in RFC 4918 §10.4, including tagged-list and no-tag-list syntax with ETag conditions and Not negation. Multiple lists for the same resource are OR'd; conditions within a list are AND'd.

// No-tag-list with lock token:
If: (<opaquelocktoken:a1b2c3d4-...>)

// Tagged-list for a specific resource:
If: </documents/file.txt> (<opaquelocktoken:a1b2c3d4-...> ["etag-value"])

// Not condition (lock token must NOT be present):
If: (Not <opaquelocktoken:old-token>)

// Multiple conditions (OR'd):
If: (<token-a>) (<token-b>)

Protocol Examples

PROPFIND Request

PROPFIND /documents/ HTTP/1.1
Host: example.com
Depth: 1
Content-Type: application/xml

<?xml version="1.0" encoding="utf-8"?>
<propfind xmlns="DAV:">
  <prop>
    <displayname/>
    <getcontentlength/>
    <getlastmodified/>
  </prop>
</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:displayname>documents</D:displayname>
      </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:displayname>report.pdf</D:displayname>
        <D:getcontentlength>245678</D:getcontentlength>
        <D:getlastmodified>Tue, 06 Jan 2026 12:00:00 GMT</D:getlastmodified>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
</D:multistatus>

LOCK Request

LOCK /documents/report.pdf HTTP/1.1
Host: example.com
Timeout: Second-3600
Content-Type: application/xml

<?xml version="1.0" encoding="utf-8"?>
<lockinfo xmlns="DAV:">
  <lockscope><exclusive/></lockscope>
  <locktype><write/></locktype>
  <owner>user@example.com</owner>
</lockinfo>

Response includes the lock token:

HTTP/1.1 200 OK
Lock-Token: <opaquelocktoken:a1b2c3d4-e5f6-7890-abcd-ef1234567890>
Content-Type: application/xml

<?xml version="1.0" encoding="utf-8"?>
<D:prop xmlns:D="DAV:">
  <D:lockdiscovery>
    <D:activelock>
      <D:locktype><D:write/></D:locktype>
      <D:lockscope><D:exclusive/></D:lockscope>
      <D:depth>infinity</D:depth>
      <D:owner>user@example.com</D:owner>
      <D:timeout>Second-3600</D:timeout>
      <D:locktoken>
        <D:href>opaquelocktoken:a1b2c3d4-e5f6-7890-abcd-ef1234567890</D:href>
      </D:locktoken>
    </D:activelock>
  </D:lockdiscovery>
</D:prop>

← Back to Main Page | HTTP Server & Client | Servlet Container | WebSocket Service & Client | FTP Server | Telemetry

Gumdrop File Server & WebDAV