├── README.md ├── config └── ngx_cache_viewer_module.c /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | nginx module which adds ability to view cache node info from FastCGI, proxy, SCGI and uWSGI caches. 4 | It inspired by [ngx_cache_purge][] module. 5 | 6 | 7 | Configuration directives (same location syntax) 8 | ===== 9 | 10 | fastcgi_cache_viewer 11 | ------------------- 12 | * **syntax**: `fastcgi_cache_viewer on|off| [from all| [.. ]]` 13 | * **default**: `none` 14 | * **context**: `http`, `server`, `location` 15 | 16 | Allow viewing of selected pages from `FastCGI`'s cache. 17 | 18 | 19 | proxy_cache_viewer 20 | ----------------- 21 | * **syntax**: `proxy_cache_viewer on|off| [from all| [.. ]]` 22 | * **default**: `none` 23 | * **context**: `http`, `server`, `location` 24 | 25 | Allow viewing of selected pages from `proxy`'s cache. 26 | 27 | 28 | scgi_cache_viewer 29 | ---------------- 30 | * **syntax**: `scgi_cache_viewer on|off| [from all| [.. ]]` 31 | * **default**: `none` 32 | * **context**: `http`, `server`, `location` 33 | 34 | Allow viewing of selected pages from `SCGI`'s cache. 35 | 36 | 37 | uwsgi_cache_viewer 38 | ----------------- 39 | * **syntax**: `uwsgi_cache_viewer on|off| [from all| [.. ]]` 40 | * **default**: `none` 41 | * **context**: `http`, `server`, `location` 42 | 43 | Allow viewing of selected pages from `uWSGI`'s cache. 44 | 45 | 46 | Configuration directives (separate location syntax) 47 | =================================================== 48 | fastcgi_cache_viewer 49 | ------------------- 50 | * **syntax**: `fastcgi_cache_viewer zone_name key` 51 | * **default**: `none` 52 | * **context**: `location` 53 | 54 | Sets area and key used for viewing selected pages from `FastCGI`'s cache. 55 | 56 | 57 | proxy_cache_viewer 58 | ----------------- 59 | * **syntax**: `proxy_cache_viewer zone_name key` 60 | * **default**: `none` 61 | * **context**: `location` 62 | 63 | Sets area and key used for viewing selected pages from `proxy`'s cache. 64 | 65 | 66 | scgi_cache_viewer 67 | ---------------- 68 | * **syntax**: `scgi_cache_viewer zone_name key` 69 | * **default**: `none` 70 | * **context**: `location` 71 | 72 | Sets area and key used for viewing selected pages from `SCGI`'s cache. 73 | 74 | 75 | uwsgi_cache_viewer 76 | ----------------- 77 | * **syntax**: `uwsgi_cache_viewer zone_name key` 78 | * **default**: `none` 79 | * **context**: `location` 80 | 81 | Sets area and key used for viewing selected pages from `uWSGI`'s cache. 82 | 83 | 84 | Sample configuration (same location syntax) 85 | =========================================== 86 | http { 87 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m max_size=1g; 88 | 89 | server { 90 | location / { 91 | proxy_pass http://127.0.0.1:8000; 92 | proxy_cache tmpcache; 93 | proxy_cache_key $uri$is_args$args; 94 | proxy_cache_viewer VIEWER from 127.0.0.1; 95 | } 96 | } 97 | } 98 | 99 | 100 | Sample configuration (separate location syntax) 101 | =============================================== 102 | http { 103 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m max_size=1g; 104 | 105 | server { 106 | location / { 107 | proxy_pass http://127.0.0.1:8000; 108 | proxy_cache tmpcache; 109 | proxy_cache_key $uri$is_args$args; 110 | } 111 | 112 | location ~ /viewer(/.*) { 113 | allow 127.0.0.1; 114 | deny all; 115 | proxy_cache_viewer tmpcache $1$is_args$args; 116 | } 117 | } 118 | } 119 | 120 | Sample Output 121 | =============================================== 122 | ```bash 123 | 124 | $ curl http://127.0.0.1:8000/003 -X VIEWER 125 | ################## share memory ################## 126 | name: tmpcache 127 | mem size(Kb): 10240 128 | cache node count: 3 129 | cache path: /tmp/cache 130 | disk blocks: 262144 131 | used disk blocks: 3 132 | disk block size: 4096 133 | inactive time(s): 600 134 | ------------------------------------------- 135 | filename: /tmp/cache/f16f9677cebace31cfe18821d4da093e 136 | valid_sec: 0 137 | count: 1 138 | uses: 3 139 | expire(UTC): 1385640959 140 | body_start: 340 141 | fs_size(block): 1 142 | exists: 1 143 | updating: 0 144 | deleting: 0 145 | 146 | 147 | $ curl http://127.0.0.1:8000/ -X VIEWER 148 | ################## share memory ################## 149 | name: tmpcache 150 | mem size(Kb): 10240 151 | cache node count: 3 152 | cache path: /tmp/cache 153 | disk blocks: 262144 154 | used disk blocks: 3 155 | disk block size: 4096 156 | inactive time(s): 600 157 | ------------------------------------------- 158 | 159 | ``` 160 | 161 | Declaration 162 | ======== 163 | This README template copy from [ngx_cache_purge][] module and make a little modification. 164 | 165 | 166 | See also 167 | ======== 168 | - [ngx_cache_purge][] 169 | 170 | [ngx_cache_purge]: https://github.com/FRiCKLE/ngx_cache_purge 171 | 172 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_cache_viewer_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_cache_viewer_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_viewer_module.c" 4 | -------------------------------------------------------------------------------- /ngx_cache_viewer_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) agile6v 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #if (NGX_HTTP_CACHE) 12 | 13 | typedef struct { 14 | ngx_flag_t enable; 15 | ngx_str_t method; 16 | ngx_array_t *access; /* array of ngx_in_cidr_t */ 17 | ngx_array_t *access6; /* array of ngx_in6_cidr_t */ 18 | } ngx_http_cache_viewer_conf_t; 19 | 20 | typedef struct { 21 | # if (NGX_HTTP_FASTCGI) 22 | ngx_http_cache_viewer_conf_t fastcgi; 23 | # endif /* NGX_HTTP_FASTCGI */ 24 | # if (NGX_HTTP_PROXY) 25 | ngx_http_cache_viewer_conf_t proxy; 26 | # endif /* NGX_HTTP_PROXY */ 27 | # if (NGX_HTTP_SCGI) 28 | ngx_http_cache_viewer_conf_t scgi; 29 | # endif /* NGX_HTTP_SCGI */ 30 | # if (NGX_HTTP_UWSGI) 31 | ngx_http_cache_viewer_conf_t uwsgi; 32 | # endif /* NGX_HTTP_UWSGI */ 33 | 34 | ngx_http_cache_viewer_conf_t *conf; 35 | ngx_http_handler_pt handler; 36 | ngx_http_handler_pt original_handler; 37 | } ngx_http_cache_viewer_loc_conf_t; 38 | 39 | # if (NGX_HTTP_FASTCGI) 40 | char *ngx_http_fastcgi_cache_viewer_conf(ngx_conf_t *cf, 41 | ngx_command_t *cmd, void *conf); 42 | ngx_int_t ngx_http_fastcgi_cache_viewer_handler(ngx_http_request_t *r); 43 | # endif /* NGX_HTTP_FASTCGI */ 44 | 45 | # if (NGX_HTTP_PROXY) 46 | char *ngx_http_proxy_cache_viewer_conf(ngx_conf_t *cf, 47 | ngx_command_t *cmd, void *conf); 48 | ngx_int_t ngx_http_proxy_cache_viewer_handler(ngx_http_request_t *r); 49 | # endif /* NGX_HTTP_PROXY */ 50 | 51 | # if (NGX_HTTP_SCGI) 52 | char *ngx_http_scgi_cache_viewer_conf(ngx_conf_t *cf, 53 | ngx_command_t *cmd, void *conf); 54 | ngx_int_t ngx_http_scgi_cache_viewer_handler(ngx_http_request_t *r); 55 | # endif /* NGX_HTTP_SCGI */ 56 | 57 | # if (NGX_HTTP_UWSGI) 58 | char *ngx_http_uwsgi_cache_viewer_conf(ngx_conf_t *cf, 59 | ngx_command_t *cmd, void *conf); 60 | ngx_int_t ngx_http_uwsgi_cache_viewer_handler(ngx_http_request_t *r); 61 | # endif /* NGX_HTTP_UWSGI */ 62 | 63 | ngx_int_t ngx_http_cache_viewer_access_handler(ngx_http_request_t *r); 64 | ngx_int_t ngx_http_cache_viewer_access(ngx_array_t *a, ngx_array_t *a6, 65 | struct sockaddr *s); 66 | 67 | ngx_int_t ngx_http_cache_viewer_send_response(ngx_http_request_t *r, ngx_uint_t flag); 68 | ngx_int_t ngx_http_cache_viewer_init(ngx_http_request_t *r, 69 | ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); 70 | void ngx_http_cache_viewer_handler(ngx_http_request_t *r); 71 | 72 | ngx_int_t ngx_http_file_cache_viewer(ngx_http_request_t *r); 73 | 74 | char *ngx_http_cache_viewer_conf(ngx_conf_t *cf, 75 | ngx_http_cache_viewer_conf_t *cpcf); 76 | 77 | void *ngx_http_cache_viewer_create_loc_conf(ngx_conf_t *cf); 78 | char *ngx_http_cache_viewer_merge_loc_conf(ngx_conf_t *cf, 79 | void *parent, void *child); 80 | 81 | #if (NGX_DEBUG) 82 | static ngx_uint_t ngx_http_viewer_cache_node_count(ngx_http_file_cache_t *cache); 83 | #endif 84 | 85 | static ngx_int_t ngx_http_viewer_cache_node_info(ngx_http_request_t *r, ngx_chain_t *out); 86 | static ngx_int_t ngx_http_viewer_cache_shm_info(ngx_http_request_t *r, ngx_chain_t *out); 87 | 88 | static ngx_command_t ngx_http_cache_viewer_module_commands[] = { 89 | 90 | # if (NGX_HTTP_FASTCGI) 91 | { ngx_string("fastcgi_cache_viewer"), 92 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 93 | ngx_http_fastcgi_cache_viewer_conf, 94 | NGX_HTTP_LOC_CONF_OFFSET, 95 | 0, 96 | NULL }, 97 | # endif /* NGX_HTTP_FASTCGI */ 98 | 99 | # if (NGX_HTTP_PROXY) 100 | { ngx_string("proxy_cache_viewer"), 101 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 102 | ngx_http_proxy_cache_viewer_conf, 103 | NGX_HTTP_LOC_CONF_OFFSET, 104 | 0, 105 | NULL }, 106 | # endif /* NGX_HTTP_PROXY */ 107 | 108 | # if (NGX_HTTP_SCGI) 109 | { ngx_string("scgi_cache_viewer"), 110 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 111 | ngx_http_scgi_cache_viewer_conf, 112 | NGX_HTTP_LOC_CONF_OFFSET, 113 | 0, 114 | NULL }, 115 | # endif /* NGX_HTTP_SCGI */ 116 | 117 | # if (NGX_HTTP_UWSGI) 118 | { ngx_string("uwsgi_cache_viewer"), 119 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 120 | ngx_http_uwsgi_cache_viewer_conf, 121 | NGX_HTTP_LOC_CONF_OFFSET, 122 | 0, 123 | NULL }, 124 | # endif /* NGX_HTTP_UWSGI */ 125 | 126 | ngx_null_command 127 | }; 128 | 129 | static ngx_http_module_t ngx_http_cache_viewer_module_ctx = { 130 | NULL, /* preconfiguration */ 131 | NULL, /* postconfiguration */ 132 | NULL, /* create main configuration */ 133 | NULL, /* init main configuration */ 134 | NULL, /* create server configuration */ 135 | NULL, /* merge server configuration */ 136 | ngx_http_cache_viewer_create_loc_conf, /* create location configuration */ 137 | ngx_http_cache_viewer_merge_loc_conf /* merge location configuration */ 138 | }; 139 | 140 | ngx_module_t ngx_http_cache_viewer_module = { 141 | NGX_MODULE_V1, 142 | &ngx_http_cache_viewer_module_ctx, /* module context */ 143 | ngx_http_cache_viewer_module_commands, /* module directives */ 144 | NGX_HTTP_MODULE, /* module type */ 145 | NULL, /* init master */ 146 | NULL, /* init module */ 147 | NULL, /* init process */ 148 | NULL, /* init thread */ 149 | NULL, /* exit thread */ 150 | NULL, /* exit process */ 151 | NULL, /* exit master */ 152 | NGX_MODULE_V1_PADDING 153 | }; 154 | 155 | #define NGX_VIEWER_LEN(STR) sizeof(STR) - 1 156 | #define SYMBOL_SEPARATOR "-------------------------------------------" 157 | #define SHM_TITLE_LINE "################## share memory ##################" 158 | #define SHM_NAME_HDR "name: " 159 | #define SHM_MEM_SIZE_HDR "mem size(Kb): " 160 | #define SHM_DISK_BLKS_HDR "disk blocks: " 161 | #define SHM_USED_DISK_BLKS_HDR "used disk blocks: " 162 | #define SHM_DISK_BLK_SIZE_HDR "disk block size: " 163 | #define SHM_NODE_INACTIVE_TIME "inactive time(s): " 164 | #define SHM_PATH_HDR "cache path: " 165 | #define SHM_FILE_COUNT_HDR "cache node count: " 166 | 167 | #define CACHE_NODE_FILENAME "filename: " 168 | #define CACHE_NODE_VALID_SEC "valid_sec: " 169 | #define CACHE_NODE_COUNT "count: " 170 | #define CACHE_NODE_USES "uses: " 171 | #define CACHE_NODE_EXISTS "exists: " 172 | #define CACHE_NODE_UPDATING "updating: " 173 | #define CACHE_NODE_DELETING "deleting: " 174 | #define CACHE_NODE_EXPIRE "expire(UTC): " 175 | #define CACHE_NODE_BODYSTART "body_start: " 176 | #define CACHE_NODE_FS_SIZE "fs_size(block): " 177 | 178 | 179 | # if (NGX_HTTP_FASTCGI) 180 | extern ngx_module_t ngx_http_fastcgi_module; 181 | 182 | typedef struct { 183 | ngx_http_upstream_conf_t upstream; 184 | 185 | ngx_str_t index; 186 | 187 | ngx_array_t *flushes; 188 | ngx_array_t *params_len; 189 | ngx_array_t *params; 190 | ngx_array_t *params_source; 191 | ngx_array_t *catch_stderr; 192 | 193 | ngx_array_t *fastcgi_lengths; 194 | ngx_array_t *fastcgi_values; 195 | 196 | # if defined(nginx_version) && (nginx_version >= 8040) 197 | ngx_hash_t headers_hash; 198 | ngx_uint_t header_params; 199 | # endif /* nginx_version >= 8040 */ 200 | 201 | # if defined(nginx_version) && (nginx_version >= 1001004) 202 | ngx_flag_t keep_conn; 203 | # endif /* nginx_version >= 1001004 */ 204 | 205 | ngx_http_complex_value_t cache_key; 206 | 207 | # if (NGX_PCRE) 208 | ngx_regex_t *split_regex; 209 | ngx_str_t split_name; 210 | # endif /* NGX_PCRE */ 211 | } ngx_http_fastcgi_loc_conf_t; 212 | 213 | char * 214 | ngx_http_fastcgi_cache_viewer_conf(ngx_conf_t *cf, ngx_command_t *cmd, 215 | void *conf) 216 | { 217 | ngx_http_compile_complex_value_t ccv; 218 | ngx_http_cache_viewer_loc_conf_t *cplcf; 219 | ngx_http_core_loc_conf_t *clcf; 220 | ngx_http_fastcgi_loc_conf_t *flcf; 221 | ngx_str_t *value; 222 | 223 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_viewer_module); 224 | 225 | /* check for duplicates / collisions */ 226 | if (cplcf->fastcgi.enable != NGX_CONF_UNSET) { 227 | return "is duplicate"; 228 | } 229 | 230 | if (cf->args->nelts != 3) { 231 | return ngx_http_cache_viewer_conf(cf, &cplcf->fastcgi); 232 | } 233 | 234 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 235 | return "(separate location syntax) is not allowed here"; 236 | } 237 | 238 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); 239 | 240 | if (flcf->upstream.cache != NGX_CONF_UNSET_PTR 241 | && flcf->upstream.cache != NULL) 242 | { 243 | return "is incompatible with \"fastcgi_cache\""; 244 | } 245 | 246 | if (flcf->upstream.upstream || flcf->fastcgi_lengths) { 247 | return "is incompatible with \"fastcgi_pass\""; 248 | } 249 | 250 | if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) { 251 | return "is incompatible with \"fastcgi_store\""; 252 | } 253 | 254 | value = cf->args->elts; 255 | 256 | /* set fastcgi_cache part */ 257 | flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 258 | &ngx_http_fastcgi_module); 259 | if (flcf->upstream.cache == NULL) { 260 | return NGX_CONF_ERROR; 261 | } 262 | 263 | /* set fastcgi_cache_key part */ 264 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 265 | 266 | ccv.cf = cf; 267 | ccv.value = &value[2]; 268 | ccv.complex_value = &flcf->cache_key; 269 | 270 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 271 | return NGX_CONF_ERROR; 272 | } 273 | 274 | /* set handler */ 275 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 276 | 277 | cplcf->fastcgi.enable = 0; 278 | clcf->handler = ngx_http_fastcgi_cache_viewer_handler; 279 | 280 | return NGX_CONF_OK; 281 | } 282 | 283 | ngx_int_t 284 | ngx_http_fastcgi_cache_viewer_handler(ngx_http_request_t *r) 285 | { 286 | ngx_http_fastcgi_loc_conf_t *flcf; 287 | 288 | flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); 289 | 290 | if (ngx_http_cache_viewer_init(r, flcf->upstream.cache->data, 291 | &flcf->cache_key) 292 | != NGX_OK) 293 | { 294 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 295 | } 296 | 297 | # if defined(nginx_version) && (nginx_version >= 8011) 298 | r->main->count++; 299 | # endif 300 | 301 | ngx_http_cache_viewer_handler(r); 302 | 303 | return NGX_DONE; 304 | } 305 | # endif /* NGX_HTTP_FASTCGI */ 306 | 307 | # if (NGX_HTTP_PROXY) 308 | extern ngx_module_t ngx_http_proxy_module; 309 | 310 | typedef struct { 311 | ngx_str_t key_start; 312 | ngx_str_t schema; 313 | ngx_str_t host_header; 314 | ngx_str_t port; 315 | ngx_str_t uri; 316 | } ngx_http_proxy_vars_t; 317 | 318 | typedef struct { 319 | ngx_http_upstream_conf_t upstream; 320 | 321 | ngx_array_t *flushes; 322 | ngx_array_t *body_set_len; 323 | ngx_array_t *body_set; 324 | ngx_array_t *headers_set_len; 325 | ngx_array_t *headers_set; 326 | ngx_hash_t headers_set_hash; 327 | 328 | ngx_array_t *headers_source; 329 | # if defined(nginx_version) && (nginx_version < 8040) 330 | ngx_array_t *headers_names; 331 | # endif /* nginx_version < 8040 */ 332 | 333 | ngx_array_t *proxy_lengths; 334 | ngx_array_t *proxy_values; 335 | 336 | ngx_array_t *redirects; 337 | # if defined(nginx_version) && (nginx_version >= 1001015) 338 | ngx_array_t *cookie_domains; 339 | ngx_array_t *cookie_paths; 340 | # endif /* nginx_version >= 1001015 */ 341 | 342 | ngx_str_t body_source; 343 | 344 | ngx_str_t method; 345 | ngx_str_t location; 346 | ngx_str_t url; 347 | 348 | ngx_http_complex_value_t cache_key; 349 | 350 | ngx_http_proxy_vars_t vars; 351 | 352 | ngx_flag_t redirect; 353 | 354 | # if defined(nginx_version) && (nginx_version >= 1001004) 355 | ngx_uint_t http_version; 356 | # endif /* nginx_version >= 1001004 */ 357 | 358 | ngx_uint_t headers_hash_max_size; 359 | ngx_uint_t headers_hash_bucket_size; 360 | } ngx_http_proxy_loc_conf_t; 361 | 362 | char * 363 | ngx_http_proxy_cache_viewer_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 364 | { 365 | ngx_http_compile_complex_value_t ccv; 366 | ngx_http_cache_viewer_loc_conf_t *cplcf; 367 | ngx_http_core_loc_conf_t *clcf; 368 | ngx_http_proxy_loc_conf_t *plcf; 369 | ngx_str_t *value; 370 | 371 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_viewer_module); 372 | 373 | /* check for duplicates / collisions */ 374 | if (cplcf->proxy.enable != NGX_CONF_UNSET) { 375 | return "is duplicate"; 376 | } 377 | 378 | if (cf->args->nelts != 3) { 379 | return ngx_http_cache_viewer_conf(cf, &cplcf->proxy); 380 | } 381 | 382 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 383 | return "(separate location syntax) is not allowed here"; 384 | } 385 | 386 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 387 | 388 | if (plcf->upstream.cache != NGX_CONF_UNSET_PTR 389 | && plcf->upstream.cache != NULL) 390 | { 391 | return "is incompatible with \"proxy_cache\""; 392 | } 393 | 394 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 395 | return "is incompatible with \"proxy_pass\""; 396 | } 397 | 398 | if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) { 399 | return "is incompatible with \"proxy_store\""; 400 | } 401 | 402 | value = cf->args->elts; 403 | 404 | /* set proxy_cache part */ 405 | plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 406 | &ngx_http_proxy_module); 407 | if (plcf->upstream.cache == NULL) { 408 | return NGX_CONF_ERROR; 409 | } 410 | 411 | /* set proxy_cache_key part */ 412 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 413 | 414 | ccv.cf = cf; 415 | ccv.value = &value[2]; 416 | ccv.complex_value = &plcf->cache_key; 417 | 418 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 419 | return NGX_CONF_ERROR; 420 | } 421 | 422 | /* set handler */ 423 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 424 | 425 | cplcf->proxy.enable = 0; 426 | clcf->handler = ngx_http_proxy_cache_viewer_handler; 427 | 428 | return NGX_CONF_OK; 429 | } 430 | 431 | ngx_int_t 432 | ngx_http_proxy_cache_viewer_handler(ngx_http_request_t *r) 433 | { 434 | ngx_http_proxy_loc_conf_t *plcf; 435 | 436 | plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 437 | 438 | if (ngx_http_cache_viewer_init(r, plcf->upstream.cache->data, 439 | &plcf->cache_key) 440 | != NGX_OK) 441 | { 442 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 443 | } 444 | 445 | # if defined(nginx_version) && (nginx_version >= 8011) 446 | r->main->count++; 447 | # endif 448 | 449 | ngx_http_cache_viewer_handler(r); 450 | 451 | return NGX_DONE; 452 | } 453 | # endif /* NGX_HTTP_PROXY */ 454 | 455 | # if (NGX_HTTP_SCGI) 456 | extern ngx_module_t ngx_http_scgi_module; 457 | 458 | typedef struct { 459 | ngx_http_upstream_conf_t upstream; 460 | 461 | ngx_array_t *flushes; 462 | ngx_array_t *params_len; 463 | ngx_array_t *params; 464 | ngx_array_t *params_source; 465 | 466 | ngx_hash_t headers_hash; 467 | ngx_uint_t header_params; 468 | 469 | ngx_array_t *scgi_lengths; 470 | ngx_array_t *scgi_values; 471 | 472 | ngx_http_complex_value_t cache_key; 473 | } ngx_http_scgi_loc_conf_t; 474 | 475 | char * 476 | ngx_http_scgi_cache_viewer_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 477 | { 478 | ngx_http_compile_complex_value_t ccv; 479 | ngx_http_cache_viewer_loc_conf_t *cplcf; 480 | ngx_http_core_loc_conf_t *clcf; 481 | ngx_http_scgi_loc_conf_t *slcf; 482 | ngx_str_t *value; 483 | 484 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_viewer_module); 485 | 486 | /* check for duplicates / collisions */ 487 | if (cplcf->scgi.enable != NGX_CONF_UNSET) { 488 | return "is duplicate"; 489 | } 490 | 491 | if (cf->args->nelts != 3) { 492 | return ngx_http_cache_viewer_conf(cf, &cplcf->scgi); 493 | } 494 | 495 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 496 | return "(separate location syntax) is not allowed here"; 497 | } 498 | 499 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 500 | 501 | if (slcf->upstream.cache != NGX_CONF_UNSET_PTR 502 | && slcf->upstream.cache != NULL) 503 | { 504 | return "is incompatible with \"scgi_cache\""; 505 | } 506 | 507 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 508 | return "is incompatible with \"scgi_pass\""; 509 | } 510 | 511 | if (slcf->upstream.store > 0 || slcf->upstream.store_lengths) { 512 | return "is incompatible with \"scgi_store\""; 513 | } 514 | 515 | value = cf->args->elts; 516 | 517 | /* set scgi_cache part */ 518 | slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 519 | &ngx_http_scgi_module); 520 | if (slcf->upstream.cache == NULL) { 521 | return NGX_CONF_ERROR; 522 | } 523 | 524 | /* set scgi_cache_key part */ 525 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 526 | 527 | ccv.cf = cf; 528 | ccv.value = &value[2]; 529 | ccv.complex_value = &slcf->cache_key; 530 | 531 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 532 | return NGX_CONF_ERROR; 533 | } 534 | 535 | /* set handler */ 536 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 537 | 538 | cplcf->scgi.enable = 0; 539 | clcf->handler = ngx_http_scgi_cache_viewer_handler; 540 | 541 | return NGX_CONF_OK; 542 | } 543 | 544 | ngx_int_t 545 | ngx_http_scgi_cache_viewer_handler(ngx_http_request_t *r) 546 | { 547 | ngx_http_scgi_loc_conf_t *slcf; 548 | 549 | slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); 550 | 551 | if (ngx_http_cache_viewer_init(r, slcf->upstream.cache->data, 552 | &slcf->cache_key) 553 | != NGX_OK) 554 | { 555 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 556 | } 557 | 558 | # if defined(nginx_version) && (nginx_version >= 8011) 559 | r->main->count++; 560 | # endif 561 | 562 | ngx_http_cache_viewer_handler(r); 563 | 564 | return NGX_DONE; 565 | } 566 | # endif /* NGX_HTTP_SCGI */ 567 | 568 | # if (NGX_HTTP_UWSGI) 569 | extern ngx_module_t ngx_http_uwsgi_module; 570 | 571 | typedef struct { 572 | ngx_http_upstream_conf_t upstream; 573 | 574 | ngx_array_t *flushes; 575 | ngx_array_t *params_len; 576 | ngx_array_t *params; 577 | ngx_array_t *params_source; 578 | 579 | ngx_hash_t headers_hash; 580 | ngx_uint_t header_params; 581 | 582 | ngx_array_t *uwsgi_lengths; 583 | ngx_array_t *uwsgi_values; 584 | 585 | ngx_http_complex_value_t cache_key; 586 | 587 | ngx_str_t uwsgi_string; 588 | 589 | ngx_uint_t modifier1; 590 | ngx_uint_t modifier2; 591 | } ngx_http_uwsgi_loc_conf_t; 592 | 593 | char * 594 | ngx_http_uwsgi_cache_viewer_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 595 | { 596 | ngx_http_compile_complex_value_t ccv; 597 | ngx_http_cache_viewer_loc_conf_t *cplcf; 598 | ngx_http_core_loc_conf_t *clcf; 599 | ngx_http_uwsgi_loc_conf_t *ulcf; 600 | ngx_str_t *value; 601 | 602 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_viewer_module); 603 | 604 | /* check for duplicates / collisions */ 605 | if (cplcf->uwsgi.enable != NGX_CONF_UNSET) { 606 | return "is duplicate"; 607 | } 608 | 609 | if (cf->args->nelts != 3) { 610 | return ngx_http_cache_viewer_conf(cf, &cplcf->uwsgi); 611 | } 612 | 613 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 614 | return "(separate location syntax) is not allowed here"; 615 | } 616 | 617 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 618 | 619 | if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR 620 | && ulcf->upstream.cache != NULL) 621 | { 622 | return "is incompatible with \"uwsgi_cache\""; 623 | } 624 | 625 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 626 | return "is incompatible with \"uwsgi_pass\""; 627 | } 628 | 629 | if (ulcf->upstream.store > 0 || ulcf->upstream.store_lengths) { 630 | return "is incompatible with \"uwsgi_store\""; 631 | } 632 | 633 | value = cf->args->elts; 634 | 635 | /* set uwsgi_cache part */ 636 | ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 637 | &ngx_http_uwsgi_module); 638 | if (ulcf->upstream.cache == NULL) { 639 | return NGX_CONF_ERROR; 640 | } 641 | 642 | /* set uwsgi_cache_key part */ 643 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 644 | 645 | ccv.cf = cf; 646 | ccv.value = &value[2]; 647 | ccv.complex_value = &ulcf->cache_key; 648 | 649 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 650 | return NGX_CONF_ERROR; 651 | } 652 | 653 | /* set handler */ 654 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 655 | 656 | cplcf->uwsgi.enable = 0; 657 | clcf->handler = ngx_http_uwsgi_cache_viewer_handler; 658 | 659 | return NGX_CONF_OK; 660 | } 661 | 662 | ngx_int_t 663 | ngx_http_uwsgi_cache_viewer_handler(ngx_http_request_t *r) 664 | { 665 | ngx_http_uwsgi_loc_conf_t *ulcf; 666 | 667 | ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); 668 | 669 | if (ngx_http_cache_viewer_init(r, ulcf->upstream.cache->data, 670 | &ulcf->cache_key) 671 | != NGX_OK) 672 | { 673 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 674 | } 675 | 676 | # if defined(nginx_version) && (nginx_version >= 8011) 677 | r->main->count++; 678 | # endif 679 | 680 | ngx_http_cache_viewer_handler(r); 681 | 682 | return NGX_DONE; 683 | } 684 | # endif /* NGX_HTTP_UWSGI */ 685 | 686 | ngx_int_t 687 | ngx_http_cache_viewer_access_handler(ngx_http_request_t *r) 688 | { 689 | ngx_http_cache_viewer_loc_conf_t *cplcf; 690 | 691 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_viewer_module); 692 | 693 | if (r->method_name.len != cplcf->conf->method.len 694 | || (ngx_strncmp(r->method_name.data, cplcf->conf->method.data, 695 | r->method_name.len))) 696 | { 697 | return cplcf->original_handler(r); 698 | } 699 | 700 | if ((cplcf->conf->access || cplcf->conf->access6) 701 | && ngx_http_cache_viewer_access(cplcf->conf->access, 702 | cplcf->conf->access6, 703 | r->connection->sockaddr) != NGX_OK) 704 | { 705 | return NGX_HTTP_FORBIDDEN; 706 | } 707 | 708 | if (cplcf->handler == NULL) { 709 | return NGX_HTTP_NOT_FOUND; 710 | } 711 | 712 | return cplcf->handler(r); 713 | } 714 | 715 | ngx_int_t 716 | ngx_http_cache_viewer_access(ngx_array_t *access, ngx_array_t *access6, 717 | struct sockaddr *s) 718 | { 719 | in_addr_t inaddr; 720 | ngx_in_cidr_t *a; 721 | ngx_uint_t i; 722 | # if (NGX_HAVE_INET6) 723 | struct in6_addr *inaddr6; 724 | ngx_in6_cidr_t *a6; 725 | u_char *p; 726 | ngx_uint_t n; 727 | # endif /* NGX_HAVE_INET6 */ 728 | 729 | switch (s->sa_family) { 730 | case AF_INET: 731 | if (access == NULL) { 732 | return NGX_DECLINED; 733 | } 734 | 735 | inaddr = ((struct sockaddr_in *) s)->sin_addr.s_addr; 736 | 737 | # if (NGX_HAVE_INET6) 738 | ipv4: 739 | # endif /* NGX_HAVE_INET6 */ 740 | 741 | a = access->elts; 742 | for (i = 0; i < access->nelts; i++) { 743 | if ((inaddr & a[i].mask) == a[i].addr) { 744 | return NGX_OK; 745 | } 746 | } 747 | 748 | return NGX_DECLINED; 749 | 750 | # if (NGX_HAVE_INET6) 751 | case AF_INET6: 752 | inaddr6 = &((struct sockaddr_in6 *) s)->sin6_addr; 753 | p = inaddr6->s6_addr; 754 | 755 | if (access && IN6_IS_ADDR_V4MAPPED(inaddr6)) { 756 | inaddr = p[12] << 24; 757 | inaddr += p[13] << 16; 758 | inaddr += p[14] << 8; 759 | inaddr += p[15]; 760 | inaddr = htonl(inaddr); 761 | 762 | goto ipv4; 763 | } 764 | 765 | if (access6 == NULL) { 766 | return NGX_DECLINED; 767 | } 768 | 769 | a6 = access6->elts; 770 | for (i = 0; i < access6->nelts; i++) { 771 | for (n = 0; n < 16; n++) { 772 | if ((p[n] & a6[i].mask.s6_addr[n]) != a6[i].addr.s6_addr[n]) { 773 | goto next; 774 | } 775 | } 776 | 777 | return NGX_OK; 778 | 779 | next: 780 | continue; 781 | } 782 | 783 | return NGX_DECLINED; 784 | # endif /* NGX_HAVE_INET6 */ 785 | } 786 | 787 | return NGX_DECLINED; 788 | } 789 | 790 | #if (NGX_DEBUG) 791 | static ngx_uint_t 792 | ngx_http_viewer_cache_node_count(ngx_http_file_cache_t *cache) 793 | { 794 | ngx_queue_t *q; 795 | ngx_uint_t count; 796 | ngx_http_file_cache_node_t *fcn; 797 | 798 | count = 0; 799 | 800 | ngx_shmtx_lock(&cache->shpool->mutex); 801 | 802 | for (q = ngx_queue_last(&cache->sh->queue); 803 | q != ngx_queue_sentinel(&cache->sh->queue); 804 | q = ngx_queue_prev(q)) 805 | { 806 | fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); 807 | 808 | ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 809 | "http viewer file cache: #%d %d %02xd%02xd%02xd%02xd", 810 | fcn->count, fcn->exists, 811 | fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); 812 | 813 | count++; 814 | } 815 | 816 | ngx_shmtx_unlock(&cache->shpool->mutex); 817 | 818 | return count; 819 | } 820 | #endif 821 | 822 | static ngx_int_t 823 | ngx_http_viewer_cache_shm_info(ngx_http_request_t *r, ngx_chain_t *out) 824 | { 825 | size_t len; 826 | ngx_buf_t *b; 827 | ngx_http_file_cache_t *cache; 828 | ngx_shm_zone_t *shm_zone; 829 | 830 | cache = r->cache->file_cache; 831 | shm_zone = cache->shm_zone; 832 | 833 | len = NGX_VIEWER_LEN(SHM_TITLE_LINE) + NGX_VIEWER_LEN(CRLF) + 834 | NGX_VIEWER_LEN(SHM_NAME_HDR) + shm_zone->shm.name.len + NGX_VIEWER_LEN(CRLF) + 835 | NGX_VIEWER_LEN(SHM_MEM_SIZE_HDR) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 836 | NGX_VIEWER_LEN(SHM_DISK_BLKS_HDR) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 837 | NGX_VIEWER_LEN(SHM_USED_DISK_BLKS_HDR) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 838 | NGX_VIEWER_LEN(SHM_DISK_BLK_SIZE_HDR) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 839 | NGX_VIEWER_LEN(SHM_NODE_INACTIVE_TIME) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 840 | #if (NGX_DEBUG) 841 | NGX_VIEWER_LEN(SHM_FILE_COUNT_HDR) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) + 842 | #endif 843 | NGX_VIEWER_LEN(SHM_PATH_HDR) + cache->path->len + NGX_VIEWER_LEN(CRLF); 844 | 845 | b = ngx_create_temp_buf(r->pool, len); 846 | if (b == NULL) { 847 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 848 | } 849 | 850 | // shm title line 851 | b->last = ngx_sprintf(b->last, SHM_TITLE_LINE CRLF); 852 | 853 | // shm name 854 | b->last = ngx_sprintf(b->last, SHM_NAME_HDR "%V" CRLF, &shm_zone->shm.name); 855 | 856 | // shm memory size 857 | b->last = ngx_sprintf(b->last, SHM_MEM_SIZE_HDR "%z" CRLF, (shm_zone->shm.size / 1024)); 858 | 859 | #if (NGX_DEBUG) 860 | // node count 861 | b->last = ngx_sprintf(b->last, SHM_FILE_COUNT_HDR "%ud" CRLF, 862 | ngx_http_viewer_cache_node_count(cache)); 863 | #endif 864 | 865 | // cache path 866 | b->last = ngx_sprintf(b->last, SHM_PATH_HDR "%V" CRLF, &cache->path->name); 867 | 868 | // disk blocks count 869 | b->last = ngx_sprintf(b->last, SHM_DISK_BLKS_HDR "%O" CRLF, cache->max_size); 870 | 871 | // used disk blocks 872 | ngx_shmtx_lock(&cache->shpool->mutex); 873 | b->last = ngx_sprintf(b->last, SHM_USED_DISK_BLKS_HDR "%O" CRLF, cache->sh->size); 874 | ngx_shmtx_unlock(&cache->shpool->mutex); 875 | 876 | // disk block size 877 | b->last = ngx_sprintf(b->last, SHM_DISK_BLK_SIZE_HDR "%z" CRLF, cache->bsize); 878 | 879 | // node inactive time 880 | b->last = ngx_sprintf(b->last, SHM_NODE_INACTIVE_TIME "%T" CRLF, cache->inactive); 881 | 882 | b->last = ngx_sprintf(b->last, SYMBOL_SEPARATOR CRLF); 883 | 884 | out->buf = b; 885 | out->next = NULL; 886 | 887 | return NGX_OK; 888 | } 889 | 890 | static ngx_int_t 891 | ngx_http_viewer_cache_node_info(ngx_http_request_t *r, ngx_chain_t *out) 892 | { 893 | ngx_http_file_cache_t *cache; 894 | ngx_http_cache_t *c; 895 | ngx_uint_t exists; 896 | size_t len; 897 | ngx_buf_t *b; 898 | 899 | len = 0; 900 | c = r->cache; 901 | cache = c->file_cache; 902 | 903 | if (c->node) { 904 | 905 | ngx_shmtx_lock(&cache->shpool->mutex); 906 | exists = c->node->exists; 907 | ngx_shmtx_unlock(&cache->shpool->mutex); 908 | 909 | if (exists) { 910 | len = NGX_VIEWER_LEN(CACHE_NODE_FILENAME) + c->file.name.len + NGX_VIEWER_LEN(CRLF); 911 | } 912 | 913 | len += NGX_VIEWER_LEN(CACHE_NODE_VALID_SEC) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 914 | + NGX_VIEWER_LEN(CACHE_NODE_COUNT) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 915 | + NGX_VIEWER_LEN(CACHE_NODE_USES) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 916 | + NGX_VIEWER_LEN(CACHE_NODE_EXPIRE) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 917 | + NGX_VIEWER_LEN(CACHE_NODE_BODYSTART) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 918 | + NGX_VIEWER_LEN(CACHE_NODE_FS_SIZE) + NGX_OFF_T_LEN + NGX_VIEWER_LEN(CRLF) 919 | + NGX_VIEWER_LEN(CACHE_NODE_EXISTS) + 1 + NGX_VIEWER_LEN(CRLF) 920 | + NGX_VIEWER_LEN(CACHE_NODE_UPDATING) + 1 + NGX_VIEWER_LEN(CRLF) 921 | + NGX_VIEWER_LEN(CACHE_NODE_DELETING) + 1 + NGX_VIEWER_LEN(CRLF); 922 | 923 | } else { 924 | return NGX_HTTP_NOT_FOUND; 925 | } 926 | 927 | b = ngx_create_temp_buf(r->pool, len); 928 | if (b == NULL) { 929 | return NGX_ERROR; 930 | } 931 | 932 | if (exists) { 933 | // cache filename 934 | b->last = ngx_sprintf(b->last, CACHE_NODE_FILENAME "%V" CRLF, &c->file.name); 935 | } 936 | 937 | ngx_shmtx_lock(&cache->shpool->mutex); 938 | 939 | // cache valid second 940 | b->last = ngx_sprintf(b->last, CACHE_NODE_VALID_SEC "%T" CRLF, c->node->valid_sec); 941 | 942 | // cache count 943 | b->last = ngx_sprintf(b->last, CACHE_NODE_COUNT "%ui" CRLF, c->node->count); 944 | 945 | // cache uses 946 | b->last = ngx_sprintf(b->last, CACHE_NODE_USES "%ui" CRLF, c->node->uses); 947 | 948 | // cache expire 949 | b->last = ngx_sprintf(b->last, CACHE_NODE_EXPIRE "%T" CRLF, c->node->expire); 950 | 951 | if (exists) { 952 | // cache body_start 953 | b->last = ngx_sprintf(b->last, CACHE_NODE_BODYSTART "%z" CRLF, c->node->body_start); 954 | 955 | // cache fs_size 956 | b->last = ngx_sprintf(b->last, CACHE_NODE_FS_SIZE "%O" CRLF, c->node->fs_size); 957 | } 958 | 959 | // cache exists 960 | b->last = ngx_sprintf(b->last, CACHE_NODE_EXISTS "%ui" CRLF, exists); 961 | 962 | // cache updating 963 | b->last = ngx_sprintf(b->last, CACHE_NODE_UPDATING "%ui" CRLF, c->node->updating); 964 | 965 | // cache deleting 966 | b->last = ngx_sprintf(b->last, CACHE_NODE_DELETING "%ui" CRLF, c->node->deleting); 967 | 968 | ngx_shmtx_unlock(&cache->shpool->mutex); 969 | 970 | out->buf = b; 971 | out->next = NULL; 972 | 973 | return NGX_OK; 974 | } 975 | 976 | ngx_int_t 977 | ngx_http_cache_viewer_send_response(ngx_http_request_t *r, ngx_uint_t flag) 978 | { 979 | ngx_chain_t shm_out, node_out; 980 | ngx_int_t rc; 981 | size_t len; 982 | 983 | len = 0; 984 | 985 | if (flag) { 986 | 987 | rc = ngx_http_viewer_cache_node_info(r, &node_out); 988 | if (rc == NGX_ERROR) { 989 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 990 | } 991 | 992 | if (rc == NGX_HTTP_NOT_FOUND) { 993 | return rc; 994 | } 995 | } 996 | 997 | rc = ngx_http_viewer_cache_shm_info(r, &shm_out); 998 | if (rc != NGX_OK) { 999 | return rc; 1000 | } 1001 | 1002 | len = shm_out.buf->last - shm_out.buf->start; 1003 | 1004 | if (flag) { 1005 | len += node_out.buf->last - node_out.buf->start; 1006 | shm_out.next = &node_out; 1007 | node_out.buf->last_buf = 1; 1008 | } else { 1009 | shm_out.buf->last_buf = 1; 1010 | } 1011 | 1012 | if (r->method == NGX_HTTP_HEAD) { 1013 | r->header_only = 1; 1014 | } 1015 | 1016 | r->headers_out.status = NGX_HTTP_OK; 1017 | ngx_str_set(&r->headers_out.content_type, "text/plain"); 1018 | r->headers_out.content_length_n = len; 1019 | 1020 | rc = ngx_http_send_header(r); 1021 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 1022 | return rc; 1023 | } 1024 | 1025 | return ngx_http_output_filter(r, &shm_out); 1026 | } 1027 | 1028 | ngx_int_t 1029 | ngx_http_cache_viewer_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, 1030 | ngx_http_complex_value_t *cache_key) 1031 | { 1032 | ngx_http_cache_t *c; 1033 | ngx_str_t *key; 1034 | ngx_int_t rc; 1035 | 1036 | rc = ngx_http_discard_request_body(r); 1037 | if (rc != NGX_OK) { 1038 | return NGX_ERROR; 1039 | } 1040 | 1041 | c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); 1042 | if (c == NULL) { 1043 | return NGX_ERROR; 1044 | } 1045 | 1046 | rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t)); 1047 | if (rc != NGX_OK) { 1048 | return NGX_ERROR; 1049 | } 1050 | 1051 | key = ngx_array_push(&c->keys); 1052 | if (key == NULL) { 1053 | return NGX_ERROR; 1054 | } 1055 | 1056 | rc = ngx_http_complex_value(r, cache_key, key); 1057 | if (rc != NGX_OK) { 1058 | return NGX_ERROR; 1059 | } 1060 | 1061 | r->cache = c; 1062 | c->body_start = ngx_pagesize; 1063 | c->file_cache = cache; 1064 | c->file.log = r->connection->log; 1065 | 1066 | ngx_http_file_cache_create_key(r); 1067 | 1068 | return NGX_OK; 1069 | } 1070 | 1071 | void 1072 | ngx_http_cache_viewer_handler(ngx_http_request_t *r) 1073 | { 1074 | ngx_int_t rc; 1075 | 1076 | if (r->uri.data[r->uri.len - 1] == '/') { 1077 | ngx_http_finalize_request(r, ngx_http_cache_viewer_send_response(r, 0)); 1078 | return; 1079 | } 1080 | 1081 | # if (NGX_HAVE_FILE_AIO) 1082 | if (r->aio) { 1083 | return; 1084 | } 1085 | # endif 1086 | 1087 | rc = ngx_http_file_cache_viewer(r); 1088 | 1089 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1090 | "http file cache viewer: %i, \"%s\"", 1091 | rc, r->cache->file.name.data); 1092 | 1093 | switch (rc) { 1094 | case NGX_OK: 1095 | r->write_event_handler = ngx_http_request_empty_handler; 1096 | ngx_http_finalize_request(r, ngx_http_cache_viewer_send_response(r, 1)); 1097 | return; 1098 | case NGX_DECLINED: 1099 | ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); 1100 | return; 1101 | # if (NGX_HAVE_FILE_AIO) 1102 | case NGX_AGAIN: 1103 | r->write_event_handler = ngx_http_cache_viewer_handler; 1104 | return; 1105 | # endif 1106 | default: 1107 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1108 | } 1109 | } 1110 | 1111 | ngx_int_t 1112 | ngx_http_file_cache_viewer(ngx_http_request_t *r) 1113 | { 1114 | ngx_http_file_cache_t *cache; 1115 | ngx_http_cache_t *c; 1116 | 1117 | switch (ngx_http_file_cache_open(r)) { 1118 | case NGX_OK: 1119 | case NGX_HTTP_CACHE_STALE: 1120 | # if defined(nginx_version) \ 1121 | && ((nginx_version >= 8001) \ 1122 | || ((nginx_version < 8000) && (nginx_version >= 7060))) 1123 | case NGX_HTTP_CACHE_UPDATING: 1124 | # endif 1125 | break; 1126 | case NGX_DECLINED: 1127 | break; 1128 | # if (NGX_HAVE_FILE_AIO) 1129 | case NGX_AGAIN: 1130 | return NGX_AGAIN; 1131 | # endif 1132 | default: 1133 | return NGX_ERROR; 1134 | } 1135 | 1136 | c = r->cache; 1137 | cache = c->file_cache; 1138 | 1139 | ngx_shmtx_lock(&cache->shpool->mutex); 1140 | 1141 | if (!c->node->exists && c->node->uses == 1) { 1142 | c->min_uses = 1; 1143 | ngx_shmtx_unlock(&cache->shpool->mutex); 1144 | return NGX_DECLINED; 1145 | } 1146 | 1147 | ngx_shmtx_unlock(&cache->shpool->mutex); 1148 | 1149 | return NGX_OK; 1150 | } 1151 | 1152 | char * 1153 | ngx_http_cache_viewer_conf(ngx_conf_t *cf, ngx_http_cache_viewer_conf_t *cpcf) 1154 | { 1155 | ngx_cidr_t cidr; 1156 | ngx_in_cidr_t *access; 1157 | # if (NGX_HAVE_INET6) 1158 | ngx_in6_cidr_t *access6; 1159 | # endif /* NGX_HAVE_INET6 */ 1160 | ngx_str_t *value; 1161 | ngx_int_t rc; 1162 | ngx_uint_t i; 1163 | 1164 | value = cf->args->elts; 1165 | 1166 | if (ngx_strcmp(value[1].data, (u_char *) "off") == 0) { 1167 | cpcf->enable = 0; 1168 | return NGX_CONF_OK; 1169 | 1170 | } else if (ngx_strcmp(value[1].data, (u_char *) "on") == 0) { 1171 | ngx_str_set(&cpcf->method, "VIEWER"); 1172 | 1173 | } else { 1174 | cpcf->method = value[1]; 1175 | } 1176 | 1177 | if (cf->args->nelts < 4) { 1178 | cpcf->enable = 1; 1179 | return NGX_CONF_OK; 1180 | } 1181 | 1182 | /* sanity check */ 1183 | if (ngx_strcmp(value[2].data, (u_char *) "from") != 0) { 1184 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1185 | "invalid parameter \"%V\", expected" 1186 | " \"from\" keyword", &value[2]); 1187 | return NGX_CONF_ERROR; 1188 | } 1189 | 1190 | if (ngx_strcmp(value[3].data, (u_char *) "all") == 0) { 1191 | cpcf->enable = 1; 1192 | return NGX_CONF_OK; 1193 | } 1194 | 1195 | for (i = 3; i < cf->args->nelts; i++) { 1196 | rc = ngx_ptocidr(&value[i], &cidr); 1197 | 1198 | if (rc == NGX_ERROR) { 1199 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1200 | "invalid parameter \"%V\"", &value[i]); 1201 | return NGX_CONF_ERROR; 1202 | } 1203 | 1204 | if (rc == NGX_DONE) { 1205 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1206 | "low address bits of %V are meaningless", 1207 | &value[i]); 1208 | } 1209 | 1210 | switch (cidr.family) { 1211 | case AF_INET: 1212 | if (cpcf->access == NULL) { 1213 | cpcf->access = ngx_array_create(cf->pool, cf->args->nelts - 3, 1214 | sizeof(ngx_in_cidr_t)); 1215 | if (cpcf->access == NULL) { 1216 | return NGX_CONF_ERROR; 1217 | } 1218 | } 1219 | 1220 | access = ngx_array_push(cpcf->access); 1221 | if (access == NULL) { 1222 | return NGX_CONF_ERROR; 1223 | } 1224 | 1225 | access->mask = cidr.u.in.mask; 1226 | access->addr = cidr.u.in.addr; 1227 | 1228 | break; 1229 | 1230 | # if (NGX_HAVE_INET6) 1231 | case AF_INET6: 1232 | if (cpcf->access6 == NULL) { 1233 | cpcf->access6 = ngx_array_create(cf->pool, cf->args->nelts - 3, 1234 | sizeof(ngx_in6_cidr_t)); 1235 | if (cpcf->access6 == NULL) { 1236 | return NGX_CONF_ERROR; 1237 | } 1238 | } 1239 | 1240 | access6 = ngx_array_push(cpcf->access6); 1241 | if (access6 == NULL) { 1242 | return NGX_CONF_ERROR; 1243 | } 1244 | 1245 | access6->mask = cidr.u.in6.mask; 1246 | access6->addr = cidr.u.in6.addr; 1247 | 1248 | break; 1249 | # endif /* NGX_HAVE_INET6 */ 1250 | } 1251 | } 1252 | 1253 | cpcf->enable = 1; 1254 | 1255 | return NGX_CONF_OK; 1256 | } 1257 | 1258 | void 1259 | ngx_http_cache_viewer_merge_conf(ngx_http_cache_viewer_conf_t *conf, 1260 | ngx_http_cache_viewer_conf_t *prev) 1261 | { 1262 | if (conf->enable == NGX_CONF_UNSET) { 1263 | if (prev->enable == 1) { 1264 | conf->enable = prev->enable; 1265 | conf->method = prev->method; 1266 | conf->access = prev->access; 1267 | conf->access6 = prev->access6; 1268 | 1269 | } else { 1270 | conf->enable = 0; 1271 | } 1272 | } 1273 | } 1274 | 1275 | void * 1276 | ngx_http_cache_viewer_create_loc_conf(ngx_conf_t *cf) 1277 | { 1278 | ngx_http_cache_viewer_loc_conf_t *conf; 1279 | 1280 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_viewer_loc_conf_t)); 1281 | if (conf == NULL) { 1282 | return NULL; 1283 | } 1284 | 1285 | /* 1286 | * set by ngx_pcalloc(): 1287 | * 1288 | * conf->*.method = { 0, NULL } 1289 | * conf->*.access = NULL 1290 | * conf->*.access6 = NULL 1291 | */ 1292 | 1293 | # if (NGX_HTTP_FASTCGI) 1294 | conf->fastcgi.enable = NGX_CONF_UNSET; 1295 | # endif /* NGX_HTTP_FASTCGI */ 1296 | # if (NGX_HTTP_PROXY) 1297 | conf->proxy.enable = NGX_CONF_UNSET; 1298 | # endif /* NGX_HTTP_PROXY */ 1299 | # if (NGX_HTTP_SCGI) 1300 | conf->scgi.enable = NGX_CONF_UNSET; 1301 | # endif /* NGX_HTTP_SCGI */ 1302 | # if (NGX_HTTP_UWSGI) 1303 | conf->uwsgi.enable = NGX_CONF_UNSET; 1304 | # endif /* NGX_HTTP_UWSGI */ 1305 | 1306 | conf->conf = NGX_CONF_UNSET_PTR; 1307 | conf->handler = NGX_CONF_UNSET_PTR; 1308 | conf->original_handler = NGX_CONF_UNSET_PTR; 1309 | 1310 | return conf; 1311 | } 1312 | 1313 | char * 1314 | ngx_http_cache_viewer_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 1315 | { 1316 | ngx_http_cache_viewer_loc_conf_t *prev = parent; 1317 | ngx_http_cache_viewer_loc_conf_t *conf = child; 1318 | ngx_http_core_loc_conf_t *clcf; 1319 | # if (NGX_HTTP_FASTCGI) 1320 | ngx_http_fastcgi_loc_conf_t *flcf; 1321 | # endif /* NGX_HTTP_FASTCGI */ 1322 | # if (NGX_HTTP_PROXY) 1323 | ngx_http_proxy_loc_conf_t *plcf; 1324 | # endif /* NGX_HTTP_PROXY */ 1325 | # if (NGX_HTTP_SCGI) 1326 | ngx_http_scgi_loc_conf_t *slcf; 1327 | # endif /* NGX_HTTP_SCGI */ 1328 | # if (NGX_HTTP_UWSGI) 1329 | ngx_http_uwsgi_loc_conf_t *ulcf; 1330 | # endif /* NGX_HTTP_UWSGI */ 1331 | 1332 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 1333 | 1334 | # if (NGX_HTTP_FASTCGI) 1335 | ngx_http_cache_viewer_merge_conf(&conf->fastcgi, &prev->fastcgi); 1336 | 1337 | if (conf->fastcgi.enable && clcf->handler != NULL) { 1338 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); 1339 | 1340 | if (flcf->upstream.upstream || flcf->fastcgi_lengths) { 1341 | conf->conf = &conf->fastcgi; 1342 | conf->handler = flcf->upstream.cache 1343 | ? ngx_http_fastcgi_cache_viewer_handler : NULL; 1344 | conf->original_handler = clcf->handler; 1345 | 1346 | clcf->handler = ngx_http_cache_viewer_access_handler; 1347 | 1348 | return NGX_CONF_OK; 1349 | } 1350 | } 1351 | # endif /* NGX_HTTP_FASTCGI */ 1352 | 1353 | # if (NGX_HTTP_PROXY) 1354 | ngx_http_cache_viewer_merge_conf(&conf->proxy, &prev->proxy); 1355 | 1356 | if (conf->proxy.enable && clcf->handler != NULL) { 1357 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 1358 | 1359 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 1360 | conf->conf = &conf->proxy; 1361 | conf->handler = plcf->upstream.cache 1362 | ? ngx_http_proxy_cache_viewer_handler : NULL; 1363 | conf->original_handler = clcf->handler; 1364 | 1365 | clcf->handler = ngx_http_cache_viewer_access_handler; 1366 | 1367 | return NGX_CONF_OK; 1368 | } 1369 | } 1370 | # endif /* NGX_HTTP_PROXY */ 1371 | 1372 | # if (NGX_HTTP_SCGI) 1373 | ngx_http_cache_viewer_merge_conf(&conf->scgi, &prev->scgi); 1374 | 1375 | if (conf->scgi.enable && clcf->handler != NULL) { 1376 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 1377 | 1378 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 1379 | conf->conf = &conf->scgi; 1380 | conf->handler = slcf->upstream.cache 1381 | ? ngx_http_scgi_cache_viewer_handler : NULL; 1382 | conf->original_handler = clcf->handler; 1383 | clcf->handler = ngx_http_cache_viewer_access_handler; 1384 | 1385 | return NGX_CONF_OK; 1386 | } 1387 | } 1388 | # endif /* NGX_HTTP_SCGI */ 1389 | 1390 | # if (NGX_HTTP_UWSGI) 1391 | ngx_http_cache_viewer_merge_conf(&conf->uwsgi, &prev->uwsgi); 1392 | 1393 | if (conf->uwsgi.enable && clcf->handler != NULL) { 1394 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 1395 | 1396 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 1397 | conf->conf = &conf->uwsgi; 1398 | conf->handler = ulcf->upstream.cache 1399 | ? ngx_http_uwsgi_cache_viewer_handler : NULL; 1400 | conf->original_handler = clcf->handler; 1401 | 1402 | clcf->handler = ngx_http_cache_viewer_access_handler; 1403 | 1404 | return NGX_CONF_OK; 1405 | } 1406 | } 1407 | # endif /* NGX_HTTP_UWSGI */ 1408 | 1409 | ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); 1410 | ngx_conf_merge_ptr_value(conf->handler, prev->handler, NULL); 1411 | ngx_conf_merge_ptr_value(conf->original_handler, prev->original_handler, 1412 | NULL); 1413 | 1414 | return NGX_CONF_OK; 1415 | } 1416 | 1417 | #else /* !NGX_HTTP_CACHE */ 1418 | 1419 | static ngx_http_module_t ngx_http_cache_viewer_module_ctx = { 1420 | NULL, /* preconfiguration */ 1421 | NULL, /* postconfiguration */ 1422 | NULL, /* create main configuration */ 1423 | NULL, /* init main configuration */ 1424 | NULL, /* create server configuration */ 1425 | NULL, /* merge server configuration */ 1426 | NULL, /* create location configuration */ 1427 | NULL, /* merge location configuration */ 1428 | }; 1429 | 1430 | ngx_module_t ngx_http_cache_viewer_module = { 1431 | NGX_MODULE_V1, 1432 | &ngx_http_cache_viewer_module_ctx, /* module context */ 1433 | NULL, /* module directives */ 1434 | NGX_HTTP_MODULE, /* module type */ 1435 | NULL, /* init master */ 1436 | NULL, /* init module */ 1437 | NULL, /* init process */ 1438 | NULL, /* init thread */ 1439 | NULL, /* exit thread */ 1440 | NULL, /* exit process */ 1441 | NULL, /* exit master */ 1442 | NGX_MODULE_V1_PADDING 1443 | }; 1444 | 1445 | #endif /* NGX_HTTP_CACHE */ 1446 | --------------------------------------------------------------------------------