Skip to content

Commit 19348b7

Browse files
authored
Merge pull request #7 from torden/dev/add-new-response-type
cache_purge_response_type directive
2 parents e2ef03b + d109007 commit 19348b7

File tree

3 files changed

+476
-31
lines changed

3 files changed

+476
-31
lines changed

README.md

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

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

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

94105

95106
Partial Keys
@@ -155,6 +166,61 @@ Sample configuration (separate location syntax)
155166
}
156167
}
157168

169+
Sample configuration (Optional)
170+
===============================================
171+
http {
172+
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
173+
174+
cache_purge_response_type text;
175+
176+
server {
177+
178+
cache_purge_response_type json;
179+
180+
location / { //json
181+
proxy_pass http://127.0.0.1:8000;
182+
proxy_cache tmpcache;
183+
proxy_cache_key $uri$is_args$args;
184+
}
185+
186+
location ~ /purge(/.*) { //xml
187+
allow 127.0.0.1;
188+
deny all;
189+
proxy_cache_purge tmpcache $1$is_args$args;
190+
cache_purge_response_type xml;
191+
}
192+
193+
location ~ /purge2(/.*) { // json
194+
allow 127.0.0.1;
195+
deny all;
196+
proxy_cache_purge tmpcache $1$is_args$args;
197+
}
198+
}
199+
200+
server {
201+
202+
location / { //text
203+
proxy_pass http://127.0.0.1:8000;
204+
proxy_cache tmpcache;
205+
proxy_cache_key $uri$is_args$args;
206+
}
207+
208+
location ~ /purge(/.*) { //text
209+
allow 127.0.0.1;
210+
deny all;
211+
proxy_cache_purge tmpcache $1$is_args$args;
212+
}
213+
214+
location ~ /purge2(/.*) { /html/
215+
allow 127.0.0.1;
216+
deny all;
217+
proxy_cache_purge tmpcache $1$is_args$args;
218+
cache_purge_response_type html;
219+
}
220+
}
221+
}
222+
223+
158224

159225
Testing
160226
=======

ngx_cache_purge_module.c

Lines changed: 165 additions & 31 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

@@ -65,6 +89,8 @@ typedef struct {
6589
ngx_http_cache_purge_conf_t *conf;
6690
ngx_http_handler_pt handler;
6791
ngx_http_handler_pt original_handler;
92+
93+
ngx_uint_t resptype; /* response content-type */
6894
} ngx_http_cache_purge_loc_conf_t;
6995

7096
# if (NGX_HTTP_FASTCGI)
@@ -91,6 +117,8 @@ char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf,
91117
ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r);
92118
# endif /* NGX_HTTP_UWSGI */
93119

120+
char *ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf,
121+
ngx_command_t *cmd, void *conf);
94122
static ngx_int_t
95123
ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
96124
static ngx_int_t
@@ -169,6 +197,14 @@ static ngx_command_t ngx_http_cache_purge_module_commands[] = {
169197
},
170198
# endif /* NGX_HTTP_UWSGI */
171199

200+
201+
{ ngx_string("cache_purge_response_type"),
202+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
203+
ngx_http_cache_purge_response_type_conf,
204+
NGX_HTTP_LOC_CONF_OFFSET,
205+
0,
206+
NULL },
207+
172208
ngx_null_command
173209
};
174210

@@ -201,20 +237,6 @@ ngx_module_t ngx_http_cache_purge_module = {
201237
NGX_MODULE_V1_PADDING
202238
};
203239

204-
static char ngx_http_cache_purge_success_page_top[] =
205-
"<html>" CRLF
206-
"<head><title>Successful purge</title></head>" CRLF
207-
"<body bgcolor=\"white\">" CRLF
208-
"<center><h1>Successful purge</h1>" CRLF
209-
;
210-
211-
static char ngx_http_cache_purge_success_page_tail[] =
212-
CRLF "</center>" CRLF
213-
"<hr><center>" NGINX_VER "</center>" CRLF
214-
"</body>" CRLF
215-
"</html>" CRLF
216-
;
217-
218240
# if (NGX_HTTP_FASTCGI)
219241
extern ngx_module_t ngx_http_fastcgi_module;
220242

@@ -1153,6 +1175,7 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
11531175
return NGX_CONF_OK;
11541176
}
11551177

1178+
11561179
ngx_int_t
11571180
ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) {
11581181
ngx_http_file_cache_t *cache;
@@ -1216,6 +1239,55 @@ ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) {
12161239
# endif /* NGX_HTTP_UWSGI */
12171240

12181241

1242+
char *
1243+
ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1244+
{
1245+
ngx_http_cache_purge_loc_conf_t *cplcf;
1246+
ngx_str_t *value;
1247+
1248+
cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module);
1249+
1250+
/* check for duplicates / collisions */
1251+
if (cplcf->resptype != NGX_CONF_UNSET_UINT && cf->cmd_type == NGX_HTTP_LOC_CONF ) {
1252+
return "is duplicate";
1253+
}
1254+
1255+
/* sanity check */
1256+
if (cf->args->nelts < 2) {
1257+
return "is invalid paramter, ex) cache_purge_response_type (html|json|xml|text)";
1258+
}
1259+
1260+
if (cf->args->nelts > 2 ) {
1261+
return "is required only 1 option, ex) cache_purge_response_type (html|json|xml|text)";
1262+
}
1263+
1264+
value = cf->args->elts;
1265+
1266+
if (ngx_strcmp(value[1].data, "html") != 0 && ngx_strcmp(value[1].data, "json") != 0
1267+
&& ngx_strcmp(value[1].data, "xml") != 0 && ngx_strcmp(value[1].data, "text") != 0) {
1268+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1269+
"invalid parameter \"%V\", expected"
1270+
" \"(html|json|xml|text)\" keyword", &value[1]);
1271+
return NGX_CONF_ERROR;
1272+
}
1273+
1274+
if (cf->cmd_type == NGX_HTTP_MODULE) {
1275+
return "(separate server or location syntax) is not allowed here";
1276+
}
1277+
1278+
if (ngx_strcmp(value[1].data, "html") == 0) {
1279+
cplcf->resptype = NGX_REPONSE_TYPE_HTML;
1280+
} else if (ngx_strcmp(value[1].data, "xml") == 0) {
1281+
cplcf->resptype = NGX_REPONSE_TYPE_XML;
1282+
} else if (ngx_strcmp(value[1].data, "json") == 0) {
1283+
cplcf->resptype = NGX_REPONSE_TYPE_JSON;
1284+
} else if (ngx_strcmp(value[1].data, "text") == 0) {
1285+
cplcf->resptype = NGX_REPONSE_TYPE_TEXT;
1286+
}
1287+
1288+
return NGX_CONF_OK;
1289+
}
1290+
12191291
static ngx_int_t
12201292
ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) {
12211293
return NGX_OK;
@@ -1397,16 +1469,82 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r) {
13971469
ngx_str_t *key;
13981470
ngx_int_t rc;
13991471
size_t len;
1472+
1473+
size_t body_len;
1474+
size_t resp_tmpl_len;
1475+
u_char *buf;
1476+
u_char *buf_keydata;
1477+
u_char *p;
1478+
const char *resp_ct;
1479+
size_t resp_ct_size;
1480+
const char *resp_body;
1481+
size_t resp_body_size;
1482+
1483+
ngx_http_cache_purge_loc_conf_t *cplcf;
1484+
cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module);
14001485

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

1403-
len = sizeof(ngx_http_cache_purge_success_page_top) - 1
1404-
+ sizeof(ngx_http_cache_purge_success_page_tail) - 1
1405-
+ sizeof("<br>Key : ") - 1 + sizeof(CRLF "<br>Path: ") - 1
1406-
+ key[0].len + r->cache->file.name.len;
1488+
buf_keydata = ngx_pcalloc(r->pool, key[0].len+1);
1489+
if (buf_keydata == NULL) {
1490+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1491+
}
1492+
1493+
p = ngx_cpymem(buf_keydata, key[0].data, key[0].len);
1494+
if (p == NULL) {
1495+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1496+
}
1497+
1498+
switch(cplcf->resptype) {
1499+
1500+
case NGX_REPONSE_TYPE_JSON:
1501+
resp_ct = ngx_http_cache_purge_content_type_json;
1502+
resp_ct_size = ngx_http_cache_purge_content_type_json_size;
1503+
resp_body = ngx_http_cache_purge_body_templ_json;
1504+
resp_body_size = ngx_http_cache_purge_body_templ_json_size;
1505+
break;
1506+
1507+
case NGX_REPONSE_TYPE_XML:
1508+
resp_ct = ngx_http_cache_purge_content_type_xml;
1509+
resp_ct_size = ngx_http_cache_purge_content_type_xml_size;
1510+
resp_body = ngx_http_cache_purge_body_templ_xml;
1511+
resp_body_size = ngx_http_cache_purge_body_templ_xml_size;
1512+
break;
1513+
1514+
case NGX_REPONSE_TYPE_TEXT:
1515+
resp_ct = ngx_http_cache_purge_content_type_text;
1516+
resp_ct_size = ngx_http_cache_purge_content_type_text_size;
1517+
resp_body = ngx_http_cache_purge_body_templ_text;
1518+
resp_body_size = ngx_http_cache_purge_body_templ_text_size;
1519+
break;
1520+
1521+
default:
1522+
case NGX_REPONSE_TYPE_HTML:
1523+
resp_ct = ngx_http_cache_purge_content_type_html;
1524+
resp_ct_size = ngx_http_cache_purge_content_type_html_size;
1525+
resp_body = ngx_http_cache_purge_body_templ_html;
1526+
resp_body_size = ngx_http_cache_purge_body_templ_html_size;
1527+
break;
1528+
}
1529+
1530+
body_len = resp_body_size - 4 - 1;
1531+
r->headers_out.content_type.len = resp_ct_size - 1;
1532+
r->headers_out.content_type.data = (u_char *) resp_ct;
1533+
1534+
resp_tmpl_len = body_len + key[0].len + r->cache->file.name.len ;
1535+
1536+
buf = ngx_pcalloc(r->pool, resp_tmpl_len);
1537+
if (buf == NULL) {
1538+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1539+
}
1540+
1541+
p = ngx_snprintf(buf, resp_tmpl_len, resp_body , buf_keydata, r->cache->file.name.data);
1542+
if (p == NULL) {
1543+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
1544+
}
1545+
1546+
len = body_len + key[0].len + r->cache->file.name.len;
14071547

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

@@ -1421,27 +1559,20 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r) {
14211559
if (b == NULL) {
14221560
return NGX_HTTP_INTERNAL_SERVER_ERROR;
14231561
}
1562+
14241563

14251564
out.buf = b;
14261565
out.next = NULL;
14271566

1428-
b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_top,
1429-
sizeof(ngx_http_cache_purge_success_page_top) - 1);
1430-
b->last = ngx_cpymem(b->last, "<br>Key : ", sizeof("<br>Key : ") - 1);
1431-
b->last = ngx_cpymem(b->last, key[0].data, key[0].len);
1432-
b->last = ngx_cpymem(b->last, CRLF "<br>Path: ",
1433-
sizeof(CRLF "<br>Path: ") - 1);
1434-
b->last = ngx_cpymem(b->last, r->cache->file.name.data,
1435-
r->cache->file.name.len);
1436-
b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_tail,
1437-
sizeof(ngx_http_cache_purge_success_page_tail) - 1);
1567+
b->last = ngx_cpymem(b->last, buf, resp_tmpl_len);
14381568
b->last_buf = 1;
14391569

14401570
rc = ngx_http_send_header(r);
14411571
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
14421572
return rc;
14431573
}
14441574

1575+
14451576
return ngx_http_output_filter(r, &out);
14461577
}
14471578

@@ -1831,7 +1962,6 @@ ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf,
18311962
conf->purge_all = prev->purge_all;
18321963
conf->access = prev->access;
18331964
conf->access6 = prev->access6;
1834-
18351965
} else {
18361966
conf->enable = 0;
18371967
}
@@ -1870,6 +2000,8 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) {
18702000
conf->uwsgi.enable = NGX_CONF_UNSET;
18712001
# endif /* NGX_HTTP_UWSGI */
18722002

2003+
conf->resptype = NGX_CONF_UNSET_UINT;
2004+
18732005
conf->conf = NGX_CONF_UNSET_PTR;
18742006

18752007
return conf;
@@ -1895,6 +2027,8 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) {
18952027

18962028
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
18972029

2030+
ngx_conf_merge_uint_value(conf->resptype, prev->resptype, NGX_REPONSE_TYPE_HTML);
2031+
18982032
# if (NGX_HTTP_FASTCGI)
18992033
ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi);
19002034

0 commit comments

Comments
 (0)