filestash
filestash copied to clipboard
[bug] Windows WebDAV client attempts `OPTIONS` on document root and breaks
Description of the bug
Originally I was trying to use Windows' Add network location feature to sync a share link, to replace Nextcloud and its client. However, it doesn't seem to work:
The issue appears to be that before Windows even attempts to poke or browse the WebDAV URI, it sends an OPTIONS
request on the document root. I assume this is Windows attempting to test if the domain provided is indeed for a WebDAV server, or otherwise allows the WebDAV request methods. Adding the headers usually returned by the library allows it to continue past this point. I don't know if the WebDAV/HTTP spec etc. specifies that the document root should be checked, but regardless, Windows does it.
One thing that really ground my gears when testing this: The result of the above check is cached and attempting to add any other link at the same domain will fail for any later attempts. However, after getting it working, I also found out that a successful check will also be cached, and it will be assumed successful on later attempts. The only way I've seen to clear this cache is to reboot.
This can easily be worked around with a rewrite in a reverse proxy. I used the following Nginx config to kludge it:
map $request_uri#$request_method#$http_user_agent $filestash_fixdav {
~^/#OPTIONS#DavClnt 1; # detect Windows DavClnt probes on root
# ...
default '';
}
# generate the variables used by the Windows WebDAV hack
map $filestash_fixdav $filestash_fixdav_davclnt_allow {
1 'OPTIONS, LOCK, PUT, MKCOL';
default $upstream_http_allow;
}
map $filestash_fixdav $filestash_fixdav_davclnt_dav {
1 '1, 2';
default $upstream_http_dav;
}
map $filestash_fixdav $filestash_fixdav_davclnt_authorvia {
1 'DAV';
default $upstream_http_ms_author_via;
}
server {
location / {
# ...
# HACK: fix for Microsoft DavClnt sending an OPTIONS request to
# document root on shared links instead of to the link itself,
# which does not work as DAV only works under the share URI
if ($filestash_fixdav = 1) {
return 200;
}
more_set_headers "Allow: $filestash_fixdav_davclnt_allow";
more_set_headers "Dav: $filestash_fixdav_davclnt_dav";
more_set_headers "Ms-Author-Via: $filestash_fixdav_davclnt_authorvia";
# ...
}
}
This appears to be the same bug as #241.
Step by step instructions to reproduce the bug
- Create a share link to any directory
- Try to use that directory in Windows Explorer
Can you replicate that error from the demo?
Yes. This shows that it isn't just my chosen backend (local folder), but it also happens with S3.
Observed behavior
It doesn't work
Expected behavior
It does work
Decided I really wanted to get this to work, as it's one of the last things preventing me from switching off Nextcloud, so I dug a bit deeper.
First thing I noticed is that, in fact, WebDAV does work just fine. I tested a share link on the Filestash demo for WebDAV, and it mounted fine. The problem is then of course how Windows handles things.
I found two issues in my investigation:
- When attempting to add an HTTP(S) link directly, Windows will attempt an
OPTIONS
request on the document root. - Windows automatically strips the trailing slash off of the share link, which Filestash chokes on.
For the first issue, I assume this is Windows attempting to test if the domain provided is indeed for a WebDAV server, or otherwise allows the WebDAV request methods. Adding the headers usually returned by the library allows it to continue past this point. I don't know if the WebDAV/HTTP spec etc. specifies that the document root should be checked, but regardless, Windows does it.
One thing that really ground my gears when testing this: The result of the above check is cached and attempting to add any other link at the same domain will fail for any later attempts. However, after getting it working, I also found out that a successful check will also be cached, and it will be assumed successful on later attempts. The only way I've seen to clear this cache is to reboot.
For the second issue, appending a trailing slash again allows it to work. This can easily be done in a rewrite in the reverse proxy.
I used the following Nginx config to fix these issues:
# check the request method, URI, and user agent, to see if we need to apply our
# nasty hack to get WebDAV to work with Windows
map $request_method$uri$http_user_agent $filestash_fixdavroot {
~OPTIONS/DavClnt 1;
default '';
}
# generate the variables used by the Windows WebDAV hack
map $filestash_fixdavroot $filestash_fixdavroot_allow {
1 'OPTIONS, LOCK, PUT, MKCOL';
default $http_allow;
}
map $filestash_fixdavroot $filestash_fixdavroot_dav {
1 '1, 2';
default $http_dav;
}
map $filestash_fixdavroot $filestash_fixdavroot_authorvia {
1 'DAV';
default $http_ms_author_via;
}
server {
# ...
# HACK: fix windows not appending slash to webdav uri
location ~ /s/[^/]+$ {
rewrite (.*) $1/ last;
}
location / {
# ...
# HACK: fix for Microsoft DavClnt sending an OPTIONS request to
# document root on shared links instead of to the link itself,
# which does not work as DAV only works under the share URI
if ($filestash_fixdavroot) {
return 200;
}
more_set_headers "Allow: $filestash_fixdavroot_allow";
more_set_headers "Dav: $filestash_fixdavroot_dav";
more_set_headers "Ms-Author-Via: $filestash_fixdavroot_authorvia";
}
}
It seems there are multiple bugs with the WebDAV implementation. I will focus this issue on the problem with Windows specifically, where it sends OPTIONS
to the document root. The issue with the trailing slash appears to not be Windows-specific as I have been able to replicate it with KDE Dolphin via the webdavs://
handler.