├── .astylerc ├── .format.sh ├── .gitattributes ├── .travis.yml ├── CHANGES ├── LICENSE ├── README.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_PREFIX=/opt/nginx 16 | matrix: 17 | - NGINX_VERSION=1.18.0 18 | - NGINX_VERSION=1.19.2 19 | 20 | before_install: 21 | - mkdir --parents download-cache 22 | - sudo apt-get update -qq 23 | - sudo apt-get install -qq zlib1g-dev libpcre3-dev cpanminus 24 | # Get OpenSSL 1.0.2 from Ubuntu Xenial 25 | # https://packages.ubuntu.com/xenial-updates/libssl1.0.0 26 | - test -f download-cache/libssl1.0.0_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb" 27 | # https://packages.ubuntu.com/xenial/libssl-dev 28 | - test -f download-cache/libssl-dev_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb" 29 | - sudo dpkg -i download-cache/libssl*_amd64.deb 30 | # Test::Nginx 31 | - git clone https://github.com/openresty/test-nginx.git test-nginx 32 | - cd test-nginx/ && sudo cpanm . && cd .. 33 | # NGINX source 34 | - test -f download-cache/nginx-$NGINX_VERSION.tar.gz || wget -O download-cache/nginx-$NGINX_VERSION.tar.gz http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz 35 | 36 | install: 37 | - tar -xzf download-cache/nginx-${NGINX_VERSION}.tar.gz 38 | - cd nginx-${NGINX_VERSION}/ 39 | - ./configure --prefix=${NGINX_PREFIX} --with-debug --with-http_ssl_module --add-module=${PWD}/.. 40 | - make -j${JOBS} 41 | - sudo make install 42 | - cd .. 43 | - export PATH="${NGINX_PREFIX}/sbin:$PATH" 44 | # - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH} 45 | 46 | script: 47 | - nginx -V 48 | - ldd $(which nginx) 49 | - prove t 50 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2020-06-27 VERSION 2.5.1 2 | * fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz 3 | * fix: purge report calloc fix - Report template has not cache file path but it's length is use in buffer memory allocation, Tuğrul Topuz 4 | 5 | 2018-08-04 VERSION 2.5 6 | * feat/docs: cache_purge_response_type directive, selecting response type (html|json|xml|text) 7 | * break: changed status of HTTP code 404 (Not Found) to 412 (Precondition Failed) 8 | * fix: remove path information of response body (#4, 3a8c08a, #11) 9 | 10 | 2020-06-27 VERSION 2.4.3 11 | * fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz 12 | 13 | 2017-09-28 VERSION 2.4.2 14 | * fix: segfault in call to `ngx_read_file` of partial key purge, Frankie Dintino 15 | * fix: segfault in `cplcf->conf->purge_all` with separate location syntax, Frankie Dintino 16 | 17 | 2017-02-21 VERSION 2.4.1 18 | * Fix compatibility with nginx-1.11.6+, Sułowicz Paweł 19 | 20 | 2016-11-20 VERSION 2.4 21 | * Fix compatibility with nginx-1.7.12+. 22 | * explain the purge logic 23 | * feat(purge all): Include option to purge all the cached files 24 | This option can be slow if a lot of content is cached, or if the 25 | storage used for the cache is slow. But you really should be using 26 | RAM as your cache storage. 27 | * feat(partial keys): Support partial keys to purge multiple keys. 28 | Put an '*' at the end of your purge cache URL. 29 | e.g: 30 | proxy_cache_key $scheme$host$uri$is_args$args$cookie_JSESSIONID; 31 | curl -X PURGE https://example.com/pass* 32 | This will remove every cached page whose key cache starting with: 33 | httpsexample.com/pass* 34 | Be careful not passing any value for the values after the $uri, or put 35 | it at the end of your cache key. 36 | * Convert a config file to build a dynamic module 37 | 38 | 2014-12-23 VERSION 2.3 39 | * Fix compatibility with nginx-1.7.9+. 40 | 41 | 2014-12-02 VERSION 2.2 42 | * Fix compatibility with nginx-1.7.8+. 43 | 44 | 2014-05-19 45 | * Fix build on Solaris with SunCC (Solaris Studio). 46 | Reported by Jussi Sallinen. 47 | 48 | 2013-03-19 VERSION 2.1 49 | * When enabled, cache purge will now catch all requests with 50 | PURGE (or specified) method, even if cache isn't configured. 51 | Previously, it would pass such requests to the upstream. 52 | 53 | 2012-12-07 VERSION 2.0 54 | * Add alternative "same location" syntax. 55 | From CloudFlare. 56 | 57 | 2012-07-02 VERSION 1.6 58 | * Fix compatibility with nginx-1.3.2+. 59 | Reported by MagicBear, patch from Ruslan Ermilov. 60 | 61 | 2011-12-20 VERSION 1.5 62 | * Fix on-disk cache size calculation. 63 | Since the initial release, recorded on-disk cache size was 64 | decreased twice for purged content (once during cache purge 65 | and once during subsequent cache update). 66 | This resulted in recorded on-disk cache size being much 67 | smaller than in reality, which could lead to on-disk cache 68 | outgrowing defined "max_size" parameter. 69 | Patch from Pyry Hakulinen. 70 | 71 | 2011-10-05 VERSION 1.4 72 | * Add AIO support. 73 | Requested by Emin Hasanov. 74 | 75 | 2011-05-03 VERSION 1.3 76 | * Fix compatibility with nginx-1.0.1. 77 | Reported by Sergey A. Osokin and Markus Linnala. 78 | 79 | 2010-08-29 80 | * Fix compatibility with nginx-0.8.0 and versions older than 81 | nginx-0.7.60. 82 | 83 | 2010-08-11 VERSION 1.2 84 | * Fix various build scenarios with disabled upstream modules. 85 | Reported by Johan Bergstroem. 86 | 87 | * Add ability to purge content from SCGI's cache. 88 | Requested by Johan Bergstroem. 89 | 90 | 2010-06-08 VERSION 1.1 91 | * Fix compatibility with nginx-0.8.40+. 92 | 93 | * Add ability to purge content from uWSGI's cache. 94 | 95 | 2010-01-10 VERSION 1.0 96 | * Initial module release. 97 | 98 | 2009-11-17 99 | * Fix patch compatibility with nginx-0.8.11+. 100 | Reported by Bing Ran. 101 | 102 | 2009-08-11 103 | * Initial patch release. 104 | -------------------------------------------------------------------------------- /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 | Sample configuration (same location syntax) 118 | =========================================== 119 | http { 120 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 121 | 122 | server { 123 | location / { 124 | proxy_pass http://127.0.0.1:8000; 125 | proxy_cache tmpcache; 126 | proxy_cache_key "$uri$is_args$args"; 127 | proxy_cache_purge PURGE from 127.0.0.1; 128 | } 129 | } 130 | } 131 | 132 | 133 | Sample configuration (same location syntax - purge all cached files) 134 | ==================================================================== 135 | http { 136 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 137 | 138 | server { 139 | location / { 140 | proxy_pass http://127.0.0.1:8000; 141 | proxy_cache tmpcache; 142 | proxy_cache_key "$uri$is_args$args"; 143 | proxy_cache_purge PURGE purge_all from 127.0.0.1 192.168.0.0/8; 144 | } 145 | } 146 | } 147 | 148 | 149 | Sample configuration (separate location syntax) 150 | =============================================== 151 | http { 152 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 153 | 154 | server { 155 | location / { 156 | proxy_pass http://127.0.0.1:8000; 157 | proxy_cache tmpcache; 158 | proxy_cache_key "$uri$is_args$args"; 159 | } 160 | 161 | location ~ /purge(/.*) { 162 | allow 127.0.0.1; 163 | deny all; 164 | proxy_cache tmpcache; 165 | proxy_cache_key "$1$is_args$args"; 166 | } 167 | } 168 | } 169 | 170 | Sample configuration (Optional) 171 | =============================================== 172 | http { 173 | proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; 174 | 175 | cache_purge_response_type text; 176 | 177 | server { 178 | 179 | cache_purge_response_type json; 180 | 181 | location / { #json 182 | proxy_pass http://127.0.0.1:8000; 183 | proxy_cache tmpcache; 184 | proxy_cache_key "$uri$is_args$args"; 185 | } 186 | 187 | location ~ /purge(/.*) { #xml 188 | allow 127.0.0.1; 189 | deny all; 190 | proxy_cache tmpcache; 191 | proxy_cache_key "$1$is_args$args"; 192 | cache_purge_response_type xml; 193 | } 194 | 195 | location ~ /purge2(/.*) { # json 196 | allow 127.0.0.1; 197 | deny all; 198 | proxy_cache tmpcache; 199 | proxy_cache_key "$1$is_args$args"; 200 | } 201 | } 202 | 203 | server { 204 | 205 | location / { #text 206 | proxy_pass http://127.0.0.1:8000; 207 | proxy_cache tmpcache; 208 | proxy_cache_key "$uri$is_args$args"; 209 | } 210 | 211 | location ~ /purge(/.*) { #text 212 | allow 127.0.0.1; 213 | deny all; 214 | proxy_cache tmpcache; 215 | proxy_cache_key "$1$is_args$args"; 216 | } 217 | 218 | location ~ /purge2(/.*) { #html 219 | allow 127.0.0.1; 220 | deny all; 221 | proxy_cache tmpcache; 222 | proxy_cache_key "$1$is_args$args"; 223 | cache_purge_response_type html; 224 | } 225 | } 226 | } 227 | 228 | 229 | 230 | Solve problems 231 | ============== 232 | * Enabling [`gzip_vary`](https://nginx.org/r/gzip_vary) can lead to different results when clearing, when enabling it, you may have problems clearing the cache. For reliable operation, you can disable [`gzip_vary`](https://nginx.org/r/gzip_vary) inside the location [#20](https://github.com/nginx-modules/ngx_cache_purge/issues/20). 233 | 234 | 235 | Testing 236 | ======= 237 | `ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx). 238 | 239 | You can test it by running: 240 | 241 | `$ prove` 242 | 243 | 244 | License 245 | ======= 246 | Copyright (c) 2009-2014, FRiCKLE 247 | Copyright (c) 2009-2014, Piotr Sikora 248 | All rights reserved. 249 | 250 | This project was fully funded by yo.se. 251 | 252 | Redistribution and use in source and binary forms, with or without 253 | modification, are permitted provided that the following conditions 254 | are met: 255 | 1. Redistributions of source code must retain the above copyright 256 | notice, this list of conditions and the following disclaimer. 257 | 2. Redistributions in binary form must reproduce the above copyright 258 | notice, this list of conditions and the following disclaimer in the 259 | documentation and/or other materials provided with the distribution. 260 | 261 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 263 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 264 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 265 | HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 266 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 267 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 268 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 269 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 270 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 271 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272 | 273 | 274 | See also 275 | ======== 276 | - [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache). 277 | - http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#purger 278 | - http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache_purge 279 | - https://github.com/wandenberg/nginx-selective-cache-purge-module 280 | - https://github.com/wandenberg/nginx-sorted-querystring-module 281 | - https://github.com/ledgetech/ledge 282 | - [Faking Surrogate Cache-Keys for Nginx Plus](https://www.innoq.com/en/blog/faking-surrogate-cache-keys-for-nginx-plus/) ([gist](https://gist.github.com/titpetric/2f142e89eaa0f36ba4e4383b16d61474)) 283 | - [Delete NGINX cached md5 items with a PURGE with wildcard support](https://gist.github.com/nosun/0cfb58d3164f829e2f027fd37b338ede) 284 | -------------------------------------------------------------------------------- /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 | # if (nginx_version >= 1019003) 544 | ngx_array_t *cookie_flags; 545 | # endif /* nginx_version >= 1019003 */ 546 | # if (nginx_version < 1007008) 547 | ngx_str_t body_source; 548 | # endif /* nginx_version < 1007008 */ 549 | 550 | # if (nginx_version >= 1011006) 551 | ngx_http_complex_value_t *method; 552 | # else 553 | ngx_str_t method; 554 | # endif /* nginx_version >= 1011006 */ 555 | ngx_str_t location; 556 | ngx_str_t url; 557 | 558 | ngx_http_complex_value_t cache_key; 559 | 560 | ngx_http_proxy_vars_t vars; 561 | 562 | ngx_flag_t redirect; 563 | 564 | # if (nginx_version >= 1001004) 565 | ngx_uint_t http_version; 566 | # endif /* nginx_version >= 1001004 */ 567 | 568 | ngx_uint_t headers_hash_max_size; 569 | ngx_uint_t headers_hash_bucket_size; 570 | 571 | # if (NGX_HTTP_SSL) 572 | # if (nginx_version >= 1005006) 573 | ngx_uint_t ssl; 574 | ngx_uint_t ssl_protocols; 575 | ngx_str_t ssl_ciphers; 576 | # endif /* nginx_version >= 1005006 */ 577 | # if (nginx_version >= 1007000) 578 | ngx_uint_t ssl_verify_depth; 579 | ngx_str_t ssl_trusted_certificate; 580 | ngx_str_t ssl_crl; 581 | # endif /* nginx_version >= 1007000 */ 582 | # if ((nginx_version >= 1007008) && (nginx_version < 1021000)) 583 | ngx_str_t ssl_certificate; 584 | ngx_str_t ssl_certificate_key; 585 | ngx_array_t *ssl_passwords; 586 | # endif /* nginx_version >= 1007008 && nginx_version < 1021000 */ 587 | # if (nginx_version >= 1019004) 588 | ngx_array_t *ssl_conf_commands; 589 | # endif /*nginx_version >= 1019004 */ 590 | # endif 591 | } ngx_http_proxy_loc_conf_t; 592 | 593 | char * 594 | ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 595 | ngx_http_compile_complex_value_t ccv; 596 | ngx_http_cache_purge_loc_conf_t *cplcf; 597 | ngx_http_core_loc_conf_t *clcf; 598 | ngx_http_proxy_loc_conf_t *plcf; 599 | ngx_str_t *value; 600 | # if (nginx_version >= 1007009) 601 | ngx_http_complex_value_t cv; 602 | # endif /* nginx_version >= 1007009 */ 603 | 604 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 605 | 606 | /* check for duplicates / collisions */ 607 | if (cplcf->proxy.enable != NGX_CONF_UNSET) { 608 | return "is duplicate"; 609 | } 610 | 611 | if (cf->args->nelts != 3) { 612 | return ngx_http_cache_purge_conf(cf, &cplcf->proxy); 613 | } 614 | 615 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 616 | return "(separate location syntax) is not allowed here"; 617 | } 618 | 619 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 620 | 621 | # if (nginx_version >= 1007009) 622 | if (plcf->upstream.cache > 0) 623 | # else 624 | if (plcf->upstream.cache != NGX_CONF_UNSET_PTR 625 | && plcf->upstream.cache != NULL) 626 | # endif /* nginx_version >= 1007009 */ 627 | { 628 | return "is incompatible with \"proxy_cache\""; 629 | } 630 | 631 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 632 | return "is incompatible with \"proxy_pass\""; 633 | } 634 | 635 | if (plcf->upstream.store > 0 636 | # if (nginx_version < 1007009) 637 | || plcf->upstream.store_lengths 638 | # endif /* nginx_version >= 1007009 */ 639 | ) { 640 | return "is incompatible with \"proxy_store\""; 641 | } 642 | 643 | value = cf->args->elts; 644 | 645 | /* set proxy_cache part */ 646 | # if (nginx_version >= 1007009) 647 | 648 | plcf->upstream.cache = 1; 649 | 650 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 651 | 652 | ccv.cf = cf; 653 | ccv.value = &value[1]; 654 | ccv.complex_value = &cv; 655 | 656 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 657 | return NGX_CONF_ERROR; 658 | } 659 | 660 | if (cv.lengths != NULL) { 661 | 662 | plcf->upstream.cache_value = ngx_palloc(cf->pool, 663 | sizeof(ngx_http_complex_value_t)); 664 | if (plcf->upstream.cache_value == NULL) { 665 | return NGX_CONF_ERROR; 666 | } 667 | 668 | *plcf->upstream.cache_value = cv; 669 | 670 | } else { 671 | 672 | plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 673 | &ngx_http_proxy_module); 674 | if (plcf->upstream.cache_zone == NULL) { 675 | return NGX_CONF_ERROR; 676 | } 677 | } 678 | 679 | # else 680 | 681 | plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 682 | &ngx_http_proxy_module); 683 | if (plcf->upstream.cache == NULL) { 684 | return NGX_CONF_ERROR; 685 | } 686 | 687 | # endif /* nginx_version >= 1007009 */ 688 | 689 | /* set proxy_cache_key part */ 690 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 691 | 692 | ccv.cf = cf; 693 | ccv.value = &value[2]; 694 | ccv.complex_value = &plcf->cache_key; 695 | 696 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 697 | return NGX_CONF_ERROR; 698 | } 699 | 700 | /* set handler */ 701 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 702 | 703 | cplcf->proxy.enable = 0; 704 | cplcf->conf = &cplcf->proxy; 705 | clcf->handler = ngx_http_proxy_cache_purge_handler; 706 | 707 | return NGX_CONF_OK; 708 | } 709 | 710 | ngx_int_t 711 | ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) { 712 | ngx_http_file_cache_t *cache; 713 | ngx_http_proxy_loc_conf_t *plcf; 714 | ngx_http_cache_purge_loc_conf_t *cplcf; 715 | # if (nginx_version >= 1007009) 716 | ngx_http_proxy_main_conf_t *pmcf; 717 | ngx_int_t rc; 718 | # endif /* nginx_version >= 1007009 */ 719 | 720 | if (ngx_http_upstream_create(r) != NGX_OK) { 721 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 722 | } 723 | 724 | plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 725 | 726 | r->upstream->conf = &plcf->upstream; 727 | 728 | # if (nginx_version >= 1007009) 729 | 730 | pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); 731 | 732 | r->upstream->caches = &pmcf->caches; 733 | 734 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 735 | if (rc != NGX_OK) { 736 | return rc; 737 | } 738 | 739 | # else 740 | 741 | cache = plcf->upstream.cache->data; 742 | 743 | # endif /* nginx_version >= 1007009 */ 744 | 745 | if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { 746 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 747 | } 748 | 749 | /* Purge-all option */ 750 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 751 | if (cplcf->conf->purge_all) { 752 | ngx_http_cache_purge_all(r, cache); 753 | } else { 754 | if (ngx_http_cache_purge_is_partial(r)) { 755 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 756 | "http file cache purge with partial enabled"); 757 | 758 | ngx_http_cache_purge_partial(r, cache); 759 | } 760 | } 761 | 762 | # if (nginx_version >= 8011) 763 | r->main->count++; 764 | # endif 765 | 766 | ngx_http_cache_purge_handler(r); 767 | 768 | return NGX_DONE; 769 | } 770 | # endif /* NGX_HTTP_PROXY */ 771 | 772 | # if (NGX_HTTP_SCGI) 773 | extern ngx_module_t ngx_http_scgi_module; 774 | 775 | # if (nginx_version >= 1007009) 776 | 777 | typedef struct { 778 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 779 | } ngx_http_scgi_main_conf_t; 780 | 781 | # endif /* nginx_version >= 1007009 */ 782 | 783 | # if (nginx_version >= 1007008) 784 | 785 | typedef struct { 786 | ngx_array_t *flushes; 787 | ngx_array_t *lengths; 788 | ngx_array_t *values; 789 | ngx_uint_t number; 790 | ngx_hash_t hash; 791 | } ngx_http_scgi_params_t; 792 | 793 | # endif /* nginx_version >= 1007008 */ 794 | 795 | typedef struct { 796 | ngx_http_upstream_conf_t upstream; 797 | 798 | # if (nginx_version >= 1007008) 799 | ngx_http_scgi_params_t params; 800 | ngx_http_scgi_params_t params_cache; 801 | ngx_array_t *params_source; 802 | # else 803 | ngx_array_t *flushes; 804 | ngx_array_t *params_len; 805 | ngx_array_t *params; 806 | ngx_array_t *params_source; 807 | 808 | ngx_hash_t headers_hash; 809 | ngx_uint_t header_params; 810 | # endif /* nginx_version >= 1007008 */ 811 | 812 | ngx_array_t *scgi_lengths; 813 | ngx_array_t *scgi_values; 814 | 815 | ngx_http_complex_value_t cache_key; 816 | } ngx_http_scgi_loc_conf_t; 817 | 818 | char * 819 | ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 820 | ngx_http_compile_complex_value_t ccv; 821 | ngx_http_cache_purge_loc_conf_t *cplcf; 822 | ngx_http_core_loc_conf_t *clcf; 823 | ngx_http_scgi_loc_conf_t *slcf; 824 | ngx_str_t *value; 825 | # if (nginx_version >= 1007009) 826 | ngx_http_complex_value_t cv; 827 | # endif /* nginx_version >= 1007009 */ 828 | 829 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 830 | 831 | /* check for duplicates / collisions */ 832 | if (cplcf->scgi.enable != NGX_CONF_UNSET) { 833 | return "is duplicate"; 834 | } 835 | 836 | if (cf->args->nelts != 3) { 837 | return ngx_http_cache_purge_conf(cf, &cplcf->scgi); 838 | } 839 | 840 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 841 | return "(separate location syntax) is not allowed here"; 842 | } 843 | 844 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 845 | 846 | # if (nginx_version >= 1007009) 847 | if (slcf->upstream.cache > 0) 848 | # else 849 | if (slcf->upstream.cache != NGX_CONF_UNSET_PTR 850 | && slcf->upstream.cache != NULL) 851 | # endif /* nginx_version >= 1007009 */ 852 | { 853 | return "is incompatible with \"scgi_cache\""; 854 | } 855 | 856 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 857 | return "is incompatible with \"scgi_pass\""; 858 | } 859 | 860 | if (slcf->upstream.store > 0 861 | # if (nginx_version < 1007009) 862 | || slcf->upstream.store_lengths 863 | # endif /* nginx_version >= 1007009 */ 864 | ) { 865 | return "is incompatible with \"scgi_store\""; 866 | } 867 | 868 | value = cf->args->elts; 869 | 870 | /* set scgi_cache part */ 871 | # if (nginx_version >= 1007009) 872 | 873 | slcf->upstream.cache = 1; 874 | 875 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 876 | 877 | ccv.cf = cf; 878 | ccv.value = &value[1]; 879 | ccv.complex_value = &cv; 880 | 881 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 882 | return NGX_CONF_ERROR; 883 | } 884 | 885 | if (cv.lengths != NULL) { 886 | 887 | slcf->upstream.cache_value = ngx_palloc(cf->pool, 888 | sizeof(ngx_http_complex_value_t)); 889 | if (slcf->upstream.cache_value == NULL) { 890 | return NGX_CONF_ERROR; 891 | } 892 | 893 | *slcf->upstream.cache_value = cv; 894 | 895 | } else { 896 | 897 | slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 898 | &ngx_http_scgi_module); 899 | if (slcf->upstream.cache_zone == NULL) { 900 | return NGX_CONF_ERROR; 901 | } 902 | } 903 | 904 | # else 905 | 906 | slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 907 | &ngx_http_scgi_module); 908 | if (slcf->upstream.cache == NULL) { 909 | return NGX_CONF_ERROR; 910 | } 911 | 912 | # endif /* nginx_version >= 1007009 */ 913 | 914 | /* set scgi_cache_key part */ 915 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 916 | 917 | ccv.cf = cf; 918 | ccv.value = &value[2]; 919 | ccv.complex_value = &slcf->cache_key; 920 | 921 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 922 | return NGX_CONF_ERROR; 923 | } 924 | 925 | /* set handler */ 926 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 927 | 928 | cplcf->scgi.enable = 0; 929 | cplcf->conf = &cplcf->scgi; 930 | clcf->handler = ngx_http_scgi_cache_purge_handler; 931 | 932 | return NGX_CONF_OK; 933 | } 934 | 935 | ngx_int_t 936 | ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) { 937 | ngx_http_file_cache_t *cache; 938 | ngx_http_scgi_loc_conf_t *slcf; 939 | ngx_http_cache_purge_loc_conf_t *cplcf; 940 | # if (nginx_version >= 1007009) 941 | ngx_http_scgi_main_conf_t *smcf; 942 | ngx_int_t rc; 943 | # endif /* nginx_version >= 1007009 */ 944 | 945 | if (ngx_http_upstream_create(r) != NGX_OK) { 946 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 947 | } 948 | 949 | slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); 950 | 951 | r->upstream->conf = &slcf->upstream; 952 | 953 | # if (nginx_version >= 1007009) 954 | 955 | smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); 956 | 957 | r->upstream->caches = &smcf->caches; 958 | 959 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 960 | if (rc != NGX_OK) { 961 | return rc; 962 | } 963 | 964 | # else 965 | 966 | cache = slcf->upstream.cache->data; 967 | 968 | # endif /* nginx_version >= 1007009 */ 969 | 970 | if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { 971 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 972 | } 973 | 974 | /* Purge-all option */ 975 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 976 | if (cplcf->conf->purge_all) { 977 | ngx_http_cache_purge_all(r, cache); 978 | } else { 979 | if (ngx_http_cache_purge_is_partial(r)) { 980 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 981 | "http file cache purge with partial enabled"); 982 | 983 | ngx_http_cache_purge_partial(r, cache); 984 | } 985 | } 986 | 987 | # if (nginx_version >= 8011) 988 | r->main->count++; 989 | # endif 990 | 991 | ngx_http_cache_purge_handler(r); 992 | 993 | return NGX_DONE; 994 | } 995 | # endif /* NGX_HTTP_SCGI */ 996 | 997 | # if (NGX_HTTP_UWSGI) 998 | extern ngx_module_t ngx_http_uwsgi_module; 999 | 1000 | # if (nginx_version >= 1007009) 1001 | 1002 | typedef struct { 1003 | ngx_array_t caches; /* ngx_http_file_cache_t * */ 1004 | } ngx_http_uwsgi_main_conf_t; 1005 | 1006 | # endif /* nginx_version >= 1007009 */ 1007 | 1008 | # if (nginx_version >= 1007008) 1009 | 1010 | typedef struct { 1011 | ngx_array_t *flushes; 1012 | ngx_array_t *lengths; 1013 | ngx_array_t *values; 1014 | ngx_uint_t number; 1015 | ngx_hash_t hash; 1016 | } ngx_http_uwsgi_params_t; 1017 | 1018 | # endif /* nginx_version >= 1007008 */ 1019 | 1020 | typedef struct { 1021 | ngx_http_upstream_conf_t upstream; 1022 | 1023 | # if (nginx_version >= 1007008) 1024 | ngx_http_uwsgi_params_t params; 1025 | ngx_http_uwsgi_params_t params_cache; 1026 | ngx_array_t *params_source; 1027 | # else 1028 | ngx_array_t *flushes; 1029 | ngx_array_t *params_len; 1030 | ngx_array_t *params; 1031 | ngx_array_t *params_source; 1032 | 1033 | ngx_hash_t headers_hash; 1034 | ngx_uint_t header_params; 1035 | # endif /* nginx_version >= 1007008 */ 1036 | 1037 | ngx_array_t *uwsgi_lengths; 1038 | ngx_array_t *uwsgi_values; 1039 | 1040 | ngx_http_complex_value_t cache_key; 1041 | 1042 | ngx_str_t uwsgi_string; 1043 | 1044 | ngx_uint_t modifier1; 1045 | ngx_uint_t modifier2; 1046 | 1047 | # if (NGX_HTTP_SSL) 1048 | # if (nginx_version >= 1005008) 1049 | ngx_uint_t ssl; 1050 | ngx_uint_t ssl_protocols; 1051 | ngx_str_t ssl_ciphers; 1052 | # endif /* nginx_version >= 1005008 */ 1053 | # if (nginx_version >= 1007000) 1054 | ngx_uint_t ssl_verify_depth; 1055 | ngx_str_t ssl_trusted_certificate; 1056 | ngx_str_t ssl_crl; 1057 | # endif /* nginx_version >= 1007000 */ 1058 | # if ((nginx_version >= 1007008) && (nginx_version < 1021000)) 1059 | ngx_str_t ssl_certificate; 1060 | ngx_str_t ssl_certificate_key; 1061 | ngx_array_t *ssl_passwords; 1062 | # endif /* nginx_version >= 1007008 && nginx_version < 1021000 */ 1063 | # if (nginx_version >= 1019004) 1064 | ngx_array_t *ssl_conf_commands; 1065 | # endif /*nginx_version >= 1019004 */ 1066 | # endif 1067 | } ngx_http_uwsgi_loc_conf_t; 1068 | 1069 | char * 1070 | ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 1071 | ngx_http_compile_complex_value_t ccv; 1072 | ngx_http_cache_purge_loc_conf_t *cplcf; 1073 | ngx_http_core_loc_conf_t *clcf; 1074 | ngx_http_uwsgi_loc_conf_t *ulcf; 1075 | ngx_str_t *value; 1076 | # if (nginx_version >= 1007009) 1077 | ngx_http_complex_value_t cv; 1078 | # endif /* nginx_version >= 1007009 */ 1079 | 1080 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 1081 | 1082 | /* check for duplicates / collisions */ 1083 | if (cplcf->uwsgi.enable != NGX_CONF_UNSET) { 1084 | return "is duplicate"; 1085 | } 1086 | 1087 | if (cf->args->nelts != 3) { 1088 | return ngx_http_cache_purge_conf(cf, &cplcf->uwsgi); 1089 | } 1090 | 1091 | if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { 1092 | return "(separate location syntax) is not allowed here"; 1093 | } 1094 | 1095 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 1096 | 1097 | # if (nginx_version >= 1007009) 1098 | if (ulcf->upstream.cache > 0) 1099 | # else 1100 | if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR 1101 | && ulcf->upstream.cache != NULL) 1102 | # endif /* nginx_version >= 1007009 */ 1103 | { 1104 | return "is incompatible with \"uwsgi_cache\""; 1105 | } 1106 | 1107 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 1108 | return "is incompatible with \"uwsgi_pass\""; 1109 | } 1110 | 1111 | if (ulcf->upstream.store > 0 1112 | # if (nginx_version < 1007009) 1113 | || ulcf->upstream.store_lengths 1114 | # endif /* nginx_version >= 1007009 */ 1115 | ) { 1116 | return "is incompatible with \"uwsgi_store\""; 1117 | } 1118 | 1119 | value = cf->args->elts; 1120 | 1121 | /* set uwsgi_cache part */ 1122 | # if (nginx_version >= 1007009) 1123 | 1124 | ulcf->upstream.cache = 1; 1125 | 1126 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 1127 | 1128 | ccv.cf = cf; 1129 | ccv.value = &value[1]; 1130 | ccv.complex_value = &cv; 1131 | 1132 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 1133 | return NGX_CONF_ERROR; 1134 | } 1135 | 1136 | if (cv.lengths != NULL) { 1137 | 1138 | ulcf->upstream.cache_value = ngx_palloc(cf->pool, 1139 | sizeof(ngx_http_complex_value_t)); 1140 | if (ulcf->upstream.cache_value == NULL) { 1141 | return NGX_CONF_ERROR; 1142 | } 1143 | 1144 | *ulcf->upstream.cache_value = cv; 1145 | 1146 | } else { 1147 | 1148 | ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 1149 | &ngx_http_uwsgi_module); 1150 | if (ulcf->upstream.cache_zone == NULL) { 1151 | return NGX_CONF_ERROR; 1152 | } 1153 | } 1154 | 1155 | # else 1156 | 1157 | ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 1158 | &ngx_http_uwsgi_module); 1159 | if (ulcf->upstream.cache == NULL) { 1160 | return NGX_CONF_ERROR; 1161 | } 1162 | 1163 | # endif /* nginx_version >= 1007009 */ 1164 | 1165 | /* set uwsgi_cache_key part */ 1166 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 1167 | 1168 | ccv.cf = cf; 1169 | ccv.value = &value[2]; 1170 | ccv.complex_value = &ulcf->cache_key; 1171 | 1172 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 1173 | return NGX_CONF_ERROR; 1174 | } 1175 | 1176 | /* set handler */ 1177 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 1178 | 1179 | cplcf->uwsgi.enable = 0; 1180 | cplcf->conf = &cplcf->uwsgi; 1181 | clcf->handler = ngx_http_uwsgi_cache_purge_handler; 1182 | 1183 | return NGX_CONF_OK; 1184 | } 1185 | 1186 | 1187 | ngx_int_t 1188 | ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) { 1189 | ngx_http_file_cache_t *cache; 1190 | ngx_http_uwsgi_loc_conf_t *ulcf; 1191 | ngx_http_cache_purge_loc_conf_t *cplcf; 1192 | # if (nginx_version >= 1007009) 1193 | ngx_http_uwsgi_main_conf_t *umcf; 1194 | ngx_int_t rc; 1195 | # endif /* nginx_version >= 1007009 */ 1196 | 1197 | if (ngx_http_upstream_create(r) != NGX_OK) { 1198 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1199 | } 1200 | 1201 | ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); 1202 | 1203 | r->upstream->conf = &ulcf->upstream; 1204 | 1205 | # if (nginx_version >= 1007009) 1206 | 1207 | umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); 1208 | 1209 | r->upstream->caches = &umcf->caches; 1210 | 1211 | rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); 1212 | if (rc != NGX_OK) { 1213 | return rc; 1214 | } 1215 | 1216 | # else 1217 | 1218 | cache = ulcf->upstream.cache->data; 1219 | 1220 | # endif /* nginx_version >= 1007009 */ 1221 | 1222 | if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { 1223 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1224 | } 1225 | 1226 | /* Purge-all option */ 1227 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1228 | if (cplcf->conf->purge_all) { 1229 | ngx_http_cache_purge_all(r, cache); 1230 | } else { 1231 | if (ngx_http_cache_purge_is_partial(r)) { 1232 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1233 | "http file cache purge with partial enabled"); 1234 | 1235 | ngx_http_cache_purge_partial(r, cache); 1236 | } 1237 | } 1238 | 1239 | # if (nginx_version >= 8011) 1240 | r->main->count++; 1241 | # endif 1242 | 1243 | ngx_http_cache_purge_handler(r); 1244 | 1245 | return NGX_DONE; 1246 | } 1247 | # endif /* NGX_HTTP_UWSGI */ 1248 | 1249 | 1250 | char * 1251 | ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1252 | { 1253 | ngx_http_cache_purge_loc_conf_t *cplcf; 1254 | ngx_str_t *value; 1255 | 1256 | cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); 1257 | 1258 | /* check for duplicates / collisions */ 1259 | if (cplcf->resptype != NGX_CONF_UNSET_UINT && cf->cmd_type == NGX_HTTP_LOC_CONF ) { 1260 | return "is duplicate"; 1261 | } 1262 | 1263 | /* sanity check */ 1264 | if (cf->args->nelts < 2) { 1265 | return "is invalid paramter, ex) cache_purge_response_type (html|json|xml|text)"; 1266 | } 1267 | 1268 | if (cf->args->nelts > 2 ) { 1269 | return "is required only 1 option, ex) cache_purge_response_type (html|json|xml|text)"; 1270 | } 1271 | 1272 | value = cf->args->elts; 1273 | 1274 | if (ngx_strcmp(value[1].data, "html") != 0 && ngx_strcmp(value[1].data, "json") != 0 1275 | && ngx_strcmp(value[1].data, "xml") != 0 && ngx_strcmp(value[1].data, "text") != 0) { 1276 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1277 | "invalid parameter \"%V\", expected" 1278 | " \"(html|json|xml|text)\" keyword", &value[1]); 1279 | return NGX_CONF_ERROR; 1280 | } 1281 | 1282 | if (cf->cmd_type == NGX_HTTP_MODULE) { 1283 | return "(separate server or location syntax) is not allowed here"; 1284 | } 1285 | 1286 | if (ngx_strcmp(value[1].data, "html") == 0) { 1287 | cplcf->resptype = NGX_REPONSE_TYPE_HTML; 1288 | } else if (ngx_strcmp(value[1].data, "xml") == 0) { 1289 | cplcf->resptype = NGX_REPONSE_TYPE_XML; 1290 | } else if (ngx_strcmp(value[1].data, "json") == 0) { 1291 | cplcf->resptype = NGX_REPONSE_TYPE_JSON; 1292 | } else if (ngx_strcmp(value[1].data, "text") == 0) { 1293 | cplcf->resptype = NGX_REPONSE_TYPE_TEXT; 1294 | } 1295 | 1296 | return NGX_CONF_OK; 1297 | } 1298 | 1299 | static ngx_int_t 1300 | ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1301 | return NGX_OK; 1302 | } 1303 | 1304 | static ngx_int_t 1305 | ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1306 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1307 | "http file cache delete: \"%s\"", path->data); 1308 | 1309 | if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { 1310 | ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 1311 | ngx_delete_file_n " \"%s\" failed", path->data); 1312 | } 1313 | 1314 | return NGX_OK; 1315 | } 1316 | 1317 | 1318 | static ngx_int_t 1319 | ngx_http_purge_file_cache_delete_partial_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { 1320 | u_char *key_partial; 1321 | u_char *key_in_file; 1322 | ngx_uint_t len; 1323 | ngx_flag_t remove_file = 0; 1324 | 1325 | key_partial = ctx->data; 1326 | len = ngx_strlen(key_partial); 1327 | 1328 | /* if key_partial is empty always match, because is a '*' */ 1329 | if (len == 0) { 1330 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1331 | "empty key_partial, forcing deletion"); 1332 | remove_file = 1; 1333 | } else { 1334 | ngx_file_t file; 1335 | 1336 | ngx_memzero(&file, sizeof(ngx_file_t)); 1337 | file.offset = file.sys_offset = 0; 1338 | file.fd = ngx_open_file(path->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 1339 | NGX_FILE_DEFAULT_ACCESS); 1340 | if (file.fd == -1) { 1341 | return NGX_OK; 1342 | } 1343 | file.log = ctx->log; 1344 | 1345 | /* I don't know if it's a good idea to use the ngx_cycle pool for this, 1346 | but the request is not available here */ 1347 | key_in_file = ngx_pcalloc(ngx_cycle->pool, sizeof(u_char) * (len + 1)); 1348 | 1349 | /* KEY: /proxy/passwd */ 1350 | /* since we don't need the "KEY: " ignore 5 + 1 extra u_char from last 1351 | intro */ 1352 | /* Optimization: we don't need to read the full key only the n chars 1353 | included in key_partial */ 1354 | ngx_read_file(&file, key_in_file, sizeof(u_char) * len, 1355 | sizeof(ngx_http_file_cache_header_t) + sizeof(u_char) * 6); 1356 | ngx_close_file(file.fd); 1357 | 1358 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1359 | "http cache file \"%s\" key read: \"%s\"", path->data, key_in_file); 1360 | 1361 | if (ngx_strncasecmp(key_in_file, key_partial, len) == 0) { 1362 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, 1363 | "match found, deleting file \"%s\"", path->data); 1364 | remove_file = 1; 1365 | } 1366 | } 1367 | 1368 | if (remove_file && ngx_delete_file(path->data) == NGX_FILE_ERROR) { 1369 | ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 1370 | ngx_delete_file_n " \"%s\" failed", path->data); 1371 | } 1372 | 1373 | return NGX_OK; 1374 | } 1375 | 1376 | ngx_int_t 1377 | ngx_http_cache_purge_access_handler(ngx_http_request_t *r) { 1378 | ngx_http_cache_purge_loc_conf_t *cplcf; 1379 | 1380 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1381 | 1382 | if (r->method_name.len != cplcf->conf->method.len 1383 | || (ngx_strncmp(r->method_name.data, cplcf->conf->method.data, 1384 | r->method_name.len))) { 1385 | return cplcf->original_handler(r); 1386 | } 1387 | 1388 | if ((cplcf->conf->access || cplcf->conf->access6) 1389 | && ngx_http_cache_purge_access(cplcf->conf->access, 1390 | cplcf->conf->access6, 1391 | r->connection->sockaddr) != NGX_OK) { 1392 | return NGX_HTTP_FORBIDDEN; 1393 | } 1394 | 1395 | if (cplcf->handler == NULL) { 1396 | return NGX_HTTP_NOT_FOUND; 1397 | } 1398 | 1399 | return cplcf->handler(r); 1400 | } 1401 | 1402 | ngx_int_t 1403 | ngx_http_cache_purge_access(ngx_array_t *access, ngx_array_t *access6, 1404 | struct sockaddr *s) { 1405 | in_addr_t inaddr; 1406 | ngx_in_cidr_t *a; 1407 | ngx_uint_t i; 1408 | # if (NGX_HAVE_INET6) 1409 | struct in6_addr *inaddr6; 1410 | ngx_in6_cidr_t *a6; 1411 | u_char *p; 1412 | ngx_uint_t n; 1413 | # endif /* NGX_HAVE_INET6 */ 1414 | 1415 | switch (s->sa_family) { 1416 | case AF_INET: 1417 | if (access == NULL) { 1418 | return NGX_DECLINED; 1419 | } 1420 | 1421 | inaddr = ((struct sockaddr_in *) s)->sin_addr.s_addr; 1422 | 1423 | # if (NGX_HAVE_INET6) 1424 | ipv4: 1425 | # endif /* NGX_HAVE_INET6 */ 1426 | 1427 | a = access->elts; 1428 | for (i = 0; i < access->nelts; i++) { 1429 | if ((inaddr & a[i].mask) == a[i].addr) { 1430 | return NGX_OK; 1431 | } 1432 | } 1433 | 1434 | return NGX_DECLINED; 1435 | 1436 | # if (NGX_HAVE_INET6) 1437 | case AF_INET6: 1438 | inaddr6 = &((struct sockaddr_in6 *) s)->sin6_addr; 1439 | p = inaddr6->s6_addr; 1440 | 1441 | if (access && IN6_IS_ADDR_V4MAPPED(inaddr6)) { 1442 | inaddr = p[12] << 24; 1443 | inaddr += p[13] << 16; 1444 | inaddr += p[14] << 8; 1445 | inaddr += p[15]; 1446 | inaddr = htonl(inaddr); 1447 | 1448 | goto ipv4; 1449 | } 1450 | 1451 | if (access6 == NULL) { 1452 | return NGX_DECLINED; 1453 | } 1454 | 1455 | a6 = access6->elts; 1456 | for (i = 0; i < access6->nelts; i++) { 1457 | for (n = 0; n < 16; n++) { 1458 | if ((p[n] & a6[i].mask.s6_addr[n]) != a6[i].addr.s6_addr[n]) { 1459 | goto next; 1460 | } 1461 | } 1462 | 1463 | return NGX_OK; 1464 | 1465 | next: 1466 | continue; 1467 | } 1468 | 1469 | return NGX_DECLINED; 1470 | # endif /* NGX_HAVE_INET6 */ 1471 | } 1472 | 1473 | return NGX_DECLINED; 1474 | } 1475 | 1476 | ngx_int_t 1477 | ngx_http_cache_purge_send_response(ngx_http_request_t *r) { 1478 | ngx_chain_t out; 1479 | ngx_buf_t *b; 1480 | ngx_str_t *key; 1481 | ngx_int_t rc; 1482 | size_t len; 1483 | 1484 | size_t body_len; 1485 | size_t resp_tmpl_len; 1486 | u_char *buf; 1487 | u_char *buf_keydata; 1488 | u_char *p; 1489 | const char *resp_ct; 1490 | size_t resp_ct_size; 1491 | const char *resp_body; 1492 | size_t resp_body_size; 1493 | 1494 | ngx_http_cache_purge_loc_conf_t *cplcf; 1495 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1496 | 1497 | key = r->cache->keys.elts; 1498 | 1499 | buf_keydata = ngx_pcalloc(r->pool, key[0].len+1); 1500 | if (buf_keydata == NULL) { 1501 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1502 | } 1503 | 1504 | p = ngx_cpymem(buf_keydata, key[0].data, key[0].len); 1505 | if (p == NULL) { 1506 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1507 | } 1508 | 1509 | switch(cplcf->resptype) { 1510 | 1511 | case NGX_REPONSE_TYPE_JSON: 1512 | resp_ct = ngx_http_cache_purge_content_type_json; 1513 | resp_ct_size = ngx_http_cache_purge_content_type_json_size; 1514 | resp_body = ngx_http_cache_purge_body_templ_json; 1515 | resp_body_size = ngx_http_cache_purge_body_templ_json_size; 1516 | break; 1517 | 1518 | case NGX_REPONSE_TYPE_XML: 1519 | resp_ct = ngx_http_cache_purge_content_type_xml; 1520 | resp_ct_size = ngx_http_cache_purge_content_type_xml_size; 1521 | resp_body = ngx_http_cache_purge_body_templ_xml; 1522 | resp_body_size = ngx_http_cache_purge_body_templ_xml_size; 1523 | break; 1524 | 1525 | case NGX_REPONSE_TYPE_TEXT: 1526 | resp_ct = ngx_http_cache_purge_content_type_text; 1527 | resp_ct_size = ngx_http_cache_purge_content_type_text_size; 1528 | resp_body = ngx_http_cache_purge_body_templ_text; 1529 | resp_body_size = ngx_http_cache_purge_body_templ_text_size; 1530 | break; 1531 | 1532 | default: 1533 | case NGX_REPONSE_TYPE_HTML: 1534 | resp_ct = ngx_http_cache_purge_content_type_html; 1535 | resp_ct_size = ngx_http_cache_purge_content_type_html_size; 1536 | resp_body = ngx_http_cache_purge_body_templ_html; 1537 | resp_body_size = ngx_http_cache_purge_body_templ_html_size; 1538 | break; 1539 | } 1540 | 1541 | body_len = resp_body_size - 2 - 1; 1542 | r->headers_out.content_type.len = resp_ct_size - 1; 1543 | r->headers_out.content_type.data = (u_char *) resp_ct; 1544 | 1545 | resp_tmpl_len = body_len + key[0].len ; 1546 | 1547 | buf = ngx_pcalloc(r->pool, resp_tmpl_len); 1548 | if (buf == NULL) { 1549 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1550 | } 1551 | 1552 | p = ngx_snprintf(buf, resp_tmpl_len, resp_body , buf_keydata); 1553 | if (p == NULL) { 1554 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1555 | } 1556 | 1557 | len = body_len + key[0].len; 1558 | 1559 | r->headers_out.status = NGX_HTTP_OK; 1560 | r->headers_out.content_length_n = len; 1561 | 1562 | if (r->method == NGX_HTTP_HEAD) { 1563 | rc = ngx_http_send_header(r); 1564 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 1565 | return rc; 1566 | } 1567 | } 1568 | 1569 | b = ngx_create_temp_buf(r->pool, len); 1570 | if (b == NULL) { 1571 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 1572 | } 1573 | 1574 | 1575 | out.buf = b; 1576 | out.next = NULL; 1577 | 1578 | b->last = ngx_cpymem(b->last, buf, resp_tmpl_len); 1579 | b->last_buf = 1; 1580 | 1581 | rc = ngx_http_send_header(r); 1582 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 1583 | return rc; 1584 | } 1585 | 1586 | return ngx_http_output_filter(r, &out); 1587 | } 1588 | 1589 | # if (nginx_version >= 1007009) 1590 | 1591 | /* 1592 | * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get 1593 | * Copyright (C) Igor Sysoev 1594 | * Copyright (C) Nginx, Inc. 1595 | */ 1596 | ngx_int_t 1597 | ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, 1598 | ngx_http_file_cache_t **cache) { 1599 | ngx_str_t *name, val; 1600 | ngx_uint_t i; 1601 | ngx_http_file_cache_t **caches; 1602 | 1603 | if (u->conf->cache_zone) { 1604 | *cache = u->conf->cache_zone->data; 1605 | return NGX_OK; 1606 | } 1607 | 1608 | if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { 1609 | return NGX_ERROR; 1610 | } 1611 | 1612 | if (val.len == 0 1613 | || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) { 1614 | return NGX_DECLINED; 1615 | } 1616 | 1617 | caches = u->caches->elts; 1618 | 1619 | for (i = 0; i < u->caches->nelts; i++) { 1620 | name = &caches[i]->shm_zone->shm.name; 1621 | 1622 | if (name->len == val.len 1623 | && ngx_strncmp(name->data, val.data, val.len) == 0) { 1624 | *cache = caches[i]; 1625 | return NGX_OK; 1626 | } 1627 | } 1628 | 1629 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1630 | "cache \"%V\" not found", &val); 1631 | 1632 | return NGX_ERROR; 1633 | } 1634 | 1635 | # endif /* nginx_version >= 1007009 */ 1636 | 1637 | ngx_int_t 1638 | ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, 1639 | ngx_http_complex_value_t *cache_key) { 1640 | ngx_http_cache_t *c; 1641 | ngx_str_t *key; 1642 | ngx_int_t rc; 1643 | 1644 | rc = ngx_http_discard_request_body(r); 1645 | if (rc != NGX_OK) { 1646 | return NGX_ERROR; 1647 | } 1648 | 1649 | c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); 1650 | if (c == NULL) { 1651 | return NGX_ERROR; 1652 | } 1653 | 1654 | rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t)); 1655 | if (rc != NGX_OK) { 1656 | return NGX_ERROR; 1657 | } 1658 | 1659 | key = ngx_array_push(&c->keys); 1660 | if (key == NULL) { 1661 | return NGX_ERROR; 1662 | } 1663 | 1664 | rc = ngx_http_complex_value(r, cache_key, key); 1665 | if (rc != NGX_OK) { 1666 | return NGX_ERROR; 1667 | } 1668 | 1669 | r->cache = c; 1670 | c->body_start = ngx_pagesize; 1671 | c->file_cache = cache; 1672 | c->file.log = r->connection->log; 1673 | 1674 | ngx_http_file_cache_create_key(r); 1675 | 1676 | return NGX_OK; 1677 | } 1678 | 1679 | void 1680 | ngx_http_cache_purge_handler(ngx_http_request_t *r) { 1681 | ngx_http_cache_purge_loc_conf_t *cplcf; 1682 | ngx_int_t rc; 1683 | 1684 | # if (NGX_HAVE_FILE_AIO) 1685 | if (r->aio) { 1686 | return; 1687 | } 1688 | # endif 1689 | 1690 | cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); 1691 | rc = NGX_OK; 1692 | if (!cplcf->conf->purge_all && !ngx_http_cache_purge_is_partial(r)) { 1693 | rc = ngx_http_file_cache_purge(r); 1694 | 1695 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1696 | "http file cache purge: %i, \"%s\"", 1697 | rc, r->cache->file.name.data); 1698 | } 1699 | 1700 | switch (rc) { 1701 | case NGX_OK: 1702 | r->write_event_handler = ngx_http_request_empty_handler; 1703 | ngx_http_finalize_request(r, ngx_http_cache_purge_send_response(r)); 1704 | return; 1705 | case NGX_DECLINED: 1706 | ngx_http_finalize_request(r, NGX_HTTP_PRECONDITION_FAILED); 1707 | return; 1708 | # if (NGX_HAVE_FILE_AIO) 1709 | case NGX_AGAIN: 1710 | r->write_event_handler = ngx_http_cache_purge_handler; 1711 | return; 1712 | # endif 1713 | default: 1714 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1715 | } 1716 | } 1717 | 1718 | ngx_int_t 1719 | ngx_http_file_cache_purge(ngx_http_request_t *r) { 1720 | ngx_http_file_cache_t *cache; 1721 | ngx_http_cache_t *c; 1722 | 1723 | switch (ngx_http_file_cache_open(r)) { 1724 | case NGX_OK: 1725 | case NGX_HTTP_CACHE_STALE: 1726 | # if (nginx_version >= 8001) \ 1727 | || ((nginx_version < 8000) && (nginx_version >= 7060)) 1728 | case NGX_HTTP_CACHE_UPDATING: 1729 | # endif 1730 | break; 1731 | case NGX_DECLINED: 1732 | return NGX_DECLINED; 1733 | # if (NGX_HAVE_FILE_AIO) 1734 | case NGX_AGAIN: 1735 | return NGX_AGAIN; 1736 | # endif 1737 | default: 1738 | return NGX_ERROR; 1739 | } 1740 | 1741 | c = r->cache; 1742 | cache = c->file_cache; 1743 | 1744 | /* 1745 | * delete file from disk but *keep* in-memory node, 1746 | * because other requests might still point to it. 1747 | */ 1748 | 1749 | ngx_shmtx_lock(&cache->shpool->mutex); 1750 | 1751 | if (!c->node->exists) { 1752 | /* race between concurrent purges, backoff */ 1753 | ngx_shmtx_unlock(&cache->shpool->mutex); 1754 | return NGX_DECLINED; 1755 | } 1756 | 1757 | # if (nginx_version >= 1000001) 1758 | cache->sh->size -= c->node->fs_size; 1759 | c->node->fs_size = 0; 1760 | # else 1761 | cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize; 1762 | c->node->length = 0; 1763 | # endif 1764 | 1765 | c->node->exists = 0; 1766 | # if (nginx_version >= 8001) \ 1767 | || ((nginx_version < 8000) && (nginx_version >= 7060)) 1768 | c->node->updating = 0; 1769 | # endif 1770 | 1771 | ngx_shmtx_unlock(&cache->shpool->mutex); 1772 | 1773 | if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) { 1774 | /* entry in error log is enough, don't notice client */ 1775 | ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 1776 | ngx_delete_file_n " \"%s\" failed", c->file.name.data); 1777 | } 1778 | 1779 | /* file deleted from cache */ 1780 | return NGX_OK; 1781 | } 1782 | 1783 | 1784 | void 1785 | ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { 1786 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1787 | "purge_all http in %s", 1788 | cache->path->name.data); 1789 | 1790 | /* Walk the tree and remove all the files */ 1791 | ngx_tree_ctx_t tree; 1792 | tree.init_handler = NULL; 1793 | tree.file_handler = ngx_http_purge_file_cache_delete_file; 1794 | tree.pre_tree_handler = ngx_http_purge_file_cache_noop; 1795 | tree.post_tree_handler = ngx_http_purge_file_cache_noop; 1796 | tree.spec_handler = ngx_http_purge_file_cache_noop; 1797 | tree.data = NULL; 1798 | tree.alloc = 0; 1799 | tree.log = ngx_cycle->log; 1800 | 1801 | ngx_walk_tree(&tree, &cache->path->name); 1802 | } 1803 | 1804 | void 1805 | ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { 1806 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1807 | "purge_partial http in %s", 1808 | cache->path->name.data); 1809 | 1810 | u_char *key_partial; 1811 | ngx_str_t *key; 1812 | ngx_http_cache_t *c; 1813 | ngx_uint_t len; 1814 | 1815 | c = r->cache; 1816 | key = c->keys.elts; 1817 | len = key[0].len; 1818 | 1819 | /* Only check the first key */ 1820 | key_partial = ngx_pcalloc(r->pool, sizeof(u_char) * len); 1821 | ngx_memcpy(key_partial, key[0].data, sizeof(u_char) * (len - 1)); 1822 | 1823 | /* Walk the tree and remove all the files matching key_partial */ 1824 | ngx_tree_ctx_t tree; 1825 | tree.init_handler = NULL; 1826 | tree.file_handler = ngx_http_purge_file_cache_delete_partial_file; 1827 | tree.pre_tree_handler = ngx_http_purge_file_cache_noop; 1828 | tree.post_tree_handler = ngx_http_purge_file_cache_noop; 1829 | tree.spec_handler = ngx_http_purge_file_cache_noop; 1830 | tree.data = key_partial; 1831 | tree.alloc = 0; 1832 | tree.log = ngx_cycle->log; 1833 | 1834 | ngx_walk_tree(&tree, &cache->path->name); 1835 | } 1836 | 1837 | ngx_int_t 1838 | ngx_http_cache_purge_is_partial(ngx_http_request_t *r) { 1839 | ngx_str_t *key; 1840 | ngx_http_cache_t *c; 1841 | 1842 | c = r->cache; 1843 | key = c->keys.elts; 1844 | 1845 | /* Only check the first key */ 1846 | return c->keys.nelts > 0 // number of array elements 1847 | && key[0].len > 0 // char length of the key 1848 | && key[0].data[key[0].len - 1] == '*'; // is the last char an asterix char? 1849 | } 1850 | 1851 | char * 1852 | ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) { 1853 | ngx_cidr_t cidr; 1854 | ngx_in_cidr_t *access; 1855 | # if (NGX_HAVE_INET6) 1856 | ngx_in6_cidr_t *access6; 1857 | # endif /* NGX_HAVE_INET6 */ 1858 | ngx_str_t *value; 1859 | ngx_int_t rc; 1860 | ngx_uint_t i; 1861 | ngx_uint_t from_position; 1862 | 1863 | from_position = 2; 1864 | 1865 | /* xxx_cache_purge on|off| [purge_all] [from all| [.. ]] */ 1866 | value = cf->args->elts; 1867 | 1868 | if (ngx_strcmp(value[1].data, "off") == 0) { 1869 | cpcf->enable = 0; 1870 | return NGX_CONF_OK; 1871 | 1872 | } else if (ngx_strcmp(value[1].data, "on") == 0) { 1873 | ngx_str_set(&cpcf->method, "PURGE"); 1874 | 1875 | } else { 1876 | cpcf->method = value[1]; 1877 | } 1878 | 1879 | if (cf->args->nelts < 4) { 1880 | cpcf->enable = 1; 1881 | return NGX_CONF_OK; 1882 | } 1883 | 1884 | /* We will purge all the keys */ 1885 | if (ngx_strcmp(value[from_position].data, "purge_all") == 0) { 1886 | cpcf->purge_all = 1; 1887 | from_position++; 1888 | } 1889 | 1890 | 1891 | /* sanity check */ 1892 | if (ngx_strcmp(value[from_position].data, "from") != 0) { 1893 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1894 | "invalid parameter \"%V\", expected" 1895 | " \"from\" keyword", &value[from_position]); 1896 | return NGX_CONF_ERROR; 1897 | } 1898 | 1899 | if (ngx_strcmp(value[from_position + 1].data, "all") == 0) { 1900 | cpcf->enable = 1; 1901 | return NGX_CONF_OK; 1902 | } 1903 | 1904 | for (i = (from_position + 1); i < cf->args->nelts; i++) { 1905 | rc = ngx_ptocidr(&value[i], &cidr); 1906 | 1907 | if (rc == NGX_ERROR) { 1908 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1909 | "invalid parameter \"%V\"", &value[i]); 1910 | return NGX_CONF_ERROR; 1911 | } 1912 | 1913 | if (rc == NGX_DONE) { 1914 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1915 | "low address bits of %V are meaningless", 1916 | &value[i]); 1917 | } 1918 | 1919 | switch (cidr.family) { 1920 | case AF_INET: 1921 | if (cpcf->access == NULL) { 1922 | cpcf->access = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), 1923 | sizeof(ngx_in_cidr_t)); 1924 | if (cpcf->access == NULL) { 1925 | return NGX_CONF_ERROR; 1926 | } 1927 | } 1928 | 1929 | access = ngx_array_push(cpcf->access); 1930 | if (access == NULL) { 1931 | return NGX_CONF_ERROR; 1932 | } 1933 | 1934 | access->mask = cidr.u.in.mask; 1935 | access->addr = cidr.u.in.addr; 1936 | 1937 | break; 1938 | 1939 | # if (NGX_HAVE_INET6) 1940 | case AF_INET6: 1941 | if (cpcf->access6 == NULL) { 1942 | cpcf->access6 = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), 1943 | sizeof(ngx_in6_cidr_t)); 1944 | if (cpcf->access6 == NULL) { 1945 | return NGX_CONF_ERROR; 1946 | } 1947 | } 1948 | 1949 | access6 = ngx_array_push(cpcf->access6); 1950 | if (access6 == NULL) { 1951 | return NGX_CONF_ERROR; 1952 | } 1953 | 1954 | access6->mask = cidr.u.in6.mask; 1955 | access6->addr = cidr.u.in6.addr; 1956 | 1957 | break; 1958 | # endif /* NGX_HAVE_INET6 */ 1959 | } 1960 | } 1961 | 1962 | cpcf->enable = 1; 1963 | 1964 | return NGX_CONF_OK; 1965 | } 1966 | 1967 | void 1968 | ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf, 1969 | ngx_http_cache_purge_conf_t *prev) { 1970 | if (conf->enable == NGX_CONF_UNSET) { 1971 | if (prev->enable == 1) { 1972 | conf->enable = prev->enable; 1973 | conf->method = prev->method; 1974 | conf->purge_all = prev->purge_all; 1975 | conf->access = prev->access; 1976 | conf->access6 = prev->access6; 1977 | } else { 1978 | conf->enable = 0; 1979 | } 1980 | } 1981 | } 1982 | 1983 | void * 1984 | ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) { 1985 | ngx_http_cache_purge_loc_conf_t *conf; 1986 | 1987 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_purge_loc_conf_t)); 1988 | if (conf == NULL) { 1989 | return NULL; 1990 | } 1991 | 1992 | /* 1993 | * set by ngx_pcalloc(): 1994 | * 1995 | * conf->*.method = { 0, NULL } 1996 | * conf->*.access = NULL 1997 | * conf->*.access6 = NULL 1998 | * conf->handler = NULL 1999 | * conf->original_handler = NULL 2000 | */ 2001 | 2002 | # if (NGX_HTTP_FASTCGI) 2003 | conf->fastcgi.enable = NGX_CONF_UNSET; 2004 | # endif /* NGX_HTTP_FASTCGI */ 2005 | # if (NGX_HTTP_PROXY) 2006 | conf->proxy.enable = NGX_CONF_UNSET; 2007 | # endif /* NGX_HTTP_PROXY */ 2008 | # if (NGX_HTTP_SCGI) 2009 | conf->scgi.enable = NGX_CONF_UNSET; 2010 | # endif /* NGX_HTTP_SCGI */ 2011 | # if (NGX_HTTP_UWSGI) 2012 | conf->uwsgi.enable = NGX_CONF_UNSET; 2013 | # endif /* NGX_HTTP_UWSGI */ 2014 | 2015 | conf->resptype = NGX_CONF_UNSET_UINT; 2016 | 2017 | conf->conf = NGX_CONF_UNSET_PTR; 2018 | 2019 | return conf; 2020 | } 2021 | 2022 | char * 2023 | ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { 2024 | ngx_http_cache_purge_loc_conf_t *prev = parent; 2025 | ngx_http_cache_purge_loc_conf_t *conf = child; 2026 | ngx_http_core_loc_conf_t *clcf; 2027 | # if (NGX_HTTP_FASTCGI) 2028 | ngx_http_fastcgi_loc_conf_t *flcf; 2029 | # endif /* NGX_HTTP_FASTCGI */ 2030 | # if (NGX_HTTP_PROXY) 2031 | ngx_http_proxy_loc_conf_t *plcf; 2032 | # endif /* NGX_HTTP_PROXY */ 2033 | # if (NGX_HTTP_SCGI) 2034 | ngx_http_scgi_loc_conf_t *slcf; 2035 | # endif /* NGX_HTTP_SCGI */ 2036 | # if (NGX_HTTP_UWSGI) 2037 | ngx_http_uwsgi_loc_conf_t *ulcf; 2038 | # endif /* NGX_HTTP_UWSGI */ 2039 | 2040 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 2041 | 2042 | ngx_conf_merge_uint_value(conf->resptype, prev->resptype, NGX_REPONSE_TYPE_HTML); 2043 | 2044 | # if (NGX_HTTP_FASTCGI) 2045 | ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi); 2046 | 2047 | if (conf->fastcgi.enable && clcf->handler != NULL) { 2048 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); 2049 | 2050 | if (flcf->upstream.upstream || flcf->fastcgi_lengths) { 2051 | conf->conf = &conf->fastcgi; 2052 | conf->handler = flcf->upstream.cache 2053 | ? ngx_http_fastcgi_cache_purge_handler : NULL; 2054 | conf->original_handler = clcf->handler; 2055 | 2056 | clcf->handler = ngx_http_cache_purge_access_handler; 2057 | 2058 | return NGX_CONF_OK; 2059 | } 2060 | } 2061 | # endif /* NGX_HTTP_FASTCGI */ 2062 | 2063 | # if (NGX_HTTP_PROXY) 2064 | ngx_http_cache_purge_merge_conf(&conf->proxy, &prev->proxy); 2065 | 2066 | if (conf->proxy.enable && clcf->handler != NULL) { 2067 | plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); 2068 | 2069 | if (plcf->upstream.upstream || plcf->proxy_lengths) { 2070 | conf->conf = &conf->proxy; 2071 | conf->handler = plcf->upstream.cache 2072 | ? ngx_http_proxy_cache_purge_handler : NULL; 2073 | conf->original_handler = clcf->handler; 2074 | 2075 | clcf->handler = ngx_http_cache_purge_access_handler; 2076 | 2077 | return NGX_CONF_OK; 2078 | } 2079 | } 2080 | # endif /* NGX_HTTP_PROXY */ 2081 | 2082 | # if (NGX_HTTP_SCGI) 2083 | ngx_http_cache_purge_merge_conf(&conf->scgi, &prev->scgi); 2084 | 2085 | if (conf->scgi.enable && clcf->handler != NULL) { 2086 | slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); 2087 | 2088 | if (slcf->upstream.upstream || slcf->scgi_lengths) { 2089 | conf->conf = &conf->scgi; 2090 | conf->handler = slcf->upstream.cache 2091 | ? ngx_http_scgi_cache_purge_handler : NULL; 2092 | conf->original_handler = clcf->handler; 2093 | clcf->handler = ngx_http_cache_purge_access_handler; 2094 | 2095 | return NGX_CONF_OK; 2096 | } 2097 | } 2098 | # endif /* NGX_HTTP_SCGI */ 2099 | 2100 | # if (NGX_HTTP_UWSGI) 2101 | ngx_http_cache_purge_merge_conf(&conf->uwsgi, &prev->uwsgi); 2102 | 2103 | if (conf->uwsgi.enable && clcf->handler != NULL) { 2104 | ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); 2105 | 2106 | if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { 2107 | conf->conf = &conf->uwsgi; 2108 | conf->handler = ulcf->upstream.cache 2109 | ? ngx_http_uwsgi_cache_purge_handler : NULL; 2110 | conf->original_handler = clcf->handler; 2111 | 2112 | clcf->handler = ngx_http_cache_purge_access_handler; 2113 | 2114 | return NGX_CONF_OK; 2115 | } 2116 | } 2117 | # endif /* NGX_HTTP_UWSGI */ 2118 | 2119 | ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); 2120 | 2121 | if (conf->handler == NULL) { 2122 | conf->handler = prev->handler; 2123 | } 2124 | 2125 | if (conf->original_handler == NULL) { 2126 | conf->original_handler = prev->original_handler; 2127 | } 2128 | 2129 | return NGX_CONF_OK; 2130 | } 2131 | 2132 | #else /* !NGX_HTTP_CACHE */ 2133 | 2134 | static ngx_http_module_t ngx_http_cache_purge_module_ctx = { 2135 | NULL, /* preconfiguration */ 2136 | NULL, /* postconfiguration */ 2137 | 2138 | NULL, /* create main configuration */ 2139 | NULL, /* init main configuration */ 2140 | 2141 | NULL, /* create server configuration */ 2142 | NULL, /* merge server configuration */ 2143 | 2144 | NULL, /* create location configuration */ 2145 | NULL, /* merge location configuration */ 2146 | }; 2147 | 2148 | ngx_module_t ngx_http_cache_purge_module = { 2149 | NGX_MODULE_V1, 2150 | &ngx_http_cache_purge_module_ctx, /* module context */ 2151 | NULL, /* module directives */ 2152 | NGX_HTTP_MODULE, /* module type */ 2153 | NULL, /* init master */ 2154 | NULL, /* init module */ 2155 | NULL, /* init process */ 2156 | NULL, /* init thread */ 2157 | NULL, /* exit thread */ 2158 | NULL, /* exit process */ 2159 | NULL, /* exit master */ 2160 | NGX_MODULE_V1_PADDING 2161 | }; 2162 | 2163 | #endif /* NGX_HTTP_CACHE */ 2164 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------