[Из песочницы] Как подружить nginx и встроенный веб клиент
В Microsoft Windows начиная с 2к встроен Веб Клиент, по сути это средство для монтирования сетевых дисков по протоколу WebDav, который ходит поверх HTTP/HTTPS.Клиент писался явно под себя (связка с IIS) и от того работает весьма корявосвоеобразно.Это единственный способ «малой» кровью примонтировать диск через интернет не настраивая VPN для проброса SAMBA протокола.SAMB-у в принципе тоже без VPN можно пробросить, но это из области поиска приключений с последствиями.Nginx в базовом функционале имеет не полную поддержку WebDav: PUT DELETE MKCOL COPY MOVE.Расширить его ещё двумя: PROPFIND и OPTIONS можно с помощью плагина: dav-ext
Дальше будет описание как заставить виндовый WebDav клиент работать с Nginx колдуя только в конфиге.+ пара мелких багов Nginx.Для работы потребуется Nginx собранный с поддержкой WebDav, dav-ext модулем и rewrite.[x] HTTP_DAV Enable http_webdav module[x] HTTP_DAV_EXT 3rd party webdav_ext module[x] HTTP_REWRITE Enable http_rewrite module
Проблема 1Майкрософт нарушает стандарты и свои обещания. (как обычно)Перед тем как создать файл WebDav клиент проверяет наличие файла посылая запрос:
Запрос PROPFIND /!!!/test.lnk HTTP/1.1 Connection: Keep-Alive User-Agent: Microsoft-WebDAV-MiniRedir/6.1.7601 Depth: 0 translate: f Content-Length: 0 Host: 172.16.0.254:8089 В ответ IIS ему выдаёт HTTP/1.1 404 Resource Not Found Content-Length: 1635 Content-Type: text/html Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Date: Sun, 10 Aug 2014 20:06:08 GMT
… Только это не правильно, должен быть код 207 и xml в котором описан элемент и код для него, те 404 должно быть в xml.с точки зрения стандартов: tools.ietf.org/html/rfc2518#page-24с точки зрения доков мс: msdn.microsoft.com/en-us/library/aa142960(v=exchg.65).aspxУ яндекса тоже в примерах xml: api.yandex.ru/disk/doc/dg/reference/propfind_property-request.xml
Ответ Nginx HTTP/1.1 207 Multi-Status Server: nginx/1.7.4 Date: Sun, 10 Aug 2014 21:17:34 GMT Transfer-Encoding: chunked Connection: keep-alive Keep-Alive: timeout=60
47
cc
11
0 Такой «неожиданный» ответ сносит голову WebDav клиенту винды.Фиксим в конфиге (возможно это сведёт с ума остальные, порядочные WebDav клиенты, но лично мне нужен был только один не такой как все):
Фикс 1 error_page 599 = @propfind_handler; if ($request_method = PROPFIND) { return 599; }
location @propfind_handler { internal;
open_file_cache off; if (!-e $webdav_root/$uri) { # Microsoft specific handle. return 404; } root $webdav_root; dav_ext_methods PROPFIND; } Проблема 2 WebDav от мс очень хочет метод PROPPATCH, которого в Nginx и расширениях нет. Совсем нет.Я рассматривал два варианта решения:1. Написать плагин к Nginx или патч к dav-ext, короче Си код и пересборка Nginx.2. Положится на кривость виндовой реализации WebDav и скормить статический ответ.Запрос PROPPATCH /Family/INSURGENCIES%20AND%20COUNTERING%20INSURGENCIES.pdf%20-%20%D0%AF%D1%80%D0%BB%D1%8B%D0%BA.lnk HTTP/1.1 Cache-Control: no-cache Connection: Keep-Alive Pragma: no-cache Content-Type: text/xml; charset=«utf-8» User-Agent: Microsoft-WebDAV-MiniRedir/6.1.7601 translate: f Content-Length: 443 Host: xxx.xxx.net
Фикс 2
if ($request_method = PROPPATCH) { # Unsupported, allways return OK.
add_header Content-Type 'text/xml';
return 207 '
Проблема 3 Создание папок.См п1:)Приходит запрос MKCOL /Family/MR3020 HTTP/1.1 Connection: Keep-Alive User-Agent: Microsoft-WebDAV-MiniRedir/6.1.7601 translate: f Content-Length: 0 Host: xxx.xxx.net Nginx на него отвечает (немного странно выбирая код, на мой взгляд, но в принципе правильно)
Ответ HTTP/1.1 409 Conflict Server: nginx/1.7.4 Date: Sun, 10 Aug 2014 21:43:15 GMT Content-Type: text/html Content-Length: 166 Connection: keep-alive Keep-Alive: timeout=60
409 Conflict
Как должно быть описано: У майкрософта: msdn.microsoft.com/en-us/library/aa142923(v=exchg.65).aspxУ яндекса: api.yandex.ru/disk/doc/dg/reference/mkcol.xmlИ даже в RFC: tools.ietf.org/html/rfc2518#page-33
Во всех примерах URL оканчивается слешем.Но только не в запросе WebDav клиента от мс.
Вариантов опять было два:1. Поправить файл: lxr.nginx.org/source/src/http/modules/ngx_http_dav_module.c строчки 484 — 493, там как раз проверка наличия слеша и его отрезание.2. Пофиксить через конфиг.
Вариант 1 я оставляю на усмотрение програмеров nginx, может по стандарту оно и должно ругаться. Связываться с отсылкой патчей тоже не хотелось.
Правим конфиг:
Фикс 3 if ($request_method = MKCOL) { # Microsoft specific handle: add trailing slash. rewrite ^(.*[^/])$ $1/; } Вот для этого пустяка и потребовался REWRITE плагин.Проблема 4 Удаление папок.Ноги тут те же что и в п3: отсутствие слеша на конце урла.Однако я столкнулся с тем, что nginx тоже ведёт себя несколько странно.1. Если слеш на конце отсутствует, то nginx считает что его просят удалить файл, и получает ошибку: 21: Is a directory при попытке удалить.2. Если слеш добавить то папку он почему то так и не удаляет. Подозреваю тут где то баг самого nginx.Фикс в конфиге:
Фикс 4 error_page 598 = @delete_handler; if ($request_method = DELETE) { return 598; }
location @delete_handler { internal;
open_file_cache off; if (-d $webdav_root/$uri) { # Add trailing slash to dirs. rewrite ^(.*[^/])$ $1/; } root $webdav_root; dav_methods DELETE; } Если кратко, то переносим обработку DELETE в отдельный локейшин (процедуру), дальше проверяем, если удаляется папка то добавляем слеш.Ещё немного о Nginx Не трудно заметить, что nginx не добавляет в ответы: Content-Type: text/xmlи хотя в данном случае это не создаёт проблем, но всё же это не правильно.Это уже третий раз когда гибкость nginx позволила мне получить результат не используя языки программирования, Игорь — молодец! Прошлые разы я сделал кешируюший прокси с фильтрацией по урл и UPnP/DLNA сервер.
Конфиг nginx для WebDav WebDav для Nginx # WebDAV set $webdav_root »/mnt/WebDav_folder»; location ^~ /Family {
root $webdav_root; error_page 599 = @propfind_handler; error_page 598 = @delete_handler; chunked_transfer_encoding on; open_file_cache off; client_max_body_size 50m; add_header Allow 'OPTIONS, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND';
if ($request_method = PROPFIND) {
return 599;
}
if ($request_method = PROPPATCH) { # Unsupported, allways return OK.
add_header Content-Type 'text/xml';
return 207 '
dav_methods PUT MKCOL COPY MOVE; # dav_ext_methods OPTIONS; create_full_put_path on; min_delete_depth 0; dav_access user: rw group: rw all: rw; } location @propfind_handler { internal;
open_file_cache off; if (!-e $webdav_root/$uri) { # Microsoft specific handle. return 404; } root $webdav_root; dav_ext_methods PROPFIND; } location @delete_handler { internal;
open_file_cache off; if (-d $webdav_root/$uri) { # Add trailing slash to dirs. rewrite ^(.*[^/])$ $1/; } root $webdav_root; dav_methods DELETE; } open_file_cache off; — нужно потому что мы меняем файлы, если кеширование включено то можно будет долго гадать почему не видно файлы которые мы только что закинули на сервер.
Немного о настройке клиента Он как капризный ребёнок, из коробки ему подавай SSL и никакой Basic аутентификации, файлы не больше 50 мегабайт, в папках не более 500–1000 файлов.Увы, но даже после всего файлы более 4 гб передавать не получится. (Скорее всего из за кривой реализации, которая файлы при открытии скачивает в память/на диск чтобы получить более менее стандартный файловый дискриптор, это мои домыслы.)Вот здесь собраны все настройки с описанием: blogs.msdn.com/b/robert_mcmurray/archive/2008/01/17/webdav-redirector-registry-settings.aspx
На данный момент мои настройки WebClient выглядят так Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\WebClient\Parameters] «SupportLocking»=dword:00000000 «InternetServerTimeoutInSec»=dword:0000001e «ServiceDllUnloadOnStop»=dword:00000001 «ServerNotFoundCacheLifeTimeInSec»=dword:0000000a «ClientDebug»=dword:00000000 «FileSizeLimitInBytes»=dword: ffffffff «SendReceiveTimeoutInSec»=dword:0000003c «LocalServerTimeoutInSec»=dword:0000000f «FileAttributesLimitInBytes»=dword:00989680 «AcceptOfficeAndTahoeServers»=dword:00000001 «ServiceDebug»=dword:00000000 «BasicAuthLevel»=dword:00000002