我负责将 Web 服务器从 apache 转换为 nginx,目前无法让 webdav 正常工作。WebDAV 由 PEAR webdav 服务器提供服务(http://pear.php.net/package/HTTP_WebDAV_Server)。我是 nginx 新手,但我已尽力按照 nginx webdav 和 webdav_ext 模块中的示例操作(或查找遇到此问题的人),但无济于事。列表/读取操作似乎都运行正常,但 PUT 操作返回 501 未实现,并且不会对文件进行任何更改。error.log 中没有任何内容,我怀疑我遗漏了一个陷阱。
nginx 版本/选项:
vagrant@precise64:~/mudlib$ /opt/nginx-1.4.4/sbin/nginx -V
nginx version: nginx/1.4.4
built by gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
TLS SNI support enabled
configure arguments: --prefix=/opt/nginx-1.4.4 --conf-path=/etc/nginx/nginx.conf --sbin-path=/opt/nginx-1.4.4/sbin/nginx --add-module=/var/chef/cache/5a85970ba61a99f55a26d2536a11d512b39bbd622f5737d25a9a8c10db81efa9 --with-http_ssl_module --with-http_gzip_static_module --with-http_dav_module --add-module=/var/chef/cache/d428a0236c933779cb40ac8c91afb19d5c25a376dc3caab825bfd543e1ee530d
chef 管理的两个扩展是 http_auth_pam (http://web.iti.upv.es/~sto/nginx/ngx_http_auth_pam_module-1.2.tar.gz)和 nginx_dav_ext (http://github.com/arut/nginx-dav-ext-module/archive/v0.0.3.tar.gz)。
Nginx 站点配置:
server {
root /home/vagrant/mudlib/www/;
listen 80;
server_name tsunami;
access_log /var/log/nginx/tsunami.access.log;
index index.php;
location / {
try_files $uri $uri/ /index.php;
}
location ~ ^(/[^./]+)$ {
proxy_pass http://localhost:8002;
}
location /wizards/ {
auth_pam "Restricted Zone";
auth_pam_service_name "nginx";
}
location ~ ^(.+\.php)(.*)$ {
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:rw;
fastcgi_pass unix:/var/run/php-fpm-www.sock;
include fastcgi_params;
}
}
nginx站点访问日志:
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "PROPFIND /webdav.php/text/WIZNEWS HTTP/1.1" 207 685 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "LOCK /webdav.php/text/WIZNEWS HTTP/1.1" 200 458 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "GET /webdav.php/text/WIZNEWS HTTP/1.1" 200 474 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "PROPFIND /webdav.php/text HTTP/1.1" 207 661 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "HEAD /webdav.php/text/WIZNEWS HTTP/1.1" 200 0 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:29 +0000] "PUT /webdav.php/text/WIZNEWS HTTP/1.1" 501 61 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "UNLOCK /webdav.php/text/WIZNEWS HTTP/1.1" 204 0 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "PROPFIND /webdav.php/text/WIZNEWS HTTP/1.1" 207 685 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "LOCK /webdav.php/text/WIZNEWS HTTP/1.1" 200 458 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "GET /webdav.php/text/WIZNEWS HTTP/1.1" 200 474 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "HEAD /webdav.php/text/WIZNEWS HTTP/1.1" 200 0 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:30 +0000] "PUT /webdav.php/text/WIZNEWS HTTP/1.1" 501 61 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
10.0.2.2 - misery [30/Aug/2014:15:51:31 +0000] "UNLOCK /webdav.php/text/WIZNEWS HTTP/1.1" 204 0 "-" "Microsoft-WebDAV-MiniRedir/6.1.7601"
答案1
在我们的案例中,解决方案是拉当前副本pear/webdav 服务器代码并重新应用我们对其所做的安全策略编辑。501 代码不是 nginx 的错误,导致 PUT 失败出现在 nginx 中而不是 apache 中的根本问题已在较新版本的 webdav 服务器代码中得到解决。
为了帮助将来遇到此问题的人找到这个问题,我将记录错误发生的位置。在http_PUT()
pear/webdav 的 Server.php 中,有许多针对不受支持的 Content-* 标头的检查:
/* RFC 2616 2.6 says: "The recipient of the entity MUST NOT
ignore any Content-* (e.g. Content-Range) headers that it
does not understand or implement and MUST return a 501
(Not Implemented) response in such cases."
*/
foreach ($this->_SERVER as $key => $val) {
if (strncmp($key, "HTTP_CONTENT", 11)) continue;
switch ($key) {
case 'HTTP_CONTENT_ENCODING': // RFC 2616 14.11
// TODO support this if ext/zlib filters are available
$this->http_status("501 not implemented");
echo "The service does not support '$val' content encoding";
return;
case 'HTTP_CONTENT_LANGUAGE': // RFC 2616 14.12
// we assume it is not critical if this one is ignored
// in the actual PUT implementation ...
$options["content_language"] = $val;
break;
case 'HTTP_CONTENT_LOCATION': // RFC 2616 14.14
/* The meaning of the Content-Location header in PUT
or POST requests is undefined; servers are free
to ignore it in those cases. */
break;
case 'HTTP_CONTENT_RANGE': // RFC 2616 14.16
// single byte range requests are supported
// the header format is also specified in RFC 2616 14.16
// TODO we have to ensure that implementations support this or send 501 instead
if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $val, $matches)) {
$this->http_status("400 bad request");
echo "The service does only support single byte ranges";
return;
}
$range = array("start"=>$matches[1], "end"=>$matches[2]);
if (is_numeric($matches[3])) {
$range["total_length"] = $matches[3];
}
$option["ranges"][] = $range;
// TODO make sure the implementation supports partial PUT
// this has to be done in advance to avoid data being overwritten
// on implementations that do not support this ...
break;
case 'HTTP_CONTENT_MD5': // RFC 2616 14.15
// TODO: maybe we can just pretend here?
$this->http_status("501 not implemented");
echo "The service does not support content MD5 checksum verification";
return;
default:
// any other unknown Content-* headers
$this->http_status("501 not implemented");
echo "The service does not support '$key'";
return;
}
}
默认情况下,当遇到似乎未预料到的 HTTP_CONTENT_LENGTH 标头时,PUT 会失败。