This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 71a2259  feat(proxy-cache): support memory-based strategy (#5028)
71a2259 is described below

commit 71a2259d1561fa8bbd0bc322054d2e004e1a797e
Author: agile6v <[email protected]>
AuthorDate: Thu Oct 21 15:57:54 2021 +0800

    feat(proxy-cache): support memory-based strategy (#5028)
---
 Makefile                                         |   3 +
 apisix/cli/ngx_tpl.lua                           |   6 +
 apisix/cli/ops.lua                               |  40 ++
 apisix/plugins/proxy-cache.lua                   | 288 -----------
 apisix/plugins/proxy-cache/disk_handler.lua      |  97 ++++
 apisix/plugins/proxy-cache/init.lua              | 188 +++++++
 apisix/plugins/proxy-cache/memory.lua            |  70 +++
 apisix/plugins/proxy-cache/memory_handler.lua    | 326 ++++++++++++
 apisix/plugins/proxy-cache/util.lua              | 102 ++++
 conf/config-default.yaml                         |  17 +-
 docs/en/latest/plugins/proxy-cache.md            |   3 +
 docs/zh/latest/plugins/proxy-cache.md            |   3 +
 t/cli/test_main.sh                               |   6 +-
 t/plugin/{proxy-cache.t => proxy-cache/disk.t}   |  59 +--
 t/plugin/{proxy-cache.t => proxy-cache/memory.t} | 604 +++++++++--------------
 15 files changed, 1102 insertions(+), 710 deletions(-)

diff --git a/Makefile b/Makefile
index c5b5483..002ed2e 100644
--- a/Makefile
+++ b/Makefile
@@ -309,6 +309,9 @@ install: runtime
        $(INSTALL) -d $(INST_LUADIR)/apisix/plugins/prometheus
        $(INSTALL) apisix/plugins/prometheus/*.lua 
$(INST_LUADIR)/apisix/plugins/prometheus/
 
+       $(INSTALL) -d $(INST_LUADIR)/apisix/plugins/proxy-cache
+       $(INSTALL) apisix/plugins/proxy-cache/*.lua 
$(INST_LUADIR)/apisix/plugins/proxy-cache/
+
        $(INSTALL) -d $(INST_LUADIR)/apisix/plugins/serverless
        $(INSTALL) apisix/plugins/serverless/*.lua 
$(INST_LUADIR)/apisix/plugins/serverless/
 
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 6b78764..80760b7 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -209,7 +209,11 @@ http {
     {% if enabled_plugins["proxy-cache"] then %}
     # for proxy cache
     {% for _, cache in ipairs(proxy_cache.zones) do %}
+    {% if cache.disk_path and cache.cache_levels and cache.disk_size then %}
     proxy_cache_path {* cache.disk_path *} levels={* cache.cache_levels *} 
keys_zone={* cache.name *}:{* cache.memory_size *} inactive=1d max_size={* 
cache.disk_size *} use_temp_path=off;
+    {% else %}
+    lua_shared_dict {* cache.name *} {* cache.memory_size *};
+    {% end %}
     {% end %}
     {% end %}
 
@@ -217,8 +221,10 @@ http {
     # for proxy cache
     map $upstream_cache_zone $upstream_cache_zone_info {
     {% for _, cache in ipairs(proxy_cache.zones) do %}
+    {% if cache.disk_path and cache.cache_levels and cache.disk_size then %}
         {* cache.name *} {* cache.disk_path *},{* cache.cache_levels *};
     {% end %}
+    {% end %}
     }
     {% end %}
 
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index 750f5b1..6856868 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -174,6 +174,46 @@ local config_schema = {
                         },
                     }
                 },
+                proxy_cache = {
+                    type = "object",
+                    properties = {
+                        zones = {
+                            type = "array",
+                            minItems = 1,
+                            items = {
+                                type = "object",
+                                properties = {
+                                    name = {
+                                        type = "string",
+                                    },
+                                    memory_size = {
+                                        type = "string",
+                                    },
+                                    disk_size = {
+                                        type = "string",
+                                    },
+                                    disk_path = {
+                                        type = "string",
+                                    },
+                                    cache_levels = {
+                                        type = "string",
+                                    },
+                                },
+                                oneOf = {
+                                    {
+                                        required = {"name", "memory_size"},
+                                        maxProperties = 2,
+                                    },
+                                    {
+                                        required = {"name", "memory_size", 
"disk_size",
+                                            "disk_path", "cache_levels"},
+                                    }
+                                },
+                            },
+                            uniqueItems = true,
+                        }
+                    }
+                },
                 port_admin = {
                     type = "integer",
                 },
diff --git a/apisix/plugins/proxy-cache.lua b/apisix/plugins/proxy-cache.lua
deleted file mode 100644
index 34f3056..0000000
--- a/apisix/plugins/proxy-cache.lua
+++ /dev/null
@@ -1,288 +0,0 @@
---
--- Licensed to the Apache Software Foundation (ASF) under one or more
--- contributor license agreements.  See the NOTICE file distributed with
--- this work for additional information regarding copyright ownership.
--- The ASF licenses this file to You under the Apache License, Version 2.0
--- (the "License"); you may not use this file except in compliance with
--- the License.  You may obtain a copy of the License at
---
---     http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
-
-local core = require("apisix.core")
-local ngx_re = require("ngx.re")
-local tab_concat = table.concat
-local string = string
-local io_open = io.open
-local io_close = io.close
-local ngx = ngx
-local os = os
-local ipairs = ipairs
-local pairs = pairs
-local tonumber = tonumber
-
-local plugin_name = "proxy-cache"
-
-local schema = {
-    type = "object",
-    properties = {
-        cache_zone = {
-            type = "string",
-            minLength = 1,
-            maxLength = 100,
-            default = "disk_cache_one",
-        },
-        cache_key = {
-            type = "array",
-            minItems = 1,
-            items = {
-                description = "a key for caching",
-                type = "string",
-                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]],
-            },
-            default = {"$host", "$request_uri"}
-        },
-        cache_http_status = {
-            type = "array",
-            minItems = 1,
-            items = {
-                description = "http response status",
-                type = "integer",
-                minimum = 200,
-                maximum = 599,
-            },
-            uniqueItems = true,
-            default = {200, 301, 404},
-        },
-        cache_method = {
-            type = "array",
-            minItems = 1,
-            items = {
-                description = "supported http method",
-                type = "string",
-                enum = {"GET", "POST", "HEAD"},
-            },
-            uniqueItems = true,
-            default = {"GET", "HEAD"},
-        },
-        hide_cache_headers = {
-            type = "boolean",
-            default = false,
-        },
-        cache_bypass = {
-            type = "array",
-            minItems = 1,
-            items = {
-                type = "string",
-                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]]
-            },
-        },
-        no_cache = {
-            type = "array",
-            minItems = 1,
-            items = {
-                type = "string",
-                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]]
-            },
-        },
-    },
-}
-
-local _M = {
-    version = 0.1,
-    priority = 1009,
-    name = plugin_name,
-    schema = schema,
-}
-
-
-function _M.check_schema(conf)
-    local ok, err = core.schema.check(schema, conf)
-    if not ok then
-        return false, err
-    end
-
-    for _, key in ipairs(conf.cache_key) do
-        if key == "$request_method" then
-            return false, "cache_key variable " .. key .. " unsupported"
-        end
-    end
-
-    local found = false
-    local local_conf = core.config.local_conf()
-    if local_conf.apisix.proxy_cache then
-        for _, cache in ipairs(local_conf.apisix.proxy_cache.zones) do
-            if cache.name == conf.cache_zone then
-                found = true
-            end
-        end
-
-        if found == false then
-            return false, "cache_zone " .. conf.cache_zone .. " not found"
-        end
-    end
-    return true
-end
-
-
-local tmp = {}
-local function generate_complex_value(data, ctx)
-    core.table.clear(tmp)
-
-    core.log.info("proxy-cache complex value: ", core.json.delay_encode(data))
-    for i, value in ipairs(data) do
-        core.log.info("proxy-cache complex value index-", i, ": ", value)
-
-        if string.byte(value, 1, 1) == string.byte('$') then
-            tmp[i] = ctx.var[string.sub(value, 2)]
-        else
-            tmp[i] = value
-        end
-    end
-
-    return tab_concat(tmp, "")
-end
-
-
--- check whether the request method and response status
--- match the user defined.
-local function match_method_and_status(conf, ctx)
-    local match_method, match_status = false, false
-
-    -- Maybe there is no need for optimization here.
-    for _, method in ipairs(conf.cache_method) do
-        if method == ctx.var.request_method then
-            match_method = true
-            break
-        end
-    end
-
-    for _, status in ipairs(conf.cache_http_status) do
-        if status == ngx.status then
-            match_status = true
-            break
-        end
-    end
-
-    if match_method and match_status then
-        return true
-    end
-
-    return false
-end
-
-
-local function file_exists(name)
-    local f = io_open(name, "r")
-    if f ~= nil then
-        io_close(f)
-        return true
-    end
-    return false
-end
-
-
-local function generate_cache_filename(cache_path, cache_levels, cache_key)
-    local md5sum = ngx.md5(cache_key)
-    local levels = ngx_re.split(cache_levels, ":")
-    local filename = ""
-
-    local index = #md5sum
-    for k, v in pairs(levels) do
-        local length = tonumber(v)
-        index = index - length
-        filename = filename .. md5sum:sub(index+1, index+length) .. "/"
-    end
-    if cache_path:sub(-1) ~= "/" then
-        cache_path = cache_path .. "/"
-    end
-    filename = cache_path .. filename .. md5sum
-    return filename
-end
-
-
-local function cache_purge(conf, ctx)
-    local cache_zone_info = ngx_re.split(ctx.var.upstream_cache_zone_info, ",")
-
-    local filename = generate_cache_filename(cache_zone_info[1], 
cache_zone_info[2],
-                                             ctx.var.upstream_cache_key)
-    if file_exists(filename) then
-        os.remove(filename)
-        return nil
-    end
-
-    return "Not found"
-end
-
-
-function _M.rewrite(conf, ctx)
-    core.log.info("proxy-cache plugin rewrite phase, conf: ", 
core.json.delay_encode(conf))
-
-    ctx.var.upstream_cache_zone = conf.cache_zone
-
-    local value = generate_complex_value(conf.cache_key, ctx)
-    ctx.var.upstream_cache_key = value
-    core.log.info("proxy-cache cache key value:", value)
-
-    if ctx.var.request_method == "PURGE" then
-        local err = cache_purge(conf, ctx)
-        if err ~= nil then
-            return 404
-        end
-
-        return 200
-    end
-
-    if conf.cache_bypass ~= nil then
-        local value = generate_complex_value(conf.cache_bypass, ctx)
-        ctx.var.upstream_cache_bypass = value
-        core.log.info("proxy-cache cache bypass value:", value)
-    end
-end
-
-
-function _M.header_filter(conf, ctx)
-    core.log.info("proxy-cache plugin header filter phase, conf: ", 
core.json.delay_encode(conf))
-
-    local no_cache = "1"
-
-    if match_method_and_status(conf, ctx) then
-        no_cache = "0"
-    end
-
-    if conf.no_cache ~= nil then
-        local value = generate_complex_value(conf.no_cache, ctx)
-        core.log.info("proxy-cache no-cache value:", value)
-
-        if value ~= nil and value ~= "" and value ~= "0" then
-            no_cache = "1"
-        end
-    end
-
-    local upstream_hdr_cache_control
-    local upstream_hdr_expires
-
-    if conf.hide_cache_headers == true then
-        upstream_hdr_cache_control = ""
-        upstream_hdr_expires = ""
-    else
-        upstream_hdr_cache_control = ctx.var.upstream_http_cache_control
-        upstream_hdr_expires = ctx.var.upstream_http_expires
-    end
-
-    core.response.set_header("Cache-Control", upstream_hdr_cache_control,
-                             "Expires", upstream_hdr_expires,
-                             "Apisix-Cache-Status", 
ctx.var.upstream_cache_status)
-
-    ctx.var.upstream_no_cache = no_cache
-    core.log.info("proxy-cache no cache:", no_cache)
-end
-
-
-return _M
diff --git a/apisix/plugins/proxy-cache/disk_handler.lua 
b/apisix/plugins/proxy-cache/disk_handler.lua
new file mode 100644
index 0000000..bf131b1
--- /dev/null
+++ b/apisix/plugins/proxy-cache/disk_handler.lua
@@ -0,0 +1,97 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local os = os
+local ngx_re = require("ngx.re")
+local core = require("apisix.core")
+local util = require("apisix.plugins.proxy-cache.util")
+
+local _M = {}
+
+
+local function disk_cache_purge(conf, ctx)
+    local cache_zone_info = ngx_re.split(ctx.var.upstream_cache_zone_info, ",")
+
+    local filename = util.generate_cache_filename(cache_zone_info[1], 
cache_zone_info[2],
+        ctx.var.upstream_cache_key)
+
+    if util.file_exists(filename) then
+        os.remove(filename)
+        return nil
+    end
+
+    return "Not found"
+end
+
+
+function _M.access(conf, ctx)
+    ctx.var.upstream_cache_zone = conf.cache_zone
+
+    if ctx.var.request_method == "PURGE" then
+        local err = disk_cache_purge(conf, ctx)
+        if err ~= nil then
+            return 404
+        end
+
+        return 200
+    end
+
+    if conf.cache_bypass ~= nil then
+        local value = util.generate_complex_value(conf.cache_bypass, ctx)
+        ctx.var.upstream_cache_bypass = value
+        core.log.info("proxy-cache cache bypass value:", value)
+    end
+end
+
+
+function _M.header_filter(conf, ctx)
+    local no_cache = "1"
+
+    if util.match_method(conf, ctx) and util.match_status(conf, ctx) then
+        no_cache = "0"
+    end
+
+    if conf.no_cache ~= nil then
+        local value = util.generate_complex_value(conf.no_cache, ctx)
+        core.log.info("proxy-cache no-cache value:", value)
+
+        if value ~= nil and value ~= "" and value ~= "0" then
+            no_cache = "1"
+        end
+    end
+
+    local upstream_hdr_cache_control
+    local upstream_hdr_expires
+
+    if conf.hide_cache_headers == true then
+        upstream_hdr_cache_control = ""
+        upstream_hdr_expires = ""
+    else
+        upstream_hdr_cache_control = ctx.var.upstream_http_cache_control
+        upstream_hdr_expires = ctx.var.upstream_http_expires
+    end
+
+    core.response.set_header("Cache-Control", upstream_hdr_cache_control,
+        "Expires", upstream_hdr_expires,
+        "Apisix-Cache-Status", ctx.var.upstream_cache_status)
+
+    ctx.var.upstream_no_cache = no_cache
+    core.log.info("proxy-cache no cache:", no_cache)
+end
+
+
+return _M
diff --git a/apisix/plugins/proxy-cache/init.lua 
b/apisix/plugins/proxy-cache/init.lua
new file mode 100644
index 0000000..5956998
--- /dev/null
+++ b/apisix/plugins/proxy-cache/init.lua
@@ -0,0 +1,188 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local memory_handler = require("apisix.plugins.proxy-cache.memory_handler")
+local disk_handler = require("apisix.plugins.proxy-cache.disk_handler")
+local util = require("apisix.plugins.proxy-cache.util")
+local core = require("apisix.core")
+local ipairs = ipairs
+
+local plugin_name = "proxy-cache"
+
+local STRATEGY_DISK = "disk"
+local STRATEGY_MEMORY = "memory"
+
+local schema = {
+    type = "object",
+    properties = {
+        cache_zone = {
+            type = "string",
+            minLength = 1,
+            maxLength = 100,
+            default = "disk_cache_one",
+        },
+        cache_strategy = {
+            type = "string",
+            enum = {STRATEGY_DISK, STRATEGY_MEMORY},
+            default = STRATEGY_DISK,
+        },
+        cache_key = {
+            type = "array",
+            minItems = 1,
+            items = {
+                description = "a key for caching",
+                type = "string",
+                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]],
+            },
+            default = {"$host", "$request_uri"}
+        },
+        cache_http_status = {
+            type = "array",
+            minItems = 1,
+            items = {
+                description = "http response status",
+                type = "integer",
+                minimum = 200,
+                maximum = 599,
+            },
+            uniqueItems = true,
+            default = {200, 301, 404},
+        },
+        cache_method = {
+            type = "array",
+            minItems = 1,
+            items = {
+                description = "supported http method",
+                type = "string",
+                enum = {"GET", "POST", "HEAD"},
+            },
+            uniqueItems = true,
+            default = {"GET", "HEAD"},
+        },
+        hide_cache_headers = {
+            type = "boolean",
+            default = false,
+        },
+        cache_control = {
+            type = "boolean",
+            default = false,
+        },
+        cache_bypass = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "string",
+                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]]
+            },
+        },
+        no_cache = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "string",
+                pattern = [[(^[^\$].+$|^\$[0-9a-zA-Z_]+$)]]
+            },
+        },
+        cache_ttl = {
+            type = "integer",
+            minimum = 1,
+            default = 300,
+        },
+    },
+}
+
+
+local _M = {
+    version = 0.2,
+    priority = 1009,
+    name = plugin_name,
+    schema = schema,
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    for _, key in ipairs(conf.cache_key) do
+        if key == "$request_method" then
+            return false, "cache_key variable " .. key .. " unsupported"
+        end
+    end
+
+    local found = false
+    local local_conf = core.config.local_conf()
+    if local_conf.apisix.proxy_cache then
+        for _, cache in ipairs(local_conf.apisix.proxy_cache.zones) do
+            if cache.name == conf.cache_zone then
+                found = true
+            end
+        end
+
+        if found == false then
+            return false, "cache_zone " .. conf.cache_zone .. " not found"
+        end
+    end
+
+    return true
+end
+
+
+function _M.access(conf, ctx)
+    core.log.info("proxy-cache plugin access phase, conf: ", 
core.json.delay_encode(conf))
+
+    local value = util.generate_complex_value(conf.cache_key, ctx)
+    ctx.var.upstream_cache_key = value
+    core.log.info("proxy-cache cache key value:", value)
+
+    local handler
+    if conf.cache_strategy == STRATEGY_MEMORY then
+        handler = memory_handler
+    else
+        handler = disk_handler
+    end
+
+    return handler.access(conf, ctx)
+end
+
+
+function _M.header_filter(conf, ctx)
+    core.log.info("proxy-cache plugin header filter phase, conf: ", 
core.json.delay_encode(conf))
+
+    local handler
+    if conf.cache_strategy == STRATEGY_MEMORY then
+        handler = memory_handler
+    else
+        handler = disk_handler
+    end
+
+    handler.header_filter(conf, ctx)
+end
+
+
+function _M.body_filter(conf, ctx)
+    core.log.info("proxy-cache plugin body filter phase, conf: ", 
core.json.delay_encode(conf))
+
+    if conf.cache_strategy == STRATEGY_MEMORY then
+        memory_handler.body_filter(conf, ctx)
+    end
+end
+
+
+return _M
diff --git a/apisix/plugins/proxy-cache/memory.lua 
b/apisix/plugins/proxy-cache/memory.lua
new file mode 100644
index 0000000..0112db6
--- /dev/null
+++ b/apisix/plugins/proxy-cache/memory.lua
@@ -0,0 +1,70 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local ngx = ngx
+local ngx_shared = ngx.shared
+local setmetatable = setmetatable
+local core = require("apisix.core")
+
+local _M = {}
+local mt = { __index = _M }
+
+
+function _M.new(opts)
+    return setmetatable({
+        dict = ngx_shared[opts.shdict_name],
+    }, mt)
+end
+
+
+function _M:set(key, obj, ttl)
+    local obj_json = core.json.encode(obj)
+    if not obj_json then
+        return nil, "could not encode object"
+    end
+
+    local succ, err = self.dict:set(key, obj_json, ttl)
+    return succ and obj_json or nil, err
+end
+
+
+function _M:get(key)
+    -- If the key does not exist or has expired, then res_json will be nil.
+    local res_json, err = self.dict:get(key)
+    if not res_json then
+        if not err then
+            return nil, "not found"
+        else
+            return nil, err
+        end
+    end
+
+    local res_obj, err = core.json.decode(res_json)
+    if not res_obj then
+        return nil, err
+    end
+
+    return res_obj, nil
+end
+
+
+function _M:purge(key)
+    self.dict:delete(key)
+end
+
+
+return _M
diff --git a/apisix/plugins/proxy-cache/memory_handler.lua 
b/apisix/plugins/proxy-cache/memory_handler.lua
new file mode 100644
index 0000000..2fd4d11
--- /dev/null
+++ b/apisix/plugins/proxy-cache/memory_handler.lua
@@ -0,0 +1,326 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local memory_strategy = require("apisix.plugins.proxy-cache.memory").new
+local util = require("apisix.plugins.proxy-cache.util")
+local core = require("apisix.core")
+local tab_new = require("table.new")
+local ngx_re_gmatch = ngx.re.gmatch
+local ngx_re_match = ngx.re.match
+local parse_http_time = ngx.parse_http_time
+local concat = table.concat
+local lower = string.lower
+local floor = math.floor
+local tostring = tostring
+local tonumber = tonumber
+local ngx = ngx
+local type = type
+local pairs = pairs
+local time = ngx.now
+local max = math.max
+
+local CACHE_VERSION = 1
+
+local _M = {}
+
+-- http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
+-- note content-length & apisix-cache-status are not strictly
+-- hop-by-hop but we will be adjusting it here anyhow
+local hop_by_hop_headers = {
+    ["connection"]          = true,
+    ["keep-alive"]          = true,
+    ["proxy-authenticate"]  = true,
+    ["proxy-authorization"] = true,
+    ["te"]                  = true,
+    ["trailers"]            = true,
+    ["transfer-encoding"]   = true,
+    ["upgrade"]             = true,
+    ["content-length"]      = true,
+    ["apisix-cache-status"] = true,
+}
+
+
+local function include_cache_header(header)
+    local n_header = lower(header)
+    if n_header == "expires" or n_header == "cache-control" then
+        return true
+    end
+
+    return false
+end
+
+
+local function overwritable_header(header)
+    local n_header = lower(header)
+
+    return not hop_by_hop_headers[n_header]
+            and not ngx_re_match(n_header, "ratelimit-remaining")
+end
+
+
+-- The following format can accept:
+--      Cache-Control: no-cache
+--      Cache-Control: no-store
+--      Cache-Control: max-age=3600
+--      Cache-Control: max-stale=3600
+--      Cache-Control: min-fresh=3600
+--      Cache-Control: private, max-age=600
+--      Cache-Control: public, max-age=31536000
+-- Refer to: https://www.holisticseo.digital/pagespeed/cache-control/
+local function parse_directive_header(h)
+    if not h then
+        return {}
+    end
+
+    if type(h) == "table" then
+        h = concat(h, ", ")
+    end
+
+    local t    = {}
+    local res  = tab_new(3, 0)
+    local iter = ngx_re_gmatch(h, "([^,]+)", "oj")
+
+    local m = iter()
+    while m do
+        local _, err = ngx_re_match(m[0], [[^\s*([^=]+)(?:=(.+))?]],
+            "oj", nil, res)
+        if err then
+            core.log.error(err)
+        end
+
+        -- store the directive token as a numeric value if it looks like a 
number;
+        -- otherwise, store the string value. for directives without token, we 
just
+        -- set the key to true
+        t[lower(res[1])] = tonumber(res[2]) or res[2] or true
+
+        m = iter()
+    end
+
+    return t
+end
+
+
+local function parse_resource_ttl(ctx, cc)
+    local max_age = cc["s-maxage"] or cc["max-age"]
+
+    if not max_age then
+        local expires = ctx.var.upstream_http_expires
+
+        -- if multiple Expires headers are present, last one wins
+        if type(expires) == "table" then
+            expires = expires[#expires]
+        end
+
+        local exp_time = parse_http_time(tostring(expires))
+        if exp_time then
+            max_age = exp_time - time()
+        end
+    end
+
+    return max_age and max(max_age, 0) or 0
+end
+
+
+local function cacheable_request(conf, ctx, cc)
+    if not util.match_method(conf, ctx) then
+        return false, "MISS"
+    end
+
+    if conf.cache_bypass ~= nil then
+        local value = util.generate_complex_value(conf.cache_bypass, ctx)
+        core.log.info("proxy-cache cache bypass value:", value)
+        if value ~= nil and value ~= "" and value ~= "0" then
+            return false, "BYPASS"
+        end
+    end
+
+    if conf.cache_control and (cc["no-store"] or cc["no-cache"]) then
+        return false, "BYPASS"
+    end
+
+    return true, ""
+end
+
+
+local function cacheable_response(conf, ctx, cc)
+    if not util.match_status(conf, ctx) then
+        return false
+    end
+
+    if conf.no_cache ~= nil then
+        local value = util.generate_complex_value(conf.no_cache, ctx)
+        core.log.info("proxy-cache no-cache value:", value)
+
+        if value ~= nil and value ~= "" and value ~= "0" then
+            return false
+        end
+    end
+
+    if conf.cache_control and (cc["private"] or cc["no-store"] or 
cc["no-cache"]) then
+        return false
+    end
+
+    if conf.cache_control and parse_resource_ttl(ctx, cc) <= 0 then
+        return false
+    end
+
+    return true
+end
+
+
+function _M.access(conf, ctx)
+    local cc = parse_directive_header(ctx.var.http_cache_control)
+
+    if ctx.var.request_method ~= "PURGE" then
+        local ret, msg = cacheable_request(conf, ctx, cc)
+        if not ret then
+            core.response.set_header("Apisix-Cache-Status", msg)
+            return
+        end
+    end
+
+    if not ctx.cache then
+        ctx.cache = {
+            memory = memory_strategy({shdict_name = conf.cache_zone}),
+            hit = false,
+            ttl = 0,
+        }
+    end
+
+    local res, err = ctx.cache.memory:get(ctx.var.upstream_cache_key)
+
+    if ctx.var.request_method == "PURGE" then
+        if err == "not found" then
+            return 404
+        end
+        ctx.cache.memory:purge(ctx.var.upstream_cache_key)
+        ctx.cache = nil
+        return 200
+    end
+
+    if err then
+        core.response.set_header("Apisix-Cache-Status", "MISS")
+        if err ~= "not found" then
+            core.log.error("failed to get from cache, err: ", err)
+        elseif conf.cache_control and cc["only-if-cached"] then
+            return 504
+        end
+        return
+    end
+
+    if res.version ~= CACHE_VERSION then
+        core.log.warn("cache format mismatch, purging ", 
ctx.var.upstream_cache_key)
+        core.response.set_header("Apisix-Cache-Status", "BYPASS")
+        ctx.cache.memory:purge(ctx.var.upstream_cache_key)
+        return
+    end
+
+    if conf.cache_control then
+        if cc["max-age"] and time() - res.timestamp > cc["max-age"] then
+            core.response.set_header("Apisix-Cache-Status", "STALE")
+            return
+        end
+
+        if cc["max-stale"] and time() - res.timestamp - res.ttl > 
cc["max-stale"] then
+            core.response.set_header("Apisix-Cache-Status", "STALE")
+            return
+        end
+
+        if cc["min-fresh"] and res.ttl - (time() - res.timestamp) < 
cc["min-fresh"] then
+            core.response.set_header("Apisix-Cache-Status", "STALE")
+            return
+        end
+    else
+        if time() - res.timestamp > res.ttl then
+            core.response.set_header("Apisix-Cache-Status", "STALE")
+            return
+        end
+    end
+
+    ctx.cache.hit = true
+
+    for key, value in pairs(res.headers) do
+        if conf.hide_cache_headers == true and include_cache_header(key) then
+            core.response.set_header(key, "")
+        elseif overwritable_header(key) then
+            core.response.set_header(key, value)
+        end
+    end
+
+    core.response.set_header("Age", floor(time() - res.timestamp))
+    core.response.set_header("Apisix-Cache-Status", "HIT")
+
+    return res.status, res.body
+end
+
+
+function _M.header_filter(conf, ctx)
+    local cache = ctx.cache
+    if not cache or cache.hit then
+        return
+    end
+
+    local res_headers = ngx.resp.get_headers(0, true)
+
+    for key in pairs(res_headers) do
+        if conf.hide_cache_headers == true and include_cache_header(key) then
+            core.response.set_header(key, "")
+        end
+    end
+
+    local cc = parse_directive_header(ctx.var.upstream_http_cache_control)
+
+    if cacheable_response(conf, ctx, cc) then
+        cache.res_headers = res_headers
+        cache.ttl = conf.cache_control and parse_resource_ttl(ctx, cc) or 
conf.cache_ttl
+    else
+        ctx.cache = nil
+    end
+end
+
+
+function _M.body_filter(conf, ctx)
+    local cache = ctx.cache
+    if not cache or cache.hit then
+        return
+    end
+
+    local res_body = core.response.hold_body_chunk(ctx)
+    if not res_body then
+        return
+    end
+
+    local res = {
+        status    = ngx.status,
+        body      = res_body,
+        body_len  = #res_body,
+        headers   = cache.res_headers,
+        ttl       = cache.ttl,
+        timestamp = time(),
+        version   = CACHE_VERSION,
+    }
+
+    local res, err = cache.memory:set(ctx.var.upstream_cache_key, res, 
cache.ttl)
+    if not res then
+        core.log.error("failed to set cache, err: ", err)
+    end
+
+    ngx.arg[1] = res_body
+end
+
+
+return _M
diff --git a/apisix/plugins/proxy-cache/util.lua 
b/apisix/plugins/proxy-cache/util.lua
new file mode 100644
index 0000000..f20d2fc
--- /dev/null
+++ b/apisix/plugins/proxy-cache/util.lua
@@ -0,0 +1,102 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core = require("apisix.core")
+local ngx_re = require("ngx.re")
+local tab_concat = table.concat
+local string = string
+local io_open = io.open
+local io_close = io.close
+local ngx = ngx
+local ipairs = ipairs
+local pairs = pairs
+local tonumber = tonumber
+
+local _M = {}
+
+local tmp = {}
+function _M.generate_complex_value(data, ctx)
+    core.table.clear(tmp)
+
+    core.log.info("proxy-cache complex value: ", core.json.delay_encode(data))
+    for i, value in ipairs(data) do
+        core.log.info("proxy-cache complex value index-", i, ": ", value)
+
+        if string.byte(value, 1, 1) == string.byte('$') then
+            tmp[i] = ctx.var[string.sub(value, 2)]
+        else
+            tmp[i] = value
+        end
+    end
+
+    return tab_concat(tmp, "")
+end
+
+
+-- check whether the request method match the user defined.
+function _M.match_method(conf, ctx)
+    for _, method in ipairs(conf.cache_method) do
+        if method == ctx.var.request_method then
+            return true
+        end
+    end
+
+    return false
+end
+
+
+-- check whether the response status match the user defined.
+function _M.match_status(conf, ctx)
+    for _, status in ipairs(conf.cache_http_status) do
+        if status == ngx.status then
+            return true
+        end
+    end
+
+    return false
+end
+
+
+function _M.file_exists(name)
+    local f = io_open(name, "r")
+    if f ~= nil then
+        io_close(f)
+        return true
+    end
+    return false
+end
+
+
+function _M.generate_cache_filename(cache_path, cache_levels, cache_key)
+    local md5sum = ngx.md5(cache_key)
+    local levels = ngx_re.split(cache_levels, ":")
+    local filename = ""
+
+    local index = #md5sum
+    for k, v in pairs(levels) do
+        local length = tonumber(v)
+        index = index - length
+        filename = filename .. md5sum:sub(index+1, index+length) .. "/"
+    end
+    if cache_path:sub(-1) ~= "/" then
+        cache_path = cache_path .. "/"
+    end
+    filename = cache_path .. filename .. md5sum
+    return filename
+end
+
+return _M
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index 1cdb76f..32ed56b 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -53,19 +53,22 @@ apisix:
   #lua_module_hook: "my_project.my_hook"  # the hook module which will be used 
to inject third party code into APISIX
 
   proxy_cache:                     # Proxy Caching configuration
-    cache_ttl: 10s                 # The default caching time if the upstream 
does not specify the cache time
+    cache_ttl: 10s                 # The default caching time in disk if the 
upstream does not specify the cache time
     zones:                         # The parameters of a cache
-      - name: disk_cache_one       # The name of the cache, administrator can 
be specify
-                                   # which cache to use by name in the admin 
api
-        memory_size: 50m           # The size of shared memory, it's used to 
store the cache index
-        disk_size: 1G              # The size of disk, it's used to store the 
cache data
-        disk_path: /tmp/disk_cache_one  # The path to store the cache data
-        cache_levels: 1:2        # The hierarchy levels of a cache
+      - name: disk_cache_one       # The name of the cache, administrator can 
specify
+                                   # which cache to use by name in the admin 
api (disk|memory)
+        memory_size: 50m           # The size of shared memory, it's used to 
store the cache index for
+                                   # disk strategy, store cache content for 
memory strategy (disk|memory)
+        disk_size: 1G              # The size of disk, it's used to store the 
cache data (disk)
+        disk_path: /tmp/disk_cache_one  # The path to store the cache data 
(disk)
+        cache_levels: 1:2        # The hierarchy levels of a cache (disk)
       #- name: disk_cache_two
       #  memory_size: 50m
       #  disk_size: 1G
       #  disk_path: "/tmp/disk_cache_two"
       #  cache_levels: "1:2"
+      - name: memory_cache
+        memory_size: 50m
 
   allow_admin:                  # 
http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
     - 127.0.0.0/24              # If we don't set any IP list, then any IP 
access is allowed by default.
diff --git a/docs/en/latest/plugins/proxy-cache.md 
b/docs/en/latest/plugins/proxy-cache.md
index 0fc3d69..2df2671 100644
--- a/docs/en/latest/plugins/proxy-cache.md
+++ b/docs/en/latest/plugins/proxy-cache.md
@@ -32,13 +32,16 @@ The proxy-cache plugin, which provides the ability to cache 
upstream response da
 
 | Name               | Type           | Requirement | Default                  
 | Valid                                                                        
   | Description                                                                
                                                                                
                                                                                
  |
 | ------------------ | -------------- | ----------- | 
------------------------- | 
------------------------------------------------------------------------------- 
| 
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 |
+| cache_strategy     | string         | optional    | disk                     
 | ["disk","memory"]                                                            
   | Cache strategy. Specify where the cache data is stored (memory or disk) |
 | cache_zone         | string         | optional    |  disk_cache_one          
 |                                                                              
   | Specify which cache area to use, each cache area can be configured with 
different paths. In addition, cache areas can be predefined in conf/config.yaml 
file. When the default value is not used, the specified cache area is 
inconsistent with the pre-defined cache area in the conf/config.yaml file, and 
the cache is invalid.  |
 | cache_key          | array[string]  | optional    | ["$host", 
"$request_uri"] |                                                               
                  | key of a cache, can use variables. For example: ["$host", 
"$uri", "-cache-id"]                                                            
                                                                                
                   |
 | cache_bypass       | array[string]  | optional    |                          
 |                                                                              
   | Whether to skip cache retrieval. That is, do not look for data in the 
cache. It can use variables, and note that cache data retrieval will be skipped 
when the value of this attribute is not empty or not '0'. For example: 
["$arg_bypass"] |
 | cache_method       | array[string]  | optional    | ["GET", "HEAD"]          
 | ["GET", "POST", "HEAD"] | Decide whether to be cached according to the 
request method                                                                  
                                                                                
                                |
 | cache_http_status  | array[integer] | optional    | [200, 301, 404]          
 | [200, 599]                                                                   
   | Decide whether to be cached according to the upstream response status      
                                                                                
                                                                                
  |
 | hide_cache_headers | boolean        | optional    | false                    
 |                                                                              
   | Whether to return the Expires and Cache-Control response headers to the 
client,                                                                         
                                                                                
     |
+| cache_control      | boolean        | optional    | false                    
 |                                                                              
   | Whether to comply with the cache-control behavior in the HTTP 
specification. Only for memory strategy. |
 | no_cache           | array[string]  | optional    |                          
 |                                                                              
   | Whether to cache data, it can use variables, and note that the data will 
not be cached when the value of this attribute is not empty or not '0'.         
                                                                                
    |
+| cache_ttl          | integer        | optional    | 300 seconds              
 |                                                                              
   | The default cache time. when the cache_control option is not enabled or 
the proxied server does not return cache header (cache-contorl or expires), it 
will be take effect.  Only for memory strategy. |
 
 Note:
 
diff --git a/docs/zh/latest/plugins/proxy-cache.md 
b/docs/zh/latest/plugins/proxy-cache.md
index c9ff8cd..bf3104e 100644
--- a/docs/zh/latest/plugins/proxy-cache.md
+++ b/docs/zh/latest/plugins/proxy-cache.md
@@ -32,13 +32,16 @@ title: proxy-cache
 
 | 名称               | 类型           | 必选项 | 默认值                    | 有效值         
                                                                 | 描述           
                                                                                
                                    |
 | ------------------ | -------------- | ------ | ------------------------- | 
------------------------------------------------------------------------------- 
| 
----------------------------------------------------------------------------------------------------------------------------------
 |
+| cache_strategy     | string         | 可选   | disk                      | 
["disk","memory"]                                                               
| 缓存策略,指定缓存数据存储在磁盘还是内存中 |
 | cache_zone         | string         | 可选   |        disk_cache_one     |     
                                                                            | 
指定使用哪个缓存区域,不同的缓存区域可以配置不同的路径,在 conf/config.yaml 
文件中可以预定义使用的缓存区域。当不使用默认值时,指定的缓存区域与 conf/config.yaml 文件中预定义的缓存区域不一致,缓存无效。   |
 | cache_key          | array[string]  | 可选   | ["$host", "$request_uri"] |     
                                                                            | 
缓存key,可以使用变量。例如:["$host", "$uri", "-cache-id"]                                  
                                      |
 | cache_bypass       | array[string]  | 可选   |                           |     
                                                                            | 
是否跳过缓存检索,即不在缓存中查找数据,可以使用变量,需要注意当此参数的值不为空或非'0'时将会跳过缓存的检索。例如:["$arg_bypass"] |
 | cache_method       | array[string]  | 可选   | ["GET", "HEAD"]           | 
["GET", "POST", "HEAD"] | 根据请求method决定是否需要缓存                                    
                                                                 |
 | cache_http_status  | array[integer] | 可选   | [200, 301, 404]           | 
[200, 599]                                                                      
| 根据响应码决定是否需要缓存                                                                 
                                        |
 | hide_cache_headers | boolean        | 可选   | false                     |     
                                                                            | 
是否将 Expires 和 Cache-Control 响应头返回给客户端                                           
                                      |
+| cache_control      | boolean        | 可选   | false                     |     
                                                                            | 
是否遵守 HTTP 协议规范中的 Cache-Control 的行为                                 |
 | no_cache           | array[string]  | 可选   |                           |     
                                                                            | 
是否缓存数据,可以使用变量,需要注意当此参数的值不为空或非'0'时将不会缓存数据                                        
              |
+| cache_ttl          | integer        | 可选   | 300 秒                    |      
                                                                           | 
当选项 cache_control 未开启或开启以后服务端没有返回缓存控制头时,提供的默认缓存时间    |
 
 注:变量以$开头,也可以使用变量和字符串的结合,但是需要以数组的形式分开写,最终变量被解析后会和字符串拼接在一起。
 
diff --git a/t/cli/test_main.sh b/t/cli/test_main.sh
index a4bb398..771d968 100755
--- a/t/cli/test_main.sh
+++ b/t/cli/test_main.sh
@@ -759,7 +759,11 @@ echo '
 apisix:
   proxy_cache:
     zones:
-      - disk_path: /tmp/disk_cache_one
+      - name: disk_cache_one
+        disk_path: /tmp/disk_cache_one
+        disk_size: 100m
+        memory_size: 20m
+        cache_levels: 1:2
 ' > conf/config.yaml
 
 make init
diff --git a/t/plugin/proxy-cache.t b/t/plugin/proxy-cache/disk.t
similarity index 96%
copy from t/plugin/proxy-cache.t
copy to t/plugin/proxy-cache/disk.t
index 1ea16ce..5f759d8 100644
--- a/t/plugin/proxy-cache.t
+++ b/t/plugin/proxy-cache/disk.t
@@ -53,6 +53,10 @@ add_block_preprocessor(sub {
 _EOC_
 
     $block->set_value("http_config", $http_config);
+
+    if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
+        $block->set_value("no_error_log", "[error]");
+    }
 });
 
 run_tests;
@@ -122,8 +126,6 @@ __DATA__
 GET /t
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
@@ -166,8 +168,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
 
 
 
@@ -211,8 +211,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
 
 
 
@@ -255,8 +253,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
 
 
 
@@ -299,8 +295,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
 
 
 
@@ -344,8 +338,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
 
 
 
@@ -359,6 +351,7 @@ qr/failed to check the configuration of plugin proxy-cache/
                     [[{
                         "plugins": {
                             "proxy-cache": {
+                               "cache_key":["$host","$uri"],
                                "cache_zone": "disk_cache_one",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
@@ -388,8 +381,6 @@ GET /t
 --- error_code: 200
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
@@ -400,8 +391,6 @@ GET /hello
 hello world!
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -414,8 +403,6 @@ hello world!
 Apisix-Cache-Status: HIT
 --- raw_response_headers_unlike
 Expires:
---- no_error_log
-[error]
 
 
 
@@ -426,8 +413,6 @@ GET /hello?bypass=1
 hello world!
 --- response_headers
 Apisix-Cache-Status: BYPASS
---- no_error_log
-[error]
 
 
 
@@ -435,8 +420,6 @@ Apisix-Cache-Status: BYPASS
 --- request
 PURGE /hello
 --- error_code: 200
---- no_error_log
-[error]
 
 
 
@@ -447,8 +430,6 @@ GET /hello?no_cache=1
 hello world!
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -461,8 +442,6 @@ hello world!
 Apisix-Cache-Status: MISS
 --- raw_response_headers_unlike
 Expires:
---- no_error_log
-[error]
 
 
 
@@ -473,8 +452,6 @@ GET /hello
 hello world!
 --- response_headers
 Apisix-Cache-Status: HIT
---- no_error_log
-[error]
 
 
 
@@ -486,8 +463,6 @@ GET /hello-not-found
 qr/404 Not Found/
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -499,8 +474,6 @@ GET /hello-not-found
 qr/404 Not Found/
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -510,8 +483,6 @@ HEAD /hello-world
 --- error_code: 200
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -521,8 +492,6 @@ HEAD /hello-world
 --- error_code: 200
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
@@ -565,8 +534,6 @@ GET /t
 --- error_code: 200
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
@@ -579,8 +546,6 @@ hello world!
 Apisix-Cache-Status: HIT
 --- response_headers_like
 Cache-Control:
---- no_error_log
-[error]
 
 
 
@@ -588,8 +553,6 @@ Cache-Control:
 --- request
 PURGE /hello
 --- error_code: 200
---- no_error_log
-[error]
 
 
 
@@ -597,8 +560,6 @@ PURGE /hello
 --- request
 PURGE /hello-world
 --- error_code: 404
---- no_error_log
-[error]
 
 
 
@@ -641,8 +602,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/cache_zone invalid_disk_cache not found/
---- no_error_log
-[error]
 
 
 
@@ -686,8 +645,6 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache err: cache_key 
variable \$request_method unsupported/
---- no_error_log
-[error]
 
 
 
@@ -719,8 +676,6 @@ qr/failed to check the configuration of plugin proxy-cache 
err: cache_key variab
 GET /t
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
@@ -735,8 +690,6 @@ Expires: any
 Apisix-Cache-Status: Foo
 Cache-Control: bar
 Expires: any
---- no_error_log
-[error]
 
 
 
@@ -779,5 +732,3 @@ GET /t
 --- error_code: 400
 --- response_body eval
 qr/failed to check the configuration of plugin proxy-cache err/
---- no_error_log
-[error]
diff --git a/t/plugin/proxy-cache.t b/t/plugin/proxy-cache/memory.t
similarity index 51%
rename from t/plugin/proxy-cache.t
rename to t/plugin/proxy-cache/memory.t
index 1ea16ce..ae80b71 100644
--- a/t/plugin/proxy-cache.t
+++ b/t/plugin/proxy-cache/memory.t
@@ -14,6 +14,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+BEGIN {
+    $ENV{TEST_NGINX_FORCE_RESTART_ON_TEST} = 0;
+}
+
 use t::APISIX 'no_plan';
 
 repeat_each(1);
@@ -22,6 +26,8 @@ no_shuffle();
 no_root_location();
 log_level('info');
 
+
+
 add_block_preprocessor(sub {
     my ($block) = @_;
 
@@ -30,6 +36,7 @@ add_block_preprocessor(sub {
     # for proxy cache
     proxy_cache_path /tmp/disk_cache_one levels=1:2 
keys_zone=disk_cache_one:50m inactive=1d max_size=1G;
     proxy_cache_path /tmp/disk_cache_two levels=1:2 
keys_zone=disk_cache_two:50m inactive=1d max_size=1G;
+    lua_shared_dict memory_cache 50m;
 
     # for proxy cache
     map \$upstream_cache_zone \$upstream_cache_zone_info {
@@ -43,6 +50,16 @@ add_block_preprocessor(sub {
 
         location / {
             expires 60s;
+
+            if (\$arg_expires) {
+                expires \$arg_expires;
+            }
+
+            if (\$arg_cc) {
+                expires off;
+                add_header Cache-Control \$arg_cc;
+            }
+
             return 200 "hello world!";
         }
 
@@ -53,125 +70,17 @@ add_block_preprocessor(sub {
 _EOC_
 
     $block->set_value("http_config", $http_config);
+
+    if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
+        $block->set_value("no_error_log", "[error]");
+    }
 });
 
 run_tests;
 
 __DATA__
 
-=== TEST 1: sanity check (missing cache_zone field, the default value is 
disk_cache_one)
---- config
-       location /t {
-           content_by_lua_block {
-               local t = require("lib.test_admin").test
-               local code, body = t('/apisix/admin/routes/1',
-                    ngx.HTTP_PUT,
-                    [[{
-                        "plugins": {
-                            "proxy-cache": {
-                               "cache_bypass": ["$arg_bypass"],
-                               "cache_method": ["GET"],
-                               "cache_http_status": [200],
-                               "hide_cache_headers": true,
-                               "no_cache": ["$arg_no_cache"]
-                            }
-                        },
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1980": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/hello"
-                   }]],
-                   [[{
-                       "node": {
-                        "value": {
-                            "uri": "/hello",
-                            "upstream": {
-                                "nodes": {
-                                    "127.0.0.1:1980": 1
-                                },
-                                "type": "roundrobin"
-                            },
-                            "plugins": {
-                                "proxy-cache":{
-                                    "cache_zone":"disk_cache_one",
-                                    "hide_cache_headers":true,
-                                    "cache_bypass":["$arg_bypass"],
-                                    "cache_key":["$host","$request_uri"],
-                                    "no_cache":["$arg_no_cache"],
-                                    "cache_http_status":[200],
-                                    "cache_method":["GET"]
-                                }
-                            }
-                        },
-                        "key": "/apisix/routes/1"
-                        },
-                        "action": "set"
-                   }]]
-                   )
-
-               if code >= 300 then
-                   ngx.status = code
-               end
-               ngx.say(body)
-           }
-       }
---- request
-GET /t
---- response_body
-passed
---- no_error_log
-[error]
-
-
-
-=== TEST 2: sanity check (invalid type for cache_method)
---- config
-       location /t {
-           content_by_lua_block {
-               local t = require("lib.test_admin").test
-               local code, body = t('/apisix/admin/routes/1',
-                    ngx.HTTP_PUT,
-                    [[{
-                        "plugins": {
-                            "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
-                               "cache_bypass": ["$arg_bypass"],
-                               "cache_method": "GET",
-                               "cache_http_status": [200],
-                               "hide_cache_headers": true,
-                               "no_cache": ["$arg_no_cache"]
-                            }
-                        },
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1980": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/hello"
-                   }]]
-                   )
-
-               if code >= 300 then
-                   ngx.status = code
-               end
-               ngx.say(body)
-           }
-       }
---- request
-GET /t
---- error_code: 400
---- response_body eval
-qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
-
-
-
-=== TEST 3: sanity check (invalid type for cache_key)
+=== TEST 1: sanity check (invalid cache strategy)
 --- config
        location /t {
            content_by_lua_block {
@@ -181,8 +90,9 @@ qr/failed to check the configuration of plugin proxy-cache/
                     [[{
                         "plugins": {
                             "proxy-cache": {
+                               "cache_strategy": "network",
+                               "cache_key":["$host","$uri"],
                                "cache_zone": "disk_cache_one",
-                               "cache_key": "${uri}-cache-key",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
                                "cache_http_status": [200],
@@ -192,99 +102,11 @@ qr/failed to check the configuration of plugin 
proxy-cache/
                         },
                         "upstream": {
                             "nodes": {
-                                "127.0.0.1:1985": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/hello"
-                   }]]
-                   )
-
-               if code >= 300 then
-                   ngx.status = code
-               end
-               ngx.say(body)
-           }
-       }
---- request
-GET /t
---- error_code: 400
---- response_body eval
-qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
-
-
-
-=== TEST 4: sanity check (invalid type for cache_bypass)
---- config
-       location /t {
-           content_by_lua_block {
-               local t = require("lib.test_admin").test
-               local code, body = t('/apisix/admin/routes/1',
-                    ngx.HTTP_PUT,
-                    [[{
-                        "plugins": {
-                            "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
-                               "cache_bypass": "$arg_bypass",
-                               "cache_method": ["GET"],
-                               "cache_http_status": [200],
-                               "hide_cache_headers": true,
-                               "no_cache": ["$arg_no_cache"]
-                            }
-                        },
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1985": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/hello"
-                   }]]
-                   )
-
-               if code >= 300 then
-                   ngx.status = code
-               end
-               ngx.say(body)
-           }
-       }
---- request
-GET /t
---- error_code: 400
---- response_body eval
-qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
-
-
-
-=== TEST 5: sanity check (invalid type for no_cache)
---- config
-       location /t {
-           content_by_lua_block {
-               local t = require("lib.test_admin").test
-               local code, body = t('/apisix/admin/routes/1',
-                    ngx.HTTP_PUT,
-                    [[{
-                        "plugins": {
-                            "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
-                               "cache_bypass": ["$arg_bypass"],
-                               "cache_method": ["GET"],
-                               "cache_http_status": [200],
-                               "hide_cache_headers": true,
-                               "no_cache": "$arg_no_cache"
-                            }
-                        },
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1985": 1
+                                "127.0.0.1:1986": 1
                             },
                             "type": "roundrobin"
                         },
-                        "uri": "/hello"
+                        "uri": "/hello*"
                    }]]
                    )
 
@@ -298,13 +120,11 @@ qr/failed to check the configuration of plugin 
proxy-cache/
 GET /t
 --- error_code: 400
 --- response_body eval
-qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
+qr/failed to check the configuration of plugin proxy-cache err: property 
\\"cache_strategy\\" validation failed: matches none of the enum values/
 
 
 
-=== TEST 6: sanity check (illegal character for cache_key)
+=== TEST 2: sanity check (invalid cache_zone when specifying cache_strategy as 
memory)
 --- config
        location /t {
            content_by_lua_block {
@@ -314,8 +134,9 @@ qr/failed to check the configuration of plugin proxy-cache/
                     [[{
                         "plugins": {
                             "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
-                               "cache_key": ["$uri-", "-cache-id"],
+                               "cache_strategy": "memory",
+                               "cache_key":["$host","$uri"],
+                               "cache_zone": "invalid_cache_zone",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
                                "cache_http_status": [200],
@@ -325,11 +146,11 @@ qr/failed to check the configuration of plugin 
proxy-cache/
                         },
                         "upstream": {
                             "nodes": {
-                                "127.0.0.1:1985": 1
+                                "127.0.0.1:1986": 1
                             },
                             "type": "roundrobin"
                         },
-                        "uri": "/hello"
+                        "uri": "/hello*"
                    }]]
                    )
 
@@ -343,13 +164,11 @@ qr/failed to check the configuration of plugin 
proxy-cache/
 GET /t
 --- error_code: 400
 --- response_body eval
-qr/failed to check the configuration of plugin proxy-cache/
---- no_error_log
-[error]
+qr/failed to check the configuration of plugin proxy-cache err: cache_zone 
invalid_cache_zone not found"/
 
 
 
-=== TEST 7: sanity check (normal case)
+=== TEST 3: sanity check (normal case for memory strategy)
 --- config
        location /t {
            content_by_lua_block {
@@ -359,11 +178,14 @@ qr/failed to check the configuration of plugin 
proxy-cache/
                     [[{
                         "plugins": {
                             "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
+                               "cache_strategy": "memory",
+                               "cache_key":["$host","$uri"],
+                               "cache_zone": "memory_cache",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
+                               "hide_cache_headers": false,
+                               "cache_ttl": 300,
                                "cache_http_status": [200],
-                               "hide_cache_headers": true,
                                "no_cache": ["$arg_no_cache"]
                             }
                         },
@@ -388,71 +210,57 @@ GET /t
 --- error_code: 200
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
-=== TEST 8: hit route (cache miss)
+=== TEST 4: hit route (cache miss)
 --- request
 GET /hello
 --- response_body chop
 hello world!
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 9: hit route (cache hit)
+=== TEST 5: hit route (cache hit)
 --- request
 GET /hello
 --- response_body chop
 hello world!
 --- response_headers
 Apisix-Cache-Status: HIT
---- raw_response_headers_unlike
-Expires:
---- no_error_log
-[error]
 
 
 
-=== TEST 10: hit route (cache bypass)
+=== TEST 6: hit route (cache bypass)
 --- request
 GET /hello?bypass=1
 --- response_body chop
 hello world!
 --- response_headers
 Apisix-Cache-Status: BYPASS
---- no_error_log
-[error]
 
 
 
-=== TEST 11: purge cache
+=== TEST 7: purge cache
 --- request
 PURGE /hello
 --- error_code: 200
---- no_error_log
-[error]
 
 
 
-=== TEST 12: hit route (nocache)
+=== TEST 8: hit route (nocache)
 --- request
 GET /hello?no_cache=1
 --- response_body chop
 hello world!
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 13: hit route (there's no cache indeed)
+=== TEST 9: hit route (there's no cache indeed)
 --- request
 GET /hello
 --- response_body chop
@@ -461,24 +269,20 @@ hello world!
 Apisix-Cache-Status: MISS
 --- raw_response_headers_unlike
 Expires:
---- no_error_log
-[error]
 
 
 
-=== TEST 14: hit route (will be cached)
+=== TEST 10: hit route (will be cached)
 --- request
 GET /hello
 --- response_body chop
 hello world!
 --- response_headers
 Apisix-Cache-Status: HIT
---- no_error_log
-[error]
 
 
 
-=== TEST 15: hit route (not found)
+=== TEST 11: hit route (not found)
 --- request
 GET /hello-not-found
 --- error_code: 404
@@ -486,12 +290,10 @@ GET /hello-not-found
 qr/404 Not Found/
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 16: hit route (404 there's no cache indeed)
+=== TEST 12: hit route (404 there's no cache indeed)
 --- request
 GET /hello-not-found
 --- error_code: 404
@@ -499,34 +301,42 @@ GET /hello-not-found
 qr/404 Not Found/
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 17: hit route (HEAD method)
+=== TEST 13: hit route (HEAD method)
 --- request
 HEAD /hello-world
 --- error_code: 200
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 18: hit route (HEAD method there's no cache)
+=== TEST 14: hit route (HEAD method there's no cache)
 --- request
 HEAD /hello-world
 --- error_code: 200
 --- response_headers
 Apisix-Cache-Status: MISS
---- no_error_log
-[error]
 
 
 
-=== TEST 19:  hide cache headers = false
+=== TEST 15: purge cache
+--- request
+PURGE /hello
+--- error_code: 200
+
+
+
+=== TEST 16: purge cache (not found)
+--- request
+PURGE /hello-world
+--- error_code: 404
+
+
+
+=== TEST 17:  hide cache headers = false
 --- config
        location /t {
            content_by_lua_block {
@@ -536,9 +346,12 @@ Apisix-Cache-Status: MISS
                     [[{
                         "plugins": {
                             "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
+                               "cache_strategy": "memory",
+                               "cache_key":["$host","$uri"],
+                               "cache_zone": "memory_cache",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
+                               "cache_ttl": 300,
                                "cache_http_status": [200],
                                "hide_cache_headers": false,
                                "no_cache": ["$arg_no_cache"]
@@ -565,44 +378,22 @@ GET /t
 --- error_code: 200
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
-=== TEST 20: hit route (catch the cache headers)
+=== TEST 18: hit route (catch the cache headers)
 --- request
 GET /hello
 --- response_body chop
 hello world!
 --- response_headers
-Apisix-Cache-Status: HIT
+Apisix-Cache-Status: MISS
 --- response_headers_like
 Cache-Control:
---- no_error_log
-[error]
-
-
-
-=== TEST 21: purge cache
---- request
-PURGE /hello
---- error_code: 200
---- no_error_log
-[error]
 
 
 
-=== TEST 22: purge cache (not found)
---- request
-PURGE /hello-world
---- error_code: 404
---- no_error_log
-[error]
-
-
-
-=== TEST 23:  invalid cache zone
+=== TEST 19: don't override cache relative headers
 --- config
        location /t {
            content_by_lua_block {
@@ -610,23 +401,13 @@ PURGE /hello-world
                local code, body = t('/apisix/admin/routes/1',
                     ngx.HTTP_PUT,
                     [[{
-                        "plugins": {
-                            "proxy-cache": {
-                               "cache_zone": "invalid_disk_cache",
-                               "cache_bypass": ["$arg_bypass"],
-                               "cache_method": ["GET"],
-                               "cache_http_status": [200],
-                               "hide_cache_headers": false,
-                               "no_cache": ["$arg_no_cache"]
-                            }
-                        },
                         "upstream": {
                             "nodes": {
-                                "127.0.0.1:1986": 1
+                                "127.0.0.1:1980": 1
                             },
                             "type": "roundrobin"
                         },
-                        "uri": "/hello*"
+                        "uri": "/echo"
                    }]]
                    )
 
@@ -638,15 +419,26 @@ PURGE /hello-world
        }
 --- request
 GET /t
---- error_code: 400
---- response_body eval
-qr/cache_zone invalid_disk_cache not found/
---- no_error_log
-[error]
+--- response_body
+passed
+
+
+
+=== TEST 20: hit route
+--- request
+GET /echo
+--- more_headers
+Apisix-Cache-Status: Foo
+Cache-Control: bar
+Expires: any
+--- response_headers
+Apisix-Cache-Status: Foo
+Cache-Control: bar
+Expires: any
 
 
 
-=== TEST 24: sanity check (invalid variable for cache_key)
+=== TEST 21:  set cache_ttl to 1
 --- config
        location /t {
            content_by_lua_block {
@@ -656,22 +448,24 @@ qr/cache_zone invalid_disk_cache not found/
                     [[{
                         "plugins": {
                             "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
-                               "cache_key": ["$uri", "$request_method"],
+                               "cache_strategy": "memory",
+                               "cache_key":["$host","$uri"],
+                               "cache_zone": "memory_cache",
                                "cache_bypass": ["$arg_bypass"],
                                "cache_method": ["GET"],
+                               "cache_ttl": 2,
                                "cache_http_status": [200],
-                               "hide_cache_headers": true,
+                               "hide_cache_headers": false,
                                "no_cache": ["$arg_no_cache"]
                             }
                         },
                         "upstream": {
                             "nodes": {
-                                "127.0.0.1:1985": 1
+                                "127.0.0.1:1986": 1
                             },
                             "type": "roundrobin"
                         },
-                        "uri": "/hello"
+                        "uri": "/hello*"
                    }]]
                    )
 
@@ -683,64 +477,44 @@ qr/cache_zone invalid_disk_cache not found/
        }
 --- request
 GET /t
---- error_code: 400
---- response_body eval
-qr/failed to check the configuration of plugin proxy-cache err: cache_key 
variable \$request_method unsupported/
---- no_error_log
-[error]
+--- error_code: 200
+--- response_body
+passed
 
 
 
-=== TEST 25: don't override cache relative headers
---- config
-       location /t {
-           content_by_lua_block {
-               local t = require("lib.test_admin").test
-               local code, body = t('/apisix/admin/routes/1',
-                    ngx.HTTP_PUT,
-                    [[{
-                        "upstream": {
-                            "nodes": {
-                                "127.0.0.1:1980": 1
-                            },
-                            "type": "roundrobin"
-                        },
-                        "uri": "/echo"
-                   }]]
-                   )
+=== TEST 22: hit route (MISS)
+--- request
+GET /hello
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: MISS
 
-               if code >= 300 then
-                   ngx.status = code
-               end
-               ngx.say(body)
-           }
-       }
+
+
+=== TEST 23: hit route (HIT)
 --- request
-GET /t
---- response_body
-passed
---- no_error_log
-[error]
+GET /hello
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: HIT
+--- wait: 2
 
 
 
-=== TEST 26: hit route
+=== TEST 24: hit route (MISS)
 --- request
-GET /echo
---- more_headers
-Apisix-Cache-Status: Foo
-Cache-Control: bar
-Expires: any
+GET /hello
+--- response_body chop
+hello world!
 --- response_headers
-Apisix-Cache-Status: Foo
-Cache-Control: bar
-Expires: any
---- no_error_log
-[error]
+Apisix-Cache-Status: MISS
 
 
 
-=== TEST 27: sanity check (invalid method for cache_method)
+=== TEST 25:  enable cache_control option
 --- config
        location /t {
            content_by_lua_block {
@@ -750,21 +524,25 @@ Expires: any
                     [[{
                         "plugins": {
                             "proxy-cache": {
-                               "cache_zone": "disk_cache_one",
+                               "cache_strategy": "memory",
+                               "cache_key":["$host","$uri"],
+                               "cache_zone": "memory_cache",
                                "cache_bypass": ["$arg_bypass"],
-                               "cache_method": ["GET", "PUT"],
+                               "cache_control": true,
+                               "cache_method": ["GET"],
+                               "cache_ttl": 10,
                                "cache_http_status": [200],
-                               "hide_cache_headers": true,
+                               "hide_cache_headers": false,
                                "no_cache": ["$arg_no_cache"]
                             }
                         },
                         "upstream": {
                             "nodes": {
-                                "127.0.0.1:1980": 1
+                                "127.0.0.1:1986": 1
                             },
                             "type": "roundrobin"
                         },
-                        "uri": "/hello"
+                        "uri": "/hello*"
                    }]]
                    )
 
@@ -776,8 +554,114 @@ Expires: any
        }
 --- request
 GET /t
---- error_code: 400
---- response_body eval
-qr/failed to check the configuration of plugin proxy-cache err/
---- no_error_log
-[error]
+--- error_code: 200
+--- response_body
+passed
+
+
+
+=== TEST 26: hit route (MISS)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: max-age=60
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: MISS
+--- wait: 1
+
+
+
+=== TEST 27: hit route (request header cache-control with max-age)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: max-age=1
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: STALE
+
+
+
+=== TEST 28: hit route  (request header cache-control with min-fresh)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: min-fresh=300
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: STALE
+--- wait: 1
+
+
+
+=== TEST 29: purge cache
+--- request
+PURGE /hello
+--- error_code: 200
+
+
+
+=== TEST 30: hit route  (request header cache-control with no-store)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: no-store
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: BYPASS
+
+
+
+=== TEST 31: hit route  (request header cache-control with no-cache)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: no-cache
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: BYPASS
+
+
+
+=== TEST 32: hit route  (response header cache-control with private)
+--- request
+GET /hello?cc=private
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: MISS
+
+
+
+=== TEST 33: hit route  (response header cache-control with no-store)
+--- request
+GET /hello?cc=no-store
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: MISS
+
+
+
+=== TEST 34: hit route  (response header cache-control with no-cache)
+--- request
+GET /hello?cc=no-cache
+--- response_body chop
+hello world!
+--- response_headers
+Apisix-Cache-Status: MISS
+
+
+
+=== TEST 35: hit route  (request header cache-control with only-if-cached)
+--- request
+GET /hello
+--- more_headers
+Cache-Control: only-if-cached
+--- error_code: 504

Reply via email to