Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37533399
en ru br
Репозитории ALT
S:1.24.0-alt3
5.1: 1.0.4-alt0.M51.1
4.1: 0.6.29-alt1.M41.2
4.0: 0.5.38-alt0.M40.1
+backports:0.5.33-alt1.M40.1
3.0: 0.1.45-alt1
www.altlinux.org/Changes

Группа :: Система/Серверы
Пакет: nginx

 Главная   Изменения   Спек   Патчи   Исходники   Загрузить   Gear   Bugs and FR  Repocop 

pax_global_header00006660000000000000000000000064115600307730014514gustar00rootroot0000000000000052 comment=af6e0c73c81a79556cdd7153e347edc242a2433e
cache_purge/000075500000000000000000000000001156003077300133235ustar00rootroot00000000000000cache_purge/CHANGES000064400000000000000000000013641156003077300143220ustar00rootroot000000000000002011-05-03 VERSION 1.3
* Fix compatibility with nginx-1.0.1.
Reported by Sergey A. Osokin and Markus Linnala.

2010-08-29
* Fix compatibility with nginx-0.8.0 and versions older than
nginx-0.7.60.

2010-08-11 VERSION 1.2
* Fix various build scenarios with disabled upstream modules.
Reported by Johan Bergstroem.

* Add ability to purge content from SCGI's cache.
Requested by Johan Bergstroem.

2010-06-08 VERSION 1.1
* Fix compatibility with nginx-0.8.40+.

* Add ability to purge content from uWSGI's cache.

2010-01-10 VERSION 1.0
* Initial module release.

2009-11-17
* Fix patch compatibility with nginx-0.8.11+.
Reported by Bing Ran.

2009-08-11
* Initial patch release.
cache_purge/LICENSE000064400000000000000000000026201156003077300143300ustar00rootroot00000000000000Copyright (c) 2009-2011, FRiCKLE <info@frickle.com>
Copyright (c) 2009-2011, Piotr Sikora <piotr.sikora@frickle.com>
All rights reserved.

This project was fully funded by yo.se.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cache_purge/README.md000064400000000000000000000071621156003077300146100ustar00rootroot00000000000000About
=====
`ngx_cache_purge` is `nginx` module which adds ability to purge content from
`FastCGI`, `proxy`, `SCGI` and `uWSGI` caches.


Sponsors
========
Work on the original patch was fully funded by [yo.se](http://yo.se).


Status
======
This module is production-ready and it's compatible with following nginx
releases:

- 0.7.x (tested with 0.7.60 to 0.7.68),
- 0.8.x (tested with 0.8.0 to 0.8.54),
- 0.9.x (tested with 0.9.0 to 0.9.7),
- 1.0.x (tested with 1.0.0 to 1.0.1).


Configuration directives
========================
fastcgi_cache_purge
-------------------
* **syntax**: `fastcgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`

Sets area and key used for purging selected pages from `FastCGI`'s cache.


proxy_cache_purge
-----------------
* **syntax**: `proxy_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`

Sets area and key used for purging selected pages from `proxy`'s cache.


scgi_cache_purge
----------------
* **syntax**: `scgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`

Sets area and key used for purging selected pages from `SCGI`'s cache.


uwsgi_cache_purge
-----------------
* **syntax**: `uwsgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`

Sets area and key used for purging selected pages from `uWSGI`'s cache.


Sample configuration
====================
http {
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;

server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key $uri$is_args$args;
}

location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge tmpcache $1$is_args$args;
}
}
}


Testing
=======
`ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx).

You can test it by running:

`$ prove`


License
=======
Copyright (c) 2009-2011, FRiCKLE <info@frickle.com>
Copyright (c) 2009-2011, Piotr Sikora <piotr.sikora@frickle.com>
All rights reserved.

This project was fully funded by yo.se.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


See also
========
- [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache).
cache_purge/TODO.md000064400000000000000000000015131156003077300144120ustar00rootroot00000000000000Features that sooner or later will be added to `ngx_cache_purge`:

* Add support for alternative in-location cache purges using specified
request method, with following configuration syntax:

location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key $uri$is_args$args;
proxy_cache_purge DELETE from 127.0.0.1;
}

This will allow for purges using:

curl -X DELETE http://example.com/logo.jpg

instead of:

curl http://example.com/purge/logo.jpg


Features that __will not__ be added to `ngx_cache_purge`:

* Support for prefixed purges (`/purge/images/*`).
Reason: Impossible with current cache implementation.

* Support for wildcard/regex purges (`/purge/*.jpg`).
Reason: Impossible with current cache implementation.
cache_purge/config000064400000000000000000000006711156003077300145170ustar00rootroot00000000000000if [ "$HTTP_FASTCGI" = "YES" ]; then
have=NGX_HTTP_FASTCGI . auto/have
fi

if [ "$HTTP_SCGI" = "YES" ]; then
have=NGX_HTTP_SCGI . auto/have
fi

if [ "$HTTP_UWSGI" = "YES" ]; then
have=NGX_HTTP_UWSGI . auto/have
fi

ngx_addon_name=ngx_http_cache_purge_module
HTTP_MODULES="$HTTP_MODULES ngx_http_cache_purge_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_purge_module.c"

have=NGX_CACHE_PURGE_MODULE . auto/have
cache_purge/ngx_cache_purge_module.c000064400000000000000000000545461156003077300201730ustar00rootroot00000000000000/*
* Copyright (c) 2009-2011, FRiCKLE <info@frickle.com>
* Copyright (c) 2009-2011, Piotr Sikora <piotr.sikora@frickle.com>
* All rights reserved.
*
* This project was fully funded by yo.se.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY FRiCKLE PIOTR SIKORA AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FRiCKLE PIOTR
* SIKORA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <nginx.h>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


#if (NGX_HTTP_CACHE)

# if (NGX_HTTP_FASTCGI)
char *ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r);
# endif /* NGX_HTTP_FASTCGI */

# if (NGX_HTTP_PROXY)
char *ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r);
# endif /* NGX_HTTP_PROXY */

# if (NGX_HTTP_SCGI)
char *ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r);
# endif /* NGX_HTTP_SCGI */

# if (NGX_HTTP_UWSGI)
char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r);
# endif /* NGX_HTTP_UWSGI */

ngx_int_t ngx_http_cache_purge_handler(ngx_http_request_t *r,
ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key);

ngx_int_t ngx_http_file_cache_purge(ngx_http_request_t *r,
ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key);

static ngx_command_t ngx_http_cache_purge_module_commands[] = {

# if (NGX_HTTP_FASTCGI)
{ ngx_string("fastcgi_cache_purge"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_http_fastcgi_cache_purge_conf,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
# endif /* NGX_HTTP_FASTCGI */

# if (NGX_HTTP_PROXY)
{ ngx_string("proxy_cache_purge"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_http_proxy_cache_purge_conf,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
# endif /* NGX_HTTP_PROXY */

# if (NGX_HTTP_SCGI)
{ ngx_string("scgi_cache_purge"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_http_scgi_cache_purge_conf,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
# endif /* NGX_HTTP_SCGI */

# if (NGX_HTTP_UWSGI)
{ ngx_string("uwsgi_cache_purge"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_http_uwsgi_cache_purge_conf,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
# endif /* NGX_HTTP_UWSGI */

ngx_null_command
};

static ngx_http_module_t ngx_http_cache_purge_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */

NULL, /* create main configuration */
NULL, /* init main configuration */

NULL, /* create server configuration */
NULL, /* merge server configuration */

NULL, /* create location configuration */
NULL /* merge location configuration */
};

ngx_module_t ngx_http_cache_purge_module = {
NGX_MODULE_V1,
&ngx_http_cache_purge_module_ctx, /* module context */
ngx_http_cache_purge_module_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};

static char ngx_http_cache_purge_success_page_top[] =
"<html>" CRLF
"<head><title>Successful purge</title></head>" CRLF
"<body bgcolor=\"white\">" CRLF
"<center><h1>Successful purge</h1>" CRLF
;

static char ngx_http_cache_purge_success_page_tail[] =
CRLF "</center>" CRLF
"<hr><center>" NGINX_VER "</center>" CRLF
"</body>" CRLF
"</html>" CRLF
;

# if (NGX_HTTP_FASTCGI)
extern ngx_module_t ngx_http_fastcgi_module;

typedef struct {
ngx_http_upstream_conf_t upstream;

ngx_str_t index;

ngx_array_t *flushes;
ngx_array_t *params_len;
ngx_array_t *params;
ngx_array_t *params_source;
ngx_array_t *catch_stderr;

ngx_array_t *fastcgi_lengths;
ngx_array_t *fastcgi_values;

# if defined(nginx_version) && (nginx_version >= 8040)
ngx_hash_t headers_hash;
ngx_uint_t header_params;
# endif /* nginx_version >= 8040 */

ngx_http_complex_value_t cache_key;

# if (NGX_PCRE)
ngx_regex_t *split_regex;
ngx_str_t split_name;
# endif /* NGX_PCRE */
} ngx_http_fastcgi_loc_conf_t;

char *
ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_compile_complex_value_t ccv;
ngx_http_core_loc_conf_t *clcf;
ngx_http_fastcgi_loc_conf_t *flcf;
ngx_str_t *value;

flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module);

/* check for duplicates / collisions */
if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
&& flcf->upstream.cache != NULL)
{
return "is either duplicate or collides with \"fastcgi_cache\"";
}

if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
return "is incompatible with \"fastcgi_pass\"";
}

if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
return "is incompatible with \"fastcgi_store\"";
}

value = cf->args->elts;

/* set fastcgi_cache part */
flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
&ngx_http_fastcgi_module);
if (flcf->upstream.cache == NULL) {
return NGX_CONF_ERROR;
}

/* set fastcgi_cache_key part */
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &flcf->cache_key;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

/* set handler */
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

clcf->handler = ngx_http_fastcgi_cache_purge_handler;

return NGX_CONF_OK;
}

ngx_int_t
ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r)
{
ngx_http_fastcgi_loc_conf_t *flcf;

if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_DELETE))) {
return NGX_HTTP_NOT_ALLOWED;
}

flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

return ngx_http_cache_purge_handler(r, flcf->upstream.cache->data,
&flcf->cache_key);
}
# endif /* NGX_HTTP_FASTCGI */

# if (NGX_HTTP_PROXY)
extern ngx_module_t ngx_http_proxy_module;

typedef struct {
ngx_str_t key_start;
ngx_str_t schema;
ngx_str_t host_header;
ngx_str_t port;
ngx_str_t uri;
} ngx_http_proxy_vars_t;

typedef struct {
ngx_http_upstream_conf_t upstream;

ngx_array_t *flushes;
ngx_array_t *body_set_len;
ngx_array_t *body_set;
ngx_array_t *headers_set_len;
ngx_array_t *headers_set;
ngx_hash_t headers_set_hash;

ngx_array_t *headers_source;
# if defined(nginx_version) && (nginx_version < 8040)
ngx_array_t *headers_names;
# endif /* nginx_version < 8040 */

ngx_array_t *proxy_lengths;
ngx_array_t *proxy_values;

ngx_array_t *redirects;

ngx_str_t body_source;

ngx_str_t method;
ngx_str_t location;
ngx_str_t url;

ngx_http_complex_value_t cache_key;

ngx_http_proxy_vars_t vars;

ngx_flag_t redirect;

ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
} ngx_http_proxy_loc_conf_t;

char *
ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_compile_complex_value_t ccv;
ngx_http_core_loc_conf_t *clcf;
ngx_http_proxy_loc_conf_t *plcf;
ngx_str_t *value;

plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module);

/* check for duplicates / collisions */
if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
&& plcf->upstream.cache != NULL)
{
return "is either duplicate or collides with \"proxy_cache\"";
}

if (plcf->upstream.upstream || plcf->proxy_lengths) {
return "is incompatible with \"proxy_pass\"";
}

if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
return "is incompatible with \"proxy_store\"";
}

value = cf->args->elts;

/* set proxy_cache part */
plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
&ngx_http_proxy_module);
if (plcf->upstream.cache == NULL) {
return NGX_CONF_ERROR;
}

/* set proxy_cache_key part */
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &plcf->cache_key;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

/* set handler */
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

clcf->handler = ngx_http_proxy_cache_purge_handler;

return NGX_CONF_OK;
}

ngx_int_t
ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r)
{
ngx_http_proxy_loc_conf_t *plcf;

if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_DELETE))) {
return NGX_HTTP_NOT_ALLOWED;
}

plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

return ngx_http_cache_purge_handler(r, plcf->upstream.cache->data,
&plcf->cache_key);
}
# endif /* NGX_HTTP_PROXY */

# if (NGX_HTTP_SCGI)
extern ngx_module_t ngx_http_scgi_module;

typedef struct {
ngx_http_upstream_conf_t upstream;

ngx_array_t *flushes;
ngx_array_t *params_len;
ngx_array_t *params;
ngx_array_t *params_source;

ngx_hash_t headers_hash;
ngx_uint_t header_params;

ngx_array_t *scgi_lengths;
ngx_array_t *scgi_values;

ngx_http_complex_value_t cache_key;
} ngx_http_scgi_loc_conf_t;

char *
ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_compile_complex_value_t ccv;
ngx_http_core_loc_conf_t *clcf;
ngx_http_scgi_loc_conf_t *slcf;
ngx_str_t *value;

slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module);

/* check for duplicates / collisions */
if (slcf->upstream.cache != NGX_CONF_UNSET_PTR
&& slcf->upstream.cache != NULL)
{
return "is either duplicate or collides with \"scgi_cache\"";
}

if (slcf->upstream.upstream || slcf->scgi_lengths) {
return "is incompatible with \"scgi_pass\"";
}

if (slcf->upstream.store > 0 || slcf->upstream.store_lengths) {
return "is incompatible with \"scgi_store\"";
}

value = cf->args->elts;

/* set scgi_cache part */
slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
&ngx_http_scgi_module);
if (slcf->upstream.cache == NULL) {
return NGX_CONF_ERROR;
}

/* set scgi_cache_key part */
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &slcf->cache_key;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

/* set handler */
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

clcf->handler = ngx_http_scgi_cache_purge_handler;

return NGX_CONF_OK;
}

ngx_int_t
ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r)
{
ngx_http_scgi_loc_conf_t *slcf;

if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_DELETE))) {
return NGX_HTTP_NOT_ALLOWED;
}

slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

return ngx_http_cache_purge_handler(r, slcf->upstream.cache->data,
&slcf->cache_key);
}
# endif /* NGX_HTTP_SCGI */

# if (NGX_HTTP_UWSGI)
extern ngx_module_t ngx_http_uwsgi_module;

typedef struct {
ngx_http_upstream_conf_t upstream;

ngx_array_t *flushes;
ngx_array_t *params_len;
ngx_array_t *params;
ngx_array_t *params_source;

ngx_hash_t headers_hash;
ngx_uint_t header_params;

ngx_array_t *uwsgi_lengths;
ngx_array_t *uwsgi_values;

ngx_http_complex_value_t cache_key;

ngx_str_t uwsgi_string;

ngx_uint_t modifier1;
ngx_uint_t modifier2;
} ngx_http_uwsgi_loc_conf_t;

char *
ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_compile_complex_value_t ccv;
ngx_http_core_loc_conf_t *clcf;
ngx_http_uwsgi_loc_conf_t *ulcf;
ngx_str_t *value;

ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module);

/* check for duplicates / collisions */
if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR
&& ulcf->upstream.cache != NULL)
{
return "is either duplicate or collides with \"uwsgi_cache\"";
}

if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) {
return "is incompatible with \"uwsgi_pass\"";
}

if (ulcf->upstream.store > 0 || ulcf->upstream.store_lengths) {
return "is incompatible with \"uwsgi_store\"";
}

value = cf->args->elts;

/* set uwsgi_cache part */
ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
&ngx_http_uwsgi_module);
if (ulcf->upstream.cache == NULL) {
return NGX_CONF_ERROR;
}

/* set uwsgi_cache_key part */
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &ulcf->cache_key;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

/* set handler */
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

clcf->handler = ngx_http_uwsgi_cache_purge_handler;

return NGX_CONF_OK;
}

ngx_int_t
ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r)
{
ngx_http_uwsgi_loc_conf_t *ulcf;

if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_DELETE))) {
return NGX_HTTP_NOT_ALLOWED;
}

ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);

return ngx_http_cache_purge_handler(r, ulcf->upstream.cache->data,
&ulcf->cache_key);
}
# endif /* NGX_HTTP_UWSGI */

ngx_int_t
ngx_http_cache_purge_handler(ngx_http_request_t *r,
ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key)
{
ngx_chain_t out;
ngx_buf_t *b;
ngx_str_t *key;
ngx_int_t rc;
size_t len;

rc = ngx_http_file_cache_purge(r, cache, cache_key);

if (rc == NGX_ERROR) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
} else if (rc == NGX_DECLINED) {
return NGX_HTTP_NOT_FOUND;
}

key = r->cache->keys.elts;

len = sizeof(ngx_http_cache_purge_success_page_top) - 1
+ sizeof(ngx_http_cache_purge_success_page_tail) - 1
+ sizeof("<br>Key : ") - 1 + sizeof(CRLF "<br>Path: ") - 1
+ key[0].len + r->cache->file.name.len;

r->headers_out.content_type.len = sizeof("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = len;

if (r->method == NGX_HTTP_HEAD) {
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
}

b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}

out.buf = b;
out.next = NULL;

b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_top,
sizeof(ngx_http_cache_purge_success_page_top) - 1);
b->last = ngx_cpymem(b->last, "<br>Key : ", sizeof("<br>Key : ") - 1);
b->last = ngx_cpymem(b->last, key[0].data, key[0].len);
b->last = ngx_cpymem(b->last, CRLF "<br>Path: ",
sizeof(CRLF "<br>Path: ") - 1);
b->last = ngx_cpymem(b->last, r->cache->file.name.data,
r->cache->file.name.len);
b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_tail,
sizeof(ngx_http_cache_purge_success_page_tail) - 1);
b->last_buf = 1;

rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}

return ngx_http_output_filter(r, &out);
}

ngx_int_t
ngx_http_file_cache_purge(ngx_http_request_t *r, ngx_http_file_cache_t *cache,
ngx_http_complex_value_t *cache_key)
{
ngx_http_cache_t *c;
ngx_str_t *key;
ngx_int_t rc;

rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return NGX_ERROR;
}

c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
if (c == NULL) {
return NGX_ERROR;
}

rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t));
if (rc != NGX_OK) {
return NGX_ERROR;
}

key = ngx_array_push(&c->keys);
if (key == NULL) {
return NGX_ERROR;
}

rc = ngx_http_complex_value(r, cache_key, key);
if (rc != NGX_OK) {
return NGX_ERROR;
}

r->cache = c;
c->body_start = ngx_pagesize;
c->file_cache = cache;
c->file.log = r->connection->log;

ngx_http_file_cache_create_key(r);

rc = ngx_http_file_cache_open(r);
# if defined(nginx_version) \
&& ((nginx_version >= 8001) \
|| ((nginx_version < 8000) && (nginx_version >= 7060)))
if (rc == NGX_HTTP_CACHE_UPDATING || rc == NGX_HTTP_CACHE_STALE) {
# else
if (rc == NGX_HTTP_CACHE_STALE) {
# endif
rc = NGX_OK;
}

if (rc != NGX_OK) {
if (rc == NGX_DECLINED) {
return rc;
} else {
return NGX_ERROR;
}
}

/*
* delete file from disk but *keep* in-memory node,
* because other requests might still point to it.
*/

ngx_shmtx_lock(&cache->shpool->mutex);

if (!c->node->exists) {
/* race between concurrent purges, backoff */
ngx_shmtx_unlock(&cache->shpool->mutex);
return NGX_DECLINED;
}

# if defined(nginx_version) && (nginx_version >= 1000001)
cache->sh->size -= c->node->fs_size;
# else
cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize;
# endif

c->node->exists = 0;
# if defined(nginx_version) \
&& ((nginx_version >= 8001) \
|| ((nginx_version < 8000) && (nginx_version >= 7060)))
c->node->updating = 0;
# endif

ngx_shmtx_unlock(&cache->shpool->mutex);

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache purge: \"%s\"", c->file.name.data);

if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) {
/* entry in error log is enough, don't notice client */
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed", c->file.name.data);
}

/* file deleted from cache */
return NGX_OK;
}

#else /* !NGX_HTTP_CACHE */

static ngx_http_module_t ngx_http_cache_purge_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */

NULL, /* create main configuration */
NULL, /* init main configuration */

NULL, /* create server configuration */
NULL, /* merge server configuration */

NULL, /* create location configuration */
NULL, /* merge location configuration */
};

ngx_module_t ngx_http_cache_purge_module = {
NGX_MODULE_V1,
&ngx_http_cache_purge_module_ctx, /* module context */
NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};

#endif /* NGX_HTTP_CACHE */
cache_purge/t/000075500000000000000000000000001156003077300135665ustar00rootroot00000000000000cache_purge/t/proxy.t000064400000000000000000000050511156003077300151350ustar00rootroot00000000000000# vi:filetype=perl

use lib 'lib';
use Test::Nginx::Socket;

repeat_each(1);

plan tests => repeat_each() * (blocks() * 3 + 3 * 1);

our $http_config = <<'_EOC_';
proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m;
proxy_temp_path /tmp/ngx_cache_purge_temp 1 2;
_EOC_

our $config = <<'_EOC_';
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_cache;
proxy_cache_key $uri$is_args$args;
proxy_cache_valid 3m;
add_header X-Cache-Status $upstream_cache_status;
}

location ~ /purge(/.*) {
proxy_cache_purge test_cache $1$is_args$args;
}

location = /etc/passwd {
root /;
}
_EOC_

worker_connections(128);
no_shuffle();
run_tests();

no_diff();

__DATA__

=== TEST 1: prepare
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd
--- error_code: 200
--- response_headers
Content-Type: text/plain
--- response_body_like: root
--- timeout: 10
--- skip_nginx2: 3: < 0.8.3 or < 0.7.62



=== TEST 2: get from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd
--- error_code: 200
--- response_headers
Content-Type: text/plain
X-Cache-Status: HIT
--- response_body_like: root
--- timeout: 10
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62



=== TEST 3: purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
DELETE /purge/proxy/passwd
--- error_code: 200
--- response_headers
Content-Type: text/html
--- response_body_like: Successful purge
--- timeout: 10
--- skip_nginx2: 3: < 0.8.3 or < 0.7.62



=== TEST 4: purge from empty cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
DELETE /purge/proxy/passwd
--- error_code: 404
--- response_headers
Content-Type: text/html
--- response_body_like: 404 Not Found
--- timeout: 10
--- skip_nginx2: 3: < 0.8.3 or < 0.7.62



=== TEST 5: get from source
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd
--- error_code: 200
--- response_headers
Content-Type: text/plain
X-Cache-Status: MISS
--- response_body_like: root
--- timeout: 10
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62



=== TEST 6: get from cache (again)
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd
--- error_code: 200
--- response_headers
Content-Type: text/plain
X-Cache-Status: HIT
--- response_body_like: root
--- timeout: 10
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin