web-dev-qa-db-ja.com

nginx + fcgiwrap:fastcgi_paramの順序はどうして重要なのですか?

Debian 6.0.3squeeze)、nginx-0.7.67fcgiwrap-1.0-1+squeeze1を実行しています。テストスクリプトは次のとおりです。

#!/usr/bin/Perl
use 5.010;
use warnings;
use strict;

use Data::Dumper;

print "Content-Type: text/html\n\n";
say Dumper {map {$_ => $ENV{$_}} 'SCRIPT_NAME', 'DOCUMENT_ROOT', 'WHATEVER'};
say "$<, $>, $(, $)";

そして、これがnginx構成です。

server {
    server_name   domain.com;
    root   /home/yuri/6;
    access_log   /var/log/nginx/domain.com-access.log;
    error_log   /var/log/nginx/domain.com-error.log;

    location /cgi-bin/ {
        fastcgi_pass   unix:/var/run/fcgiwrap.socket;
        fastcgi_param   DOCUMENT_ROOT   $document_root;
        fastcgi_param   DOCUMENT_ROOT   /home/yuri/7/;
        fastcgi_param   SCRIPT_NAME   $fastcgi_script_name;
        fastcgi_param   WHATEVER   1;
        fastcgi_param   WHATEVER   2;
    }

    location /1.php {
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_param   PHP_ADMIN_VALUE   cgi.fix_pathinfo=1;
        fastcgi_param   REQUEST_METHOD    $request_method;
        fastcgi_param   SCRIPT_FILENAME   whatever;
        fastcgi_param   SCRIPT_FILENAME   $document_root$fastcgi_script_name;
    }
}

これが、URLに移動した場合にブラウザで取得するものです http://domain.com/cgi-bin/1.pl

$VAR1 = { 'SCRIPT_NAME' => '/cgi-bin/1.pl', 'DOCUMENT_ROOT' => '/home/yuri/7/', 'WHATEVER' => '2' };

したがって、fcgiwrapは最初のDOCUMENT_ROOTを使用してスクリプトを検索しているようですが、スクリプトはparamsの最後の値を取得します。 DOCUMENT_ROOTディレクティブの順序を変更すると、Webサーバーは403を返します。問題は...どうしてですか?

phpは期待どおりに機能しますが、2番目のSCRIPT_FILENAMEは最初のものをオーバーライドします。

3
x-yuri

Fastcgiライブラリは、指定されたパラメータをenvironポインタに渡すだけです。 fcgiwrapによって使用されるgetenv()は、最初に来た環境変数を使用します(最適化?)。 PHP FPMはこの環境を配列データ型と同じように扱い、後者のキーは最初のキーを上書きする可能性があります。

順序に依存せず、キーが1つしかないことを確認してください。正しい動作が文書化されているかどうかにかかわらず、私はFastCGI仕様を見ていません。

why 403を取得した場合、_/home/yuri/7/1.pl_ファイルはないと思います。 (最初のパラメーターはfcgiwrapによって一致することを忘れないでください)。実行可能ではないため、fcgiwrapは403を返します。

テスト

以下のパッチは、FCGI_Accept()で指定された環境を出力します。

_diff --git a/fcgiwrap.c b/fcgiwrap.c
index e86ff9d..0dff2e6 100644
--- a/fcgiwrap.c
+++ b/fcgiwrap.c
@@ -470,6 +470,11 @@ static void inherit_environment(void)
    char * const * p;
    char *q;

+   for (p = environ; *p; p++)
+       fprintf(stderr, "ENV: %s\n", *p);
+
+   fprintf(stderr, "ENV[FOO] = %s\n", getenv("FOO"));
+
    for (p = inherited_environ; *p; p++) {
        q = strchr(*p, '=');
        if (!q) {
_

テストに使用されるnginx構成:

_events {
    worker_connections 768;
}

pid pid;
error_log error_log;
http {
    server {
        access_log off;
        listen 5555;
        location / {
            fastcgi_param FOO BAR;
            fastcgi_param FOO BARRED;
            fastcgi_pass unix:/tmp/sock;
        }
    }
}
_

サーバーを起動するコマンド(現在のディレクトリに_nginx.conf_があると仮定):

_$ nginx -p . -c nginx.conf
$ env -i ./fcgiwrap -p /dev/null -s unix:/tmp/sock
_

ここで、_curl http://localhost:5555/_を実行すると、stderrは次のように出力します。

_ENV: FCGI_ROLE=RESPONDER
ENV: FOO=BAR
ENV: FOO=BARRED
ENV: HTTP_USER_AGENT=curl/7.30.0
ENV: HTTP_Host=localhost:5555
ENV: HTTP_ACCEPT=*/*
ENV[FOO] = BAR
Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?
_

さておき、これは開発バージョンです。現在の安定版(1.1.0)には、上記の_-p_パラメーターが含まれていません。結果については、実際には問題ではありません。ドロップして、_SCRIPT_NAME_が指定されていないなどのエラーを受け取った可能性もあります。

2
Lekensteyn