@@ -113,6 +113,8 @@ ngx_int_t ngx_http_file_cache_purge(ngx_http_request_t *r);
113
113
114
114
115
115
void ngx_http_cache_purge_all (ngx_http_request_t * r , ngx_http_file_cache_t * cache );
116
+ void ngx_http_cache_purge_partial (ngx_http_request_t * r , ngx_http_file_cache_t * cache );
117
+ ngx_int_t ngx_http_cache_purge_is_partial (ngx_http_request_t * r );
116
118
117
119
char * ngx_http_cache_purge_conf (ngx_conf_t * cf ,
118
120
ngx_http_cache_purge_conf_t * cpcf );
@@ -429,6 +431,14 @@ ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r)
429
431
if (cplcf -> conf -> purge_all ) {
430
432
ngx_http_cache_purge_all (r , cache );
431
433
}
434
+ else {
435
+ if (ngx_http_cache_purge_is_partial (r )) {
436
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
437
+ "http file cache purge with partial enabled" );
438
+
439
+ ngx_http_cache_purge_partial (r , cache );
440
+ }
441
+ }
432
442
433
443
# if (nginx_version >= 8011 )
434
444
r -> main -> count ++ ;
@@ -707,6 +717,14 @@ ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r)
707
717
if (cplcf -> conf -> purge_all ) {
708
718
ngx_http_cache_purge_all (r , cache );
709
719
}
720
+ else {
721
+ if (ngx_http_cache_purge_is_partial (r )) {
722
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
723
+ "http file cache purge with partial enabled" );
724
+
725
+ ngx_http_cache_purge_partial (r , cache );
726
+ }
727
+ }
710
728
711
729
# if (nginx_version >= 8011 )
712
730
r -> main -> count ++ ;
@@ -927,6 +945,14 @@ ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r)
927
945
if (cplcf -> conf -> purge_all ) {
928
946
ngx_http_cache_purge_all (r , cache );
929
947
}
948
+ else {
949
+ if (ngx_http_cache_purge_is_partial (r )) {
950
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
951
+ "http file cache purge with partial enabled" );
952
+
953
+ ngx_http_cache_purge_partial (r , cache );
954
+ }
955
+ }
930
956
931
957
# if (nginx_version >= 8011 )
932
958
r -> main -> count ++ ;
@@ -1170,6 +1196,14 @@ ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r)
1170
1196
if (cplcf -> conf -> purge_all ) {
1171
1197
ngx_http_cache_purge_all (r , cache );
1172
1198
}
1199
+ else {
1200
+ if (ngx_http_cache_purge_is_partial (r )) {
1201
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
1202
+ "http file cache purge with partial enabled" );
1203
+
1204
+ ngx_http_cache_purge_partial (r , cache );
1205
+ }
1206
+ }
1173
1207
1174
1208
# if (nginx_version >= 8011 )
1175
1209
r -> main -> count ++ ;
@@ -1202,6 +1236,59 @@ ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
1202
1236
return NGX_OK ;
1203
1237
}
1204
1238
1239
+
1240
+ static ngx_int_t
1241
+ ngx_http_purge_file_cache_delete_partial_file (ngx_tree_ctx_t * ctx , ngx_str_t * path )
1242
+ {
1243
+ u_char * key_partial ;
1244
+ u_char * key_in_file ;
1245
+ ngx_uint_t len ;
1246
+ ngx_flag_t remove_file = 0 ;
1247
+
1248
+ key_partial = ctx -> data ;
1249
+ len = ngx_strlen (key_partial );
1250
+
1251
+ // if key_partial is empty always match, because is a *
1252
+ if (len == 0 ) {
1253
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , ctx -> log , 0 ,
1254
+ "empty key_partial, forcing deletion" );
1255
+ remove_file = 1 ;
1256
+ }
1257
+ else {
1258
+ ngx_file_t file ;
1259
+
1260
+ file .offset = file .sys_offset = 0 ;
1261
+ file .fd = ngx_open_file (path -> data , NGX_FILE_RDONLY , NGX_FILE_OPEN ,
1262
+ NGX_FILE_DEFAULT_ACCESS );
1263
+
1264
+ // I don't know if it's a good idea to use the ngx_cycle pool for this, but the request is not available here
1265
+ key_in_file = ngx_pcalloc (ngx_cycle -> pool , sizeof (u_char ) * (len + 1 ));
1266
+
1267
+ // KEY: /proxy/passwd
1268
+ // since we don't need the "KEY: " ignore 5 + 1 extra u_char from last intro
1269
+ // Optimization: we don't need to read the full key only the n chars included in key_partial
1270
+ ngx_read_file (& file , key_in_file , sizeof (u_char ) * len ,
1271
+ sizeof (ngx_http_file_cache_header_t ) + sizeof (u_char ) * 6 );
1272
+ ngx_close_file (file .fd );
1273
+
1274
+ ngx_log_debug2 (NGX_LOG_DEBUG_HTTP , ctx -> log , 0 ,
1275
+ "http cache file \"%s\" key read: \"%s\"" , path -> data , key_in_file );
1276
+
1277
+ if (ngx_strncasecmp (key_in_file , key_partial , len ) == 0 ) {
1278
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , ctx -> log , 0 ,
1279
+ "match found, deleting file \"%s\"" , path -> data );
1280
+ remove_file = 1 ;
1281
+ }
1282
+ }
1283
+
1284
+ if (remove_file && ngx_delete_file (path -> data ) == NGX_FILE_ERROR ) {
1285
+ ngx_log_error (NGX_LOG_CRIT , ctx -> log , ngx_errno ,
1286
+ ngx_delete_file_n " \"%s\" failed" , path -> data );
1287
+ }
1288
+
1289
+ return NGX_OK ;
1290
+ }
1291
+
1205
1292
ngx_int_t
1206
1293
ngx_http_cache_purge_access_handler (ngx_http_request_t * r )
1207
1294
{
@@ -1469,15 +1556,13 @@ ngx_http_cache_purge_handler(ngx_http_request_t *r)
1469
1556
# endif
1470
1557
1471
1558
cplcf = ngx_http_get_module_loc_conf (r , ngx_http_cache_purge_module );
1472
- if (cplcf -> conf -> purge_all ) {
1473
- rc = NGX_OK ;
1474
- }
1475
- else {
1559
+ rc = NGX_OK ;
1560
+ if (!cplcf -> conf -> purge_all && !ngx_http_cache_purge_is_partial (r )) {
1476
1561
rc = ngx_http_file_cache_purge (r );
1477
1562
1478
1563
ngx_log_debug2 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
1479
- "http file cache purge: %i, \"%s\"" ,
1480
- rc , r -> cache -> file .name .data );
1564
+ "http file cache purge: %i, \"%s\"" ,
1565
+ rc , r -> cache -> file .name .data );
1481
1566
}
1482
1567
1483
1568
switch (rc ) {
@@ -1578,13 +1663,59 @@ ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache) {
1578
1663
tree .pre_tree_handler = ngx_http_purge_file_cache_noop ;
1579
1664
tree .post_tree_handler = ngx_http_purge_file_cache_noop ;
1580
1665
tree .spec_handler = ngx_http_purge_file_cache_noop ;
1581
- tree .data = cache ;
1666
+ tree .data = NULL ;
1582
1667
tree .alloc = 0 ;
1583
1668
tree .log = ngx_cycle -> log ;
1584
1669
1585
1670
ngx_walk_tree (& tree , & cache -> path -> name );
1586
1671
}
1587
1672
1673
+ void
1674
+ ngx_http_cache_purge_partial (ngx_http_request_t * r , ngx_http_file_cache_t * cache ) {
1675
+ ngx_log_debug (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
1676
+ "purge_partial http in %s" ,
1677
+ cache -> path -> name .data );
1678
+
1679
+ u_char * key_partial ;
1680
+ ngx_str_t * key ;
1681
+ ngx_http_cache_t * c ;
1682
+ ngx_uint_t len ;
1683
+
1684
+ c = r -> cache ;
1685
+ key = c -> keys .elts ;
1686
+ len = key [0 ].len ;
1687
+
1688
+ // Only check the first key
1689
+ key_partial = ngx_pcalloc (r -> pool , sizeof (u_char ) * len );
1690
+ ngx_memcpy (key_partial , key [0 ].data , sizeof (u_char ) * (len - 1 ));
1691
+
1692
+ // Walk the tree and remove all the files matching key_partial
1693
+ ngx_tree_ctx_t tree ;
1694
+ tree .init_handler = NULL ;
1695
+ tree .file_handler = ngx_http_purge_file_cache_delete_partial_file ;
1696
+ tree .pre_tree_handler = ngx_http_purge_file_cache_noop ;
1697
+ tree .post_tree_handler = ngx_http_purge_file_cache_noop ;
1698
+ tree .spec_handler = ngx_http_purge_file_cache_noop ;
1699
+ tree .data = key_partial ;
1700
+ tree .alloc = 0 ;
1701
+ tree .log = ngx_cycle -> log ;
1702
+
1703
+ ngx_walk_tree (& tree , & cache -> path -> name );
1704
+ }
1705
+
1706
+ ngx_int_t
1707
+ ngx_http_cache_purge_is_partial (ngx_http_request_t * r )
1708
+ {
1709
+ ngx_str_t * key ;
1710
+ ngx_http_cache_t * c ;
1711
+
1712
+ c = r -> cache ;
1713
+ key = c -> keys .elts ;
1714
+
1715
+ // Only check the first key
1716
+ return key [0 ].data [key [0 ].len - 1 ] == '*' ;
1717
+ }
1718
+
1588
1719
char *
1589
1720
ngx_http_cache_purge_conf (ngx_conf_t * cf , ngx_http_cache_purge_conf_t * cpcf )
1590
1721
{
0 commit comments