1+ # vim: set ft=nginx:
2+
3+ {{ - $chosenBackend := default "" .Env.STACK_PAGE_CACHE_BACKEND }}
4+ {{ - $allowedBackends := list "redis" "memcached" "custom" }}
5+ {{ - $memcachedHost := default "127.0.0.1" .Env.STACK_PAGE_CACHE_MEMCACHED_HOST }}
6+ {{ - $memcachedPort := default "11211" .Env.STACK_PAGE_CACHE_MEMCACHED_PORT }}
7+ {{ - $truthStrings := list "true" "on" "yes" -}}
8+ {{ - $keyPrefix := default "nginx-cache:" .Env.STACK_PAGE_CACHE_KEY_PREFIX }}
9+ {{ - $keyUID := default "https$request_method$host$request_uri" .Env.STACK_PAGE_CACHE_KEY_UID }}
10+
11+ {{ - if has $chosenBackend $allowedBackends }}
12+ set $skip_cache 0;
13+
14+ set_by_lua_block $skip_cache {
15+ local scheme = ngx.var.scheme
16+ local uri = ngx.var.request_uri
17+ local request = ngx.ctx.request or {}
18+ ngx.ctx.request = request
19+ local user_agent = ngx.var.http_user_agent or ''
20+ local request_method = ngx.req.get_method()
21+
22+ re = {}
23+ re.wp_loggedin = [[wordpress_logged_in|wordpress_no_cache|comment_author_|wp-postpass_|wp_gdsr_|fbs_|wp-query_monitor_]]
24+ re.woocommerce_cookies = [[woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_]]
25+ re.woocommerce_args = [[remove_item|removed_item|remove_coupon|undo_item|order|add-to-cart|added-to-cart|revoke-key]]
26+ re.bbpress_cookies = [[EmailID]]
27+
28+ function find_plain( s, sub)
29+ if string.find( s, sub, 1, true) == nil then
30+ return false
31+ end
32+
33+ return true
34+ end
35+
36+ request.is_wp_admin = (
37+ not ngx.re.match ( uri, "^.*/wp-admin/admin-ajax.php" )
38+ and ngx.re.match ( uri, "^.*/(wp-admin/|wp-login.php|wp-signup.php|wp-cron.php|xmlrpc.php|git-webhook.php|feed/|sitemap.xml|sitemap_index.xml)" , "o" )
39+ )
40+
41+ request.wp_loggedin = ( ngx.re.match ( ngx.var.http_cookie or '', re.wp_loggedin, 'io' ) and true or false)
42+
43+ request.query_string = ( ngx.var.is_args or '') .. (ngx.var.args or '' )
44+
45+ request.is_woocommerce = (
46+ ngx.re.match ( request.query_string or '', re.woocommerce_args, 'io' ) or
47+ ( ngx.re.match ( ngx.var.http_cookie or '', re.woocommerce_cookies, 'io' ) and true) or
48+ ( find_plain( uri, '/wc-api/') or ngx.re.match(request.query_string, 'wc-api=', 'o' ))
49+ )
50+
51+ request.is_dynamic = (
52+ request.is_wp_admin or
53+ request.wp_loggedin or
54+ request.is_woocommerce or
55+ ( request_method ~ = 'GET' and
56+ request_method ~ = 'HEAD' ) or
57+ -- skip cache if there are query strings ( TODO: improve this logic for better cache hit)
58+ request.query_string ~ = ''
59+ )
60+
61+ local cache_bypass = ( ngx.var.skip_cache or '0') ~= '0'
62+ or ( ngx.re.match ( ngx.var.http_cookie or '', re.bbpress_cookies, 'io' ) and true)
63+ or false
64+
65+ local skip_cache = 0
66+ if request.is_dynamic or cache_bypass then
67+ skip_cache = 1
68+ end
69+
70+ return skip_cache
71+ }
72+
73+ set $key "" ;
74+ set $key_prefix {{ $keyPrefix }} ;
75+ set $key_uid {{ $keyUID }} ;
76+ set $escaped_key "" ;
77+ set_escape_uri $escaped_key_prefix $key_prefix ;
78+ set_escape_uri $escaped_key_uid $key_uid ;
79+
80+ # Use versioned keys with memcached by default, for implementing cache flush
81+ {{ - if and ( eq $chosenBackend "memcached" ) ( has ( default "on" .Env.STACK_PAGE_CACHE_MEMCACHED_USE_VERSION) $truthStrings ) }}
82+ rewrite_by_lua_block {
83+ if ngx.var.skip_cache == "1" then
84+ return
85+ end
86+
87+ local memcached = require "resty.memcached"
88+
89+ local function identity( key) return key end
90+
91+ local memc, err = memcached:new{
92+ -- don't escape/unescape keys
93+ key_transform = { identity, identity }
94+ }
95+
96+ if not memc then
97+ ngx.log( ngx.ERR, "failed to instantiate memcached: " , err)
98+ return
99+ end
100+
101+ memc:set_timeout( 1000 )
102+
103+ local ok, err = memc:connect( "{{ $memcachedHost }}:{{ $memcachedPort }}" )
104+ if not ok then
105+ ngx.log( ngx.ERR, "failed to connect to memcached: " , err)
106+ return
107+ end
108+
109+ local versionKey = ngx.var.key_prefix .. "version"
110+
111+ local version, flags, err = memc:get( versionKey)
112+ if err then
113+ ngx.log( ngx.ERR, "failed to get memcached version: " , err)
114+ return
115+ end
116+
117+ if not version then
118+ ngx.log( ngx.INFO, "memcached version not found, attempting to set one..." )
119+
120+ version = tostring( os.time()) .. ":"
121+ local ok, err = memc:set ( versionKey, version)
122+ if not ok then
123+ ngx.log( ngx.ERR, "failed to set memcached version: " , err)
124+ return
125+ end
126+ end
127+
128+ ngx.var.key = ngx.var.key_prefix .. version .. ngx.var.key_uid
129+ ngx.var.escaped_key = ngx.var.escaped_key_prefix .. ngx.escape_uri( version) .. ngx.var.escaped_key_uid
130+
131+ local ok, err = memc:close()
132+ if not ok then
133+ ngx.say( "failed to close memcached: " , err)
134+ return
135+ end
136+ }
137+
138+ {{ - else }}
139+ # default key is nginx-cache:https$request_method$host$request_uri
140+ set $key $key_prefix$key_uid ;
141+ set $escaped_key $escaped_key_prefix$escaped_key_uid ;
142+ {{ - end }}
143+
144+ srcache_fetch_skip $skip_cache ;
145+ srcache_store_skip $skip_cache ;
146+ srcache_store_statuses {{ default "200 301 302" .Env.STACK_PAGE_CACHE_STORE_STATUSES }} ;
147+
148+ # https://github.com/openresty/srcache-nginx-module#srcache_response_cache_control
149+ srcache_response_cache_control {{ default "on" .Env.STACK_PAGE_CACHE_RESPONSE_CACHE_CONTROL }} ;
150+
151+ srcache_fetch GET /.stack-cache-fetch $key ;
152+ srcache_store PUT /.stack-cache-store key=$escaped_key &exptime={{ default "360" .Env.STACK_PAGE_CACHE_EXPIRE_SECONDS | atoi }} ;
153+
154+ more_set_headers "x-cache-fetch $srcache_fetch_status" ;
155+
156+ {{ - end }}
0 commit comments