├── .astylerc ├── .format.sh ├── .gitattributes ├── .travis.yml ├── CHANGES ├── LICENSE ├── README.md ├── TODO.md ├── config ├── ngx_cache_purge_module.c └── t ├── proxy1.t ├── proxy1_vars.t ├── proxy2.t ├── proxy2_vars.t ├── proxy3.t ├── proxy4.t └── resptype1.t /.astylerc: -------------------------------------------------------------------------------- 1 | # astylerc 2 | align-pointer=name 3 | align-reference=name 4 | break-after-logical 5 | #indent=spaces=2 6 | max-code-length=120 7 | style=google 8 | suffix=none 9 | 10 | # Indent 11 | indent-preproc-block 12 | 13 | # Padding 14 | pad-header 15 | unpad-paren 16 | 17 | # Formatting: 18 | add-brackets 19 | #convert-tabs 20 | 21 | # Output: 22 | formatted -------------------------------------------------------------------------------- /.format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Search in the script folder 4 | pushd "$(dirname $0)" >/dev/null 5 | CWD="$(pwd -P)" 6 | popd >/dev/null 7 | FILES='ngx_cache_purge_module.c' 8 | 9 | # The file format in accordance with the style defined in .astylerc 10 | astyle -v --options='.astylerc' ${FILES} || (echo 'astyle failed'; exit 1); 11 | 12 | # To correct this, the issuance dos2unix on each file 13 | # sometimes adds in Windows as a string-endins (\r\n). 14 | dos2unix --quiet ${FILES} || (echo 'dos2unix failed'; exit 2); -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.t linguist-language=Text -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | os: linux 3 | dist: trusty 4 | language: c 5 | compiler: 6 | - gcc 7 | - clang 8 | cache: 9 | apt: true 10 | directories: 11 | - download-cache 12 | env: 13 | global: 14 | - JOBS=4 15 | - NGINX_VERSION=1.12.0 16 | - NGINX_PREFIX=/opt/nginx 17 | - OPENSSL_PREFIX=/opt/ssl 18 | - OPENSSL_LIB=$OPENSSL_PREFIX/lib 19 | - OPENSSL_INC=$OPENSSL_PREFIX/include 20 | - OPENSSL_VER=1.0.2k 21 | 22 | before_install: 23 | - sudo apt-get install -qq -y cpanminus 24 | 25 | install: 26 | - if [ ! -d /opt ]; then mkdir /opt; fi 27 | - if [ ! -d download-cache ]; then mkdir download-cache; fi 28 | - if [ ! -f download-cache/nginx-$NGINX_VERSION.tar.gz ]; then wget -O download-cache/nginx-$NGINX_VERSION.tar.gz http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz; fi 29 | - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -O download-cache/openssl-$OPENSSL_VER.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz; fi 30 | - git clone https://github.com/openresty/test-nginx.git 31 | 32 | script: 33 | - cd test-nginx/ && sudo cpanm . && cd .. 34 | - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz 35 | - cd openssl-$OPENSSL_VER/ 36 | - ./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) 37 | - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) 38 | - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) 39 | - cd .. 40 | - tar zxf download-cache/nginx-$NGINX_VERSION.tar.gz 41 | - cd nginx-$NGINX_VERSION/ 42 | - ./configure --prefix=$NGINX_PREFIX --with-debug --add-module=$PWD/.. > build.log 2>&1 || (cat build.log && exit 1) 43 | - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) 44 | - sudo make install > build.log 2>&1 || (cat build.log && exit 1) 45 | - cd .. 46 | - export PATH=$NGINX_PREFIX/sbin:$PATH 47 | # - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH 48 | - nginx -V 49 | - ldd `which nginx` 50 | - prove t 51 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2017-02-21 VERSION 2.4.1 2 | * Fix compatibility with nginx-1.11.6+, Sułowicz Paweł 3 | 4 | 2016-11-20 VERSION 2.4 5 | * Fix compatibility with nginx-1.7.12+. 6 | * explain the purge logic 7 | * feat(purge all): Include option to purge all the cached files 8 | This option can be slow if a lot of content is cached, or if the 9 | storage used for the cache is slow. But you really should be using 10 | RAM as your cache storage. 11 | * feat(partial keys): Support partial keys to purge multiple keys. 12 | Put an '*' at the end of your purge cache URL. 13 | e.g: 14 | proxy_cache_key $scheme$host$uri$is_args$args$cookie_JSESSIONID; 15 | curl -X PURGE https://example.com/pass* 16 | This will remove every cached page whose key cache starting with: 17 | httpsexample.com/pass* 18 | Be careful not passing any value for the values after the $uri, or put 19 | it at the end of your cache key. 20 | * Convert a config file to build a dynamic module 21 | 22 | 2014-12-23 VERSION 2.3 23 | * Fix compatibility with nginx-1.7.9+. 24 | 25 | 2014-12-02 VERSION 2.2 26 | * Fix compatibility with nginx-1.7.8+. 27 | 28 | 2014-05-19 29 | * Fix build on Solaris with SunCC (Solaris Studio). 30 | Reported by Jussi Sallinen. 31 | 32 | 2013-03-19 VERSION 2.1 33 | * When enabled, cache purge will now catch all requests with 34 | PURGE (or specified) method, even if cache isn't configured. 35 | Previously, it would pass such requests to the upstream. 36 | 37 | 2012-12-07 VERSION 2.0 38 | * Add alternative "same location" syntax. 39 | From CloudFlare. 40 | 41 | 2012-07-02 VERSION 1.6 42 | * Fix compatibility with nginx-1.3.2+. 43 | Reported by MagicBear, patch from Ruslan Ermilov. 44 | 45 | 2011-12-20 VERSION 1.5 46 | * Fix on-disk cache size calculation. 47 | Since the initial release, recorded on-disk cache size was 48 | decreased twice for purged content (once during cache purge 49 | and once during subsequent cache update). 50 | This resulted in recorded on-disk cache size being much 51 | smaller than in reality, which could lead to on-disk cache 52 | outgrowing defined "max_size" parameter. 53 | Patch from Pyry Hakulinen. 54 | 55 | 2011-10-05 VERSION 1.4 56 | * Add AIO support. 57 | Requested by Emin Hasanov. 58 | 59 | 2011-05-03 VERSION 1.3 60 | * Fix compatibility with nginx-1.0.1. 61 | Reported by Sergey A. Osokin and Markus Linnala. 62 | 63 | 2010-08-29 64 | * Fix compatibility with nginx-0.8.0 and versions older than 65 | nginx-0.7.60. 66 | 67 | 2010-08-11 VERSION 1.2 68 | * Fix various build scenarios with disabled upstream modules. 69 | Reported by Johan Bergstroem. 70 | 71 | * Add ability to purge content from SCGI's cache. 72 | Requested by Johan Bergstroem. 73 | 74 | 2010-06-08 VERSION 1.1 75 | * Fix compatibility with nginx-0.8.40+. 76 | 77 | * Add ability to purge content from uWSGI's cache. 78 | 79 | 2010-01-10 VERSION 1.0 80 | * Initial module release. 81 | 82 | 2009-11-17 83 | * Fix patch compatibility with nginx-0.8.11+. 84 | Reported by Bing Ran. 85 | 86 | 2009-08-11 87 | * Initial patch release. 88 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2014, FRiCKLE 2 | Copyright (c) 2009-2014, Piotr Sikora 3 | All rights reserved. 4 | 5 | This project was fully funded by yo.se. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | `ngx_cache_purge` is `nginx` module which adds ability to purge content from 4 | `FastCGI`, `proxy`, `SCGI` and `uWSGI` caches. A purge operation removes the 5 | content with the same cache key as the purge request has. 6 | 7 | 8 | Sponsors 9 | ======== 10 | Work on the original patch was fully funded by [yo.se](http://yo.se). 11 | 12 | 13 | Status 14 | ====== 15 | This module is production-ready. 16 | 17 | 18 | Configuration directives (same location syntax) 19 | =============================================== 20 | fastcgi_cache_purge 21 | ------------------- 22 | * **syntax**: `fastcgi_cache_purge on|off| [purge_all] [from all| [.. ]]` 23 | * **default**: `none` 24 | * **context**: `http`, `server`, `location` 25 | 26 | Allow purging of selected pages from `FastCGI`'s cache. 27 | 28 | 29 | proxy_cache_purge 30 | ----------------- 31 | * **syntax**: `proxy_cache_purge on|off| [purge_all] [from all| [.. ]]` 32 | * **default**: `none` 33 | * **context**: `http`, `server`, `location` 34 | 35 | Allow purging of selected pages from `proxy`'s cache. 36 | 37 | 38 | scgi_cache_purge 39 | ---------------- 40 | * **syntax**: `scgi_cache_purge on|off| [purge_all] [from all| [.. ]]` 41 | * **default**: `none` 42 | * **context**: `http`, `server`, `location` 43 | 44 | Allow purging of selected pages from `SCGI`'s cache. 45 | 46 | 47 | uwsgi_cache_purge 48 | ----------------- 49 | * **syntax**: `uwsgi_cache_purge on|off| [purge_all] [from all| [.. ]]` 50 | * **default**: `none` 51 | * **context**: `http`, `server`, `location` 52 | 53 | Allow purging of selected pages from `uWSGI`'s cache. 54 | 55 | 56 | Configuration directives (separate location syntax) 57 | =================================================== 58 | fastcgi_cache_purge 59 | ------------------- 60 | * **syntax**: `fastcgi_cache_purge zone_name key` 61 | * **default**: `none` 62 | * **context**: `location` 63 | 64 | Sets area and key used for purging selected pages from `FastCGI`'s cache. 65 | 66 | 67 | proxy_cache_purge 68 | ----------------- 69 | * **syntax**: `proxy_cache_purge zone_name key` 70 | * **default**: `none` 71 | * **context**: `location` 72 | 73 | Sets area and key used for purging selected pages from `proxy`'s cache. 74 | 75 | 76 | scgi_cache_purge 77 | ---------------- 78 | * **syntax**: `scgi_cache_purge zone_name key` 79 | * **default**: `none` 80 | * **context**: `location` 81 | 82 | Sets area and key used for purging selected pages from `SCGI`'s cache. 83 | 84 | 85 | uwsgi_cache_purge 86 | ----------------- 87 | * **syntax**: `uwsgi_cache_purge zone_name key` 88 | * **default**: `none` 89 | * **context**: `location` 90 | 91 | Sets area and key used for purging selected pages from `uWSGI`'s cache. 92 | 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 | 104 | 105 | 106 | Partial Keys 107 | ============ 108 | Sometimes it's not possible to pass the exact key cache to purge a page. For example; when the content of a cookie or the params are part of the key. 109 | You can specify a partial key adding an asterisk at the end of the URL. 110 | 111 | curl -X PURGE /page* 112 | 113 | The asterisk must be the last character of the key, so you **must** put the $uri variable at the end. 114 | 115 | 116 | 117 | Purging multiple cache entries with the same cache key 118 | ====================================================== 119 | Caching requests that use the "Vary" header may result in multiple cache 120 | entries with the same cache key. For example, when using the request header 121 | "Vary: Accept-Encoding", a separate cache entry (with different file hash) 122 | will be stored for each content encoding (like compressed or uncompressed), 123 | but they will all have the exact same cache key. 124 | 125 | Trying to purge such cached content will fail unless both the "Vary" header 126 | is specified in the purge request, plus all headers as listed in the "Vary" 127 | header, with the exact same values as used when the request was cached. 128 | 129 | To be able to purge *all* pages with the same cache key, specify the key with 130 | a "$" at the end, like this: 131 | 132 | curl -X PURGE /page$ 133 | 134 | This will purge all content with the exact key "/page" from the cache. 135 | 136 | 137 | 138 | Sample configuration (same location syntax) 139 | =========================================== 140 | http { 141 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 142 | 143 | server { 144 | location / { 145 | proxy_pass http://127.0.0.1:8000; 146 | proxy_cache tmpcache; 147 | proxy_cache_key $uri$is_args$args; 148 | proxy_cache_purge PURGE from 127.0.0.1; 149 | } 150 | } 151 | } 152 | 153 | 154 | Sample configuration (same location syntax - purge all cached files) 155 | ==================================================================== 156 | http { 157 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 158 | 159 | server { 160 | location / { 161 | proxy_pass http://127.0.0.1:8000; 162 | proxy_cache tmpcache; 163 | proxy_cache_key $uri$is_args$args; 164 | proxy_cache_purge PURGE purge_all from 127.0.0.1; 165 | } 166 | } 167 | } 168 | 169 | 170 | Sample configuration (separate location syntax) 171 | =============================================== 172 | http { 173 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 174 | 175 | server { 176 | location / { 177 | proxy_pass http://127.0.0.1:8000; 178 | proxy_cache tmpcache; 179 | proxy_cache_key $uri$is_args$args; 180 | } 181 | 182 | location ~ /purge(/.*) { 183 | allow 127.0.0.1; 184 | deny all; 185 | proxy_cache_purge tmpcache $1$is_args$args; 186 | } 187 | } 188 | } 189 | 190 | Sample configuration (Optional) 191 | =============================================== 192 | http { 193 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 194 | 195 | cache_purge_response_type text; 196 | 197 | server { 198 | 199 | cache_purge_response_type json; 200 | 201 | location / { #json 202 | proxy_pass http://127.0.0.1:8000; 203 | proxy_cache tmpcache; 204 | proxy_cache_key $uri$is_args$args; 205 | } 206 | 207 | location ~ /purge(/.*) { #xml 208 | allow 127.0.0.1; 209 | deny all; 210 | proxy_cache_purge tmpcache $1$is_args$args; 211 | cache_purge_response_type xml; 212 | } 213 | 214 | location ~ /purge2(/.*) { # json 215 | allow 127.0.0.1; 216 | deny all; 217 | proxy_cache_purge tmpcache $1$is_args$args; 218 | } 219 | } 220 | 221 | server { 222 | 223 | location / { #text 224 | proxy_pass http://127.0.0.1:8000; 225 | proxy_cache tmpcache; 226 | proxy_cache_key $uri$is_args$args; 227 | } 228 | 229 | location ~ /purge(/.*) { #text 230 | allow 127.0.0.1; 231 | deny all; 232 | proxy_cache_purge tmpcache $1$is_args$args; 233 | } 234 | 235 | location ~ /purge2(/.*) { #html 236 | allow 127.0.0.1; 237 | deny all; 238 | proxy_cache_purge tmpcache $1$is_args$args; 239 | cache_purge_response_type html; 240 | } 241 | } 242 | } 243 | 244 | 245 | 246 | Testing 247 | ======= 248 | `ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx). 249 | 250 | You can test it by running: 251 | 252 | `$ prove` 253 | 254 | 255 | License 256 | ======= 257 | Copyright (c) 2009-2014, FRiCKLE 258 | Copyright (c) 2009-2014, Piotr Sikora 259 | All rights reserved. 260 | 261 | This project was fully funded by yo.se. 262 | 263 | Redistribution and use in source and binary forms, with or without 264 | modification, are permitted provided that the following conditions 265 | are met: 266 | 1. Redistributions of source code must retain the above copyright 267 | notice, this list of conditions and the following disclaimer. 268 | 2. Redistributions in binary form must reproduce the above copyright 269 | notice, this list of conditions and the following disclaimer in the 270 | documentation and/or other materials provided with the distribution. 271 | 272 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 273 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 274 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 275 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 276 | HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 277 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 278 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 279 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 280 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 281 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 282 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 283 | 284 | 285 | See also 286 | ======== 287 | - [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache). 288 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | Features that __will not__ be added to `ngx_cache_purge`: 2 | 3 | * Support for prefixed purges (`/purge/images/*`). 4 | Reason: Impossible with current cache implementation. 5 | 6 | * Support for wildcard/regex purges (`/purge/*.jpg`). 7 | Reason: Impossible with current cache implementation. 8 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | if [ "$HTTP_PROXY" = "YES" ]; then 2 | have=NGX_HTTP_PROXY . auto/have 3 | fi 4 | 5 | if [ "$HTTP_FASTCGI" = "YES" ]; then 6 | have=NGX_HTTP_FASTCGI . auto/have 7 | fi 8 | 9 | if [ "$HTTP_SCGI" = "YES" ]; then 10 | have=NGX_HTTP_SCGI . auto/have 11 | fi 12 | 13 | if [ "$HTTP_UWSGI" = "YES" ]; then 14 | have=NGX_HTTP_UWSGI . auto/have 15 | fi 16 | 17 | ngx_addon_name=ngx_http_cache_purge_module 18 | CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c" 19 | 20 | if [ -n "$ngx_module_link" ]; then 21 | ngx_module_type=HTTP 22 | ngx_module_name="$ngx_addon_name" 23 | ngx_module_srcs="$CACHE_PURGE_SRCS" 24 | 25 | . auto/module 26 | else 27 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" 28 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS" 29 | fi 30 | 31 | have=NGX_CACHE_PURGE_MODULE . auto/have 32 | -------------------------------------------------------------------------------- /ngx_cache_purge_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2014, FRiCKLE 3 | * Copyright (c) 2009-2014, Piotr Sikora 4 | * All rights reserved. 5 | * 6 | * This project was fully funded by yo.se. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #ifndef nginx_version 37 | #error This module cannot be build against an unknown nginx version. 38 | #endif 39 | 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\"}"; 56 | static const char ngx_http_cache_purge_body_templ_html[] = "Successful purge

Successful purge

Key : %s

"; 57 | static const char ngx_http_cache_purge_body_templ_xml[] = ""; 58 | static const char ngx_http_cache_purge_body_templ_text[] = "Key:%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); 64 | 65 | #if (NGX_HTTP_CACHE) 66 | 67 | typedef struct { 68 | ngx_flag_t enable; 69 | ngx_str_t method; 70 | ngx_flag_t purge_all; 71 | ngx_array_t *access; /* array of ngx_in_cidr_t */ 72 | ngx_array_t *access6; /* array of ngx_in6_cidr_t */ 73 | } ngx_http_cache_purge_conf_t; 74 | 75 | typedef struct { 76 | # if (NGX_HTTP_FASTCGI) 77 | ngx_http_cache_purge_conf_t fastcgi; 78 | # endif /* NGX_HTTP_FASTCGI */ 79 | # if (NGX_HTTP_PROXY) 80 | ngx_http_cache_purge_conf_t proxy; 81 | # endif /* NGX_HTTP_PROXY */ 82 | # if (NGX_HTTP_SCGI) 83 | ngx_http_cache_purge_conf_t scgi; 84 | # endif /* NGX_HTTP_SCGI */ 85 | # if (NGX_HTTP_UWSGI) 86 | ngx_http_cache_purge_conf_t uwsgi; 87 | # endif /* NGX_HTTP_UWSGI */ 88 | 89 | ngx_http_cache_purge_conf_t *conf; 90 | ngx_http_handler_pt handler; 91 | ngx_http_handler_pt original_handler; 92 | 93 | ngx_uint_t resptype; /* response content-type */ 94 | } ngx_http_cache_purge_loc_conf_t; 95 | 96 | # if (NGX_HTTP_FASTCGI) 97 | char *ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, 98 | ngx_command_t *cmd, void *conf); 99 | ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r); 100 | # endif /* NGX_HTTP_FASTCGI */ 101 | 102 | # if (NGX_HTTP_PROXY) 103 | char *ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, 104 | ngx_command_t *cmd, void *conf); 105 | ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r); 106 | # endif /* NGX_HTTP_PROXY */ 107 | 108 | # if (NGX_HTTP_SCGI) 109 | char *ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, 110 | ngx_command_t *cmd, void *conf); 111 | ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r); 112 | # endif /* NGX_HTTP_SCGI */ 113 | 114 | # if (NGX_HTTP_UWSGI) 115 | char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, 116 | ngx_command_t *cmd, void *conf); 117 | ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r); 118 | # endif /* NGX_HTTP_UWSGI */ 119 | 120 | char *ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, 121 | ngx_command_t *cmd, void *conf); 122 | static ngx_int_t 123 | ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); 124 | static ngx_int_t 125 | ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); 126 | 127 | ngx_int_t ngx_http_cache_purge_access_handler(ngx_http_request_t *r); 128 | ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6, 129 | struct sockaddr *s); 130 | 131 | ngx_int_t ngx_http_cache_purge_send_response(ngx_http_request_t *r); 132 | # if (nginx_version >= 1007009) 133 | ngx_int_t ngx_http_cache_purge_cache_get(ngx_http_request_t *r, 134 | ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); 135 | # endif /* nginx_version >= 1007009 */ 136 | ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, 137 | ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); 138 | void ngx_http_cache_purge_handler(ngx_http_request_t *r); 139 | 140 | ngx_int_t ngx_http_file_cache_purge(ngx_http_request_t *r); 141 | 142 | 143 | void ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache); 144 | void ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache); 145 | ngx_int_t ngx_http_cache_purge_is_partial(ngx_http_request_t *r); 146 | 147 | char *ngx_http_cache_purge_conf(ngx_conf_t *cf, 148 | ngx_http_cache_purge_conf_t *cpcf); 149 | 150 | void *ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf); 151 | char *ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, 152 | void *parent, void *child); 153 | 154 | static ngx_command_t ngx_http_cache_purge_module_commands[] = { 155 | 156 | # if (NGX_HTTP_FASTCGI) 157 | { 158 | ngx_string("fastcgi_cache_purge"), 159 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 160 | ngx_http_fastcgi_cache_purge_conf, 161 | NGX_HTTP_LOC_CONF_OFFSET, 162 | 0, 163 | NULL 164 | }, 165 | # endif /* NGX_HTTP_FASTCGI */ 166 | 167 | # if (NGX_HTTP_PROXY) 168 | { 169 | ngx_string("proxy_cache_purge"), 170 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 171 | ngx_http_proxy_cache_purge_conf, 172 | NGX_HTTP_LOC_CONF_OFFSET, 173 | 0, 174 | NULL 175 | }, 176 | # endif /* NGX_HTTP_PROXY */ 177 | 178 | # if (NGX_HTTP_SCGI) 179 | { 180 | ngx_string("scgi_cache_purge"), 181 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 182 | ngx_http_scgi_cache_purge_conf, 183 | NGX_HTTP_LOC_CONF_OFFSET, 184 | 0, 185 | NULL 186 | }, 187 | # endif /* NGX_HTTP_SCGI */ 188 | 189 | # if (NGX_HTTP_UWSGI) 190 | { 191 | ngx_string("uwsgi_cache_purge"), 192 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 193 | ngx_http_uwsgi_cache_purge_conf, 194 | NGX_HTTP_LOC_CONF_OFFSET, 195 | 0, 196 | NULL 197 | }, 198 | # endif /* NGX_HTTP_UWSGI */ 199 | 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 | 208 | ngx_null_command 209 | }; 210 | 211 | static ngx_http_module_t ngx_http_cache_purge_module_ctx = { 212 | NULL, /* preconfiguration */ 213 | NULL, /* postconfiguration */ 214 | 215 | NULL, /* create main configuration */ 216 | NULL, /* init main configuration */ 217 | 218 | NULL, /* create server configuration */ 219 | NULL, /* merge server configuration */ 220 | 221 | ngx_http_cache_purge_create_loc_conf, /* create location configuration */ 222 | ngx_http_cache_purge_merge_loc_conf /* merge location configuration */ 223 | }; 224 | 225 | ngx_module_t ngx_http_cache_purge_module = { 226 | NGX_MODULE_V1, 227 | &ngx_http_cache_purge_module_ctx, /* module context */ 228 | ngx_http_cache_purge_module_commands, /* module directives */ 229 | NGX_HTTP_MODULE, /* module type */ 230 | NULL, /* init master */ 231 | NULL, /* init module */ 232 | NULL, /* init process */ 233 | NULL, /* init thread */ 234 | NULL, /* exit thread */ 235 | NULL, /* exit process */ 236 | NULL, /* exit master */ 237 | NGX_MODULE_V1_PADDING 238 | }; 239 | 240 | # if (NGX_HTTP_FASTCGI) 241 | extern ngx_module_t ngx_http_fastcgi_module; 242 | 243 | # if (nginx_version >= 1007009) 244 | 245 | typedef struct { 246 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 247 | } ngx_http_fastcgi_main_conf_t; 248 | 249 | # endif /* nginx_version >= 1007009 */ 250 | 251 | # if (nginx_version >= 1007008) 252 | 253 | typedef struct { 254 | ngx_array_t *flushes; 255 | ngx_array_t *lengths; 256 | ngx_array_t *values; 257 | ngx_uint_t number; 258 | ngx_hash_t hash; 259 | } ngx_http_fastcgi_params_t; 260 | 261 | # endif /* nginx_version >= 1007008 */ 262 | 263 | typedef struct { 264 | ngx_http_upstream_conf_t upstream; 265 | 266 | ngx_str_t index; 267 | 268 | # if (nginx_version >= 1007008) 269 | ngx_http_fastcgi_params_t params; 270 | ngx_http_fastcgi_params_t params_cache; 271 | # else 272 | ngx_array_t *flushes; 273 | ngx_array_t *params_len; 274 | ngx_array_t *params; 275 | # endif /* nginx_version >= 1007008 */ 276 | 277 | ngx_array_t *params_source; 278 | ngx_array_t *catch_stderr; 279 | 280 | ngx_array_t *fastcgi_lengths; 281 | ngx_array_t *fastcgi_values; 282 | 283 | # if (nginx_version >= 8040) && (nginx_version < 1007008) 284 | ngx_hash_t headers_hash; 285 | ngx_uint_t header_params; 286 | # endif /* nginx_version >= 8040 && nginx_version < 1007008 */ 287 | 288 | # if (nginx_version >= 1001004) 289 | ngx_flag_t keep_conn; 290 | # endif /* nginx_version >= 1001004 */ 291 | 292 | ngx_http_complex_value_t cache_key; 293 | 294 | # if (NGX_PCRE) 295 | ngx_regex_t *split_regex; 296 | ngx_str_t split_name; 297 | # endif /* NGX_PCRE */ 298 | } ngx_http_fastcgi_loc_conf_t; 299 | 300 | char * 301 | ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, 302 | void *conf) { 303 | ngx_http_compile_complex_value_t ccv; 304 | ngx_http_cache_purge_loc_conf_t *cplcf; 305 | ngx_http_core_loc_conf_t *clcf; 306 | ngx_http_fastcgi_loc_conf_t *flcf; 307 | ngx_str_t *value; 308 | # if (nginx_version >= 1007009) 309 | ngx_http_complex_value_t cv; 310 | # endif /* nginx_version >= 1007009 */ 311 | 312 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 313 | 314 | /* check for duplicates / collisions */ 315 | if (cplcf->fastcgi.enable != NGX_CONF_UNSET) { 316 | return "is duplicate"; 317 | } 318 | 319 | if (cf->args->nelts != 3) { 320 | return ngx_http_cache_purge_conf(cf, &cplcf->fastcgi); 321 | } 322 | 323 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 324 | return "(separate location syntax) is not allowed here"; 325 | } 326 | 327 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); 328 | 329 | # if (nginx_version >= 1007009) 330 | if (flcf->upstream.cache > 0) 331 | # else 332 | if (flcf->upstream.cache != NGX_CONF_UNSET_PTR 333 | && flcf->upstream.cache != NULL) 334 | # endif /* nginx_version >= 1007009 */ 335 | { 336 | return "is incompatible with \"fastcgi_cache\""; 337 | } 338 | 339 | if (flcf->upstream.upstream || flcf->fastcgi_lengths) { 340 | return "is incompatible with \"fastcgi_pass\""; 341 | } 342 | 343 | if (flcf->upstream.store > 0 344 | # if (nginx_version < 1007009) 345 | || flcf->upstream.store_lengths 346 | # endif /* nginx_version >= 1007009 */ 347 | ) { 348 | return "is incompatible with \"fastcgi_store\""; 349 | } 350 | 351 | value = cf->args->elts; 352 | 353 | /* set fastcgi_cache part */ 354 | # if (nginx_version >= 1007009) 355 | 356 | flcf->upstream.cache = 1; 357 | 358 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 359 | 360 | ccv.cf = cf; 361 | ccv.value = &value[1]; 362 | ccv.complex_value = &cv; 363 | 364 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 365 | return NGX_CONF_ERROR; 366 | } 367 | 368 | if (cv.lengths != NULL) { 369 | 370 | flcf->upstream.cache_value = ngx_palloc(cf->pool, 371 | sizeof(ngx_http_complex_value_t)); 372 | if (flcf->upstream.cache_value == NULL) { 373 | return NGX_CONF_ERROR; 374 | } 375 | 376 | *flcf->upstream.cache_value = cv; 377 | 378 | } else { 379 | 380 | flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 381 | &ngx_http_fastcgi_module); 382 | if (flcf->upstream.cache_zone == NULL) { 383 | return NGX_CONF_ERROR; 384 | } 385 | } 386 | 387 | # else 388 | 389 | flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 390 | &ngx_http_fastcgi_module); 391 | if (flcf->upstream.cache == NULL) { 392 | return NGX_CONF_ERROR; 393 | } 394 | 395 | # endif /* nginx_version >= 1007009 */ 396 | 397 | /* set fastcgi_cache_key part */ 398 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 399 | 400 | ccv.cf = cf; 401 | ccv.value = &value[2]; 402 | ccv.complex_value = &flcf->cache_key; 403 | 404 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 405 | return NGX_CONF_ERROR; 406 | } 407 | 408 | /* set handler */ 409 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 410 | 411 | cplcf->fastcgi.enable = 0; 412 | cplcf->conf = &cplcf->fastcgi; 413 | clcf->handler = ngx_http_fastcgi_cache_purge_handler; 414 | 415 | return NGX_CONF_OK; 416 | } 417 | 418 | ngx_int_t 419 | ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r) { 420 | ngx_http_file_cache_t *cache; 421 | ngx_http_fastcgi_loc_conf_t *flcf; 422 | ngx_http_cache_purge_loc_conf_t *cplcf; 423 | # if (nginx_version >= 1007009) 424 | ngx_http_fastcgi_main_conf_t *fmcf; 425 | ngx_int_t rc; 426 | # endif /* nginx_version >= 1007009 */ 427 | 428 | if (ngx_http_upstream_create(r) != NGX_OK) { 429 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 430 | } 431 | 432 | flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); 433 | 434 | r->upstream->conf = &flcf->upstream; 435 | 436 | # if (nginx_version >= 1007009) 437 | 438 | fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); 439 | 440 | r->upstream->caches = &fmcf->caches; 441 | 442 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 443 | if (rc != NGX_OK) { 444 | return rc; 445 | } 446 | 447 | # else 448 | 449 | cache = flcf->upstream.cache->data; 450 | 451 | # endif /* nginx_version >= 1007009 */ 452 | 453 | if (ngx_http_cache_purge_init(r, cache, &flcf->cache_key) != NGX_OK) { 454 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 455 | } 456 | 457 | /* Purge-all option */ 458 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 459 | if (cplcf->conf->purge_all) { 460 | ngx_http_cache_purge_all(r, cache); 461 | } else { 462 | if (ngx_http_cache_purge_is_partial(r)) { 463 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 464 | "http file cache purge with partial enabled"); 465 | 466 | ngx_http_cache_purge_partial(r, cache); 467 | } 468 | } 469 | 470 | # if (nginx_version >= 8011) 471 | r->main->count++; 472 | # endif 473 | 474 | ngx_http_cache_purge_handler(r); 475 | 476 | return NGX_DONE; 477 | } 478 | # endif /* NGX_HTTP_FASTCGI */ 479 | 480 | # if (NGX_HTTP_PROXY) 481 | extern ngx_module_t ngx_http_proxy_module; 482 | 483 | typedef struct { 484 | ngx_str_t key_start; 485 | ngx_str_t schema; 486 | ngx_str_t host_header; 487 | ngx_str_t port; 488 | ngx_str_t uri; 489 | } ngx_http_proxy_vars_t; 490 | 491 | # if (nginx_version >= 1007009) 492 | 493 | typedef struct { 494 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 495 | } ngx_http_proxy_main_conf_t; 496 | 497 | # endif /* nginx_version >= 1007009 */ 498 | 499 | # if (nginx_version >= 1007008) 500 | 501 | typedef struct { 502 | ngx_array_t *flushes; 503 | ngx_array_t *lengths; 504 | ngx_array_t *values; 505 | ngx_hash_t hash; 506 | } ngx_http_proxy_headers_t; 507 | 508 | # endif /* nginx_version >= 1007008 */ 509 | 510 | typedef struct { 511 | ngx_http_upstream_conf_t upstream; 512 | 513 | # if (nginx_version >= 1007008) 514 | ngx_array_t *body_flushes; 515 | ngx_array_t *body_lengths; 516 | ngx_array_t *body_values; 517 | ngx_str_t body_source; 518 | 519 | ngx_http_proxy_headers_t headers; 520 | ngx_http_proxy_headers_t headers_cache; 521 | # else 522 | ngx_array_t *flushes; 523 | ngx_array_t *body_set_len; 524 | ngx_array_t *body_set; 525 | ngx_array_t *headers_set_len; 526 | ngx_array_t *headers_set; 527 | ngx_hash_t headers_set_hash; 528 | # endif /* nginx_version >= 1007008 */ 529 | 530 | ngx_array_t *headers_source; 531 | # if (nginx_version < 8040) 532 | ngx_array_t *headers_names; 533 | # endif /* nginx_version < 8040 */ 534 | 535 | ngx_array_t *proxy_lengths; 536 | ngx_array_t *proxy_values; 537 | 538 | ngx_array_t *redirects; 539 | # if (nginx_version >= 1001015) 540 | ngx_array_t *cookie_domains; 541 | ngx_array_t *cookie_paths; 542 | # endif /* nginx_version >= 1001015 */ 543 | 544 | # if (nginx_version < 1007008) 545 | ngx_str_t body_source; 546 | # endif /* nginx_version < 1007008 */ 547 | 548 | # if (nginx_version >= 1011006) 549 | ngx_http_complex_value_t *method; 550 | # else 551 | ngx_str_t method; 552 | # endif /* nginx_version >= 1011006 */ 553 | ngx_str_t location; 554 | ngx_str_t url; 555 | 556 | ngx_http_complex_value_t cache_key; 557 | 558 | ngx_http_proxy_vars_t vars; 559 | 560 | ngx_flag_t redirect; 561 | 562 | # if (nginx_version >= 1001004) 563 | ngx_uint_t http_version; 564 | # endif /* nginx_version >= 1001004 */ 565 | 566 | ngx_uint_t headers_hash_max_size; 567 | ngx_uint_t headers_hash_bucket_size; 568 | 569 | # if (NGX_HTTP_SSL) 570 | # if (nginx_version >= 1005006) 571 | ngx_uint_t ssl; 572 | ngx_uint_t ssl_protocols; 573 | ngx_str_t ssl_ciphers; 574 | # endif /* nginx_version >= 1005006 */ 575 | # if (nginx_version >= 1007000) 576 | ngx_uint_t ssl_verify_depth; 577 | ngx_str_t ssl_trusted_certificate; 578 | ngx_str_t ssl_crl; 579 | # endif /* nginx_version >= 1007000 */ 580 | # if (nginx_version >= 1007008) 581 | ngx_str_t ssl_certificate; 582 | ngx_str_t ssl_certificate_key; 583 | ngx_array_t *ssl_passwords; 584 | # endif /* nginx_version >= 1007008 */ 585 | # endif 586 | } ngx_http_proxy_loc_conf_t; 587 | 588 | char * 589 | ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 590 | ngx_http_compile_complex_value_t ccv; 591 | ngx_http_cache_purge_loc_conf_t *cplcf; 592 | ngx_http_core_loc_conf_t *clcf; 593 | ngx_http_proxy_loc_conf_t *plcf; 594 | ngx_str_t *value; 595 | # if (nginx_version >= 1007009) 596 | ngx_http_complex_value_t cv; 597 | # endif /* nginx_version >= 1007009 */ 598 | 599 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 600 | 601 | /* check for duplicates / collisions */ 602 | if (cplcf->proxy.enable != NGX_CONF_UNSET) { 603 | return "is duplicate"; 604 | } 605 | 606 | if (cf->args->nelts != 3) { 607 | return ngx_http_cache_purge_conf(cf, &cplcf->proxy); 608 | } 609 | 610 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 611 | return "(separate location syntax) is not allowed here"; 612 | } 613 | 614 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 615 | 616 | # if (nginx_version >= 1007009) 617 | if (plcf->upstream.cache > 0) 618 | # else 619 | if (plcf->upstream.cache != NGX_CONF_UNSET_PTR 620 | && plcf->upstream.cache != NULL) 621 | # endif /* nginx_version >= 1007009 */ 622 | { 623 | return "is incompatible with \"proxy_cache\""; 624 | } 625 | 626 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 627 | return "is incompatible with \"proxy_pass\""; 628 | } 629 | 630 | if (plcf->upstream.store > 0 631 | # if (nginx_version < 1007009) 632 | || plcf->upstream.store_lengths 633 | # endif /* nginx_version >= 1007009 */ 634 | ) { 635 | return "is incompatible with \"proxy_store\""; 636 | } 637 | 638 | value = cf->args->elts; 639 | 640 | /* set proxy_cache part */ 641 | # if (nginx_version >= 1007009) 642 | 643 | plcf->upstream.cache = 1; 644 | 645 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 646 | 647 | ccv.cf = cf; 648 | ccv.value = &value[1]; 649 | ccv.complex_value = &cv; 650 | 651 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 652 | return NGX_CONF_ERROR; 653 | } 654 | 655 | if (cv.lengths != NULL) { 656 | 657 | plcf->upstream.cache_value = ngx_palloc(cf->pool, 658 | sizeof(ngx_http_complex_value_t)); 659 | if (plcf->upstream.cache_value == NULL) { 660 | return NGX_CONF_ERROR; 661 | } 662 | 663 | *plcf->upstream.cache_value = cv; 664 | 665 | } else { 666 | 667 | plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 668 | &ngx_http_proxy_module); 669 | if (plcf->upstream.cache_zone == NULL) { 670 | return NGX_CONF_ERROR; 671 | } 672 | } 673 | 674 | # else 675 | 676 | plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 677 | &ngx_http_proxy_module); 678 | if (plcf->upstream.cache == NULL) { 679 | return NGX_CONF_ERROR; 680 | } 681 | 682 | # endif /* nginx_version >= 1007009 */ 683 | 684 | /* set proxy_cache_key part */ 685 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 686 | 687 | ccv.cf = cf; 688 | ccv.value = &value[2]; 689 | ccv.complex_value = &plcf->cache_key; 690 | 691 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 692 | return NGX_CONF_ERROR; 693 | } 694 | 695 | /* set handler */ 696 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 697 | 698 | cplcf->proxy.enable = 0; 699 | cplcf->conf = &cplcf->proxy; 700 | clcf->handler = ngx_http_proxy_cache_purge_handler; 701 | 702 | return NGX_CONF_OK; 703 | } 704 | 705 | ngx_int_t 706 | ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) { 707 | ngx_http_file_cache_t *cache; 708 | ngx_http_proxy_loc_conf_t *plcf; 709 | ngx_http_cache_purge_loc_conf_t *cplcf; 710 | # if (nginx_version >= 1007009) 711 | ngx_http_proxy_main_conf_t *pmcf; 712 | ngx_int_t rc; 713 | # endif /* nginx_version >= 1007009 */ 714 | 715 | if (ngx_http_upstream_create(r) != NGX_OK) { 716 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 717 | } 718 | 719 | plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 720 | 721 | r->upstream->conf = &plcf->upstream; 722 | 723 | # if (nginx_version >= 1007009) 724 | 725 | pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); 726 | 727 | r->upstream->caches = &pmcf->caches; 728 | 729 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 730 | if (rc != NGX_OK) { 731 | return rc; 732 | } 733 | 734 | # else 735 | 736 | cache = plcf->upstream.cache->data; 737 | 738 | # endif /* nginx_version >= 1007009 */ 739 | 740 | if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { 741 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 742 | } 743 | 744 | /* Purge-all option */ 745 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 746 | if (cplcf->conf->purge_all) { 747 | ngx_http_cache_purge_all(r, cache); 748 | } else { 749 | if (ngx_http_cache_purge_is_partial(r)) { 750 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 751 | "http file cache purge with partial enabled"); 752 | 753 | ngx_http_cache_purge_partial(r, cache); 754 | } 755 | } 756 | 757 | # if (nginx_version >= 8011) 758 | r->main->count++; 759 | # endif 760 | 761 | ngx_http_cache_purge_handler(r); 762 | 763 | return NGX_DONE; 764 | } 765 | # endif /* NGX_HTTP_PROXY */ 766 | 767 | # if (NGX_HTTP_SCGI) 768 | extern ngx_module_t ngx_http_scgi_module; 769 | 770 | # if (nginx_version >= 1007009) 771 | 772 | typedef struct { 773 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 774 | } ngx_http_scgi_main_conf_t; 775 | 776 | # endif /* nginx_version >= 1007009 */ 777 | 778 | # if (nginx_version >= 1007008) 779 | 780 | typedef struct { 781 | ngx_array_t *flushes; 782 | ngx_array_t *lengths; 783 | ngx_array_t *values; 784 | ngx_uint_t number; 785 | ngx_hash_t hash; 786 | } ngx_http_scgi_params_t; 787 | 788 | # endif /* nginx_version >= 1007008 */ 789 | 790 | typedef struct { 791 | ngx_http_upstream_conf_t upstream; 792 | 793 | # if (nginx_version >= 1007008) 794 | ngx_http_scgi_params_t params; 795 | ngx_http_scgi_params_t params_cache; 796 | ngx_array_t *params_source; 797 | # else 798 | ngx_array_t *flushes; 799 | ngx_array_t *params_len; 800 | ngx_array_t *params; 801 | ngx_array_t *params_source; 802 | 803 | ngx_hash_t headers_hash; 804 | ngx_uint_t header_params; 805 | # endif /* nginx_version >= 1007008 */ 806 | 807 | ngx_array_t *scgi_lengths; 808 | ngx_array_t *scgi_values; 809 | 810 | ngx_http_complex_value_t cache_key; 811 | } ngx_http_scgi_loc_conf_t; 812 | 813 | char * 814 | ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 815 | ngx_http_compile_complex_value_t ccv; 816 | ngx_http_cache_purge_loc_conf_t *cplcf; 817 | ngx_http_core_loc_conf_t *clcf; 818 | ngx_http_scgi_loc_conf_t *slcf; 819 | ngx_str_t *value; 820 | # if (nginx_version >= 1007009) 821 | ngx_http_complex_value_t cv; 822 | # endif /* nginx_version >= 1007009 */ 823 | 824 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 825 | 826 | /* check for duplicates / collisions */ 827 | if (cplcf->scgi.enable != NGX_CONF_UNSET) { 828 | return "is duplicate"; 829 | } 830 | 831 | if (cf->args->nelts != 3) { 832 | return ngx_http_cache_purge_conf(cf, &cplcf->scgi); 833 | } 834 | 835 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 836 | return "(separate location syntax) is not allowed here"; 837 | } 838 | 839 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 840 | 841 | # if (nginx_version >= 1007009) 842 | if (slcf->upstream.cache > 0) 843 | # else 844 | if (slcf->upstream.cache != NGX_CONF_UNSET_PTR 845 | && slcf->upstream.cache != NULL) 846 | # endif /* nginx_version >= 1007009 */ 847 | { 848 | return "is incompatible with \"scgi_cache\""; 849 | } 850 | 851 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 852 | return "is incompatible with \"scgi_pass\""; 853 | } 854 | 855 | if (slcf->upstream.store > 0 856 | # if (nginx_version < 1007009) 857 | || slcf->upstream.store_lengths 858 | # endif /* nginx_version >= 1007009 */ 859 | ) { 860 | return "is incompatible with \"scgi_store\""; 861 | } 862 | 863 | value = cf->args->elts; 864 | 865 | /* set scgi_cache part */ 866 | # if (nginx_version >= 1007009) 867 | 868 | slcf->upstream.cache = 1; 869 | 870 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 871 | 872 | ccv.cf = cf; 873 | ccv.value = &value[1]; 874 | ccv.complex_value = &cv; 875 | 876 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 877 | return NGX_CONF_ERROR; 878 | } 879 | 880 | if (cv.lengths != NULL) { 881 | 882 | slcf->upstream.cache_value = ngx_palloc(cf->pool, 883 | sizeof(ngx_http_complex_value_t)); 884 | if (slcf->upstream.cache_value == NULL) { 885 | return NGX_CONF_ERROR; 886 | } 887 | 888 | *slcf->upstream.cache_value = cv; 889 | 890 | } else { 891 | 892 | slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 893 | &ngx_http_scgi_module); 894 | if (slcf->upstream.cache_zone == NULL) { 895 | return NGX_CONF_ERROR; 896 | } 897 | } 898 | 899 | # else 900 | 901 | slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 902 | &ngx_http_scgi_module); 903 | if (slcf->upstream.cache == NULL) { 904 | return NGX_CONF_ERROR; 905 | } 906 | 907 | # endif /* nginx_version >= 1007009 */ 908 | 909 | /* set scgi_cache_key part */ 910 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 911 | 912 | ccv.cf = cf; 913 | ccv.value = &value[2]; 914 | ccv.complex_value = &slcf->cache_key; 915 | 916 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 917 | return NGX_CONF_ERROR; 918 | } 919 | 920 | /* set handler */ 921 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 922 | 923 | cplcf->scgi.enable = 0; 924 | cplcf->conf = &cplcf->scgi; 925 | clcf->handler = ngx_http_scgi_cache_purge_handler; 926 | 927 | return NGX_CONF_OK; 928 | } 929 | 930 | ngx_int_t 931 | ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) { 932 | ngx_http_file_cache_t *cache; 933 | ngx_http_scgi_loc_conf_t *slcf; 934 | ngx_http_cache_purge_loc_conf_t *cplcf; 935 | # if (nginx_version >= 1007009) 936 | ngx_http_scgi_main_conf_t *smcf; 937 | ngx_int_t rc; 938 | # endif /* nginx_version >= 1007009 */ 939 | 940 | if (ngx_http_upstream_create(r) != NGX_OK) { 941 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 942 | } 943 | 944 | slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); 945 | 946 | r->upstream->conf = &slcf->upstream; 947 | 948 | # if (nginx_version >= 1007009) 949 | 950 | smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); 951 | 952 | r->upstream->caches = &smcf->caches; 953 | 954 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 955 | if (rc != NGX_OK) { 956 | return rc; 957 | } 958 | 959 | # else 960 | 961 | cache = slcf->upstream.cache->data; 962 | 963 | # endif /* nginx_version >= 1007009 */ 964 | 965 | if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { 966 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 967 | } 968 | 969 | /* Purge-all option */ 970 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 971 | if (cplcf->conf->purge_all) { 972 | ngx_http_cache_purge_all(r, cache); 973 | } else { 974 | if (ngx_http_cache_purge_is_partial(r)) { 975 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 976 | "http file cache purge with partial enabled"); 977 | 978 | ngx_http_cache_purge_partial(r, cache); 979 | } 980 | } 981 | 982 | # if (nginx_version >= 8011) 983 | r->main->count++; 984 | # endif 985 | 986 | ngx_http_cache_purge_handler(r); 987 | 988 | return NGX_DONE; 989 | } 990 | # endif /* NGX_HTTP_SCGI */ 991 | 992 | # if (NGX_HTTP_UWSGI) 993 | extern ngx_module_t ngx_http_uwsgi_module; 994 | 995 | # if (nginx_version >= 1007009) 996 | 997 | typedef struct { 998 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 999 | } ngx_http_uwsgi_main_conf_t; 1000 | 1001 | # endif /* nginx_version >= 1007009 */ 1002 | 1003 | # if (nginx_version >= 1007008) 1004 | 1005 | typedef struct { 1006 | ngx_array_t *flushes; 1007 | ngx_array_t *lengths; 1008 | ngx_array_t *values; 1009 | ngx_uint_t number; 1010 | ngx_hash_t hash; 1011 | } ngx_http_uwsgi_params_t; 1012 | 1013 | # endif /* nginx_version >= 1007008 */ 1014 | 1015 | typedef struct { 1016 | ngx_http_upstream_conf_t upstream; 1017 | 1018 | # if (nginx_version >= 1007008) 1019 | ngx_http_uwsgi_params_t params; 1020 | ngx_http_uwsgi_params_t params_cache; 1021 | ngx_array_t *params_source; 1022 | # else 1023 | ngx_array_t *flushes; 1024 | ngx_array_t *params_len; 1025 | ngx_array_t *params; 1026 | ngx_array_t *params_source; 1027 | 1028 | ngx_hash_t headers_hash; 1029 | ngx_uint_t header_params; 1030 | # endif /* nginx_version >= 1007008 */ 1031 | 1032 | ngx_array_t *uwsgi_lengths; 1033 | ngx_array_t *uwsgi_values; 1034 | 1035 | ngx_http_complex_value_t cache_key; 1036 | 1037 | ngx_str_t uwsgi_string; 1038 | 1039 | ngx_uint_t modifier1; 1040 | ngx_uint_t modifier2; 1041 | 1042 | # if (NGX_HTTP_SSL) 1043 | # if (nginx_version >= 1005008) 1044 | ngx_uint_t ssl; 1045 | ngx_uint_t ssl_protocols; 1046 | ngx_str_t ssl_ciphers; 1047 | # endif /* nginx_version >= 1005008 */ 1048 | # if (nginx_version >= 1007000) 1049 | ngx_uint_t ssl_verify_depth; 1050 | ngx_str_t ssl_trusted_certificate; 1051 | ngx_str_t ssl_crl; 1052 | # endif /* nginx_version >= 1007000 */ 1053 | # if (nginx_version >= 1007008) 1054 | ngx_str_t ssl_certificate; 1055 | ngx_str_t ssl_certificate_key; 1056 | ngx_array_t *ssl_passwords; 1057 | # endif /* nginx_version >= 1007008 */ 1058 | # endif 1059 | } ngx_http_uwsgi_loc_conf_t; 1060 | 1061 | char * 1062 | ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 1063 | ngx_http_compile_complex_value_t ccv; 1064 | ngx_http_cache_purge_loc_conf_t *cplcf; 1065 | ngx_http_core_loc_conf_t *clcf; 1066 | ngx_http_uwsgi_loc_conf_t *ulcf; 1067 | ngx_str_t *value; 1068 | # if (nginx_version >= 1007009) 1069 | ngx_http_complex_value_t cv; 1070 | # endif /* nginx_version >= 1007009 */ 1071 | 1072 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 1073 | 1074 | /* check for duplicates / collisions */ 1075 | if (cplcf->uwsgi.enable != NGX_CONF_UNSET) { 1076 | return "is duplicate"; 1077 | } 1078 | 1079 | if (cf->args->nelts != 3) { 1080 | return ngx_http_cache_purge_conf(cf, &cplcf->uwsgi); 1081 | } 1082 | 1083 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 1084 | return "(separate location syntax) is not allowed here"; 1085 | } 1086 | 1087 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 1088 | 1089 | # if (nginx_version >= 1007009) 1090 | if (ulcf->upstream.cache > 0) 1091 | # else 1092 | if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR 1093 | && ulcf->upstream.cache != NULL) 1094 | # endif /* nginx_version >= 1007009 */ 1095 | { 1096 | return "is incompatible with \"uwsgi_cache\""; 1097 | } 1098 | 1099 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 1100 | return "is incompatible with \"uwsgi_pass\""; 1101 | } 1102 | 1103 | if (ulcf->upstream.store > 0 1104 | # if (nginx_version < 1007009) 1105 | || ulcf->upstream.store_lengths 1106 | # endif /* nginx_version >= 1007009 */ 1107 | ) { 1108 | return "is incompatible with \"uwsgi_store\""; 1109 | } 1110 | 1111 | value = cf->args->elts; 1112 | 1113 | /* set uwsgi_cache part */ 1114 | # if (nginx_version >= 1007009) 1115 | 1116 | ulcf->upstream.cache = 1; 1117 | 1118 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 1119 | 1120 | ccv.cf = cf; 1121 | ccv.value = &value[1]; 1122 | ccv.complex_value = &cv; 1123 | 1124 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 1125 | return NGX_CONF_ERROR; 1126 | } 1127 | 1128 | if (cv.lengths != NULL) { 1129 | 1130 | ulcf->upstream.cache_value = ngx_palloc(cf->pool, 1131 | sizeof(ngx_http_complex_value_t)); 1132 | if (ulcf->upstream.cache_value == NULL) { 1133 | return NGX_CONF_ERROR; 1134 | } 1135 | 1136 | *ulcf->upstream.cache_value = cv; 1137 | 1138 | } else { 1139 | 1140 | ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 1141 | &ngx_http_uwsgi_module); 1142 | if (ulcf->upstream.cache_zone == NULL) { 1143 | return NGX_CONF_ERROR; 1144 | } 1145 | } 1146 | 1147 | # else 1148 | 1149 | ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 1150 | &ngx_http_uwsgi_module); 1151 | if (ulcf->upstream.cache == NULL) { 1152 | return NGX_CONF_ERROR; 1153 | } 1154 | 1155 | # endif /* nginx_version >= 1007009 */ 1156 | 1157 | /* set uwsgi_cache_key part */ 1158 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 1159 | 1160 | ccv.cf = cf; 1161 | ccv.value = &value[2]; 1162 | ccv.complex_value = &ulcf->cache_key; 1163 | 1164 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 1165 | return NGX_CONF_ERROR; 1166 | } 1167 | 1168 | /* set handler */ 1169 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 1170 | 1171 | cplcf->uwsgi.enable = 0; 1172 | cplcf->conf = &cplcf->uwsgi; 1173 | clcf->handler = ngx_http_uwsgi_cache_purge_handler; 1174 | 1175 | return NGX_CONF_OK; 1176 | } 1177 | 1178 | 1179 | ngx_int_t 1180 | ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) { 1181 | ngx_http_file_cache_t *cache; 1182 | ngx_http_uwsgi_loc_conf_t *ulcf; 1183 | ngx_http_cache_purge_loc_conf_t *cplcf; 1184 | # if (nginx_version >= 1007009) 1185 | ngx_http_uwsgi_main_conf_t *umcf; 1186 | ngx_int_t rc; 1187 | # endif /* nginx_version >= 1007009 */ 1188 | 1189 | if (ngx_http_upstream_create(r) != NGX_OK) { 1190 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1191 | } 1192 | 1193 | ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); 1194 | 1195 | r->upstream->conf = &ulcf->upstream; 1196 | 1197 | # if (nginx_version >= 1007009) 1198 | 1199 | umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); 1200 | 1201 | r->upstream->caches = &umcf->caches; 1202 | 1203 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 1204 | if (rc != NGX_OK) { 1205 | return rc; 1206 | } 1207 | 1208 | # else 1209 | 1210 | cache = ulcf->upstream.cache->data; 1211 | 1212 | # endif /* nginx_version >= 1007009 */ 1213 | 1214 | if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { 1215 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1216 | } 1217 | 1218 | /* Purge-all option */ 1219 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1220 | if (cplcf->conf->purge_all) { 1221 | ngx_http_cache_purge_all(r, cache); 1222 | } else { 1223 | if (ngx_http_cache_purge_is_partial(r)) { 1224 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1225 | "http file cache purge with partial enabled"); 1226 | 1227 | ngx_http_cache_purge_partial(r, cache); 1228 | } 1229 | } 1230 | 1231 | # if (nginx_version >= 8011) 1232 | r->main->count++; 1233 | # endif 1234 | 1235 | ngx_http_cache_purge_handler(r); 1236 | 1237 | return NGX_DONE; 1238 | } 1239 | # endif /* NGX_HTTP_UWSGI */ 1240 | 1241 | 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 | 1291 | static ngx_int_t 1292 | ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1293 | return NGX_OK; 1294 | } 1295 | 1296 | static ngx_int_t 1297 | ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1298 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1299 | "http file cache delete: \"%s\"", path->data); 1300 | 1301 | if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { 1302 | ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 1303 | ngx_delete_file_n " \"%s\" failed", path->data); 1304 | } 1305 | 1306 | return NGX_OK; 1307 | } 1308 | 1309 | 1310 | static ngx_int_t 1311 | ngx_http_purge_file_cache_delete_partial_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1312 | u_char *key_partial; 1313 | u_char *key_in_file; 1314 | ngx_uint_t len; 1315 | ngx_flag_t remove_file = 0; 1316 | 1317 | key_partial = ctx->data; 1318 | len = ngx_strlen(key_partial); 1319 | 1320 | /* if key_partial is empty always match, because is a '*' */ 1321 | if (len == 0) { 1322 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1323 | "empty key_partial, forcing deletion"); 1324 | remove_file = 1; 1325 | } else { 1326 | ngx_file_t file; 1327 | 1328 | ngx_memzero(&file, sizeof(ngx_file_t)); 1329 | file.offset = file.sys_offset = 0; 1330 | file.fd = ngx_open_file(path->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 1331 | NGX_FILE_DEFAULT_ACCESS); 1332 | file.log = ctx->log; 1333 | 1334 | /* I don't know if it's a good idea to use the ngx_cycle pool for this, 1335 | but the request is not available here */ 1336 | key_in_file = ngx_pcalloc(ngx_cycle->pool, sizeof(u_char) * (len + 1)); 1337 | 1338 | /* KEY: /proxy/passwd */ 1339 | /* since we don't need the "KEY: " ignore 5 + 1 extra u_char from last 1340 | intro */ 1341 | /* Optimization: we don't need to read the full key only the n chars 1342 | included in key_partial */ 1343 | ngx_read_file(&file, key_in_file, sizeof(u_char) * len, 1344 | sizeof(ngx_http_file_cache_header_t) + sizeof(u_char) * 6); 1345 | ngx_close_file(file.fd); 1346 | 1347 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1348 | "http cache file \"%s\" key read: \"%s\"", path->data, key_in_file); 1349 | 1350 | if (ngx_strncasecmp(key_in_file, key_partial, len) == 0) { 1351 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1352 | "match found, deleting file \"%s\"", path->data); 1353 | remove_file = 1; 1354 | } 1355 | } 1356 | 1357 | if (remove_file && ngx_delete_file(path->data) == NGX_FILE_ERROR) { 1358 | ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 1359 | ngx_delete_file_n " \"%s\" failed", path->data); 1360 | } 1361 | 1362 | return NGX_OK; 1363 | } 1364 | 1365 | ngx_int_t 1366 | ngx_http_cache_purge_access_handler(ngx_http_request_t *r) { 1367 | ngx_http_cache_purge_loc_conf_t *cplcf; 1368 | 1369 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1370 | 1371 | if (r->method_name.len != cplcf->conf->method.len 1372 | || (ngx_strncmp(r->method_name.data, cplcf->conf->method.data, 1373 | r->method_name.len))) { 1374 | return cplcf->original_handler(r); 1375 | } 1376 | 1377 | if ((cplcf->conf->access || cplcf->conf->access6) 1378 | && ngx_http_cache_purge_access(cplcf->conf->access, 1379 | cplcf->conf->access6, 1380 | r->connection->sockaddr) != NGX_OK) { 1381 | return NGX_HTTP_FORBIDDEN; 1382 | } 1383 | 1384 | if (cplcf->handler == NULL) { 1385 | return NGX_HTTP_NOT_FOUND; 1386 | } 1387 | 1388 | return cplcf->handler(r); 1389 | } 1390 | 1391 | ngx_int_t 1392 | ngx_http_cache_purge_access(ngx_array_t *access, ngx_array_t *access6, 1393 | struct sockaddr *s) { 1394 | in_addr_t inaddr; 1395 | ngx_in_cidr_t *a; 1396 | ngx_uint_t i; 1397 | # if (NGX_HAVE_INET6) 1398 | struct in6_addr *inaddr6; 1399 | ngx_in6_cidr_t *a6; 1400 | u_char *p; 1401 | ngx_uint_t n; 1402 | # endif /* NGX_HAVE_INET6 */ 1403 | 1404 | switch (s->sa_family) { 1405 | case AF_INET: 1406 | if (access == NULL) { 1407 | return NGX_DECLINED; 1408 | } 1409 | 1410 | inaddr = ((struct sockaddr_in *) s)->sin_addr.s_addr; 1411 | 1412 | # if (NGX_HAVE_INET6) 1413 | ipv4: 1414 | # endif /* NGX_HAVE_INET6 */ 1415 | 1416 | a = access->elts; 1417 | for (i = 0; i < access->nelts; i++) { 1418 | if ((inaddr & a[i].mask) == a[i].addr) { 1419 | return NGX_OK; 1420 | } 1421 | } 1422 | 1423 | return NGX_DECLINED; 1424 | 1425 | # if (NGX_HAVE_INET6) 1426 | case AF_INET6: 1427 | inaddr6 = &((struct sockaddr_in6 *) s)->sin6_addr; 1428 | p = inaddr6->s6_addr; 1429 | 1430 | if (access && IN6_IS_ADDR_V4MAPPED(inaddr6)) { 1431 | inaddr = p[12] << 24; 1432 | inaddr += p[13] << 16; 1433 | inaddr += p[14] << 8; 1434 | inaddr += p[15]; 1435 | inaddr = htonl(inaddr); 1436 | 1437 | goto ipv4; 1438 | } 1439 | 1440 | if (access6 == NULL) { 1441 | return NGX_DECLINED; 1442 | } 1443 | 1444 | a6 = access6->elts; 1445 | for (i = 0; i < access6->nelts; i++) { 1446 | for (n = 0; n < 16; n++) { 1447 | if ((p[n] & a6[i].mask.s6_addr[n]) != a6[i].addr.s6_addr[n]) { 1448 | goto next; 1449 | } 1450 | } 1451 | 1452 | return NGX_OK; 1453 | 1454 | next: 1455 | continue; 1456 | } 1457 | 1458 | return NGX_DECLINED; 1459 | # endif /* NGX_HAVE_INET6 */ 1460 | } 1461 | 1462 | return NGX_DECLINED; 1463 | } 1464 | 1465 | ngx_int_t 1466 | ngx_http_cache_purge_send_response(ngx_http_request_t *r) { 1467 | ngx_chain_t out; 1468 | ngx_buf_t *b; 1469 | ngx_str_t *key; 1470 | ngx_int_t rc; 1471 | 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); 1485 | 1486 | key = r->cache->keys.elts; 1487 | 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 - 2 - 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 | p = ngx_snprintf(buf, resp_tmpl_len, resp_body , buf_keydata, buf_keydata); 1543 | if (p == NULL) { 1544 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1545 | } 1546 | 1547 | len = body_len + key[0].len + r->cache->file.name.len; 1548 | 1549 | r->headers_out.status = NGX_HTTP_OK; 1550 | r->headers_out.content_length_n = len; 1551 | 1552 | if (r->method == NGX_HTTP_HEAD) { 1553 | rc = ngx_http_send_header(r); 1554 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 1555 | return rc; 1556 | } 1557 | } 1558 | 1559 | b = ngx_create_temp_buf(r->pool, len); 1560 | if (b == NULL) { 1561 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1562 | } 1563 | 1564 | 1565 | out.buf = b; 1566 | out.next = NULL; 1567 | 1568 | b->last = ngx_cpymem(b->last, buf, resp_tmpl_len); 1569 | b->last_buf = 1; 1570 | 1571 | rc = ngx_http_send_header(r); 1572 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 1573 | return rc; 1574 | } 1575 | 1576 | return ngx_http_output_filter(r, &out); 1577 | } 1578 | 1579 | # if (nginx_version >= 1007009) 1580 | 1581 | /* 1582 | * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get 1583 | * Copyright (C) Igor Sysoev 1584 | * Copyright (C) Nginx, Inc. 1585 | */ 1586 | ngx_int_t 1587 | ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, 1588 | ngx_http_file_cache_t **cache) { 1589 | ngx_str_t *name, val; 1590 | ngx_uint_t i; 1591 | ngx_http_file_cache_t **caches; 1592 | 1593 | if (u->conf->cache_zone) { 1594 | *cache = u->conf->cache_zone->data; 1595 | return NGX_OK; 1596 | } 1597 | 1598 | if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { 1599 | return NGX_ERROR; 1600 | } 1601 | 1602 | if (val.len == 0 1603 | || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) { 1604 | return NGX_DECLINED; 1605 | } 1606 | 1607 | caches = u->caches->elts; 1608 | 1609 | for (i = 0; i < u->caches->nelts; i++) { 1610 | name = &caches[i]->shm_zone->shm.name; 1611 | 1612 | if (name->len == val.len 1613 | && ngx_strncmp(name->data, val.data, val.len) == 0) { 1614 | *cache = caches[i]; 1615 | return NGX_OK; 1616 | } 1617 | } 1618 | 1619 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1620 | "cache \"%V\" not found", &val); 1621 | 1622 | return NGX_ERROR; 1623 | } 1624 | 1625 | # endif /* nginx_version >= 1007009 */ 1626 | 1627 | ngx_int_t 1628 | ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, 1629 | ngx_http_complex_value_t *cache_key) { 1630 | ngx_http_cache_t *c; 1631 | ngx_str_t *key; 1632 | ngx_int_t rc; 1633 | 1634 | rc = ngx_http_discard_request_body(r); 1635 | if (rc != NGX_OK) { 1636 | return NGX_ERROR; 1637 | } 1638 | 1639 | c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); 1640 | if (c == NULL) { 1641 | return NGX_ERROR; 1642 | } 1643 | 1644 | rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t)); 1645 | if (rc != NGX_OK) { 1646 | return NGX_ERROR; 1647 | } 1648 | 1649 | key = ngx_array_push(&c->keys); 1650 | if (key == NULL) { 1651 | return NGX_ERROR; 1652 | } 1653 | 1654 | rc = ngx_http_complex_value(r, cache_key, key); 1655 | if (rc != NGX_OK) { 1656 | return NGX_ERROR; 1657 | } 1658 | 1659 | r->cache = c; 1660 | c->body_start = ngx_pagesize; 1661 | c->file_cache = cache; 1662 | c->file.log = r->connection->log; 1663 | 1664 | ngx_http_file_cache_create_key(r); 1665 | 1666 | return NGX_OK; 1667 | } 1668 | 1669 | void 1670 | ngx_http_cache_purge_handler(ngx_http_request_t *r) { 1671 | ngx_http_cache_purge_loc_conf_t *cplcf; 1672 | ngx_int_t rc; 1673 | 1674 | # if (NGX_HAVE_FILE_AIO) 1675 | if (r->aio) { 1676 | return; 1677 | } 1678 | # endif 1679 | 1680 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1681 | rc = NGX_OK; 1682 | if (!cplcf->conf->purge_all && !ngx_http_cache_purge_is_partial(r)) { 1683 | rc = ngx_http_file_cache_purge(r); 1684 | 1685 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1686 | "http file cache purge: %i, \"%s\"", 1687 | rc, r->cache->file.name.data); 1688 | } 1689 | 1690 | switch (rc) { 1691 | case NGX_OK: 1692 | r->write_event_handler = ngx_http_request_empty_handler; 1693 | ngx_http_finalize_request(r, ngx_http_cache_purge_send_response(r)); 1694 | return; 1695 | case NGX_DECLINED: 1696 | ngx_http_finalize_request(r, NGX_HTTP_PRECONDITION_FAILED); 1697 | return; 1698 | # if (NGX_HAVE_FILE_AIO) 1699 | case NGX_AGAIN: 1700 | r->write_event_handler = ngx_http_cache_purge_handler; 1701 | return; 1702 | # endif 1703 | default: 1704 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1705 | } 1706 | } 1707 | 1708 | ngx_int_t 1709 | ngx_http_file_cache_purge(ngx_http_request_t *r) { 1710 | ngx_http_file_cache_t *cache; 1711 | ngx_http_cache_t *c; 1712 | 1713 | switch (ngx_http_file_cache_open(r)) { 1714 | case NGX_OK: 1715 | case NGX_HTTP_CACHE_STALE: 1716 | # if (nginx_version >= 8001) \ 1717 | || ((nginx_version < 8000) && (nginx_version >= 7060)) 1718 | case NGX_HTTP_CACHE_UPDATING: 1719 | # endif 1720 | break; 1721 | case NGX_DECLINED: 1722 | return NGX_DECLINED; 1723 | # if (NGX_HAVE_FILE_AIO) 1724 | case NGX_AGAIN: 1725 | return NGX_AGAIN; 1726 | # endif 1727 | default: 1728 | return NGX_ERROR; 1729 | } 1730 | 1731 | c = r->cache; 1732 | cache = c->file_cache; 1733 | 1734 | /* 1735 | * delete file from disk but *keep* in-memory node, 1736 | * because other requests might still point to it. 1737 | */ 1738 | 1739 | ngx_shmtx_lock(&cache->shpool->mutex); 1740 | 1741 | if (!c->node->exists) { 1742 | /* race between concurrent purges, backoff */ 1743 | ngx_shmtx_unlock(&cache->shpool->mutex); 1744 | return NGX_DECLINED; 1745 | } 1746 | 1747 | # if (nginx_version >= 1000001) 1748 | cache->sh->size -= c->node->fs_size; 1749 | c->node->fs_size = 0; 1750 | # else 1751 | cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize; 1752 | c->node->length = 0; 1753 | # endif 1754 | 1755 | c->node->exists = 0; 1756 | # if (nginx_version >= 8001) \ 1757 | || ((nginx_version < 8000) && (nginx_version >= 7060)) 1758 | c->node->updating = 0; 1759 | # endif 1760 | 1761 | ngx_shmtx_unlock(&cache->shpool->mutex); 1762 | 1763 | if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) { 1764 | /* entry in error log is enough, don't notice client */ 1765 | ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 1766 | ngx_delete_file_n " \"%s\" failed", c->file.name.data); 1767 | } 1768 | 1769 | /* file deleted from cache */ 1770 | return NGX_OK; 1771 | } 1772 | 1773 | 1774 | void 1775 | ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { 1776 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1777 | "purge_all http in %s", 1778 | cache->path->name.data); 1779 | 1780 | /* Walk the tree and remove all the files */ 1781 | ngx_tree_ctx_t tree; 1782 | tree.init_handler = NULL; 1783 | tree.file_handler = ngx_http_purge_file_cache_delete_file; 1784 | tree.pre_tree_handler = ngx_http_purge_file_cache_noop; 1785 | tree.post_tree_handler = ngx_http_purge_file_cache_noop; 1786 | tree.spec_handler = ngx_http_purge_file_cache_noop; 1787 | tree.data = NULL; 1788 | tree.alloc = 0; 1789 | tree.log = ngx_cycle->log; 1790 | 1791 | ngx_walk_tree(&tree, &cache->path->name); 1792 | } 1793 | 1794 | void 1795 | ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { 1796 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1797 | "purge_partial http in %s", 1798 | cache->path->name.data); 1799 | 1800 | u_char *key_partial; 1801 | ngx_str_t *key; 1802 | ngx_http_cache_t *c; 1803 | ngx_uint_t len; 1804 | 1805 | c = r->cache; 1806 | key = c->keys.elts; 1807 | len = key[0].len; 1808 | 1809 | /* Only check the first key */ 1810 | if (key[0].data[key[0].len - 1] == '$') { 1811 | /* Check key for exact match (key terminated by newline) */ 1812 | key_partial = ngx_pcalloc(r->pool, sizeof(u_char) * (len + 1)); 1813 | ngx_memcpy(key_partial, key[0].data, sizeof(u_char) * (len - 1)); 1814 | key_partial[len - 1] = '\n'; 1815 | } else { 1816 | /* Check key for prefix match */ 1817 | key_partial = ngx_pcalloc(r->pool, sizeof(u_char) * len); 1818 | ngx_memcpy(key_partial, key[0].data, sizeof(u_char) * (len - 1)); 1819 | } 1820 | 1821 | /* Walk the tree and remove all the files matching key_partial */ 1822 | ngx_tree_ctx_t tree; 1823 | tree.init_handler = NULL; 1824 | tree.file_handler = ngx_http_purge_file_cache_delete_partial_file; 1825 | tree.pre_tree_handler = ngx_http_purge_file_cache_noop; 1826 | tree.post_tree_handler = ngx_http_purge_file_cache_noop; 1827 | tree.spec_handler = ngx_http_purge_file_cache_noop; 1828 | tree.data = key_partial; 1829 | tree.alloc = 0; 1830 | tree.log = ngx_cycle->log; 1831 | 1832 | ngx_walk_tree(&tree, &cache->path->name); 1833 | } 1834 | 1835 | ngx_int_t 1836 | ngx_http_cache_purge_is_partial(ngx_http_request_t *r) { 1837 | ngx_str_t *key; 1838 | ngx_http_cache_t *c; 1839 | 1840 | c = r->cache; 1841 | key = c->keys.elts; 1842 | 1843 | /* Only check the first key */ 1844 | return (key[0].data[key[0].len - 1] == '*' || 1845 | key[0].data[key[0].len - 1] == '$'); 1846 | } 1847 | 1848 | char * 1849 | ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) { 1850 | ngx_cidr_t cidr; 1851 | ngx_in_cidr_t *access; 1852 | # if (NGX_HAVE_INET6) 1853 | ngx_in6_cidr_t *access6; 1854 | # endif /* NGX_HAVE_INET6 */ 1855 | ngx_str_t *value; 1856 | ngx_int_t rc; 1857 | ngx_uint_t i; 1858 | ngx_uint_t from_position; 1859 | 1860 | from_position = 2; 1861 | 1862 | /* xxx_cache_purge on|off| [purge_all] [from all| [.. ]] */ 1863 | value = cf->args->elts; 1864 | 1865 | if (ngx_strcmp(value[1].data, "off") == 0) { 1866 | cpcf->enable = 0; 1867 | return NGX_CONF_OK; 1868 | 1869 | } else if (ngx_strcmp(value[1].data, "on") == 0) { 1870 | ngx_str_set(&cpcf->method, "PURGE"); 1871 | 1872 | } else { 1873 | cpcf->method = value[1]; 1874 | } 1875 | 1876 | if (cf->args->nelts < 4) { 1877 | cpcf->enable = 1; 1878 | return NGX_CONF_OK; 1879 | } 1880 | 1881 | /* We will purge all the keys */ 1882 | if (ngx_strcmp(value[from_position].data, "purge_all") == 0) { 1883 | cpcf->purge_all = 1; 1884 | from_position++; 1885 | } 1886 | 1887 | 1888 | /* sanity check */ 1889 | if (ngx_strcmp(value[from_position].data, "from") != 0) { 1890 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1891 | "invalid parameter \"%V\", expected" 1892 | " \"from\" keyword", &value[from_position]); 1893 | return NGX_CONF_ERROR; 1894 | } 1895 | 1896 | if (ngx_strcmp(value[from_position + 1].data, "all") == 0) { 1897 | cpcf->enable = 1; 1898 | return NGX_CONF_OK; 1899 | } 1900 | 1901 | for (i = (from_position + 1); i < cf->args->nelts; i++) { 1902 | rc = ngx_ptocidr(&value[i], &cidr); 1903 | 1904 | if (rc == NGX_ERROR) { 1905 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1906 | "invalid parameter \"%V\"", &value[i]); 1907 | return NGX_CONF_ERROR; 1908 | } 1909 | 1910 | if (rc == NGX_DONE) { 1911 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1912 | "low address bits of %V are meaningless", 1913 | &value[i]); 1914 | } 1915 | 1916 | switch (cidr.family) { 1917 | case AF_INET: 1918 | if (cpcf->access == NULL) { 1919 | cpcf->access = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), 1920 | sizeof(ngx_in_cidr_t)); 1921 | if (cpcf->access == NULL) { 1922 | return NGX_CONF_ERROR; 1923 | } 1924 | } 1925 | 1926 | access = ngx_array_push(cpcf->access); 1927 | if (access == NULL) { 1928 | return NGX_CONF_ERROR; 1929 | } 1930 | 1931 | access->mask = cidr.u.in.mask; 1932 | access->addr = cidr.u.in.addr; 1933 | 1934 | break; 1935 | 1936 | # if (NGX_HAVE_INET6) 1937 | case AF_INET6: 1938 | if (cpcf->access6 == NULL) { 1939 | cpcf->access6 = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), 1940 | sizeof(ngx_in6_cidr_t)); 1941 | if (cpcf->access6 == NULL) { 1942 | return NGX_CONF_ERROR; 1943 | } 1944 | } 1945 | 1946 | access6 = ngx_array_push(cpcf->access6); 1947 | if (access6 == NULL) { 1948 | return NGX_CONF_ERROR; 1949 | } 1950 | 1951 | access6->mask = cidr.u.in6.mask; 1952 | access6->addr = cidr.u.in6.addr; 1953 | 1954 | break; 1955 | # endif /* NGX_HAVE_INET6 */ 1956 | } 1957 | } 1958 | 1959 | cpcf->enable = 1; 1960 | 1961 | return NGX_CONF_OK; 1962 | } 1963 | 1964 | void 1965 | ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf, 1966 | ngx_http_cache_purge_conf_t *prev) { 1967 | if (conf->enable == NGX_CONF_UNSET) { 1968 | if (prev->enable == 1) { 1969 | conf->enable = prev->enable; 1970 | conf->method = prev->method; 1971 | conf->purge_all = prev->purge_all; 1972 | conf->access = prev->access; 1973 | conf->access6 = prev->access6; 1974 | } else { 1975 | conf->enable = 0; 1976 | } 1977 | } 1978 | } 1979 | 1980 | void * 1981 | ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) { 1982 | ngx_http_cache_purge_loc_conf_t *conf; 1983 | 1984 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_purge_loc_conf_t)); 1985 | if (conf == NULL) { 1986 | return NULL; 1987 | } 1988 | 1989 | /* 1990 | * set by ngx_pcalloc(): 1991 | * 1992 | * conf->*.method = { 0, NULL } 1993 | * conf->*.access = NULL 1994 | * conf->*.access6 = NULL 1995 | * conf->handler = NULL 1996 | * conf->original_handler = NULL 1997 | */ 1998 | 1999 | # if (NGX_HTTP_FASTCGI) 2000 | conf->fastcgi.enable = NGX_CONF_UNSET; 2001 | # endif /* NGX_HTTP_FASTCGI */ 2002 | # if (NGX_HTTP_PROXY) 2003 | conf->proxy.enable = NGX_CONF_UNSET; 2004 | # endif /* NGX_HTTP_PROXY */ 2005 | # if (NGX_HTTP_SCGI) 2006 | conf->scgi.enable = NGX_CONF_UNSET; 2007 | # endif /* NGX_HTTP_SCGI */ 2008 | # if (NGX_HTTP_UWSGI) 2009 | conf->uwsgi.enable = NGX_CONF_UNSET; 2010 | # endif /* NGX_HTTP_UWSGI */ 2011 | 2012 | conf->resptype = NGX_CONF_UNSET_UINT; 2013 | 2014 | conf->conf = NGX_CONF_UNSET_PTR; 2015 | 2016 | return conf; 2017 | } 2018 | 2019 | char * 2020 | ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { 2021 | ngx_http_cache_purge_loc_conf_t *prev = parent; 2022 | ngx_http_cache_purge_loc_conf_t *conf = child; 2023 | ngx_http_core_loc_conf_t *clcf; 2024 | # if (NGX_HTTP_FASTCGI) 2025 | ngx_http_fastcgi_loc_conf_t *flcf; 2026 | # endif /* NGX_HTTP_FASTCGI */ 2027 | # if (NGX_HTTP_PROXY) 2028 | ngx_http_proxy_loc_conf_t *plcf; 2029 | # endif /* NGX_HTTP_PROXY */ 2030 | # if (NGX_HTTP_SCGI) 2031 | ngx_http_scgi_loc_conf_t *slcf; 2032 | # endif /* NGX_HTTP_SCGI */ 2033 | # if (NGX_HTTP_UWSGI) 2034 | ngx_http_uwsgi_loc_conf_t *ulcf; 2035 | # endif /* NGX_HTTP_UWSGI */ 2036 | 2037 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 2038 | 2039 | ngx_conf_merge_uint_value(conf->resptype, prev->resptype, NGX_REPONSE_TYPE_HTML); 2040 | 2041 | # if (NGX_HTTP_FASTCGI) 2042 | ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi); 2043 | 2044 | if (conf->fastcgi.enable && clcf->handler != NULL) { 2045 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); 2046 | 2047 | if (flcf->upstream.upstream || flcf->fastcgi_lengths) { 2048 | conf->conf = &conf->fastcgi; 2049 | conf->handler = flcf->upstream.cache 2050 | ? ngx_http_fastcgi_cache_purge_handler : NULL; 2051 | conf->original_handler = clcf->handler; 2052 | 2053 | clcf->handler = ngx_http_cache_purge_access_handler; 2054 | 2055 | return NGX_CONF_OK; 2056 | } 2057 | } 2058 | # endif /* NGX_HTTP_FASTCGI */ 2059 | 2060 | # if (NGX_HTTP_PROXY) 2061 | ngx_http_cache_purge_merge_conf(&conf->proxy, &prev->proxy); 2062 | 2063 | if (conf->proxy.enable && clcf->handler != NULL) { 2064 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 2065 | 2066 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 2067 | conf->conf = &conf->proxy; 2068 | conf->handler = plcf->upstream.cache 2069 | ? ngx_http_proxy_cache_purge_handler : NULL; 2070 | conf->original_handler = clcf->handler; 2071 | 2072 | clcf->handler = ngx_http_cache_purge_access_handler; 2073 | 2074 | return NGX_CONF_OK; 2075 | } 2076 | } 2077 | # endif /* NGX_HTTP_PROXY */ 2078 | 2079 | # if (NGX_HTTP_SCGI) 2080 | ngx_http_cache_purge_merge_conf(&conf->scgi, &prev->scgi); 2081 | 2082 | if (conf->scgi.enable && clcf->handler != NULL) { 2083 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 2084 | 2085 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 2086 | conf->conf = &conf->scgi; 2087 | conf->handler = slcf->upstream.cache 2088 | ? ngx_http_scgi_cache_purge_handler : NULL; 2089 | conf->original_handler = clcf->handler; 2090 | clcf->handler = ngx_http_cache_purge_access_handler; 2091 | 2092 | return NGX_CONF_OK; 2093 | } 2094 | } 2095 | # endif /* NGX_HTTP_SCGI */ 2096 | 2097 | # if (NGX_HTTP_UWSGI) 2098 | ngx_http_cache_purge_merge_conf(&conf->uwsgi, &prev->uwsgi); 2099 | 2100 | if (conf->uwsgi.enable && clcf->handler != NULL) { 2101 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 2102 | 2103 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 2104 | conf->conf = &conf->uwsgi; 2105 | conf->handler = ulcf->upstream.cache 2106 | ? ngx_http_uwsgi_cache_purge_handler : NULL; 2107 | conf->original_handler = clcf->handler; 2108 | 2109 | clcf->handler = ngx_http_cache_purge_access_handler; 2110 | 2111 | return NGX_CONF_OK; 2112 | } 2113 | } 2114 | # endif /* NGX_HTTP_UWSGI */ 2115 | 2116 | ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); 2117 | 2118 | if (conf->handler == NULL) { 2119 | conf->handler = prev->handler; 2120 | } 2121 | 2122 | if (conf->original_handler == NULL) { 2123 | conf->original_handler = prev->original_handler; 2124 | } 2125 | 2126 | return NGX_CONF_OK; 2127 | } 2128 | 2129 | #else /* !NGX_HTTP_CACHE */ 2130 | 2131 | static ngx_http_module_t ngx_http_cache_purge_module_ctx = { 2132 | NULL, /* preconfiguration */ 2133 | NULL, /* postconfiguration */ 2134 | 2135 | NULL, /* create main configuration */ 2136 | NULL, /* init main configuration */ 2137 | 2138 | NULL, /* create server configuration */ 2139 | NULL, /* merge server configuration */ 2140 | 2141 | NULL, /* create location configuration */ 2142 | NULL, /* merge location configuration */ 2143 | }; 2144 | 2145 | ngx_module_t ngx_http_cache_purge_module = { 2146 | NGX_MODULE_V1, 2147 | &ngx_http_cache_purge_module_ctx, /* module context */ 2148 | NULL, /* module directives */ 2149 | NGX_HTTP_MODULE, /* module type */ 2150 | NULL, /* init master */ 2151 | NULL, /* init module */ 2152 | NULL, /* init process */ 2153 | NULL, /* init thread */ 2154 | NULL, /* exit thread */ 2155 | NULL, /* exit process */ 2156 | NULL, /* exit master */ 2157 | NGX_MODULE_V1_PADDING 2158 | }; 2159 | 2160 | #endif /* NGX_HTTP_CACHE */ 2161 | -------------------------------------------------------------------------------- /t/proxy1.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 4 + 3 * 1); 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | location /proxy { 17 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 18 | proxy_cache test_cache; 19 | proxy_cache_key $uri$is_args$args; 20 | proxy_cache_valid 3m; 21 | add_header X-Cache-Status $upstream_cache_status; 22 | } 23 | 24 | location ~ /purge(/.*) { 25 | proxy_cache_purge test_cache $1$is_args$args; 26 | } 27 | 28 | location = /etc/passwd { 29 | root /; 30 | } 31 | _EOC_ 32 | 33 | worker_connections(128); 34 | no_shuffle(); 35 | run_tests(); 36 | 37 | no_diff(); 38 | 39 | __DATA__ 40 | 41 | === TEST 1: prepare 42 | --- http_config eval: $::http_config 43 | --- config eval: $::config 44 | --- request 45 | GET /proxy/passwd 46 | --- error_code: 200 47 | --- response_headers 48 | Content-Type: text/plain 49 | --- response_body_like: root 50 | --- timeout: 10 51 | --- no_error_log eval 52 | qr/\[(warn|error|crit|alert|emerg)\]/ 53 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 54 | 55 | 56 | 57 | === TEST 2: get from cache 58 | --- http_config eval: $::http_config 59 | --- config eval: $::config 60 | --- request 61 | GET /proxy/passwd 62 | --- error_code: 200 63 | --- response_headers 64 | Content-Type: text/plain 65 | X-Cache-Status: HIT 66 | --- response_body_like: root 67 | --- timeout: 10 68 | --- no_error_log eval 69 | qr/\[(warn|error|crit|alert|emerg)\]/ 70 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 71 | 72 | 73 | 74 | === TEST 3: purge from cache 75 | --- http_config eval: $::http_config 76 | --- config eval: $::config 77 | --- request 78 | PURGE /purge/proxy/passwd 79 | --- error_code: 200 80 | --- response_headers 81 | Content-Type: text/html 82 | --- response_body_like: Successful purge 83 | --- timeout: 10 84 | --- no_error_log eval 85 | qr/\[(warn|error|crit|alert|emerg)\]/ 86 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 87 | 88 | 89 | 90 | === TEST 4: purge from empty cache 91 | --- http_config eval: $::http_config 92 | --- config eval: $::config 93 | --- request 94 | PURGE /purge/proxy/passwd 95 | --- error_code: 412 96 | --- response_headers 97 | Content-Type: text/html 98 | --- response_body_like: 412 Precondition Failed 99 | --- timeout: 10 100 | --- no_error_log eval 101 | qr/\[(warn|error|crit|alert|emerg)\]/ 102 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 103 | 104 | 105 | 106 | === TEST 5: get from source 107 | --- http_config eval: $::http_config 108 | --- config eval: $::config 109 | --- request 110 | GET /proxy/passwd 111 | --- error_code: 200 112 | --- response_headers 113 | Content-Type: text/plain 114 | X-Cache-Status: MISS 115 | --- response_body_like: root 116 | --- timeout: 10 117 | --- no_error_log eval 118 | qr/\[(warn|error|crit|alert|emerg)\]/ 119 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 120 | 121 | 122 | 123 | === TEST 6: get from cache 124 | --- http_config eval: $::http_config 125 | --- config eval: $::config 126 | --- request 127 | GET /proxy/passwd 128 | --- error_code: 200 129 | --- response_headers 130 | Content-Type: text/plain 131 | X-Cache-Status: HIT 132 | --- response_body_like: root 133 | --- timeout: 10 134 | --- no_error_log eval 135 | qr/\[(warn|error|crit|alert|emerg)\]/ 136 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 137 | -------------------------------------------------------------------------------- /t/proxy1_vars.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 4 + 3 * 1); 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | set $cache test_cache; 17 | 18 | location /proxy { 19 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 20 | proxy_cache $cache; 21 | proxy_cache_key $uri$is_args$args; 22 | proxy_cache_valid 3m; 23 | add_header X-Cache-Status $upstream_cache_status; 24 | } 25 | 26 | location ~ /purge(/.*) { 27 | proxy_cache_purge $cache $1$is_args$args; 28 | } 29 | 30 | location = /etc/passwd { 31 | root /; 32 | } 33 | _EOC_ 34 | 35 | worker_connections(128); 36 | no_shuffle(); 37 | run_tests(); 38 | 39 | no_diff(); 40 | 41 | __DATA__ 42 | 43 | === TEST 1: prepare 44 | --- http_config eval: $::http_config 45 | --- config eval: $::config 46 | --- request 47 | GET /proxy/passwd 48 | --- error_code: 200 49 | --- response_headers 50 | Content-Type: text/plain 51 | --- response_body_like: root 52 | --- timeout: 10 53 | --- no_error_log eval 54 | qr/\[(warn|error|crit|alert|emerg)\]/ 55 | --- skip_nginx: 4: < 1.7.9 56 | 57 | 58 | 59 | === TEST 2: get from cache 60 | --- http_config eval: $::http_config 61 | --- config eval: $::config 62 | --- request 63 | GET /proxy/passwd 64 | --- error_code: 200 65 | --- response_headers 66 | Content-Type: text/plain 67 | X-Cache-Status: HIT 68 | --- response_body_like: root 69 | --- timeout: 10 70 | --- no_error_log eval 71 | qr/\[(warn|error|crit|alert|emerg)\]/ 72 | --- skip_nginx: 5: < 1.7.9 73 | 74 | 75 | 76 | === TEST 3: purge from cache 77 | --- http_config eval: $::http_config 78 | --- config eval: $::config 79 | --- request 80 | PURGE /purge/proxy/passwd 81 | --- error_code: 200 82 | --- response_headers 83 | Content-Type: text/html 84 | --- response_body_like: Successful purge 85 | --- timeout: 10 86 | --- no_error_log eval 87 | qr/\[(warn|error|crit|alert|emerg)\]/ 88 | --- skip_nginx: 4: < 1.7.9 89 | 90 | 91 | 92 | === TEST 4: purge from empty cache 93 | --- http_config eval: $::http_config 94 | --- config eval: $::config 95 | --- request 96 | PURGE /purge/proxy/passwd 97 | --- error_code: 412 98 | --- response_headers 99 | Content-Type: text/html 100 | --- response_body_like: 412 Precondition Failed 101 | --- timeout: 10 102 | --- no_error_log eval 103 | qr/\[(warn|error|crit|alert|emerg)\]/ 104 | --- skip_nginx: 4: < 1.7.9 105 | 106 | 107 | 108 | === TEST 5: get from source 109 | --- http_config eval: $::http_config 110 | --- config eval: $::config 111 | --- request 112 | GET /proxy/passwd 113 | --- error_code: 200 114 | --- response_headers 115 | Content-Type: text/plain 116 | X-Cache-Status: MISS 117 | --- response_body_like: root 118 | --- timeout: 10 119 | --- no_error_log eval 120 | qr/\[(warn|error|crit|alert|emerg)\]/ 121 | --- skip_nginx: 5: < 1.7.9 122 | 123 | 124 | 125 | === TEST 6: get from cache 126 | --- http_config eval: $::http_config 127 | --- config eval: $::config 128 | --- request 129 | GET /proxy/passwd 130 | --- error_code: 200 131 | --- response_headers 132 | Content-Type: text/plain 133 | X-Cache-Status: HIT 134 | --- response_body_like: root 135 | --- timeout: 10 136 | --- no_error_log eval 137 | qr/\[(warn|error|crit|alert|emerg)\]/ 138 | --- skip_nginx: 5: < 1.7.9 139 | -------------------------------------------------------------------------------- /t/proxy2.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 4 + 6 * 1); 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | proxy_cache_purge on; 17 | 18 | location /proxy { 19 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 20 | proxy_cache test_cache; 21 | proxy_cache_key $uri$is_args$args; 22 | proxy_cache_valid 3m; 23 | add_header X-Cache-Status $upstream_cache_status; 24 | 25 | if ($uri) { } 26 | } 27 | 28 | location = /etc/passwd { 29 | root /; 30 | } 31 | _EOC_ 32 | 33 | our $config_allowed = <<'_EOC_'; 34 | proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 35 | 36 | location /proxy { 37 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 38 | proxy_cache test_cache; 39 | proxy_cache_key $uri$is_args$args; 40 | proxy_cache_valid 3m; 41 | add_header X-Cache-Status $upstream_cache_status; 42 | } 43 | 44 | location = /etc/passwd { 45 | root /; 46 | } 47 | _EOC_ 48 | 49 | our $config_forbidden = <<'_EOC_'; 50 | proxy_cache_purge PURGE from 1.0.0.0/8; 51 | 52 | location /proxy { 53 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 54 | proxy_cache test_cache; 55 | proxy_cache_key $uri$is_args$args; 56 | proxy_cache_valid 3m; 57 | add_header X-Cache-Status $upstream_cache_status; 58 | } 59 | 60 | location = /etc/passwd { 61 | root /; 62 | } 63 | _EOC_ 64 | 65 | worker_connections(128); 66 | no_shuffle(); 67 | run_tests(); 68 | 69 | no_diff(); 70 | 71 | __DATA__ 72 | 73 | === TEST 1: prepare 74 | --- http_config eval: $::http_config 75 | --- config eval: $::config 76 | --- request 77 | GET /proxy/passwd 78 | --- error_code: 200 79 | --- response_headers 80 | Content-Type: text/plain 81 | --- response_body_like: root 82 | --- timeout: 10 83 | --- no_error_log eval 84 | qr/\[(warn|error|crit|alert|emerg)\]/ 85 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 86 | 87 | 88 | 89 | === TEST 2: get from cache 90 | --- http_config eval: $::http_config 91 | --- config eval: $::config 92 | --- request 93 | GET /proxy/passwd 94 | --- error_code: 200 95 | --- response_headers 96 | Content-Type: text/plain 97 | X-Cache-Status: HIT 98 | --- response_body_like: root 99 | --- timeout: 10 100 | --- no_error_log eval 101 | qr/\[(warn|error|crit|alert|emerg)\]/ 102 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 103 | 104 | 105 | 106 | === TEST 3: purge from cache 107 | --- http_config eval: $::http_config 108 | --- config eval: $::config 109 | --- request 110 | PURGE /proxy/passwd 111 | --- error_code: 200 112 | --- response_headers 113 | Content-Type: text/html 114 | --- response_body_like: Successful purge 115 | --- timeout: 10 116 | --- no_error_log eval 117 | qr/\[(warn|error|crit|alert|emerg)\]/ 118 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 119 | 120 | 121 | 122 | === TEST 4: purge from empty cache 123 | --- http_config eval: $::http_config 124 | --- config eval: $::config 125 | --- request 126 | PURGE /proxy/passwd 127 | --- error_code: 412 128 | --- response_headers 129 | Content-Type: text/html 130 | --- response_body_like: 412 Precondition Failed 131 | --- timeout: 10 132 | --- no_error_log eval 133 | qr/\[(warn|error|crit|alert|emerg)\]/ 134 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 135 | 136 | 137 | 138 | === TEST 5: get from source 139 | --- http_config eval: $::http_config 140 | --- config eval: $::config 141 | --- request 142 | GET /proxy/passwd 143 | --- error_code: 200 144 | --- response_headers 145 | Content-Type: text/plain 146 | X-Cache-Status: MISS 147 | --- response_body_like: root 148 | --- timeout: 10 149 | --- no_error_log eval 150 | qr/\[(warn|error|crit|alert|emerg)\]/ 151 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 152 | 153 | 154 | 155 | === TEST 6: get from cache 156 | --- http_config eval: $::http_config 157 | --- config eval: $::config 158 | --- request 159 | GET /proxy/passwd 160 | --- error_code: 200 161 | --- response_headers 162 | Content-Type: text/plain 163 | X-Cache-Status: HIT 164 | --- response_body_like: root 165 | --- timeout: 10 166 | --- no_error_log eval 167 | qr/\[(warn|error|crit|alert|emerg)\]/ 168 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 169 | 170 | 171 | 172 | === TEST 7: purge from cache (PURGE allowed) 173 | --- http_config eval: $::http_config 174 | --- config eval: $::config_allowed 175 | --- request 176 | PURGE /proxy/passwd 177 | --- error_code: 200 178 | --- response_headers 179 | Content-Type: text/html 180 | --- response_body_like: Successful purge 181 | --- timeout: 10 182 | --- no_error_log eval 183 | qr/\[(warn|error|crit|alert|emerg)\]/ 184 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 185 | 186 | 187 | 188 | === TEST 8: purge from empty cache (PURGE allowed) 189 | --- http_config eval: $::http_config 190 | --- config eval: $::config_allowed 191 | --- request 192 | PURGE /proxy/passwd 193 | --- error_code: 412 194 | --- response_headers 195 | Content-Type: text/html 196 | --- response_body_like: 412 Precondition Failed 197 | --- timeout: 10 198 | --- no_error_log eval 199 | qr/\[(warn|error|crit|alert|emerg)\]/ 200 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 201 | 202 | 203 | 204 | === TEST 9: get from source (PURGE allowed) 205 | --- http_config eval: $::http_config 206 | --- config eval: $::config_allowed 207 | --- request 208 | GET /proxy/passwd 209 | --- error_code: 200 210 | --- response_headers 211 | Content-Type: text/plain 212 | X-Cache-Status: MISS 213 | --- response_body_like: root 214 | --- timeout: 10 215 | --- no_error_log eval 216 | qr/\[(warn|error|crit|alert|emerg)\]/ 217 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 218 | 219 | 220 | 221 | === TEST 10: get from cache (PURGE allowed) 222 | --- http_config eval: $::http_config 223 | --- config eval: $::config_allowed 224 | --- request 225 | GET /proxy/passwd 226 | --- error_code: 200 227 | --- response_headers 228 | Content-Type: text/plain 229 | X-Cache-Status: HIT 230 | --- response_body_like: root 231 | --- timeout: 10 232 | --- no_error_log eval 233 | qr/\[(warn|error|crit|alert|emerg)\]/ 234 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 235 | 236 | 237 | 238 | === TEST 11: purge from cache (PURGE not allowed) 239 | --- http_config eval: $::http_config 240 | --- config eval: $::config_forbidden 241 | --- request 242 | PURGE /proxy/passwd 243 | --- error_code: 403 244 | --- response_headers 245 | Content-Type: text/html 246 | --- response_body_like: 403 Forbidden 247 | --- timeout: 10 248 | --- no_error_log eval 249 | qr/\[(warn|error|crit|alert|emerg)\]/ 250 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 251 | 252 | 253 | 254 | === TEST 12: get from cache (PURGE not allowed) 255 | --- http_config eval: $::http_config 256 | --- config eval: $::config_forbidden 257 | --- request 258 | GET /proxy/passwd 259 | --- error_code: 200 260 | --- response_headers 261 | Content-Type: text/plain 262 | X-Cache-Status: HIT 263 | --- response_body_like: root 264 | --- timeout: 10 265 | --- no_error_log eval 266 | qr/\[(warn|error|crit|alert|emerg)\]/ 267 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 268 | 269 | 270 | 271 | === TEST 13: no cache (PURGE allowed) 272 | --- http_config eval: $::http_config 273 | --- config 274 | proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 275 | 276 | location /proxy { 277 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 278 | } 279 | 280 | location = /etc/passwd { 281 | root /; 282 | } 283 | --- request 284 | PURGE /proxy/passwd 285 | --- error_code: 404 286 | --- response_headers 287 | Content-Type: text/html 288 | --- response_body_like: 404 Not Found 289 | --- timeout: 10 290 | --- no_error_log eval 291 | qr/\[(warn|error|crit|alert|emerg)\]/ 292 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 293 | 294 | 295 | 296 | === TEST 14: no cache (PURGE not allowed) 297 | --- http_config eval: $::http_config 298 | --- config 299 | proxy_cache_purge PURGE from 1.0.0.0/8; 300 | 301 | location /proxy { 302 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 303 | } 304 | 305 | location = /etc/passwd { 306 | root /; 307 | } 308 | --- request 309 | PURGE /proxy/passwd 310 | --- error_code: 403 311 | --- response_headers 312 | Content-Type: text/html 313 | --- response_body_like: 403 Forbidden 314 | --- timeout: 10 315 | --- no_error_log eval 316 | qr/\[(warn|error|crit|alert|emerg)\]/ 317 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 318 | 319 | 320 | 321 | === TEST 15: multiple cache purge directives 322 | --- http_config eval: $::http_config 323 | --- config 324 | fastcgi_cache_purge on; 325 | proxy_cache_purge on; 326 | 327 | location /proxy { 328 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 329 | proxy_cache test_cache; 330 | proxy_cache_key $uri$is_args$args; 331 | proxy_cache_valid 3m; 332 | add_header X-Cache-Status $upstream_cache_status; 333 | 334 | if ($uri) { } 335 | } 336 | 337 | location = /etc/passwd { 338 | root /; 339 | } 340 | --- request 341 | PURGE /proxy/passwd 342 | --- error_code: 200 343 | --- response_headers 344 | Content-Type: text/html 345 | --- response_body_like: Successful purge 346 | --- timeout: 10 347 | --- no_error_log eval 348 | qr/\[(warn|error|crit|alert|emerg)\]/ 349 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 350 | -------------------------------------------------------------------------------- /t/proxy2_vars.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 4 + 6 * 1); 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | proxy_cache_purge on; 17 | set $cache test_cache; 18 | 19 | location /proxy { 20 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 21 | proxy_cache $cache; 22 | proxy_cache_key $uri$is_args$args; 23 | proxy_cache_valid 3m; 24 | add_header X-Cache-Status $upstream_cache_status; 25 | 26 | if ($uri) { } 27 | } 28 | 29 | location = /etc/passwd { 30 | root /; 31 | } 32 | _EOC_ 33 | 34 | our $config_allowed = <<'_EOC_'; 35 | proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 36 | set $cache test_cache; 37 | 38 | location /proxy { 39 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 40 | proxy_cache $cache; 41 | proxy_cache_key $uri$is_args$args; 42 | proxy_cache_valid 3m; 43 | add_header X-Cache-Status $upstream_cache_status; 44 | } 45 | 46 | location = /etc/passwd { 47 | root /; 48 | } 49 | _EOC_ 50 | 51 | our $config_forbidden = <<'_EOC_'; 52 | proxy_cache_purge PURGE from 1.0.0.0/8; 53 | set $cache test_cache; 54 | 55 | location /proxy { 56 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 57 | proxy_cache $cache; 58 | proxy_cache_key $uri$is_args$args; 59 | proxy_cache_valid 3m; 60 | add_header X-Cache-Status $upstream_cache_status; 61 | } 62 | 63 | location = /etc/passwd { 64 | root /; 65 | } 66 | _EOC_ 67 | 68 | worker_connections(128); 69 | no_shuffle(); 70 | run_tests(); 71 | 72 | no_diff(); 73 | 74 | __DATA__ 75 | 76 | === TEST 1: prepare 77 | --- http_config eval: $::http_config 78 | --- config eval: $::config 79 | --- request 80 | GET /proxy/passwd 81 | --- error_code: 200 82 | --- response_headers 83 | Content-Type: text/plain 84 | --- response_body_like: root 85 | --- timeout: 10 86 | --- no_error_log eval 87 | qr/\[(warn|error|crit|alert|emerg)\]/ 88 | --- skip_nginx: 4: < 1.7.9 89 | 90 | 91 | 92 | === TEST 2: get from cache 93 | --- http_config eval: $::http_config 94 | --- config eval: $::config 95 | --- request 96 | GET /proxy/passwd 97 | --- error_code: 200 98 | --- response_headers 99 | Content-Type: text/plain 100 | X-Cache-Status: HIT 101 | --- response_body_like: root 102 | --- timeout: 10 103 | --- no_error_log eval 104 | qr/\[(warn|error|crit|alert|emerg)\]/ 105 | --- skip_nginx: 5: < 1.7.9 106 | 107 | 108 | 109 | === TEST 3: purge from cache 110 | --- http_config eval: $::http_config 111 | --- config eval: $::config 112 | --- request 113 | PURGE /proxy/passwd 114 | --- error_code: 200 115 | --- response_headers 116 | Content-Type: text/html 117 | --- response_body_like: Successful purge 118 | --- timeout: 10 119 | --- no_error_log eval 120 | qr/\[(warn|error|crit|alert|emerg)\]/ 121 | --- skip_nginx: 4: < 1.7.9 122 | 123 | 124 | 125 | === TEST 4: purge from empty cache 126 | --- http_config eval: $::http_config 127 | --- config eval: $::config 128 | --- request 129 | PURGE /proxy/passwd 130 | --- error_code: 412 131 | --- response_headers 132 | Content-Type: text/html 133 | --- response_body_like: 412 Precondition Failed 134 | --- timeout: 10 135 | --- no_error_log eval 136 | qr/\[(warn|error|crit|alert|emerg)\]/ 137 | --- skip_nginx: 4: < 1.7.9 138 | 139 | 140 | 141 | === TEST 5: get from source 142 | --- http_config eval: $::http_config 143 | --- config eval: $::config 144 | --- request 145 | GET /proxy/passwd 146 | --- error_code: 200 147 | --- response_headers 148 | Content-Type: text/plain 149 | X-Cache-Status: MISS 150 | --- response_body_like: root 151 | --- timeout: 10 152 | --- no_error_log eval 153 | qr/\[(warn|error|crit|alert|emerg)\]/ 154 | --- skip_nginx: 5: < 1.7.9 155 | 156 | 157 | 158 | === TEST 6: get from cache 159 | --- http_config eval: $::http_config 160 | --- config eval: $::config 161 | --- request 162 | GET /proxy/passwd 163 | --- error_code: 200 164 | --- response_headers 165 | Content-Type: text/plain 166 | X-Cache-Status: HIT 167 | --- response_body_like: root 168 | --- timeout: 10 169 | --- no_error_log eval 170 | qr/\[(warn|error|crit|alert|emerg)\]/ 171 | --- skip_nginx: 5: < 1.7.9 172 | 173 | 174 | 175 | === TEST 7: purge from cache (PURGE allowed) 176 | --- http_config eval: $::http_config 177 | --- config eval: $::config_allowed 178 | --- request 179 | PURGE /proxy/passwd 180 | --- error_code: 200 181 | --- response_headers 182 | Content-Type: text/html 183 | --- response_body_like: Successful purge 184 | --- timeout: 10 185 | --- no_error_log eval 186 | qr/\[(warn|error|crit|alert|emerg)\]/ 187 | --- skip_nginx: 4: < 1.7.9 188 | 189 | 190 | 191 | === TEST 8: purge from empty cache (PURGE allowed) 192 | --- http_config eval: $::http_config 193 | --- config eval: $::config_allowed 194 | --- request 195 | PURGE /proxy/passwd 196 | --- error_code: 412 197 | --- response_headers 198 | Content-Type: text/html 199 | --- response_body_like: 412 Precondition Failed 200 | --- timeout: 10 201 | --- no_error_log eval 202 | qr/\[(warn|error|crit|alert|emerg)\]/ 203 | --- skip_nginx: 4: < 1.7.9 204 | 205 | 206 | 207 | === TEST 9: get from source (PURGE allowed) 208 | --- http_config eval: $::http_config 209 | --- config eval: $::config_allowed 210 | --- request 211 | GET /proxy/passwd 212 | --- error_code: 200 213 | --- response_headers 214 | Content-Type: text/plain 215 | X-Cache-Status: MISS 216 | --- response_body_like: root 217 | --- timeout: 10 218 | --- no_error_log eval 219 | qr/\[(warn|error|crit|alert|emerg)\]/ 220 | --- skip_nginx: 5: < 1.7.9 221 | 222 | 223 | 224 | === TEST 10: get from cache (PURGE allowed) 225 | --- http_config eval: $::http_config 226 | --- config eval: $::config_allowed 227 | --- request 228 | GET /proxy/passwd 229 | --- error_code: 200 230 | --- response_headers 231 | Content-Type: text/plain 232 | X-Cache-Status: HIT 233 | --- response_body_like: root 234 | --- timeout: 10 235 | --- no_error_log eval 236 | qr/\[(warn|error|crit|alert|emerg)\]/ 237 | --- skip_nginx: 5: < 1.7.9 238 | 239 | 240 | 241 | === TEST 11: purge from cache (PURGE not allowed) 242 | --- http_config eval: $::http_config 243 | --- config eval: $::config_forbidden 244 | --- request 245 | PURGE /proxy/passwd 246 | --- error_code: 403 247 | --- response_headers 248 | Content-Type: text/html 249 | --- response_body_like: 403 Forbidden 250 | --- timeout: 10 251 | --- no_error_log eval 252 | qr/\[(warn|error|crit|alert|emerg)\]/ 253 | --- skip_nginx: 4: < 1.7.9 254 | 255 | 256 | 257 | === TEST 12: get from cache (PURGE not allowed) 258 | --- http_config eval: $::http_config 259 | --- config eval: $::config_forbidden 260 | --- request 261 | GET /proxy/passwd 262 | --- error_code: 200 263 | --- response_headers 264 | Content-Type: text/plain 265 | X-Cache-Status: HIT 266 | --- response_body_like: root 267 | --- timeout: 10 268 | --- no_error_log eval 269 | qr/\[(warn|error|crit|alert|emerg)\]/ 270 | --- skip_nginx: 5: < 1.7.9 271 | 272 | 273 | 274 | === TEST 13: no cache (PURGE allowed) 275 | --- http_config eval: $::http_config 276 | --- config 277 | proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 278 | 279 | location /proxy { 280 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 281 | } 282 | 283 | location = /etc/passwd { 284 | root /; 285 | } 286 | --- request 287 | PURGE /proxy/passwd 288 | --- error_code: 404 289 | --- response_headers 290 | Content-Type: text/html 291 | --- response_body_like: 404 Not Found 292 | --- timeout: 10 293 | --- no_error_log eval 294 | qr/\[(warn|error|crit|alert|emerg)\]/ 295 | --- skip_nginx: 4: < 1.7.9 296 | 297 | 298 | 299 | === TEST 14: no cache (PURGE not allowed) 300 | --- http_config eval: $::http_config 301 | --- config 302 | proxy_cache_purge PURGE from 1.0.0.0/8; 303 | 304 | location /proxy { 305 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 306 | } 307 | 308 | location = /etc/passwd { 309 | root /; 310 | } 311 | --- request 312 | PURGE /proxy/passwd 313 | --- error_code: 403 314 | --- response_headers 315 | Content-Type: text/html 316 | --- response_body_like: 403 Forbidden 317 | --- timeout: 10 318 | --- no_error_log eval 319 | qr/\[(warn|error|crit|alert|emerg)\]/ 320 | --- skip_nginx: 4: < 1.7.9 321 | 322 | 323 | 324 | === TEST 15: multiple cache purge directives 325 | --- http_config eval: $::http_config 326 | --- config 327 | fastcgi_cache_purge on; 328 | proxy_cache_purge on; 329 | set $cache test_cache; 330 | 331 | location /proxy { 332 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 333 | proxy_cache $cache; 334 | proxy_cache_key $uri$is_args$args; 335 | proxy_cache_valid 3m; 336 | add_header X-Cache-Status $upstream_cache_status; 337 | 338 | if ($uri) { } 339 | } 340 | 341 | location = /etc/passwd { 342 | root /; 343 | } 344 | --- request 345 | PURGE /proxy/passwd 346 | --- error_code: 200 347 | --- response_headers 348 | Content-Type: text/html 349 | --- response_body_like: Successful purge 350 | --- timeout: 10 351 | --- no_error_log eval 352 | qr/\[(warn|error|crit|alert|emerg)\]/ 353 | --- skip_nginx: 4: < 1.7.9 354 | -------------------------------------------------------------------------------- /t/proxy3.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => 32; 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | location /proxy { 17 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 18 | proxy_cache test_cache; 19 | proxy_cache_key $uri$is_args$args; 20 | proxy_cache_valid 3m; 21 | add_header X-Cache-Status $upstream_cache_status; 22 | 23 | proxy_cache_purge PURGE purge_all from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 24 | } 25 | 26 | 27 | location = /etc/passwd { 28 | root /; 29 | } 30 | _EOC_ 31 | 32 | worker_connections(128); 33 | no_shuffle(); 34 | run_tests(); 35 | 36 | no_diff(); 37 | 38 | __DATA__ 39 | 40 | === TEST 1: prepare passwd 41 | --- http_config eval: $::http_config 42 | --- config eval: $::config 43 | --- request 44 | GET /proxy/passwd 45 | --- error_code: 200 46 | --- response_headers 47 | Content-Type: text/plain 48 | --- response_body_like: root 49 | --- timeout: 10 50 | --- no_error_log eval 51 | qr/\[(warn|error|crit|alert|emerg)\]/ 52 | 53 | 54 | === TEST 2: prepare shadow 55 | --- http_config eval: $::http_config 56 | --- config eval: $::config 57 | --- request 58 | GET /proxy/shadow 59 | --- error_code: 200 60 | --- response_headers 61 | Content-Type: text/plain 62 | --- response_body_like: root 63 | --- timeout: 10 64 | --- no_error_log eval 65 | qr/\[(warn|error|crit|alert|emerg)\]/ 66 | 67 | 68 | 69 | === TEST 3: get from cache passwd 70 | --- http_config eval: $::http_config 71 | --- config eval: $::config 72 | --- request 73 | GET /proxy/passwd 74 | --- error_code: 200 75 | --- response_headers 76 | Content-Type: text/plain 77 | X-Cache-Status: HIT 78 | --- response_body_like: root 79 | --- timeout: 10 80 | --- no_error_log eval 81 | qr/\[(warn|error|crit|alert|emerg)\]/ 82 | 83 | 84 | === TEST 4: get from cache shadow 85 | --- http_config eval: $::http_config 86 | --- config eval: $::config 87 | --- request 88 | GET /proxy/shadow 89 | --- error_code: 200 90 | --- response_headers 91 | Content-Type: text/plain 92 | X-Cache-Status: HIT 93 | --- response_body_like: root 94 | --- timeout: 10 95 | --- no_error_log eval 96 | qr/\[(warn|error|crit|alert|emerg)\]/ 97 | 98 | 99 | === TEST 5: purge from cache 100 | --- http_config eval: $::http_config 101 | --- config eval: $::config 102 | --- request 103 | PURGE /proxy/any 104 | --- error_code: 200 105 | --- response_headers 106 | Content-Type: text/html 107 | --- response_body_like: Successful purge 108 | --- timeout: 10 109 | --- no_error_log eval 110 | qr/\[(warn|error|crit|alert|emerg)\]/ 111 | 112 | 113 | === TEST 6: get from empty cache passwd 114 | --- http_config eval: $::http_config 115 | --- config eval: $::config 116 | --- request 117 | GET /proxy/passwd 118 | --- error_code: 200 119 | --- response_headers 120 | Content-Type: text/plain 121 | X-Cache-Status: MISS 122 | --- response_body_like: root 123 | --- timeout: 10 124 | --- no_error_log eval 125 | qr/\[(warn|error|crit|alert|emerg)\]/ 126 | 127 | 128 | === TEST 7: get from empty cache shadow 129 | --- http_config eval: $::http_config 130 | --- config eval: $::config 131 | --- request 132 | GET /proxy/shadow 133 | --- error_code: 200 134 | --- response_headers 135 | Content-Type: text/plain 136 | X-Cache-Status: MISS 137 | --- response_body_like: root 138 | --- timeout: 10 139 | --- no_error_log eval 140 | qr/\[(warn|error|crit|alert|emerg)\]/ 141 | -------------------------------------------------------------------------------- /t/proxy4.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => 41; 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | location /proxy { 17 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 18 | proxy_cache test_cache; 19 | proxy_cache_key $uri$is_args$args; 20 | proxy_cache_valid 3m; 21 | add_header X-Cache-Status $upstream_cache_status; 22 | 23 | proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; 24 | } 25 | 26 | 27 | location = /etc/passwd { 28 | root /; 29 | } 30 | _EOC_ 31 | 32 | worker_connections(128); 33 | no_shuffle(); 34 | run_tests(); 35 | 36 | no_diff(); 37 | 38 | __DATA__ 39 | 40 | === TEST 1: prepare passwd 41 | --- http_config eval: $::http_config 42 | --- config eval: $::config 43 | --- request 44 | GET /proxy/passwd 45 | --- error_code: 200 46 | --- response_headers 47 | Content-Type: text/plain 48 | --- response_body_like: root 49 | --- timeout: 10 50 | --- no_error_log eval 51 | qr/\[(warn|error|crit|alert|emerg)\]/ 52 | 53 | 54 | === TEST 2: prepare passwd2 55 | --- http_config eval: $::http_config 56 | --- config eval: $::config 57 | --- request 58 | GET /proxy/passwd2 59 | --- error_code: 200 60 | --- response_headers 61 | Content-Type: text/plain 62 | --- response_body_like: root 63 | --- timeout: 10 64 | --- no_error_log eval 65 | qr/\[(warn|error|crit|alert|emerg)\]/ 66 | 67 | 68 | === TEST 3: prepare shadow 69 | --- http_config eval: $::http_config 70 | --- config eval: $::config 71 | --- request 72 | GET /proxy/shadow 73 | --- error_code: 200 74 | --- response_headers 75 | Content-Type: text/plain 76 | --- response_body_like: root 77 | --- timeout: 10 78 | --- no_error_log eval 79 | qr/\[(warn|error|crit|alert|emerg)\]/ 80 | 81 | 82 | === TEST 4: get from cache passwd 83 | --- http_config eval: $::http_config 84 | --- config eval: $::config 85 | --- request 86 | GET /proxy/passwd 87 | --- error_code: 200 88 | --- response_headers 89 | Content-Type: text/plain 90 | X-Cache-Status: HIT 91 | --- response_body_like: root 92 | --- timeout: 10 93 | --- no_error_log eval 94 | qr/\[(warn|error|crit|alert|emerg)\]/ 95 | 96 | 97 | === TEST 5: get from cache passwd2 98 | --- http_config eval: $::http_config 99 | --- config eval: $::config 100 | --- request 101 | GET /proxy/passwd2 102 | --- error_code: 200 103 | --- response_headers 104 | Content-Type: text/plain 105 | X-Cache-Status: HIT 106 | --- response_body_like: root 107 | --- timeout: 10 108 | --- no_error_log eval 109 | qr/\[(warn|error|crit|alert|emerg)\]/ 110 | 111 | 112 | === TEST 6: purge from cache 113 | --- http_config eval: $::http_config 114 | --- config eval: $::config 115 | --- request 116 | PURGE /proxy/pass* 117 | --- error_code: 200 118 | --- response_headers 119 | Content-Type: text/html 120 | --- response_body_like: Successful purge 121 | --- timeout: 10 122 | --- no_error_log eval 123 | qr/\[(warn|error|crit|alert|emerg)\]/ 124 | 125 | 126 | === TEST 7: get from empty cache passwd 127 | --- http_config eval: $::http_config 128 | --- config eval: $::config 129 | --- request 130 | GET /proxy/passwd 131 | --- error_code: 200 132 | --- response_headers 133 | Content-Type: text/plain 134 | X-Cache-Status: MISS 135 | --- response_body_like: root 136 | --- timeout: 10 137 | --- no_error_log eval 138 | qr/\[(warn|error|crit|alert|emerg)\]/ 139 | 140 | 141 | === TEST 8: get from empty cache passwd2 142 | --- http_config eval: $::http_config 143 | --- config eval: $::config 144 | --- request 145 | GET /proxy/passwd2 146 | --- error_code: 200 147 | --- response_headers 148 | Content-Type: text/plain 149 | X-Cache-Status: MISS 150 | --- response_body_like: root 151 | --- timeout: 10 152 | --- no_error_log eval 153 | qr/\[(warn|error|crit|alert|emerg)\]/ 154 | 155 | 156 | === TEST 9: get from cache shadow 157 | --- http_config eval: $::http_config 158 | --- config eval: $::config 159 | --- request 160 | GET /proxy/shadow 161 | --- error_code: 200 162 | --- response_headers 163 | Content-Type: text/plain 164 | X-Cache-Status: HIT 165 | --- response_body_like: root 166 | --- timeout: 10 167 | --- no_error_log eval 168 | qr/\[(warn|error|crit|alert|emerg)\]/ 169 | -------------------------------------------------------------------------------- /t/resptype1.t: -------------------------------------------------------------------------------- 1 | # vi:filetype=perl 2 | 3 | use lib 'lib'; 4 | use Test::Nginx::Socket; 5 | 6 | repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 4 + 3 * 1); 9 | 10 | our $http_config = <<'_EOC_'; 11 | proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; 12 | proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; 13 | _EOC_ 14 | 15 | our $config = <<'_EOC_'; 16 | 17 | cache_purge_response_type json; 18 | 19 | location /proxy { 20 | proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; 21 | proxy_cache test_cache; 22 | proxy_cache_key $uri$is_args$args; 23 | proxy_cache_valid 3m; 24 | add_header X-Cache-Status $upstream_cache_status; 25 | } 26 | 27 | location ~ /purge(/.*) { 28 | proxy_cache_purge test_cache $1$is_args$args; 29 | cache_purge_response_type html; 30 | } 31 | 32 | location ~ /purge_json(/.*) { 33 | proxy_cache_purge test_cache $1$is_args$args; 34 | } 35 | 36 | location ~ /purge_xml(/.*) { 37 | proxy_cache_purge test_cache $1$is_args$args; 38 | cache_purge_response_type xml; 39 | } 40 | 41 | location ~ /purge_text(/.*) { 42 | proxy_cache_purge test_cache $1$is_args$args; 43 | cache_purge_response_type text; 44 | } 45 | 46 | 47 | 48 | location = /etc/passwd { 49 | root /; 50 | } 51 | _EOC_ 52 | 53 | worker_connections(128); 54 | no_shuffle(); 55 | run_tests(); 56 | 57 | no_diff(); 58 | 59 | __DATA__ 60 | 61 | === TEST 1: prepare 62 | --- http_config eval: $::http_config 63 | --- config eval: $::config 64 | --- request 65 | GET /proxy/passwd 66 | --- error_code: 200 67 | --- response_headers 68 | Content-Type: text/plain 69 | --- response_body_like: root 70 | --- timeout: 10 71 | --- no_error_log eval 72 | qr/\[(warn|error|crit|alert|emerg)\]/ 73 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 74 | 75 | 76 | 77 | === TEST 2: get from cache 78 | --- http_config eval: $::http_config 79 | --- config eval: $::config 80 | --- request 81 | GET /proxy/passwd 82 | --- error_code: 200 83 | --- response_headers 84 | Content-Type: text/plain 85 | X-Cache-Status: HIT 86 | --- response_body_like: root 87 | --- timeout: 10 88 | --- no_error_log eval 89 | qr/\[(warn|error|crit|alert|emerg)\]/ 90 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 91 | 92 | 93 | 94 | === TEST 3: purge from cache 95 | --- http_config eval: $::http_config 96 | --- config eval: $::config 97 | --- request 98 | PURGE /purge/proxy/passwd 99 | --- error_code: 200 100 | --- response_headers 101 | Content-Type: text/html 102 | --- response_body_like: Successful purge 103 | --- timeout: 10 104 | --- no_error_log eval 105 | qr/\[(warn|error|crit|alert|emerg)\]/ 106 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 107 | 108 | 109 | 110 | === TEST 4: purge from empty cache 111 | --- http_config eval: $::http_config 112 | --- config eval: $::config 113 | --- request 114 | PURGE /purge/proxy/passwd 115 | --- error_code: 412 116 | --- response_headers 117 | Content-Type: text/html 118 | --- response_body_like: 412 Precondition Failed 119 | --- timeout: 10 120 | --- no_error_log eval 121 | qr/\[(warn|error|crit|alert|emerg)\]/ 122 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 123 | 124 | 125 | 126 | === TEST 5: get from source 127 | --- http_config eval: $::http_config 128 | --- config eval: $::config 129 | --- request 130 | GET /proxy/passwd 131 | --- error_code: 200 132 | --- response_headers 133 | Content-Type: text/plain 134 | X-Cache-Status: MISS 135 | --- response_body_like: root 136 | --- timeout: 10 137 | --- no_error_log eval 138 | qr/\[(warn|error|crit|alert|emerg)\]/ 139 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 140 | 141 | 142 | 143 | === TEST 6: get from cache 144 | --- http_config eval: $::http_config 145 | --- config eval: $::config 146 | --- request 147 | GET /proxy/passwd 148 | --- error_code: 200 149 | --- response_headers 150 | Content-Type: text/plain 151 | X-Cache-Status: HIT 152 | --- response_body_like: root 153 | --- timeout: 10 154 | --- no_error_log eval 155 | qr/\[(warn|error|crit|alert|emerg)\]/ 156 | --- skip_nginx2: 5: < 0.8.3 or < 0.7.62 157 | 158 | === TEST 7-prepare: prepare purge 159 | --- http_config eval: $::http_config 160 | --- config eval: $::config 161 | --- request 162 | GET /proxy/passwd?t=7 163 | --- error_code: 200 164 | --- response_headers 165 | Content-Type: text/plain 166 | --- response_body_like: root 167 | --- timeout: 10 168 | --- no_error_log eval 169 | qr/\[(warn|error|crit|alert|emerg)\]/ 170 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 171 | 172 | 173 | === TEST 7: get a JSON response after purge from cache 174 | --- http_config eval: $::http_config 175 | --- config eval: $::config 176 | --- request 177 | PURGE /purge_json/proxy/passwd?t=7 178 | --- error_code: 200 179 | --- response_headers 180 | Content-Type: application/json 181 | --- response_body_like: {\"Key\": \"\/proxy\/passwd\?t=7\" 182 | --- timeout: 10 183 | --- no_error_log eval 184 | qr/\[(warn|error|crit|alert|emerg)\]/ 185 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 186 | 187 | === TEST 8-prepare: prepare purge 188 | --- http_config eval: $::http_config 189 | --- config eval: $::config 190 | --- request 191 | GET /proxy/passwd?t=8 192 | --- error_code: 200 193 | --- response_headers 194 | Content-Type: text/plain 195 | --- response_body_like: root 196 | --- timeout: 10 197 | --- no_error_log eval 198 | qr/\[(warn|error|crit|alert|emerg)\]/ 199 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 200 | 201 | 202 | === TEST 8: get a XML response after purge from cache 203 | --- http_config eval: $::http_config 204 | --- config eval: $::config 205 | --- request 206 | PURGE /purge_xml/proxy/passwd?t=8 207 | --- error_code: 200 208 | --- response_headers 209 | Content-Type: text/xml 210 | --- response_body_like: \<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><\!\[CDATA\[\/proxy\/passwd\?t=8\]\]><\/Key> 211 | --- timeout: 10 212 | --- no_error_log eval 213 | qr/\[(warn|error|crit|alert|emerg)\]/ 214 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 215 | 216 | === TEST 9-prepare: prepare purge 217 | --- http_config eval: $::http_config 218 | --- config eval: $::config 219 | --- request 220 | GET /proxy/passwd?t=9 221 | --- error_code: 200 222 | --- response_headers 223 | Content-Type: text/plain 224 | --- response_body_like: root 225 | --- timeout: 10 226 | --- no_error_log eval 227 | qr/\[(warn|error|crit|alert|emerg)\]/ 228 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 229 | 230 | 231 | === TEST 9: get a TEXT response after purge from cache 232 | --- http_config eval: $::http_config 233 | --- config eval: $::config 234 | --- request 235 | PURGE /purge_text/proxy/passwd?t=9 236 | --- error_code: 200 237 | --- response_headers 238 | Content-Type: text/plain 239 | --- response_body_like: Key 240 | --- timeout: 10 241 | --- no_error_log eval 242 | qr/\[(warn|error|crit|alert|emerg)\]/ 243 | --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 244 | 245 | 246 | --------------------------------------------------------------------------------