Is this how variable (set $var) inheritance works?

Max nginxyz at mail.ru
Sat Feb 4 01:15:02 UTC 2012


03 февраля 2012, 22:59 от Edho Arief <edho at myconan.net>:
> On Sat, Feb 4, 2012 at 1:50 AM, Edho Arief <edho at myconan.net> wrote:
> >> Why did I get warning for using uninitialized variables even though
> >> it's not specified at all in the relevant location block?
> >>
> >
> > After a bit more thinking, does it mean that the "alias $userfile"
> > from parent location block was inherited but the $userfile was passed
> > literally?
> >
> 
> More self-reply: it certainly looks like the $userfile is passed but
> still in variable, not expanded with the contents as the following
> test showed.
> 
> Skipping "set $userfile ..." and put the capture in alias directly:
> 
>   location ~ ^/~([^/]+)(|/.*)$ {
>     alias /home/$1/public_html/$2;
>     location ~ \.php$ {
>       include fastcgi_params;
>       fastcgi_param SCRIPT_FILENAME $request_filename;
>       fastcgi_pass 127.0.0.1:9000;
>     }
>   }
> 
> resulted in this:
> 
> 2012/02/03 13:51:28 [debug] 14951#0: *13 fastcgi param: "REDIRECT_STATUS: 200"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script copy: "/home/"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script capture: ""
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script copy: "/public_html/"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script capture: ""
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script copy: "SCRIPT_FILENAME"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 http script var: "/home//public_html/"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 fastcgi param:
> "SCRIPT_FILENAME: /home//public_html/"
> 2012/02/03 13:51:28 [debug] 14951#0: *13 fastcgi param: "HTTP_HOST:
> yutsuki.myconan.net"
> 
> Which explains why I got "/opt/nginx/" for $request_filename on
> previous config - the \.php$ location block was basically using `alias
> $userfile` but as $userfile was empty, it became empty alias for that
> block.

Nested location blocks inherit variables only by name, which means
the inherited variables are only created and marked as uninitialized.
Note that this is not the same as creating an empty variable that
contains "". The distinction should be similar to the one between
defined vs. empty variables in Perl: if you set $variable to "",
then 'if ($variable)' would evaluate to false, while
'if (defined($variable))' would evaluate to true.

This distinction exists in nginx as well, where 'if ($variable)'
would also evaluate to false, but there's no direct way to
test whether a variable is defined. However nginx tests for
this automatically - if you try to use an undefined variable,
nginx will report an 'unknown "<variable_name>" variable' error
and fail to start.

That's why a variable that was set to a certain value inside the
outermost (parent) location block will be inherited by nested location
blocks only by name, which means that if you try to use such a
variable inside a nested location block, nginx won't report any
errors, but instead of the original contents of the variable, you will
only get an empty string when you try to access the contents.

This feature/bug is especially confusing when you use variables
inside root and alias directives, because the nested location blocks
will inherit the root and alias contents (unless specifically set),
which will have any uninitialized inherited variable names replaced
with "", so "/home/$variable/abc/$dir/" would become "/home//abc//".

Another important thing to remember is that if you set root or alias
to contain nothing but a variable (root $home;), then the root inside
any nested location block where you do not set root or alias specifically,
will be reset NOT to your default root value from the server
configuration block, but to the value of the prefix configure argument
that nginx was compiled with (/usr/local/etc/nginx), which you can see
under --prefix= when you run nginx -V.

Your nginx was probably compiled with --prefix=/opt/nginx/.

Max


More information about the nginx mailing list