在 nginx webdav 上,PUT 返回 501

在 nginx webdav 上,PUT 返回 501

我负责将 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 会失败。

相关内容