Sub-requests poisoning r->variables cache

Maxim Dounin mdounin at mdounin.ru
Thu Feb 22 12:26:09 UTC 2018


Hello!

On Thu, Feb 22, 2018 at 11:53:14AM +1100, Lawrence Stewart via nginx-devel wrote:

> Greetings nginx developers,
> 
> The root cause analysis for a bug I observed during development of some
> custom nginx module code turns out to be an unfortunate interaction between
> sub-requests and indexed variable lookups using
> ngx_http_get_indexed_variable(). We're based on nginx 1.13.6.
> 
> The sequence of events is:
> 
> - Main request arrives and triggers an access-phase sub-request. Main
> request includes request variable "x=blah", but sub-request does not.
> 
> - Sub-request arrives at custom module's header filter
> 
> - Custom module looks up variable "x" with ngx_http_get_indexed_variable(),
> and it is not found in the sub-request. This causes the "not_found" flag to
> be set in the sr->variables var cache for variable "x", but
> because ngx_http_subrequest() shallow copies r->variables from parent
> request to sub-request, the not_found flag change affects the main
> request's r->variables too.
> 
> - Sub-request completes, main request is allowed to progress and arrives at
> custom module's header filter
> 
> - Custom module again looks up variable "x"
> with ngx_http_get_indexed_variable(), and even though "x" is present in
> r->args and I've confirmed can be found by
> ngx_http_arg(), ngx_http_get_indexed_variable() sees the not_found flag,
> does not refresh the variable cache and returns the poisoned
> ngx_http_variable_value_t.
> 
> There are ways to deal with this in our custom code, but it seems like a
> fundamental problem in the current design of the sub-request mechanism and
> I'm thinking that it may be appropriate to address this in the nginx core
> code e.g. by deep copying r->variables in ngx_http_subrequest(), or by
> somehow tracking when to invalidate the ngx_http_variable_value_t flags and
> refresh the r->variables cache.
> 
> Thoughts?

Variables are expected to be shared between the main request and 
subrequests.  If a variable can have different values in the main 
request and subrequests, consider marking it non-cacheable.  For 
example, the $arg_* variables are defined as follows:

    { ngx_string("arg_"), NULL, ngx_http_variable_argument,
      0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },

This is because request arguments can be changed, and, in 
particular, can be different in a subrequest.

While the approach with shared variables might not be convenient 
in some scenarious, it is certainly is in many of them - for 
example, you don't need to recalculate various map{} results, you 
can freely use variables in SSI includes (the actual use case 
subrequests were created for), and so on.

Given the above, I don't really think we need to change things 
here.  Suggested changes are likely to break more things they will 
fix.

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list