Skip to content

Commit bb744ca

Browse files
committed
added cache_purge_response_type directive, selecting a response type (html|json|xml|text)
1 parent 331fe43 commit bb744ca

File tree

3 files changed

+479
-33
lines changed

3 files changed

+479
-33
lines changed

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ uwsgi_cache_purge
8989

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

92+
Configuration directives (Optional)
93+
===================================================
94+
95+
cache_purge_response_type
96+
-----------------
97+
* **syntax**: `cache_purge_response_type html|json|xml|text`
98+
* **default**: `html`
99+
* **context**: `http`, `server`, `location`
100+
101+
Sets a response type of purging result.
102+
92103

93104
Sample configuration (same location syntax)
94105
===========================================
@@ -126,6 +137,61 @@ Sample configuration (separate location syntax)
126137
}
127138
}
128139

140+
Sample configuration (Optional)
141+
===============================================
142+
http {
143+
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
144+
145+
cache_purge_response_type text;
146+
147+
server {
148+
149+
cache_purge_response_type json;
150+
151+
location / { //json
152+
proxy_pass http://127.0.0.1:8000;
153+
proxy_cache tmpcache;
154+
proxy_cache_key $uri$is_args$args;
155+
}
156+
157+
location ~ /purge(/.*) { //xml
158+
allow 127.0.0.1;
159+
deny all;
160+
proxy_cache_purge tmpcache $1$is_args$args;
161+
cache_purge_response_type xml;
162+
}
163+
164+
location ~ /purge2(/.*) { // json
165+
allow 127.0.0.1;
166+
deny all;
167+
proxy_cache_purge tmpcache $1$is_args$args;
168+
}
169+
}
170+
171+
server {
172+
173+
location / { //text
174+
proxy_pass http://127.0.0.1:8000;
175+
proxy_cache tmpcache;
176+
proxy_cache_key $uri$is_args$args;
177+
}
178+
179+
location ~ /purge(/.*) { //text
180+
allow 127.0.0.1;
181+
deny all;
182+
proxy_cache_purge tmpcache $1$is_args$args;
183+
}
184+
185+
location ~ /purge2(/.*) { /html/
186+
allow 127.0.0.1;
187+
deny all;
188+
proxy_cache_purge tmpcache $1$is_args$args;
189+
cache_purge_response_type html;
190+
}
191+
}
192+
}
193+
194+
129195

130196
Testing
131197
=======

ngx_cache_purge_module.c

Lines changed: 168 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,30 @@
3737
#error This module cannot be build against an unknown nginx version.
3838
#endif
3939

40+
#define NGX_REPONSE_TYPE_HTML 1
41+
#define NGX_REPONSE_TYPE_XML 2
42+
#define NGX_REPONSE_TYPE_JSON 3
43+
#define NGX_REPONSE_TYPE_TEXT 4
44+
45+
static const char ngx_http_cache_purge_content_type_json[] = "application/json";
46+
static const char ngx_http_cache_purge_content_type_html[] = "text/html";
47+
static const char ngx_http_cache_purge_content_type_xml[] = "text/xml";
48+
static const char ngx_http_cache_purge_content_type_text[] = "text/plain";
49+
50+
static size_t ngx_http_cache_purge_content_type_json_size = sizeof(ngx_http_cache_purge_content_type_json);
51+
static size_t ngx_http_cache_purge_content_type_html_size = sizeof(ngx_http_cache_purge_content_type_html);
52+
static size_t ngx_http_cache_purge_content_type_xml_size = sizeof(ngx_http_cache_purge_content_type_xml);
53+
static size_t ngx_http_cache_purge_content_type_text_size = sizeof(ngx_http_cache_purge_content_type_text);
54+
55+
static const char ngx_http_cache_purge_body_templ_json[] = "{\"Key\": \"%s\",\"Path\": \"%s\"}";
56+
static const char ngx_http_cache_purge_body_templ_html[] = "<html><head><title>Successful purge</title></head><body bgcolor=\"white\"><center><h1>Successful purge</h1><br>Key : %s<br>Path : %s</center></body></html>";
57+
static const char ngx_http_cache_purge_body_templ_xml[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><status><Key><![CDATA[%s]]></Key><Path><![CDATA[%s]]></Path></status>";
58+
static const char ngx_http_cache_purge_body_templ_text[] = "Key:%s\nPath:%s\n";
59+
60+
static size_t ngx_http_cache_purge_body_templ_json_size = sizeof(ngx_http_cache_purge_body_templ_json);
61+
static size_t ngx_http_cache_purge_body_templ_html_size = sizeof(ngx_http_cache_purge_body_templ_html);
62+
static size_t ngx_http_cache_purge_body_templ_xml_size = sizeof(ngx_http_cache_purge_body_templ_xml);
63+
static size_t ngx_http_cache_purge_body_templ_text_size = sizeof(ngx_http_cache_purge_body_templ_text);
4064

4165
#if (NGX_HTTP_CACHE)
4266

@@ -64,6 +88,8 @@ typedef struct {
6488
ngx_http_cache_purge_conf_t *conf;
6589
ngx_http_handler_pt handler;
6690
ngx_http_handler_pt original_handler;
91+
92+
ngx_uint_t resptype; /* response content-type */
6793
} ngx_http_cache_purge_loc_conf_t;
6894

6995
# if (NGX_HTTP_FASTCGI)
@@ -90,6 +116,9 @@ char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf,
90116
ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r);
91117
# endif /* NGX_HTTP_UWSGI */
92118

119+
char *ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf,
120+
ngx_command_t *cmd, void *conf);
121+
93122
ngx_int_t ngx_http_cache_purge_access_handler(ngx_http_request_t *r);
94123
ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6,
95124
struct sockaddr *s);
@@ -150,7 +179,14 @@ static ngx_command_t ngx_http_cache_purge_module_commands[] = {
150179
NULL },
151180
# endif /* NGX_HTTP_UWSGI */
152181

153-
ngx_null_command
182+
{ ngx_string("cache_purge_response_type"),
183+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
184+
ngx_http_cache_purge_response_type_conf,
185+
NGX_HTTP_LOC_CONF_OFFSET,
186+
0,
187+
NULL },
188+
189+
ngx_null_command
154190
};
155191

156192
static ngx_http_module_t ngx_http_cache_purge_module_ctx = {
@@ -182,20 +218,6 @@ ngx_module_t ngx_http_cache_purge_module = {
182218
NGX_MODULE_V1_PADDING
183219
};
184220

185-
static char ngx_http_cache_purge_success_page_top[] =
186-
"<html>" CRLF
187-
"<head><title>Successful purge</title></head>" CRLF
188-
"<body bgcolor=\"white\">" CRLF
189-
"<center><h1>Successful purge</h1>" CRLF
190-
;
191-
192-
static char ngx_http_cache_purge_success_page_tail[] =
193-
CRLF "</center>" CRLF
194-
"<hr><center>" NGINX_VER "</center>" CRLF
195-
"</body>" CRLF
196-
"</html>" CRLF
197-
;
198-
199221
# if (NGX_HTTP_FASTCGI)
200222
extern ngx_module_t ngx_http_fastcgi_module;
201223

@@ -1095,6 +1117,7 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
10951117
return NGX_CONF_OK;
10961118
}
10971119

1120+
10981121
ngx_int_t
10991122
ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r)
11001123
{
@@ -1144,6 +1167,56 @@ ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r)
11441167
}
11451168
# endif /* NGX_HTTP_UWSGI */
11461169

1170+
1171+
char *
1172+
ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1173+
{
1174+
ngx_http_cache_purge_loc_conf_t *cplcf;
1175+
ngx_str_t *value;
1176+
1177+
cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module);
1178+
1179+
/* check for duplicates / collisions */
1180+
if (cplcf->resptype != NGX_CONF_UNSET_UINT && cf->cmd_type == NGX_HTTP_LOC_CONF ) {
1181+
return "is duplicate";
1182+
}
1183+
1184+
/* sanity check */
1185+
if (cf->args->nelts < 2) {
1186+
return "is invalid paramter, ex) cache_purge_response_type (html|json|xml|text)";
1187+
}
1188+
1189+
if (cf->args->nelts > 2 ) {
1190+
return "is required only 1 option, ex) cache_purge_response_type (html|json|xml|text)";
1191+
}
1192+
1193+
value = cf->args->elts;
1194+
1195+
if (ngx_strcmp(value[1].data, "html") != 0 && ngx_strcmp(value[1].data, "json") != 0
1196+
&& ngx_strcmp(value[1].data, "xml") != 0 && ngx_strcmp(value[1].data, "text") != 0) {
1197+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1198+
"invalid parameter \"%V\", expected"
1199+
" \"(html|json|xml|text)\" keyword", &value[1]);
1200+
return NGX_CONF_ERROR;
1201+
}
1202+
1203+
if (cf->cmd_type == NGX_HTTP_MODULE) {
1204+
return "(separate server or location syntax) is not allowed here";
1205+
}
1206+
1207+
if (ngx_strcmp(value[1].data, "html") == 0) {
1208+
cplcf->resptype = NGX_REPONSE_TYPE_HTML;
1209+
} else if (ngx_strcmp(value[1].data, "xml") == 0) {
1210+
cplcf->resptype = NGX_REPONSE_TYPE_XML;
1211+
} else if (ngx_strcmp(value[1].data, "json") == 0) {
1212+
cplcf->resptype = NGX_REPONSE_TYPE_JSON;
1213+
} else if (ngx_strcmp(value[1].data, "text") == 0) {
1214+
cplcf->resptype = NGX_REPONSE_TYPE_TEXT;
1215+
}
1216+
1217+
return NGX_CONF_OK;
1218+
}
1219+
11471220
ngx_int_t
11481221
ngx_http_cache_purge_access_handler(ngx_http_request_t *r)
11491222
{
@@ -1256,16 +1329,82 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r)
12561329
ngx_str_t *key;
12571330
ngx_int_t rc;
12581331
size_t len;
1332+
1333+
size_t body_len;
1334+
size_t resp_tmpl_len;
1335+
u_char *buf;
1336+
u_char *buf_keydata;
1337+
u_char *p;
1338+
const char *resp_ct;
1339+
size_t resp_ct_size;
1340+
const char *resp_body;
1341+
size_t resp_body_size;
1342+
1343+
ngx_http_cache_purge_loc_conf_t *cplcf;
1344+
cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module);
12591345

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

1262-
len = sizeof(ngx_http_cache_purge_success_page_top) - 1
1263-
+ sizeof(ngx_http_cache_purge_success_page_tail) - 1
1264-
+ sizeof("<br>Key : ") - 1 + sizeof(CRLF "<br>Path: ") - 1
1265-
+ key[0].len + r->cache->file.name.len;
1348+
buf_keydata = ngx_pcalloc(r->pool, key[0].len+1);
1349+
if (buf_keydata == NULL) {
1350+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1351+
}
1352+
1353+
p = ngx_cpymem(buf_keydata, key[0].data, key[0].len);
1354+
if (p == NULL) {
1355+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1356+
}
1357+
1358+
switch(cplcf->resptype) {
1359+
1360+
case NGX_REPONSE_TYPE_JSON:
1361+
resp_ct = ngx_http_cache_purge_content_type_json;
1362+
resp_ct_size = ngx_http_cache_purge_content_type_json_size;
1363+
resp_body = ngx_http_cache_purge_body_templ_json;
1364+
resp_body_size = ngx_http_cache_purge_body_templ_json_size;
1365+
break;
1366+
1367+
case NGX_REPONSE_TYPE_XML:
1368+
resp_ct = ngx_http_cache_purge_content_type_xml;
1369+
resp_ct_size = ngx_http_cache_purge_content_type_xml_size;
1370+
resp_body = ngx_http_cache_purge_body_templ_xml;
1371+
resp_body_size = ngx_http_cache_purge_body_templ_xml_size;
1372+
break;
1373+
1374+
case NGX_REPONSE_TYPE_TEXT:
1375+
resp_ct = ngx_http_cache_purge_content_type_text;
1376+
resp_ct_size = ngx_http_cache_purge_content_type_text_size;
1377+
resp_body = ngx_http_cache_purge_body_templ_text;
1378+
resp_body_size = ngx_http_cache_purge_body_templ_text_size;
1379+
break;
1380+
1381+
default:
1382+
case NGX_REPONSE_TYPE_HTML:
1383+
resp_ct = ngx_http_cache_purge_content_type_html;
1384+
resp_ct_size = ngx_http_cache_purge_content_type_html_size;
1385+
resp_body = ngx_http_cache_purge_body_templ_html;
1386+
resp_body_size = ngx_http_cache_purge_body_templ_html_size;
1387+
break;
1388+
}
1389+
1390+
body_len = resp_body_size - 4 - 1;
1391+
r->headers_out.content_type.len = resp_ct_size - 1;
1392+
r->headers_out.content_type.data = (u_char *) resp_ct;
1393+
1394+
resp_tmpl_len = body_len + key[0].len + r->cache->file.name.len ;
1395+
1396+
buf = ngx_pcalloc(r->pool, resp_tmpl_len);
1397+
if (buf == NULL) {
1398+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1399+
}
1400+
1401+
p = ngx_snprintf(buf, resp_tmpl_len, resp_body , buf_keydata, r->cache->file.name.data);
1402+
if (p == NULL) {
1403+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1404+
}
1405+
1406+
len = body_len + key[0].len + r->cache->file.name.len;
12661407

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

@@ -1280,27 +1419,20 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r)
12801419
if (b == NULL) {
12811420
return NGX_HTTP_INTERNAL_SERVER_ERROR;
12821421
}
1422+
12831423

12841424
out.buf = b;
12851425
out.next = NULL;
12861426

1287-
b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_top,
1288-
sizeof(ngx_http_cache_purge_success_page_top) - 1);
1289-
b->last = ngx_cpymem(b->last, "<br>Key : ", sizeof("<br>Key : ") - 1);
1290-
b->last = ngx_cpymem(b->last, key[0].data, key[0].len);
1291-
b->last = ngx_cpymem(b->last, CRLF "<br>Path: ",
1292-
sizeof(CRLF "<br>Path: ") - 1);
1293-
b->last = ngx_cpymem(b->last, r->cache->file.name.data,
1294-
r->cache->file.name.len);
1295-
b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_tail,
1296-
sizeof(ngx_http_cache_purge_success_page_tail) - 1);
1427+
b->last = ngx_cpymem(b->last, buf, resp_tmpl_len);
12971428
b->last_buf = 1;
12981429

12991430
rc = ngx_http_send_header(r);
13001431
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
1301-
return rc;
1432+
return rc;
13021433
}
13031434

1435+
13041436
return ngx_http_output_filter(r, &out);
13051437
}
13061438

@@ -1615,7 +1747,6 @@ ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf,
16151747
conf->method = prev->method;
16161748
conf->access = prev->access;
16171749
conf->access6 = prev->access6;
1618-
16191750
} else {
16201751
conf->enable = 0;
16211752
}
@@ -1655,6 +1786,8 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf)
16551786
conf->uwsgi.enable = NGX_CONF_UNSET;
16561787
# endif /* NGX_HTTP_UWSGI */
16571788

1789+
conf->resptype = NGX_CONF_UNSET_UINT;
1790+
16581791
conf->conf = NGX_CONF_UNSET_PTR;
16591792

16601793
return conf;
@@ -1681,6 +1814,8 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
16811814

16821815
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
16831816

1817+
ngx_conf_merge_uint_value(conf->resptype, prev->resptype, NGX_REPONSE_TYPE_HTML);
1818+
16841819
# if (NGX_HTTP_FASTCGI)
16851820
ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi);
16861821

0 commit comments

Comments
 (0)