Coder Social home page Coder Social logo

caddy-webdav's People

Contributors

francislavoie avatar heimoshuiyu avatar mcieno avatar mholt avatar mohammed90 avatar pgaskin avatar wader avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

caddy-webdav's Issues

Run as unprivileged user

Hi,

This webdav module is working extremely well with a few lines of configuration, congratulations for the awesome job ๐Ÿ†

One issue I'm facing now is that file manipulations done via webdav are done with the permissions of the user Caddy runs as (which is root when using Docker).

I'd love to be able to configure another user to perform file manipulations as, probably following the user[:group] or uid[:gid] format like this:

webdav.{$BASE_URL} {
  webdav {
    root /share/
    user mike:mike
  }
}

Using Docker or Docker Compose, it would even be configurable like this:

webdav.{$BASE_URL} {
  webdav {
    root /share/
    user {$UID}:{$GID}
  }
}

Do you think that might be considered?
Or should I gosu/su-exec the whole Caddy server instead?
Or do you recomment another solution?

Thanks a lot in advance ๐Ÿ™

FR: hide option

i would love to hide a folder on webdav listening. something like the hide option in file_server.

405 Method not allowed on default configuration

Clean download (from https://caddyserver.com/download) and installation of Caddy2+webdav on Mac OS Catalina.

Browser gets status code 405 and shows Method not allowed for https://localhost/dav, with Caddyfile extracted from Readme as below,

localhost

root * /srv

route {
rewrite /dav /dav/
webdav /dav/* {
prefix /dav
}
file_server
}
<<<

If replaced it with below (basically remove rewrite and prefix), everything works with http://localhost URL.

localhost
root * /srv
route {
webdav {
}
file_server
}
<<<

Cannot find any clues anywhere :(... please kindly share any advices. Thanks.

How to have WebDAV server run under a subdirectory of a subdomain?

I'm having some trouble setting this up. I want:

  • A file browser web interface running on cloud.example.com
  • This WebDAV server running under cloud.example.com/dav

How can I do this?

I tried this, but it didn't work:

drive.example.com {
    webdav /dav/* {
        root /srv/files
        prefix /dav
    }
}

It gives me a blank screen when I navigate to drive.example.com/dav.

Can not upload large file

Hi,

Thanks for the awesome work. There is an issue trouble me when I use this module. Large file can not be upload to the webdav server even caddy and caddy-webdav start normally. However, small file can be uploaded and deleted, and large file can alse be deleted. And all is well if basicauth is not set, similar to the issue mentioned here. Here is my detailed info:

  • version
v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=
  • my Caddyfile
{
    email [email protected]
    order webdav before file_server
}

dav.mydomain.com {
    log {
        output file /var/log/caddy/caddy.log
    }
    header {
            Access-Control-Allow-Origin *
            Access-Control-Allow-Credentials true
            Access-Control-Allow-Methods "GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"
            Access-Control-Allow-Headers "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"
            Access-Control-Expose-Headers "ETag"
            Access-Control-Max-Age 1728000
    }
    file_server
    webdav {
        root /data/webdav
    }
    basicauth {
        username JDJhJDE0JGxYYWhxUVd6a1RRd01PS2xtNnBkNHUzUllqenFaSGFib1Zid1BFaGNRSmpOLktXNXBJbGhH
    }
}
  • log
    note: the size of file1 is 5 bytes, file2 is 18.6 MB and file3 is 18.6 MB.
{"level":"error","ts":1649603015.3900425,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:16834","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file1","headers":{"Content-Type":["application/octet-stream"],"Content-Length":["5"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:03:35 +0000] \"PUT /zotero/file1 HTTP/1.1\" 401 0","user_id":"","duration":0.000256805,"size":0,"status":401,"resp_headers":{"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Access-Control-Allow-Credentials":["true"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"]}}
{"level":"info","ts":1649603017.5407305,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:16834","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file1","headers":{"Authorization":["Basic bHloNDU4OkxZSDEyMzQ1Njc5"],"Content-Type":["application/octet-stream"],"Content-Length":["5"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - username [10/Apr/2022:15:03:37 +0000] \"PUT /zotero/file1 HTTP/1.1\" 201 7","user_id":"username","duration":1.982221712,"size":7,"status":201,"resp_headers":{"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Etag":["\"16e4913458b93d2d5\""],"Server":["Caddy"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"]}}
{"level":"error","ts":1649603055.6700094,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:16834","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file3","headers":{"Content-Type":["application/octet-stream"],"Content-Length":["18633601"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:15 +0000] \"PUT /zotero/file3 HTTP/1.1\" 401 0","user_id":"","duration":0.000145973,"size":0,"status":401,"resp_headers":{"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"]}}
{"level":"error","ts":1649603058.8734984,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17028","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file3","headers":{"Content-Type":["application/octet-stream"],"Content-Length":["18633601"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:18 +0000] \"PUT /zotero/file3 HTTP/1.1\" 401 0","user_id":"","duration":0.000120796,"size":0,"status":401,"resp_headers":{"Access-Control-Max-Age":["1728000"],"Access-Control-Allow-Credentials":["true"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"]}}
{"level":"error","ts":1649603061.5329177,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17056","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file3","headers":{"Content-Type":["application/octet-stream"],"Content-Length":["18633601"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:21 +0000] \"PUT /zotero/file3 HTTP/1.1\" 401 0","user_id":"","duration":0.000104573,"size":0,"status":401,"resp_headers":{"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"]}}
{"level":"error","ts":1649603064.0896423,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17080","proto":"HTTP/1.1","method":"PUT","host":"dav.mydomain","uri":"/zotero/file3","headers":{"Content-Length":["18633601"],"Content-Type":["application/octet-stream"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:24 +0000] \"PUT /zotero/file3 HTTP/1.1\" 401 0","user_id":"","duration":0.000129379,"size":0,"status":401,"resp_headers":{"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"]}}
{"level":"error","ts":1649603067.0620177,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17116","proto":"HTTP/1.1","method":"PROPFIND","host":"dav.mydomain","uri":"/zotero/","headers":{"Depth":["1"],"Traceparent":["00-95bcf341ff0e0f898331c275b059a2aa-d1700fca3284ce5e-00"],"Content-Type":["application/xml; charset=utf-8"],"Content-Length":["96"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:27 +0000] \"PROPFIND /zotero/ HTTP/1.1\" 401 0","user_id":"","duration":0.000231393,"size":0,"status":401,"resp_headers":{"Access-Control-Max-Age":["1728000"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"]}}
{"level":"info","ts":1649603067.272328,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17116","proto":"HTTP/1.1","method":"PROPFIND","host":"dav.mydomain","uri":"/zotero/","headers":{"Depth":["1"],"Traceparent":["00-95bcf341ff0e0f898331c275b059a2aa-d1700fca3284ce5e-00"],"Authorization":["Basic bHloNDU4OkxZSDEyMzQ1Njc5"],"Content-Type":["application/xml; charset=utf-8"],"Content-Length":["96"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - username [10/Apr/2022:15:04:27 +0000] \"PROPFIND /zotero/ HTTP/1.1\" 207 1674","user_id":"username","duration":0.008953879,"size":1674,"status":207,"resp_headers":{"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"],"Content-Type":["text/xml; charset=utf-8"],"Server":["Caddy"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"]}}
{"level":"error","ts":1649603067.4928412,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17116","proto":"HTTP/1.1","method":"PROPFIND","host":"dav.mydomain","uri":"/","headers":{"Depth":["1"],"Traceparent":["00-95bcf341ff0e0f898331c275b059a2aa-cde040a9d5b79e46-00"],"Content-Type":["application/xml; charset=utf-8"],"Content-Length":["96"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - - [10/Apr/2022:15:04:27 +0000] \"PROPFIND / HTTP/1.1\" 401 0","user_id":"","duration":0.000132876,"size":0,"status":401,"resp_headers":{"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],"Access-Control-Max-Age":["1728000"],"Access-Control-Allow-Credentials":["true"]}}
{"level":"info","ts":1649603067.6733172,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"my_ip:17116","proto":"HTTP/1.1","method":"PROPFIND","host":"dav.mydomain","uri":"/","headers":{"Traceparent":["00-95bcf341ff0e0f898331c275b059a2aa-cde040a9d5b79e46-00"],"Authorization":["Basic bHloNDU4OkxZSDEyMzQ1Njc5"],"Content-Type":["application/xml; charset=utf-8"],"Content-Length":["96"],"Depth":["1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"dav.mydomain"}},"common_log":"my_ip - username [10/Apr/2022:15:04:27 +0000] \"PROPFIND / HTTP/1.1\" 207 969","user_id":"username","duration":0.000882937,"size":969,"status":207,"resp_headers":{"Content-Type":["text/xml; charset=utf-8"],"Server":["Caddy"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite,X-CustomHeader"],"Access-Control-Allow-Methods":["GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND, MKCOL"],"Access-Control-Allow-Origin":["*"],"Access-Control-Expose-Headers":["ETag"],"Access-Control-Max-Age":["1728000"]}}

Thanks in advance.

webdav can not work in caddy v2

I want use webdav with caddy v2, but can not work.

caddy version: 2.1.1
My website root: /home/website, webdav root: /home/webdav

Caddyfile:

{
  http_port 8080
  order webdav last
}
http:// {
  root * /home/website
  log {
    output stdout
  }
  file_server
  webdav /webdav/* {
    root /home/
  }
}

When file_server is normal, the website can be accessed, but WebDAV cannot work.
The comment file_server, WebDAV works normally and the website cannot be accessed.

Permission/Path issues with webdav-module using systemd service

Hi,

first of all, thanks a lot for the webdav-module. :) I had some trouble getting things to run smoothly and thought it might be a good idea to share the solutions.

Background: I wanted to use webdav to store and share notes with my wife. I encountered the following problems while installing, which my have occurred to others.

My system: Debian Buster running caddy v2.3.0 h1 with a systemd service (I swapped the executable in /usr/bin/ with the one including the webdav module).

Things that were not clear for me from the webdav module readme:

1. get the root right:
The readme example does not work with the systemd service.
Read-me example:

webdav /some/path/match/* {
	root /path
	prefix /some/path/match
}

I had to change it to:

        webdav /webdav/* {
           root /usr/share/caddy/webdav
           prefix /webdav
        }

In my case the webserver root in the caddyfile is root * /usr/share/caddy, which means that the path structure of the example is different.

2. Fix permissions while using a systemd service:
Although caddy had all the necessary permissions to the webdav directory it still complained about permissions:
Feb 18 23:18:48 vps caddy[12627]: {"level":"error","ts":1613686728.1413567,"logger":"http.handlers.webdav","msg":"internal handler error","error":"open /usr/share/caddy/webdav/silentnotes_repository.silentnotes: read-only file system","request":{"remote_addr":"x.x.x.x:123","proto":"HTTP/1.1","method":"PUT","host":"x.x.com","uri":"/webdav/silentnotes_repository.silentnotes","headers":{"Content-Length":["832"],"Authorization":["Basic c3xlZmAuOlYySXIxZg=="],"Accept-Encoding":["gzip, deflate"]},"tls":{"resumed":false,"version":771,"cipher_suite":49200,"proto":"","proto_mutual":true,"server_name":"x.x.com"}}}

Fix: Follow https://caddy.community/t/problem-with-filemanager-plugin-and-systemd/3900/3 and add a ReadWriteDirectories directive to the systemd file, as ProtectSystem=full prevents this.
In my case this results in:

User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
ReadWriteDirectories=/usr/share/caddy/webdav

If you find these notes useful, please add them to the module read-me page. Thanks!

Can not build with the new Go version

Hello,

I can not build / install the Webdav plugin for Docker.
I've tried numerous times.

I've tried to update my GO version with this tutorial:
https://go.dev/doc/install

This is the error message:
18.94 go: github.com/mholt/[email protected] requires go >= 1.22.0 (running go 1.21.10; GOTOOLCHAIN=local) 18.94 2024/05/22 02:58:06 [FATAL] exit status 1

go version:
go version go1.22.3 linux/amd64

Please help.

root directive appears to ignore {http.auth.user.id}

I am trying to setup a multi-user WebDAV configuration.

I have things configured in the Caddyfile as follows:

*.example.com {
   ...
   @storage host storage.example.com
   handle @storage {
      basicauth {
         username1 <hashed_pw>
         username2 <hashed_pw>
      }
      root * /path/to/webdav/{http.auth.user.id}
      webdav
   }
   ...
}

Which is working, but the individual users see the root of the webdav path when they connect (i.e. /path/to/webdav/, not /path/to/webdav/user1 as expected.)

It appears someone else ran into the same issue, as posted here:
https://caddy.community/t/multiple-users-with-different-roots-in-webdav/19502

But they never replied to the debugging suggestions.

As suggested, I turned on debugging and tried the custom X-Auth header. From that, I can see the username from {http.auth.user.id} as expected in the response.

Other than that, there don't appear to be any debug messages indicating a problem.

I'm not hugely familiar with go, but I also took a look at the Caddyfile parsing code for this module, and it all looks pretty straightforward and boiler-platey, so it doesn't seem likely the issue would be there.

Any ideas?

Every time you use webdav to sync photos, an error will be reported๏ผŒ

Caddy server is windows 10. The phone uses photosync+webdav to synchronize photos, and an error will be reported every time a photo is synchronized.

Error message๏ผš Cannot create a file when that file already exists

Tip: The error log will be output, but it does not affect the use

Caddyfile๏ผš

{
	order webdav before file_server
}

:7001 {
	webdav {
		root D:/_data
		prefix /
	}
}

error.log๏ผš

{"level":"error","ts":1627832105.3054144,"logger":"http.handlers.webdav","msg":"internal handler error","error":"mkdir D:\\_data\\ๆ‰‹ๆœบ็›ธๅ†Œ\\Screenshots\\2020: Cannot create a file when that file already exists.

Not compatible with MacOS Finder

I have Caddy with this module configured and it is working fine for iPhone KeePassium.

For MacOS, I am using KeePassXC, which does not support webdav directly, so I have to mount the directory with MacOS Finder.

It lists the files, but I cannot create or rename files, so KeepassXC cannot save the database. I also tried create and rename directly in the Finder and it does not work.

After some investigation, it looks like MacOS requires the webdav server to support "Level 2 locking". Apache can do that and Nginx with some workarounds, but looks like this module does not.

I tried various configs, including the standard:

        webdav /dav/* {
                root /dav/
                prefix /dav
        }

HEAD requests should work also on folders

HEAD requests to folders return HTTP 405 Method Not Allowed.

I believe this is an issue because, according to RFC 4918ยง9.4, HEAD should be valid also on collections.

The current behaviour makes it impossible to use this extension with some WebDAV clients/libraries (e.g., java's Sardine).

How to reproduce

# Caddyfile
:8080
log
root * /var/www
route {
        webdav
}
# Content of the webroot
$ ls -lah /var/www
total 12K
drwxr-xr-x  3 root root 4.0K Jan 02 15:04 .
drwxr-xr-x 14 root root 4.0K Jan 02 15:04 ..
-rw-r--r--  1 root root   11 Jan 02 15:04 a-file
drwxr-xr-x  2 root root 4.0K Jan 02 15:04 a-folder

GET requests work for both file and folder:

$ curl -X GET http://localhost:8080/a-file
I'm a file

$ curl -X GET http://localhost:8080/a-folder
<?xml version="1.0" encoding="UTF-8"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>/a-folder/</D:href><D:propstat><D:prop><D:getlastmodified>Mon, 02 Jan 2006 15:04:05 MST</D:getlastmodified><D:resourcetype><D:collection xmlns:D="DAV:"/></D:resourcetype><D:displayname>a-folder</D:displayname><D:supportedlock><D:lockentry xmlns:D="DAV:"><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry></D:supportedlock></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>

HEAD requests to a-file work, but to a-folder fail:

$ curl --head http://localhost:8080/a-file
HTTP/1.1 200 OK
[...]

$ curl --head http://localhost:8080/a-folder
HTTP/1.1 405 Method Not Allowed
Server: Caddy
Date: Mon, 02 Jan 2006 15:04:05 MST

Note: This would close #19, where the workarounds proposed so far don't work.

Multiuser/scope support is missing in the new webdav addon

Scopes as provided by the webdav "predecessor" addon in caddy 1.0.4 is not available in caddy 2 (2.2.1)

I used the following config in caddy 1.0.4 which worked just as wanted. Couldn't get similar mult user access functionality in caddy 2 and the new webdav addon.

webdav.somedomain.duckdns.org {
	basicauth / super userpwd
	basicauth / user2 userpwd
	basicauth / user3 userpwd
	basicauth / user4 userpwd
	webdav {
		super:
		scope /home/DATA/webdav
		user2:
		scope /home/DATA/webdav/.user2
		user3:
		scope /home/DATA/webdav/.user3
		user4:
		scope /home/DATA/webdav/.user3
	}
	log /etc/caddy/access-webdav.log
}

Separately publish executable files for caddy with webdav plugin.

Separately publish executable files for caddy with webdav plugin.
https://github.com/mholt/caddy-webdav/releases

Since webdav requires higher performance than static files and reverse proxy, I think webdav should be run as a separate process, and then it would be better for caddy gateway service to do reverse proxy for webdav.

It is better to separate the gateway service and webdav service into separate processes.

Compiling caddy with plug-ins still has some costs. Wouldn't it be better to publish it as an executable file?

In this way, you can get a webdav server out of the box.

Document prefix option

The readme doesn't document the prefix option at the moment, which is required whenever a matcher is used on the directive.

I spent an hour or two of confusion before finding the option in the code, documenting it might save the next person some time. :D

Empty response from Caddy + Webdav

Hello, I'm using caddy1 + webdav and would like to migrate, but this version of the webdav plugin gives me empty responses, except on the root path where I get the xml right.

Thanks,

Response (on any request except / )

HTTP/1.1 200 OK
Server: Caddy
Date: Fri, 22 May 2020 23:04:21 GMT
Content-Length: 0

Caddyfile

{
	order webdav last
}

:2015 {
    webdav / {
		root ./
	}
}

CF

Can we get some support added for chunked uploads / setting max body size ?
I'm trying to use this behind cloudflare proxy and it always fails on large files.

Webdav with Jetbrains Rider, Caddy and ASP NET Core Umbraco CMS

Hi,
I have these settings as default in webdav:

danobe.dev {
        # Set this path to your site's directory.
        #root * /usr/share/caddy

        # Enable the static file server.
        #file_server

        # Another common task is to set up a reverse proxy:
        reverse_proxy localhost:5000

        # Or serve a PHP site through php-fpm:
        # php_fastcgi localhost:9000
}

I tried by know all different choices with webdav and tutorials in the internet, but I can't get it to work.
Bildschirmfoto 2023-08-12 um 12 06 40

This are the fields I have to enter in the image.
I'm not really familiar with webdav, it seems to be the only convinient way to deploy my application.

I have a linux server with the path /var/www/personalWebsite into which I would like to deploy my application.

It works via scp and rsync but it looks like I'm to dumb to get it to work with debdav.

Could you provide a clear explanation on how I have to change the caddy configuration file?

Like I've said I tried all possible combinations but I couldn't get it to work...

And how do I restrict the access, is this like a public ftp where everyone can deploy files?
I've read this here, and here it get's shown I have to create a password hash, but I don't know if this is necessary?
https://marko.euptera.com/posts/caddy-webdav.html

That would be very kind of you,
kind regards
greets from Italy,
Daniel

PROPFIND of file that does not exist

When receiving a PROPFIND request for a file that does not exist, the plugin is logging an internal handler error, instead of responding appropriately, which I imagine would be with a 404.

{
  "level": "error",
  "ts": 1595606346.000593,
  "logger": "http.handlers.webdav",
  "msg": "internal handler error",
  "error": "stat /var/www/.../image.png: no such file or directory",
  "request": {
    "method": "PROPFIND",
    "uri": "/webdav/.../image.png",
    "proto": "HTTP/1.1",
    "remote_addr": "...",
    "host": "example.com",
    "headers": {
      "Connection": [
        "close"
      ],
      "Content-Length": [
        "0"
      ],
      "Accept": [
        "text/plain"
      ],
      "Depth": [
        "0"
      ],
      "Authorization": [
        "Basic ..."
      ],
      "User-Agent": [
        "axios/0.18.0"
      ]
    },
    "tls": {
      "resumed": true,
      "version": 771,
      "ciphersuite": 52393,
      "proto": "",
      "proto_mutual": true,
      "server_name": "example.com"
    }
  }
}

TLS and Webdav client

Hi there, apologies, this is completely off topic.

Have you ever been able to access a webdav server via caddy with TLS 1.2?

I have tried cadaver, davx, thunar (the file manager) but they all seem to send a TLS 1.0 Client Hello and that fails with the current Caddy.

Thank you, just wondering because I am going a bit nuts :D

Trying to confirm if it's working

I wanted to see if you could clarify something in my Caddyfile, or maybe build. I cannot get /webdav to work with a docker build of Caddy. When I browse to the docker box, I get my test page. When I go to http://dockerip/static to redirect to /static/ and does the browse plugin. So those are working. When I go to http://dockerip/webdav I'm getting 404.

Is the root element of webdav relative to the site blocks root? or is it a full file path?

My Caddyfile:

{
    order webdav last
}

(global) {
  encode gzip zstd
  log {
    output file /data/logs/caddy_access.log
  }
  handle_errors /data/logs/caddy_errors.log
  php_fastcgi phpfpm:9000
}

:80 {
  root * /usr/share/caddy/html
  file_server
  file_server /static/* browse
  import global

  redir /static /static/

  webdav /webdav {
    root /usr/share/caddy/webdav
  }
}

The Dockerfile builder:

FROM caddy:2.0.0-builder AS builder

RUN caddy-builder \
    github.com/mholt/caddy-webdav

FROM caddy:2.0.0

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Relevant docker-compose.yml:

version: '3.4'

services:
# Caddy web server, doing reverse proxy
  caddy:
    image: "caddy:2.0.0-custom"
    container_name: "caddy"
    ports:
     - "80:80"
     - "443:443"
    volumes:
     - /srv/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
     - /srv/caddy/www:/usr/share/caddy:rw
     - /srv/caddy/data:/data:rw
    restart: always

can not use xcaddy build caddy v2.4.3 with webdav

I use xcaddy build caddy 2.4.3 with webdav, it is failed.

root@debian:~# /root/go/bin/xcaddy build v2.4.3 --with github.com/mholt/caddy-webdav
2021/07/07 10:15:03 [INFO] Temporary folder: /tmp/buildenv_2021-07-07-1015.138554826
2021/07/07 10:15:03 [INFO] Writing main module: /tmp/buildenv_2021-07-07-1015.138554826/main.go
2021/07/07 10:15:03 [INFO] Initializing Go module
2021/07/07 10:15:03 [INFO] exec (timeout=10s): /usr/bin/go mod init caddy
go: creating new go.mod: module caddy
2021/07/07 10:15:03 [INFO] Pinning versions
2021/07/07 10:15:03 [INFO] exec (timeout=0s): /usr/bin/go get -d -v github.com/caddyserver/caddy/[email protected]
2021/07/07 10:15:23 [INFO] exec (timeout=0s): /usr/bin/go get -d -v github.com/mholt/caddy-webdav
go: github.com/mholt/caddy-webdav upgrade => v0.0.0-20200916200058-c949b3226234
go: downloading google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
go: downloading github.com/smallstep/certificates v0.15.15
2021/07/07 10:15:29 [INFO] Build environment ready
2021/07/07 10:15:29 [INFO] Building Caddy
2021/07/07 10:15:29 [INFO] exec (timeout=0s): /usr/bin/go mod tidy
go: downloading google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
go: downloading github.com/smallstep/certificates v0.15.15
go: downloading github.com/klauspost/compress v1.13.0
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki imports
github.com/smallstep/certificates/authority: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki imports
github.com/smallstep/certificates/db: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki/acmeserver imports
github.com/smallstep/certificates/acme: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki/acmeserver imports
github.com/smallstep/certificates/acme/api: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki/acmeserver imports
github.com/smallstep/certificates/acme/db/nosql: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddypki/acmeserver imports
github.com/smallstep/certificates/authority/provisioner: github.com/smallstep/[email protected]: reading https://proxy.golang.org/github.com/smallstep/certificates/@v/v0.15.15.zip: 403 Forbidden
caddy imports
github.com/mholt/caddy-webdav imports
github.com/caddyserver/caddy/v2/modules/caddyhttp imports
google.golang.org/genproto/googleapis/api/expr/v1alpha1: google.golang.org/[email protected]: reading https://proxy.golang.org/google.golang.org/genproto/@v/v0.0.0-20210602131652-f16073e35f0c.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddyhttp/standard imports
github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/gzip imports
github.com/klauspost/compress/gzip: github.com/klauspost/[email protected]: reading https://proxy.golang.org/github.com/klauspost/compress/@v/v1.13.0.zip: 403 Forbidden
caddy imports
github.com/caddyserver/caddy/v2/modules/standard imports
github.com/caddyserver/caddy/v2/modules/caddyhttp/standard imports
github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/zstd imports
github.com/klauspost/compress/zstd: github.com/klauspost/[email protected]: reading https://proxy.golang.org/github.com/klauspost/compress/@v/v1.13.0.zip: 403 Forbidden
2021/07/07 10:15:32 [INFO] Cleaning up temporary folder: /tmp/buildenv_2021-07-07-1015.138554826
2021/07/07 10:15:32 [FATAL] exit status 1

Is it possible to have directory listing with WebDAV enabled in the same path?

Based on the documents and my test, it seems like WebDAV has to be served in a different path with directory listing, one cannot have them both functioning under the same path, is that correct?

As an Apache & Nginx user, I felt quite surprised, as it is an expected behaviour to have them working in the same path.

Cheers,
Jayden

Permissions error with one file prevents listing the whole directory

I think this is a bug or limitation in the upstream webdav library, but I noticed that when listing the contents of a directory, the whole request returns an error if just one of the files has a permissions error. Instead, that file should not be in the list, and the request should still succeed, listing the rest of the files in the directory.

Issue with webdav RANGE requests

Hello,

I tired using caddy webdav plugin as backend for the excellent rclone project, and indeed was working somewhat fine for small files, however i discovered that there is a problem related to the RANGE request and downloads failing for big files and having to-download that lead me to rclone issue #4459 comment by @ncw, it seems there is problem related to the range requests in webdav plugin causing the multipart download files to not send correct range the file real size is 875607573 or 836M. As far as i know single request downloads works fine.

2022/12/04 13:03:39 DEBUG : rclone: Version "v1.60.0" starting with parameters ["rclone" "copy" "caddy:/files/test.mp4" "." "-P" "-vvv"]
2022/12/04 13:03:39 DEBUG : Creating backend with remote "caddy:/files/test.mp4"
2022/12/04 13:03:39 DEBUG : Using config file from "/home/user/.config/rclone/rclone.conf"
2022/12/04 13:03:39 DEBUG : found headers:
2022/12/04 13:03:40 DEBUG : fs cache: adding new entry for parent of "caddy:/files/test.mp4", "caddy:files"
2022/12/04 13:03:40 DEBUG : Creating backend with remote "."
2022/12/04 13:03:40 DEBUG : fs cache: renaming cache item "." to be canonical "/home/user/tests"
2022-12-04 13:03:40 DEBUG : test.mp4: Need to transfer - File not found at Destination
2022-12-04 13:03:40 DEBUG : test.mp4: Starting multi-thread copy with 3 parts of size 278.375Mi
2022-12-04 13:03:40 DEBUG : test.mp4: multi-thread copy: stream 3/3 (583794688-875607573) size 278.294Mi starting
2022-12-04 13:03:40 DEBUG : test.mp4: multi-thread copy: stream 2/3 (291897344-583794688) size 278.375Mi starting
2022-12-04 13:03:40 DEBUG : test.mp4: multi-thread copy: stream 1/3 (0-291897344) size 278.375Mi starting
2022-12-04 13:04:00 DEBUG : test.mp4: multi-thread copy: stream 1/3 (0-291897344) size 278.375Mi finished
2022-12-04 13:04:00 DEBUG : test.mp4: multi-thread copy: stream 2/3 (291897344-583794688) size 278.375Mi finished
2022-12-04 13:04:17 DEBUG : test.mp4: multi-thread copy: stream 3/3 failed: multipart copy: wrote 875607573 bytes but expected to write 291812885
2022-12-04 13:04:17 ERROR : test.mp4: Failed to copy: multipart copy: wrote 875607573 bytes but expected to write 291812885
2022-12-04 13:04:17 ERROR : Attempt 1/3 failed with 1 errors and: multipart copy: wrote 875607573 bytes but expected to write 291812885
2022-12-04 13:04:18 DEBUG : test.mp4: Sizes differ (src 875607573 vs dst 1459402261)
2022-12-04 13:04:18 DEBUG : test.mp4: Starting multi-thread copy with 3 parts of size 278.375Mi
2022-12-04 13:04:18 DEBUG : test.mp4: multi-thread copy: stream 3/3 (583794688-875607573) size 278.294Mi starting
2022-12-04 13:04:18 DEBUG : test.mp4: multi-thread copy: stream 1/3 (0-291897344) size 278.375Mi starting
2022-12-04 13:04:18 DEBUG : test.mp4: multi-thread copy: stream 2/3 (291897344-583794688) size 278.375Mi starting
2022-12-04 13:04:33 DEBUG : test.mp4: multi-thread copy: stream 2/3 (291897344-583794688) size 278.375Mi finished
2022-12-04 13:04:33 DEBUG : test.mp4: multi-thread copy: stream 3/3 (583794688-875607573) size 278.294Mi finished
2022-12-04 13:04:33 DEBUG : test.mp4: multi-thread copy: stream 1/3 (0-291897344) size 278.375Mi finished
2022-12-04 13:04:33 DEBUG : test.mp4: Finished multi-thread copy with 3 parts of size 278.375Mi
2022-12-04 13:04:33 INFO  : test.mp4: Multi-thread Copied (replaced existing)
2022-12-04 13:04:33 ERROR : Attempt 2/3 succeeded
Transferred:        2.175 GiB / 2.175 GiB, 100%, 47.549 MiB/s, ETA 0s
Transferred:            1 / 1, 100%
Elapsed time:        53.3s
2022/12/04 13:04:33 INFO  :
Transferred:        2.175 GiB / 2.175 GiB, 100%, 47.549 MiB/s, ETA 0s
Transferred:            1 / 1, 100%
Elapsed time:        53.3s

2022/12/04 13:04:33 DEBUG : 4 go routines active
v2.6.2 h1:wKoFIxpmOJLGl3QXoo6PNbYvGW4xLEgo32GPBEjWL8o=
$ caddy list-modules
admin.api.load
admin.api.metrics
admin.api.pki
admin.api.reverse_proxy
caddy.adapters.caddyfile
caddy.config_loaders.http
caddy.listeners.http_redirect
caddy.listeners.tls
caddy.logging.encoders.console
caddy.logging.encoders.filter
caddy.logging.encoders.filter.cookie
caddy.logging.encoders.filter.delete
caddy.logging.encoders.filter.hash
caddy.logging.encoders.filter.ip_mask
caddy.logging.encoders.filter.query
caddy.logging.encoders.filter.regexp
caddy.logging.encoders.filter.rename
caddy.logging.encoders.filter.replace
caddy.logging.encoders.json
caddy.logging.writers.discard
caddy.logging.writers.file
caddy.logging.writers.net
caddy.logging.writers.stderr
caddy.logging.writers.stdout
caddy.storage.file_system
events
http
http.authentication.hashes.bcrypt
http.authentication.hashes.scrypt
http.authentication.providers.http_basic
http.encoders.gzip
http.encoders.zstd
http.handlers.acme_server
http.handlers.authentication
http.handlers.copy_response
http.handlers.copy_response_headers
http.handlers.encode
http.handlers.error
http.handlers.file_server
http.handlers.headers
http.handlers.map
http.handlers.metrics
http.handlers.push
http.handlers.request_body
http.handlers.reverse_proxy
http.handlers.rewrite
http.handlers.static_response
http.handlers.subroute
http.handlers.templates
http.handlers.tracing
http.handlers.vars
http.matchers.expression
http.matchers.file
http.matchers.header
http.matchers.header_regexp
http.matchers.host
http.matchers.method
http.matchers.not
http.matchers.path
http.matchers.path_regexp
http.matchers.protocol
http.matchers.query
http.matchers.remote_ip
http.matchers.vars
http.matchers.vars_regexp
http.precompressed.br
http.precompressed.gzip
http.precompressed.zstd
http.reverse_proxy.selection_policies.cookie
http.reverse_proxy.selection_policies.first
http.reverse_proxy.selection_policies.header
http.reverse_proxy.selection_policies.ip_hash
http.reverse_proxy.selection_policies.least_conn
http.reverse_proxy.selection_policies.random
http.reverse_proxy.selection_policies.random_choose
http.reverse_proxy.selection_policies.round_robin
http.reverse_proxy.selection_policies.uri_hash
http.reverse_proxy.transport.fastcgi
http.reverse_proxy.transport.http
http.reverse_proxy.upstreams.a
http.reverse_proxy.upstreams.multi
http.reverse_proxy.upstreams.srv
pki
tls
tls.certificates.automate
tls.certificates.load_files
tls.certificates.load_folders
tls.certificates.load_pem
tls.certificates.load_storage
tls.client_auth.leaf
tls.get_certificate.http
tls.get_certificate.tailscale
tls.handshake_match.remote_ip
tls.handshake_match.sni
tls.issuance.acme
tls.issuance.internal
tls.issuance.zerossl
tls.stek.distributed
tls.stek.standard

  Standard modules: 99

caddy.logging.encoders.formatted
caddy.logging.encoders.transform
dns.providers.cloudflare
http.handlers.webdav
layer4
layer4.handlers.echo
layer4.handlers.proxy
layer4.handlers.proxy_protocol
layer4.handlers.socks5
layer4.handlers.subroute
layer4.handlers.tee
layer4.handlers.throttle
layer4.handlers.tls
layer4.matchers.http
layer4.matchers.ip
layer4.matchers.proxy_protocol
layer4.matchers.socks4
layer4.matchers.socks5
layer4.matchers.ssh
layer4.matchers.tls
layer4.matchers.xmpp
layer4.proxy.selection_policies.first
layer4.proxy.selection_policies.ip_hash
layer4.proxy.selection_policies.least_conn
layer4.proxy.selection_policies.random
layer4.proxy.selection_policies.random_choose
layer4.proxy.selection_policies.round_robin
tls.handshake_match.alpn

  Non-standard modules: 28

  Unknown modules: 0

The webdav service filter some files for unknown reason

The caddy and webdav module is downloaded today from the homepage.

Caddyfile :

{
    admin off
    auto_https off
    local_certs
    order webdav before file_server
}

:9999 {
    encode gzip
    root * /data      
    file_server browse
    tls /root/caddy/server.cert /root/caddy/server.key

    webdav /webdav/* {
        root /data
        prefix /webdav
    }
}

Step 1

Generate some text files as the snapshot, then refresh the webdav directory, no any text file is shown.
snapshot_20221019142605

Step 2

Then, just rename the text file to another filetype as the snapshot, and refresh the webdav directory again, one of them appeared.
snapshot_20221019143333

Step 3

Let's continue. This time i just rename the filename, did not change the filetype. Here is the snapshot.
snapshot_20221019143559

Step 4

Not only text files is filtered strangely, other filetype is the same. Here is another test.
snapshot_20221019144319

This is my webdav client conf:
snapshot_20221019144626

I dont know why and how to resolve it. Thanks.

LOCK/UNLOCK and other Webdav method support

Hi there, really liking caddy and learning a bunch, while trying to contribute a bit! To the forum.

I was wondering if you see this plugin evolving so that it can support class 1 or class 2 WebDAV.

My current need does not involve anything fancy but it would be nice to stay with caddy if the need for a lock, for instance, arises.

Thanks for your effort!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.