Skip to content

Commit 2e37e64

Browse files
committed
ngx_cache_purge: fix 404 on non-PURGE requests when "if" block is present
When nginx processes an "if" directive inside a location block, it creates an anonymous child location and calls merge_loc_conf to propagate the parent's configuration into it. At that point clcf->handler is already set to ngx_http_cache_purge_access_handler by the parent merge pass. The child merge re-entered the proxy.enable (or fastcgi/scgi/uwsgi) branch, saved ngx_http_cache_purge_access_handler into original_handler, then set clcf->handler to ngx_http_cache_purge_access_handler again. On any non-PURGE request that triggered the "if" block, access_handler called original_handler(r), which called access_handler again, producing a 404 instead of forwarding to the upstream handler. Fix: in each of the four protocol branches in merge_loc_conf, check whether clcf->handler is already our own access handler before recording it as original_handler. If it is, the merge is being called for an anonymous "if" child location; inherit original_handler from the parent conf instead. This preserves the pointer to the real upstream handler (e.g. ngx_http_proxy_handler) across the child merge and ensures that non-PURGE requests entering the "if" branch are forwarded correctly. The bug is present in v3.0.0 and later. v2.x is not affected because it used a different handler installation strategy. Issues: #63
1 parent 6147443 commit 2e37e64

1 file changed

Lines changed: 32 additions & 22 deletions

File tree

ngx_cache_purge_module.c

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,10 +3353,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
33533353
ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi);
33543354

33553355
if (conf->fastcgi.enable) {
3356-
conf->conf = &conf->fastcgi;
3357-
conf->handler = ngx_http_fastcgi_cache_purge_handler;
3358-
conf->original_handler = clcf->handler; /* may be NULL */
3359-
clcf->handler = ngx_http_cache_purge_access_handler;
3356+
conf->conf = &conf->fastcgi;
3357+
conf->handler = ngx_http_fastcgi_cache_purge_handler;
3358+
if (clcf->handler != ngx_http_cache_purge_access_handler) {
3359+
conf->original_handler = clcf->handler;
3360+
clcf->handler = ngx_http_cache_purge_access_handler;
3361+
} else {
3362+
conf->original_handler = prev->original_handler;
3363+
}
33603364
return NGX_CONF_OK;
33613365
}
33623366
# endif
@@ -3365,16 +3369,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
33653369
ngx_http_cache_purge_merge_conf(&conf->proxy, &prev->proxy);
33663370

33673371
if (conf->proxy.enable) {
3368-
/*
3369-
* Install the purge access-handler even when clcf->handler is
3370-
* NULL (i.e. when proxy_cache is configured without proxy_pass).
3371-
* original_handler may legitimately be NULL here; the access
3372-
* handler guards against dereferencing it below.
3373-
*/
3374-
conf->conf = &conf->proxy;
3375-
conf->handler = ngx_http_proxy_cache_purge_handler;
3376-
conf->original_handler = clcf->handler; /* may be NULL */
3377-
clcf->handler = ngx_http_cache_purge_access_handler;
3372+
conf->conf = &conf->proxy;
3373+
conf->handler = ngx_http_proxy_cache_purge_handler;
3374+
if (clcf->handler != ngx_http_cache_purge_access_handler) {
3375+
conf->original_handler = clcf->handler;
3376+
clcf->handler = ngx_http_cache_purge_access_handler;
3377+
} else {
3378+
conf->original_handler = prev->original_handler;
3379+
}
33783380
return NGX_CONF_OK;
33793381
}
33803382
# endif
@@ -3383,10 +3385,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
33833385
ngx_http_cache_purge_merge_conf(&conf->scgi, &prev->scgi);
33843386

33853387
if (conf->scgi.enable) {
3386-
conf->conf = &conf->scgi;
3387-
conf->handler = ngx_http_scgi_cache_purge_handler;
3388-
conf->original_handler = clcf->handler; /* may be NULL */
3389-
clcf->handler = ngx_http_cache_purge_access_handler;
3388+
conf->conf = &conf->scgi;
3389+
conf->handler = ngx_http_scgi_cache_purge_handler;
3390+
if (clcf->handler != ngx_http_cache_purge_access_handler) {
3391+
conf->original_handler = clcf->handler;
3392+
clcf->handler = ngx_http_cache_purge_access_handler;
3393+
} else {
3394+
conf->original_handler = prev->original_handler;
3395+
}
33903396
return NGX_CONF_OK;
33913397
}
33923398
# endif
@@ -3395,10 +3401,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
33953401
ngx_http_cache_purge_merge_conf(&conf->uwsgi, &prev->uwsgi);
33963402

33973403
if (conf->uwsgi.enable) {
3398-
conf->conf = &conf->uwsgi;
3399-
conf->handler = ngx_http_uwsgi_cache_purge_handler;
3400-
conf->original_handler = clcf->handler; /* may be NULL */
3401-
clcf->handler = ngx_http_cache_purge_access_handler;
3404+
conf->conf = &conf->uwsgi;
3405+
conf->handler = ngx_http_uwsgi_cache_purge_handler;
3406+
if (clcf->handler != ngx_http_cache_purge_access_handler) {
3407+
conf->original_handler = clcf->handler;
3408+
clcf->handler = ngx_http_cache_purge_access_handler;
3409+
} else {
3410+
conf->original_handler = prev->original_handler;
3411+
}
34023412
return NGX_CONF_OK;
34033413
}
34043414
# endif

0 commit comments

Comments
 (0)