[PATCH] SSI: ensure context of main request exists for subrequest using SSI

Maxim Dounin mdounin at mdounin.ru
Tue Nov 8 06:51:37 UTC 2022


On Fri, Nov 04, 2022 at 09:00:33AM +0000, Ciel via nginx-devel wrote:

> Hi Maxim,
> Thanks for the quick reply.
> > It looks like an attempt to fix ticket #1263
> > (https://trac.nginx.org/nginx/ticket/1263). I've linked this
> > thread to the ticket. It might be a good idea to add a reference
> > into commit log.
> I encountered this problem building my own website, and spent some hours to
> figure out the problem and patch. I didn't guess this bug have such history.
> Reference will be in the updated patch.
> > In many cases the main request context is not needed. It might be
> > a good idea to create it only when needed, and avoid doing so if
> > it isn't.
> > 
> > Further, in theory, SSI processing of a (in-memory/background)
> > subrequest might happen even before main request is actually seen
> > by the SSI module, so the actual context will be created later.
> > This probably needs to be taken into account.
> As we only use the main context for variables and stub blocks, it seems appreciable
> to have the context created on demand. However, we can't say if the SSI templates
> use these commands until we processed them. So I think this left us merely two 
> options:
> a. create main context for every requests having SSI enabled (previous patch)
> b. check main context existence everywhere we use it
> From my purview, most SSI templates have some variables involved, so just go ahead
> and create context can save many checks, while not introducing much waste of memory.

Certainly there are SSI templates which only use include commands, 
but you are probably right and creating the main request context 
would be easier.  With on-demand creation, even if we'll introduce 
a function to obtain/create main request context, we'll have to 
check for memory allocation errors in all places we use it.

Another option might be to link the first subrequest's context as 
the main one - till the main request context is created (if at 
all).  Especially given that we anyway have to upgrade the main 
request context if the main request is seen after the first 
subrequest.  This will imply an additional check in the body 
filter along with the flag, but a trivial one.

> > This does not look like a good solution to filter out processing
> > of a main request if SSI is not enabled for it. Rather, there
> > should be an explicit flag, so it would be possible to avoid
> > evaluation of complex constructs on each body filter call - there
> > can be a lot of such calls.
> Totally agree, and this can be checked by `ngx_http_ssi_header_filter` in main request,
> to initialize the dummy context if needed. But I wonder shall I add a bit field into 
> `ngx_http_ssi_ctx_t` (as there're already some so no memory cost) or add an
> `ngx_flag_t` (8B on amd64) instead.

The ngx_flag_t type is configuration-specific, and shouldn't be 
used in runtime structures such as SSI contexts.

The general rule for runtime flags is that they are created as 
ngx_uint_t with appropriate comment if there are no other 
bit fields in the structure, for example

    ngx_uint_t                 always;  /* unsigned  always:1 */

and upgraded to proper bit fields as long as there is more than 

Given that ngx_http_ssi_ctx_t already contains bit fields, the new 
flag should be added as a bit field.

> In the issue tracker 6 years ago, you mentioned,
> > It was written when there were no subrequests except subrequests created by the SSI
> > module itself, and assumes in many places that its context always exists in the main
> > request.
> Though I'm not 100% familiar with the process of subrequests, this arise some more
> questions in my mind: If subrequests are processed by the SSI filter (before postpone)
> asynchronously and concurrently, could this introduce some out-of-order execution of
> SSI commands among subrequests, then lead to non-determined result? If this really
> happens, should we move the SSI filter past the postpone filter? Looking forward to
> some enlightenment.

The idea of the postpone filter is to glue all subrequests 
together in the correct order.  Basically, it makes it possible to 
execute SSI subrequests in parallel.

For sure this can be a problem if subrequests are used without 
taking this into account.  For example, if you'll set a variable 
in an SSI include virtual, trying to use it in the main SSI 
document or other included files might easily fail because it is 
not yet set.

To fix this, there is a special parameter of the include SSI 
command, "wait".  Quoting docs 

: wait
: a non-standard parameter that instructs to wait for a request to 
: fully complete before continuing with SSI processing, for example:
: <!--# include virtual="/remote/body.php?argument=value" wait="yes" -->

This makes it possible to add "sequence points" to SSI, resolving 
undefined behaviour due to parallel execution of requests.

Maxim Dounin

More information about the nginx-devel mailing list